How to rotate a div across the axis of an svg circle - css

I have a black circle and a small red circle on the axis of the bigger one:
Both are created with simple svg code:
export default function App() {
return (
<div>
<svg className="main-svg" viewBox="0 0 100 100">
<circle pathLength="25" cx="50%" cy="50%" r="50%" />
</svg>
<svg viewBox="0 0 100 100">
<circle
className="small-circle"
transform-origin="center"
fill="green"
pathLength="25.5"
cx="50%"
cy="50%"
r="50%"
/>
</svg>
</div>
);
}
It's easy to rotate the smaller one, because both circles have the same radius so you just need to change the degree:
svg {
position: absolute;
}
.small-circle {
transform: rotate(20deg);
stroke-linecap: round;
stroke-width: 5;
stroke-dasharray: 0 25;
stroke-dashoffset: -2.5;
fill: none;
stroke: red;
}
However I would like to insert some content into that red circle svg, namely use a div, and to my knowledge it's very difficult to do with svg. How can I create a rotating div instead of the red svg, hopefully without constant pixel values to it's sizable like the svgs?
The code on stackblitz: https://stackblitz.com/edit/react-ts-fwmjzn?file=style.css

Although <foreignObject can be inserted to SVG, It's hard to implement your requirement.
Because of .small-circle is rendered by stroke, it's hard to locate x and y's positions when it is rotating.
Maybe using div and CSS3 is a good implement.
https://stackblitz.com/edit/react-ts-iq2aqm?file=App.tsx,style.css,index.tsx
import * as React from 'react';
import './style.css';
export default function App() {
return (
<div className="container">
<svg className="main-svg" viewBox="0 0 100 100">
<circle pathLength="25" cx="50%" cy="50%" r="50%" />
</svg>
<div className="small-circle">A</div>
</div>
);
}
h1,
p {
font-family: Lato;
}
body {
margin: 0;
}
.container {
position: relative;
outline: 1px solid red;
}
#keyframes rotate {
to {
transform: rotate(1turn);
}
}
.small-circle {
width: 5vw;
height: 5vw;
border-radius: 50%;
background-color: coral;
top: 50%;
margin-top: -2.5vw;
margin-left: -2.5vw;
position: absolute;
outline: 1px solid red;
transform-origin: 52.5vw center;
animation: rotate 8s linear infinite;
text-align: center;
}
hope help you.

Related

Why does the svg shape dissapear after setting the transform-origin to 50%? [duplicate]

This question already has an answer here:
How to use transform-origin in conjunction with SVGs? [duplicate]
(1 answer)
Closed last month.
Transform-origin 50% 50% sets the center of scaling to the center of the element. So when I scale the element, it should just scale from the circles center meaning, the viewbox stays in place, and only the element scales from the elements center, but that's not what is happening. Is this actually setting the point of origin for the whole viewbox of the element?
svg{
border: 1px solid red;
}
circle{
fill: red;
fill-opacity: 50%;
stroke: red;
stroke-width: 1px;
}
circle:hover{
transform:scale(2);
transform-origin: 50% 50%;
}
<svg width="800" height="600" viewBox="0 0 800 600">
<circle cx="50" cy="50" r="20"/>
</svg>
Here, I tried to explain both the problem and possible solution. I have considered 50px 50px in the transform. Because, it is the dimension of the circle. Hope this helps.. Good luck!
svg {
border: 1px solid red;
}
circle {
fill: red;
fill-opacity: 50%;
stroke: red;
stroke-width: 1px;
}
.problem circle:hover {
transform: scale(2);
transform-origin: 50% 50%;
}
.solution circle:hover {
transform: scale(2);
transform-origin: 50px 50px;
}
<svg class="problem" width="200" height="200" viewBox="0 0 200 200">
<circle cx="50" cy="50" r="20"/>
</svg>
<svg class="solution" width="200" height="200" viewBox="0 0 200 200">
<circle cx="50" cy="50" r="20"/>
</svg>

Firefox transform-origin on SVG still broken

When we apply a 2D CSS rotation to an SVG shape in Firefox (I'm on 63.0.1 - latest version), it gets misaligned. There are plenty of questions on this topic, eg. Setting transform-origin on SVG group not working in FireFox
I'm not seeing it as fixed, but perhaps I'm missing something. Best to look at my CodePen first: https://codepen.io/MSCAU/pen/GwozbO
Here's the gist of it:
circle {
fill: none;
transform-origin: center;
// transform-origin: 6px 6px; /* Makes no difference */
// transform-box: fill-box; /* Makes no difference */
}
circle:nth-child(1) {
stroke: red;
stroke-width: 2;
}
circle:nth-child(2) {
stroke: blue;
stroke-width: 1;
transform: rotate(-90deg);
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" width="120" height="120">
<circle cx="6" cy="6" r="5"/>
<circle cx="6" cy="6" r="5"/>
</svg>

How to make an svg text's position depend on another text's position?

Here is an SVG with two texts one below the other. I need to keep the first text always at a fixed position from the next text, And it would be better if this gap could be responsive, that is, it should decrease if size of svg is reduced, and increase accordingly as well.
I searched a lot and found a lot of answers that went over my head.
Cant we do something that looks like y=".text--line2.y" ?
Here is the svg:
.text--line {
font-size: .5em;
}
svg {
background: black;
position: absolute;
width: 100%;
height: 100%;
font: 5em/1 Arial;
}
.text-copy {
fill: none;
stroke: white;
stroke-dasharray: 7% 28%;
stroke-width: 3px;
}
.text-copy:nth-child(1) {
stroke: #cccccc;
stroke-dashoffset: 7%;
}
.text-copy:nth-child(2) {
stroke: #ffffff;
stroke-dashoffset: 14%;
}
.text-copy:nth-child(3) {
stroke: #eeeeee;
stroke-dashoffset: 21%;
}
.text-copy:nth-child(4) {
stroke: #aaaaaa;
stroke-dashoffset: 28%;
}
.text-copy:nth-child(5) {
stroke: #bbbbbb;
stroke-dashoffset: 35%;
}
#-webkit-keyframes stroke-offset {
50% {
stroke-dashoffset: 35%;
stroke-dasharray: 0 87.5%;
}
}
#keyframes stroke-offset {
50% {
stroke-dashoffset: 35%;
stroke-dasharray: 0 87.5%;
}
}
<svg viewBox="0 0 800px 600px">
<symbol id="s-text">
<text text-anchor="middle" x="42%" class="text--line" y="40%">
sdsds
</text>
<text text-anchor="middle" x="50%" y="68%" class="text--line2">
gfgfg
</text>
</symbol>
<g class="g-ants">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#s-text" class="text-copy"></use>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#s-text" class="text-copy"></use>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#s-text" class="text-copy"></use>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#s-text" class="text-copy"></use>
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#s-text" class="text-copy"></use>
</g>
</svg>
You can position parts of a string with the dx and dy attributes. The attribute describes the position of the next tspan relative to the end of the previous one. Imagine it like this: initially, "abcde" and "fghij" would be rendered in one line, next to each other. Setting a dx/dy then moves the "fghij" by that amount.
Remember that whitespace also results in a horizontal advance. If you use percentage values, they are in relation to the size of the viewport (the <svg> element, not its viewBox).
.text--line {
font-size: .5em;
}
svg {
position: absolute;
width: 100%;
height: 100%;
font: 5em/1 Arial;
}
<svg viewBox="0 0 800px 600px">
<text text-anchor="middle">
<tspan x="42%" y="40%" class="text--line">abcde</tspan><tspan
dx="-7%" dy="30%" class="text--line2">fghij</tspan>
</text>
</svg>

I can manipulate only fill value on my svg's path with css

So when i set fill to red i get this: . And when i get fill to none, i get as expected this: . So, I selected the svg and path properly. However, i can't manipulate the stroke values. Why? (The 'className' attributes is reactJs thing)
CSS:
svg.logo {
height: 26px;
width: 40px;
stroke-dasharray: 14;
stroke-dashoffset: 1;
transition: all 1s ease-in-out;
.logo-path {
width: 26px;
fill: none;
stroke: '#E15E94';
stroke-opacity: 1;
stroke-width: 2px;
}
}
SVG:
<svg className="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44.63 68.2" ><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"> <path className="logo-path" d="M22.83,66.2A22.43,22.43,0,0,1,7.45,60C3.43,56.3,1,51.35.9,46.79.75,38.5,8.31,32.85,15,27.85q2.14-1.6,4.43-3l-.93-.46c-2.92-1.44-5.89-2.9-8.56-4.48A18.47,18.47,0,0,1,6.33,21.4a18.37,18.37,0,0,1-5.1.66,1.25,1.25,0,0,1,0-2.5h.22A15.55,15.55,0,0,0,5.66,19a14.27,14.27,0,0,0,1.77-.66,21.61,21.61,0,0,1-5.05-4.58A8.71,8.71,0,0,1,.46,8.68,8.45,8.45,0,0,1,5.27.85a9.3,9.3,0,0,1,8.56.42,8.68,8.68,0,0,1,4.12,7.17A9.3,9.3,0,0,1,16.84,13a14.69,14.69,0,0,1-4.55,5.43c2.3,1.3,4.81,2.54,7.29,3.75L22,23.35a62,62,0,0,1,17.86-6.29,1.25,1.25,0,1,1,.47,2.46,60,60,0,0,0-15.6,5.23c1.43.75,2.82,1.52,4.1,2.32C33.49,30,44.39,36.72,44.63,46.31c.22,8.88-8.57,19.26-20.67,19.86Zm-.76-40a54.26,54.26,0,0,0-5.59,3.67C10,34.71,3.27,39.74,3.4,46.74c.07,3.9,2.22,8.19,5.75,11.48a20,20,0,0,0,14.68,5.45c10.7-.54,18.48-9.58,18.29-17.31-.2-8.24-10.29-14.5-14.6-17.17C25.86,28.16,24,27.16,22.07,26.18ZM9.14,2.5a6.61,6.61,0,0,0-2.8.61A5.94,5.94,0,0,0,3,8.62a6.19,6.19,0,0,0,1.41,3.62A21.21,21.21,0,0,0,9.93,17a12.67,12.67,0,0,0,4.65-5.09,6.93,6.93,0,0,0,.87-3.38,6.07,6.07,0,0,0-2.89-5.1A6.77,6.77,0,0,0,9.14,2.5Z" /></g></g></svg>
There are a few problems with your code:
If what you posted is indeed CSS, nesting is invalid. It's only allowed in SCSS which gets pre-processed into valid CSS (by concatenating the selectors). So use:
svg.logo { ... }
svg.logo .logo-path { ... }
... in CSS.
If the final HTML markup is the one you posted in your question, className="logo" will never be matched by .logo {}.
Either use class="logo" on the element or [className="logo"]{} in CSS. Obviously, same goes for className="logo-path", on the <path>.
Don't quote color values in CSS. Use stroke:#E15E94;
Here it is:
svg.logo {
width: 40px;
stroke-dasharray: 14;
stroke-dashoffset: 1;
transition: all 1s ease-in-out;
}
svg.logo .logo-path {
stroke:#E15E94;
width: 26px;
fill: none;
stroke-opacity: 1;
stroke-width: 2px;
}
<svg class="logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44.63 68.2">
<path class="logo-path" d="M22.83,66.2A22.43,22.43,0,0,1,7.45,60C3.43,56.3,1,51.35.9,46.79.75,38.5,8.31,32.85,15,27.85q2.14-1.6,4.43-3l-.93-.46c-2.92-1.44-5.89-2.9-8.56-4.48A18.47,18.47,0,0,1,6.33,21.4a18.37,18.37,0,0,1-5.1.66,1.25,1.25,0,0,1,0-2.5h.22A15.55,15.55,0,0,0,5.66,19a14.27,14.27,0,0,0,1.77-.66,21.61,21.61,0,0,1-5.05-4.58A8.71,8.71,0,0,1,.46,8.68,8.45,8.45,0,0,1,5.27.85a9.3,9.3,0,0,1,8.56.42,8.68,8.68,0,0,1,4.12,7.17A9.3,9.3,0,0,1,16.84,13a14.69,14.69,0,0,1-4.55,5.43c2.3,1.3,4.81,2.54,7.29,3.75L22,23.35a62,62,0,0,1,17.86-6.29,1.25,1.25,0,1,1,.47,2.46,60,60,0,0,0-15.6,5.23c1.43.75,2.82,1.52,4.1,2.32C33.49,30,44.39,36.72,44.63,46.31c.22,8.88-8.57,19.26-20.67,19.86Zm-.76-40a54.26,54.26,0,0,0-5.59,3.67C10,34.71,3.27,39.74,3.4,46.74c.07,3.9,2.22,8.19,5.75,11.48a20,20,0,0,0,14.68,5.45c10.7-.54,18.48-9.58,18.29-17.31-.2-8.24-10.29-14.5-14.6-17.17C25.86,28.16,24,27.16,22.07,26.18ZM9.14,2.5a6.61,6.61,0,0,0-2.8.61A5.94,5.94,0,0,0,3,8.62a6.19,6.19,0,0,0,1.41,3.62A21.21,21.21,0,0,0,9.93,17a12.67,12.67,0,0,0,4.65-5.09,6.93,6.93,0,0,0,.87-3.38,6.07,6.07,0,0,0-2.89-5.1A6.77,6.77,0,0,0,9.14,2.5Z" />
</svg>

How to create reuleaux triangle shape using CSS3

I need a help to make reuleaux triangle shape using CSS3 like below the image. The shape has a white border around. How is it possible?
CSS is not the right tool for creating such shapes even though they can be created using it. They will require multiple real/pseudo-elements, transforms etc and even then maintenance of the curves, their radii etc are very tricky. It gets even more complex when you require borders around them or have to place images or gradients inside them.
The best and recommended tool for creating such shapes is SVG as they have the following pros:
SVGs are scalable by nature and so are very good for responsive designs
SVG shapes can take images or gradients as fills
Curve and radii control is very optimum
Below is a sample snippet for creating the reuleaux triangle shape using SVG. All it needs is a single path element with 3 Quadratic Curveto commands.
svg {
height: 200px;
width: 200px;
}
path {
fill: steelblue;
stroke: white;
stroke-width: 2;
}
path.image {
fill: url(#g-image);
}
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<svg viewBox="0 0 105 105" preserveAspectRatio="none">
<path d="M2,15 q50,-25 100,0 q0,50 -50,85 q-50,-30 -50,-85z" />
</svg>
<svg viewBox="0 0 105 105" preserveAspectRatio="none">
<defs>
<pattern id="g-image" width="1" height="1" patternUnits="objectBoundingBox">
<image xlink:href="http://lorempixel.com/200/200/nature/4" width="200" height="200" />
</pattern>
</defs>
<path d="M2,15 q50,-25 100,0 q0,50 -50,85 q-50,-30 -50,-85z" class="image" />
</svg>
The same can be achieved by using CSS Clip-path with inline SVG for the path also but the support is non-existent in IE for this and hence it is not recommended.
div {
position: relative;
background: white;
height: 200px;
width: 200px;
-webkit-clip-path: url(#clipper);
clip-path: url(#clipper);
}
div:after {
position: absolute;
content: '';
height: calc(100% - 4px);
width: calc(100% - 4px);
top: 2px;
left: 2px;
background: steelblue;
-webkit-clip-path: url(#clipper);
clip-path: url(#clipper);
}
div.image:after{
background: url(http://lorempixel.com/200/200);
}
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
/* Just for demo */
div{
display: inline-block;
}
<svg width="0" height="0">
<defs>
<clipPath id="clipper" clipPathUnits="objectBoundingBox">
<path d="M0,0.15 q0.5,-0.25 1,0 q0,0.5 -0.5,0.85 q-0.5,-0.3 -0.5,-0.85z" />
</clipPath>
</defs>
</svg>
<div></div>
<div class='image'></div>
SVG solution
svg {
border: 1px solid black;
}
<svg width="400px" viewBox="0 0 100 100">
<path stroke="black" d="m50 90,
q -40 -20, -40 -80,
q 40 -10, 80 0,
q 0 60, -40 80z" />
</svg>
This shape is possible with pure CSS in a single element with a little bit of creativity.
It is not exactly the shape as above as it has rounded corners but its still pretty darn close.
div {
width: 200px;
height: 200px;
background: blue;
border-radius: 75% 75% 80% 80% / 15% 15% 150% 150%;
}
<div></div>
Here is another possible way to do it
div {
width: 200px;
height: 200px;
background: blue;
border-radius: 10% 100% 100% 0 / 100% 100% 10% 0;
transform: rotate(-45deg);
margin-left: 50px;
}
<div></div>

Resources