How to make an svg circle with edge divided into 3 parts? - css

I'm trying to create a circle with only its edge, divided into 3 parts.
The result of my attempt:
Not great, what I'm trying to do is have those 3 parts come together to form the edge of a circle, while having some space between each part (as you can see on the left, that gap is what it should look like)
I'm doing this using svg with 3 paths:
<svg viewBox="0 0 100 100">
<linearGradient id="gradient" x1="0" y1="0" x2="0" y2="100%">
<stop offset="0%" stop-color="#56c4fb" />
<stop offset="100%" stop-color="#0baeff" />
</linearGradient>
<path className="grey" d="M50,90 A30,25 0 0,1 10,90" fill="none" />
<path className="grey" d="M5,80 A30,25 0 0,1 20,50" fill="none" />
<path className="grey" d="M50,50 A30,25 0 0,1 80,90" fill="none" />
</svg>
Is manual calculation the way to go in this case, in order to create the different paths? What makes is complex for me is having to account for the small gaps between each part (as you can see the gap on the left, this is how it should be drawn)
What would be the easiest way to calculate the coordinates of the 3 paths, so they form a circle from 3 prats with small gaps between them?

You can do this almost completely in CSS. Draw a circle (or following your example, an ellipse), define an attribute pathLength for further use in CSS, and then make a stroke-dasharray that equally divides the stroke in three dashes and three gaps.
In this example, the total path length is treated as if it was 30. A dash length of 7 and a gap length of 3 add to 10, so can be repeated three times for the total of the circumference. If you wanted to divide the stroke in dashes of uneven length, the dasharray can contain individual lengths for each of them, like this – uneven positions are dashes, even positions gaps inbetween:
stroke-dasharray: 7 3 9 3 5 3;
The first dash starts at the right side and goes down. A positive stroke-dashoffset moves the start point counterclockwise.
svg {
height: 100vh;
}
.grey {
fill: none;
stroke: url(#gradient);
stroke-width: 8;
}
.dashed {
stroke-linecap: round;
stroke-dasharray: 7 3;
stroke-dashoffset: 2;
}
<svg viewBox="0 0 100 100">
<linearGradient id="gradient" x1="0" y1="0" x2="0" y2="100%">
<stop offset="0%" stop-color="#56c4fb" />
<stop offset="100%" stop-color="#0baeff" />
</linearGradient>
<ellipse class="grey dashed" pathLength="30" cx="50" cy="50" rx="30" ry="25" />
</svg>

Can do, for example, in Figma?
<svg width="411" height="410" viewBox="0 0 411 410" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M389 205C389 229.032 384.267 252.828 375.07 275.031C365.873 297.234 352.394 317.407 335.401 334.401C318.407 351.394 298.234 364.873 276.031 374.07C253.828 383.267 230.032 388 206 388"
stroke="black"
stroke-width="44"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M114.5 46.5174C135.312 34.5014 158.287 26.7024 182.114 23.5656C205.94 20.4288 230.151 22.0157 253.364 28.2356C276.577 34.4555 298.338 45.1866 317.403 59.8163C336.469 74.446 352.467 92.6878 364.483 113.5"
stroke="black"
stroke-width="44"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M114.483 363.465C93.6704 351.449 75.4287 335.452 60.799 316.386C46.1693 297.32 35.4382 275.56 29.2182 252.347C22.9983 229.134 21.4115 204.923 24.5483 181.096C27.6851 157.27 35.4841 134.295 47.5 113.483"
stroke="black"
stroke-width="44"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>

Related

Why is my SVG's radialGradient NOT showing in Chrome based browsers, but does in Firefox?

Problem
My <radialGradient> for the ellipses below won't show in Chrome based browsers, but will show the other content. Whereas firefox will show both.
I read this page, and this page, and they gave clues that it was a radialGradient issue, but I'm not dealing with any external files like the first page has, nor trying a conical gradient like the other one.
Goal
I want to have my first <svg> tag strictly for <defs> only, so I can reference parts later on to cut down the file size, and keep it clean. And to get rid of blank space, I added style="display: none;" to this first <svg> tag.
What I tried
Once I do the above, I add my other <svg>'s (email, SMS, etc) to reference them many times. Again, the first blank svg with the defs does not show (which is good), and the <path>, ellipses, etc. will show fine in Firefox, but not Chrome.
The ellipses will only show in Chrome when I take off style="display: none;" from the first svg, even though they're in the same element.
When I noticed it might be a <radialGradient> issue, I added fill:yellow;stroke:purple;stroke-width:2 to my ellipses style attribute, and that makes the ellipse show with that styling, so I know the ellipse is there, but the gradient won't show inside it.
Anyone know why the <radialGradient> will not show up in Chrome based browsers while style="display: none;" is on the first svg??? Or does anyone have any work arounds to fix this / do this more efficiently??? I know I can put everything in 1 svg, but I need them all separate so I can style them with css more easily, since they're all icons.
Thanks!
<!DOCTYPE html>
<html>
<body>
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
style="display:none;"
>
<defs>
<symbol id="ellipsesymbol" viewBox="0 0 126 76">
<radialGradient id="_Radial1" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(62.5,0,0,37.5,62.5069,37.5066)">
<stop offset="0" style="stop-color:#000;stop-opacity:0.5"/>
<stop offset="0.62" style="stop-color:#170725;stop-opacity:0.58"/>
<stop offset="0.82" style="stop-color:#4e187f;stop-opacity:0.78"/>
<stop offset="1" style="stop-color:#8a2be2;stop-opacity:1"/>
</radialGradient>
<ellipse cx="62.5" cy="37.839" rx="62.5" ry="37.5" style="fill:url(#_Radial1);" />
</symbol>
<symbol id="emailsymbol" viewBox="0 0 126 76">
<path
d="M31.15,17.125l0,40.763l62.713,0l0,-40.763l-62.713,-0Zm36.687,24.928c-1.411,1.411 -3.292,2.195 -5.33,2.195c-2.038,0 -3.92,-0.784 -5.331,-2.195l-21.792,-21.792l54.089,-0l-21.636,21.792Zm-17.402,-4.546l-16.149,16.148l0,-32.297l16.149,16.149Zm1.097,1.097l4.547,4.547c1.724,1.724 4.076,2.665 6.428,2.665c2.508,0 4.703,-0.941 6.428,-2.665l4.547,-4.547l16.148,16.149l-54.246,-0l16.148,-16.149Zm23.047,-1.097l16.149,-16.149l-0,32.454l-16.149,-16.305Z"
style="fill:#00bfff;fill-rule:nonzero;"/>
</symbol>
<symbol id="SMSsymbol" viewBox="0 0 126 76">
<path d="M98.587,27.064c0,-4.29 -3.483,-7.773 -7.773,-7.773l-56.464,0c-4.29,0 -7.773,3.483 -7.773,7.773l0,15.546c0,4.29 3.483,7.773 7.773,7.773l15.631,0l-9.002,13.326l19.803,-13.326l30.032,0c4.29,0 7.773,-3.483 7.773,-7.773l0,-15.546Z"
style="fill:#00bfff;"/>
<text x="36.276px" y="42.521px" style="font-family:'KnightsTemplar', 'Knights Templar';font-size:25.665px;">SMS</text>
</symbol>
<!-- .... -->
</defs>
</svg>
<svg id="emailgroup">
<use xlink:href="#ellipsesymbol" />
<use xlink:href="#emailsymbol" />
</svg>
<svg id="smsgroup">
<use xlink:href="#ellipsesymbol" />
<use xlink:href="#SMSsymbol" />
</svg>
<!-- more svg's.... -->
</body>
</html>
Instead of display:none, you can hide the first SVG with width="0" height="0". Then it works in Chrome:
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<defs>
<symbol id="ellipsesymbol" viewBox="0 0 126 76">
<radialGradient id="_Radial1" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(62.5,0,0,37.5,62.5069,37.5066)">
<stop offset="0" style="stop-color:#000;stop-opacity:0.5"/>
<stop offset="0.62" style="stop-color:#170725;stop-opacity:0.58"/>
<stop offset="0.82" style="stop-color:#4e187f;stop-opacity:0.78"/>
<stop offset="1" style="stop-color:#8a2be2;stop-opacity:1"/>
</radialGradient>
<ellipse cx="62.5" cy="37.839" rx="62.5" ry="37.5" style="fill:url(#_Radial1);" />
</symbol>
<symbol id="emailsymbol" viewBox="0 0 126 76">
<path d="M31.15,17.125l0,40.763l62.713,0l0,-40.763l-62.713,-0Zm36.687,24.928c-1.411,1.411 -3.292,2.195 -5.33,2.195c-2.038,0 -3.92,-0.784 -5.331,-2.195l-21.792,-21.792l54.089,-0l-21.636,21.792Zm-17.402,-4.546l-16.149,16.148l0,-32.297l16.149,16.149Zm1.097,1.097l4.547,4.547c1.724,1.724 4.076,2.665 6.428,2.665c2.508,0 4.703,-0.941 6.428,-2.665l4.547,-4.547l16.148,16.149l-54.246,-0l16.148,-16.149Zm23.047,-1.097l16.149,-16.149l-0,32.454l-16.149,-16.305Z"
style="fill:#00bfff;fill-rule:nonzero;"/>
</symbol>
<symbol id="SMSsymbol" viewBox="0 0 126 76">
<path d="M98.587,27.064c0,-4.29 -3.483,-7.773 -7.773,-7.773l-56.464,0c-4.29,0 -7.773,3.483 -7.773,7.773l0,15.546c0,4.29 3.483,7.773 7.773,7.773l15.631,0l-9.002,13.326l19.803,-13.326l30.032,0c4.29,0 7.773,-3.483 7.773,-7.773l0,-15.546Z"
style="fill:#00bfff;"/>
<text x="36.276px" y="42.521px" style="font-family:'KnightsTemplar', 'Knights Templar';font-size:25.665px;">SMS</text>
</symbol>
</defs>
</svg>
<svg id="emailgroup">
<use href="#ellipsesymbol" />
<use href="#emailsymbol" />
</svg>
<svg id="smsgroup">
<use href="#ellipsesymbol" />
<use href="#SMSsymbol" />
</svg>
Also note that xlink:href is deprecated, and you can simply use href now:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/href

How to animate an svg line from the center point?

I have the following vertical line as an svg element(made using Inkscape), now i would like to make it to draw itself from the center, instead of top to bottom or bottom to top.
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48.136105mm"
height="79.598999mm"
viewBox="0 0 48.136105 79.598999"
version="1.1"
id="bluetoothIconSvg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="bluethood-break-apart-icon.svg">
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-33.604957,-76.75465)">
<path
style="fill:none;
stroke:#000000;
stroke-width:1px;
stroke-linecap:butt;
stroke-linejoin:miter;
stroke-opacity:1"
d="M 49.924165,76.866652 V 156.24165"
id="path4508"
inkscape:connector-curvature="0" />
</g>
</svg>
Also using just a normal html element such as a <div> or a <span>, this could be achieved easily like so HERE. But i would like to achieve the same using an svg.
I'm animating your path although I've removed the transformation and changed the viewBox because I wanted to see the hole path. You can use what you have.
I'm using a SMIL animation but you can use the same idea to animate it using css.
In my code 79.375 is the total length of the path. You can get the total length of path using getTotalLength().
39.69 is the half of the total length.
The main idea is this: I'm animating the stroke-dasharray from strokes = 0 gaps = 79.375 to gaps = 0 strokes = 79.375
Also I'm animating the stroke-dashoffset from="-39.69" to="0"
svg{width:50px; border:1px solid silver;}
<svg
viewBox="40 70 48.136105 95"
>
<g>
<path
style="fill:none;
stroke:#000000;
stroke-width:1px;
stroke-linecap:butt;
stroke-linejoin:miter;
stroke-opacity:1"
d="M 49.924165,76.866652 V 156.24165"
id="path4508"
stroke-dasharray="79.375 0"
stroke-dasharray="-39.69"
>
<animate attributeName="stroke-dasharray"
attributeType="XML"
from="0 79.375" to="79.375 0"
dur="5s"
repeatCount="indefinite" />
<animate attributeName="stroke-dashoffset"
attributeType="XML"
from="-39.69" to="0"
dur="5s"
repeatCount="indefinite" />
</path>
</g>
</svg>

How to make animated, gradient filled, SVG donut chart

I was trying to find clean simple solution to create SVG kind of donut charts with gradient fill going along the edge of the circle with the possibility to animate it from 0% to x% and I found out that there's no easy way and no ready copy & paste solution. Most solution used one linear gradient, which didn't help in my case or were over complicated.
The kind of (static) result I expected to get was:
So after some research and work I created this solution which I decided to share it with you.
It is based on the prozorov's solution. His circle wasn't 360deg and lacked the needed animation part. It isn't true gradient going with the stroke around the edge of the circle (which is not easy to do with SVG) but rather two linear gradients put together, but for most cases that trick does it.
And here's the complete solution:
.animated {
animation: dash 5s infinite;
}
#keyframes dash {
0% {
stroke-dashoffset: 0;
}
50% {
stroke-dashoffset: 1570;
}
100% {
stroke-dashoffset: 0;
}
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="800" width="800">
<defs>
<linearGradient id="Gradient1" gradientTransform="rotate(90)">
<stop offset="0%" stop-color="#ff0000"/>
<stop offset="100%" stop-color="#00ff00"/>
</linearGradient>
<linearGradient id="Gradient2" gradientTransform="rotate(90)">
<stop offset="0%" stop-color="#0000ff"/>
<stop offset="100%" stop-color="#00ff00"/>
</linearGradient>
<pattern id="Pattern" x="0" y="0" width="600" height="600" patternUnits="userSpaceOnUse">
<g transform="rotate(0, 300, 300)">
<rect shape-rendering="crispEdges" x="0" y="0" width="300" height="600" fill="url(#Gradient1)"/>
<rect shape-rendering="crispEdges" x="300" y="0" width="300" height="600" fill="url(#Gradient2)"/>
</g>
</pattern>
</defs>
<path id='arc5' class="animated"
style="stroke: url(#Pattern);" fill='transparent'
stroke-dasharray="1570 1570"
stroke-dashoffset="0"
stroke-width='60'
d='M 300 58 A 250 250 0 1 1 299.99 58'/>
</svg
And link to JS Fiddle

Circular arrows with gradient

I tried to make it with border but gradient makes it impossible. Maybe I can make four divs and make it like that?
CSS might not be the best way to create such shapes. You should use SVG instead.
We can use SVG's path element to create a pointing arrow like shape and fill it with gradient created with linearGradient.
Only one attribute d is used to define shapes in path element. This attribute itself contains a number of short commands and few parameters that are necessary for those commands to work.
Here is a detailed information about SVG paths:
body {
text-align: center;
background: #333;
margin: 20px;
}
<svg width="400" height="400" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="gradient">
<stop offset="0" stop-color="#212121"></stop>
<stop offset="1" stop-color="#a7a7a7"></stop>
</linearGradient>
<path id="arrow" x="0" y="0" d="M0,200
A200,200 0, 0, 1, 200,0
L225,25
L200,50
A150,150, 0, 0, 0 50,200
L25,175" fill="url(#gradient)" />
</defs>
<use xlink:href="#arrow" transform="translate(0,400) rotate(270)"></use>
<use xlink:href="#arrow" transform="translate(400,400) rotate(180)"></use>
<use xlink:href="#arrow" transform="translate(400,0) rotate(90)"></use>
<use xlink:href="#arrow"></use>
</svg>

SVG position different in WebKit and Firefox

I'm working on a site redesign and am using SVGs to render some of the graphics in the design. For some reason, the SVG is being shifted down in WebKit browser windows by about 31px as compared to Firefox. Screen capture:
Here is the code:
<svg version="1.1" id="shape1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" x="2" y="2" viewBox="-2 0 1002 704" xml:space="preserve" preserveAspectRatio="xMidYMid meet" style="min-width:980px; max-width: 1800px;">
<defs>
<linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="100%" spreadMethod="pad">
<stop offset="10%" stop-color="#ff7405" stop-opacity="1"/>
<stop offset="90%" stop-color="#f89512" stop-opacity="1"/>
</linearGradient>
<filter id="shadow1" y="-1%" x="-1%" width="110%" height="150%">
<feOffset in="SourceAlpha" dx="-2" dy="4" result="offset" />
<feGaussianBlur in="offset" stdDeviation="1" result="blur" />
<feColorMatrix in="blur" result="shadow" type="matrix"
values="0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 .6 0"/>
<feMerge>
<feMergeNode in="shadow" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<!-- MAIN BOX -->
<path class="wrap" fill-rule="evenodd" clip-rule="evenodd" style="fill: url(#gradient1); filter: url(#shadow1);" d="M32.3 0.3L935 82.8c34.3 4.2 38.7 28.9 34.1 59.2l-56.7 398.3c-6.4 23.2-29.8 32.9-66.4 34.8L95.4 643.3c-20.2 0-38.7-17.3-41.4-38.5L0.6 38.9C-2 17.6 12.1 0.3 32.3 0.3z"/>
<!-- STROKE -->
<path fill="none" class="wrap-stroke" stroke="#FFEB00" transform="translate(-42,-28)" d="M84.9,37.3l883.1,80c33.6,4.1,37.9,28.1,33.4,57.4l-55.5,386.5c-6.3,22.5-29.1,31.9-64.9,33.8l-734.3,66.2c-19.7,0-37.9-16.7-40.5-37.4L53.9,74.7C51.3,54.1,65.2,37.3,84.9,37.3z"/>
<!-- CONTACT BOX -->
<svg x="290" y="490">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFC80C" style="stroke: #F26222; stroke-width: 3px;" stroke-miterlimit="10" d="M107.7,68.1l456.9-19.3 c9.1,0,16.5,7.9,16.5,17.5l-8.2,75.4c0,9.7-7.4,17.5-16.5,17.5L116,143.5c-9.1,0-16.5-7.9-16.5-17.5l-8.2-40.3 C91.3,75.9,98.6,68.1,107.7,68.1z"/>
</svg>
<!-- NAV BOX -->
<svg y="-40" x="230">
<linearGradient id="gradient2" x1="0%" y1="0%" x2="100%" y2="100%" spreadMethod="pad">
<stop offset="5%" style="stop-color:#F68A1F"/>
<stop offset="95%" style="stop-color:#F99F1B"/>
</linearGradient>
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:url(#gradient2);stroke:#FFC80C;stroke-width:2;stroke-miterlimit:4;" d="M69.2,90.5l580.3-4.8c7.7,0,11.5,1.9,9.8,8.8l-6.7,29c-2.1,5.5-6.2,7.1-13.9,7.1l-564.2-9.4c-5.6,0-7.7-1.8-9.5-7.1l-3.8-13.5 C59.1,92.9,61.4,90.9,69.2,90.5z"/>
</svg>
</svg>
</svg>
When I look at this is web inspector, I see nothing that would be making the SVG dropdown like this. Any ideas?
The issue turned out to be the preserveAspectRatio setting I had in the SVG. I had it set to: preserveAspectRatio="xMidYMid meet" which made the elements in the SVG render in the middle of the viewBox. From MDN:
xMidYMin - Force uniform scaling.
Align the midpoint X value of the element's viewBox with the midpoint X value of the viewport.
Align the of the element's viewBox with the smallest Y value of the viewport.
Changing this setting to xMinyMin made the elements in the SVG render at the top and left of the viewBox.
From MDN:
xMinYMin - Force uniform scaling.
Align the of the element's viewBox with the smallest X value of the viewport.
Align the of the element's viewBox with the smallest Y value of the viewport.
preserveAspectRatio on MDN

Resources