SVG Piechart with stroke-dasharray: box-shadow on slice not working - svg

I generated a SVG piechart with stroke-dasharray but unfortunately I could not set a box-shadow for a specific slice (to mark is as active etc.). Normally it would work with filter: drop-shadow(0 4px 25px rgba(0, 0, 0, 0.75));. I also tried some different ways to integrate <filter> inside the svg but then it changed the whole size of the slide. Can somebody help to achieve this?
body {
padding: 1rem;
background: #bbb;
text-align: center;
}
svg:not(:root) {
overflow: visible;
}
svg {
height: 280px;
width: 280px;
border: 20px solid white;
border-radius: 50%;
[id="1"] {
filter: drop-shadow(0 4px 25px rgba(0, 0, 0, 0.75));
}
}
<!-- 4 Elements -->
<svg height="20" width="20" viewBox="0 0 20 20">
<circle id="1" r="5" cx="10" cy="10"
stroke="tomato"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform="rotate(-90)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="blue"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="yellow"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform="rotate(90) scale(1.15)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="green"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform="rotate(180)"
transform-origin="center center"
/>
</svg>
<!-- 5 Elements -->
<!-- <svg height="20" width="20" viewBox="0 0 20 20">
<circle r="10" cx="10" cy="10" fill="white" />
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="tomato"
stroke-width="10"
stroke-dasharray="calc(72 * 31.42 / 360) 31.42"
transform="rotate(-90)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="blue"
stroke-width="8"
stroke-dasharray="calc(72 * 31.42 / 360) 31.42"
transform="rotate(-18)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="yellow"
stroke-width="8"
stroke-dasharray="calc(72 * 31.42 / 360) 31.42"
360-6 transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="magenta"
stroke-width="8"
stroke-dasharray="calc(72 * 31.42 / 360) 31.42"
transform="rotate(126)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="green"
stroke-width="8"
stroke-dasharray="calc(72 * 31.42 / 360) 31.42"
transform="rotate(198)"
transform-origin="center center"
/>
</svg> -->
<!-- <svg height="20" width="20" viewBox="0 0 20 20">
<circle r="10" cx="10" cy="10" stroke="pink" />
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="tomato"
stroke-width="10"
stroke-dasharray="calc(60 * 31.42 / 360) 31.42"
transform="rotate(-90)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="blue"
stroke-width="10"
stroke-dasharray="calc(60 * 31.42 / 360) 31.42"
transform="rotate(-30)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="yellow"
stroke-width="10"
transform="rotate(30)"
stroke-dasharray="calc(60 * 31.42 / 360) 31.42"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="magenta"
stroke-width="10"
stroke-dasharray="calc(60 * 31.42 / 360) 31.42"
transform="rotate(90)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="green"
stroke-width="10"
stroke-dasharray="calc(60 * 31.42 / 360) 31.42"
transform="rotate(150)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="aqua"
stroke-width="10"
stroke-dasharray="calc(60 * 31.42 / 360) 31.42"
transform="rotate(210)"
transform-origin="center center"
/>
</svg> -->
What it should look like

The shape that you want to apply the shadow to, has to be drawn last, so the shadow is not overdrawn by the other shapes. Also, the CSS filter version doesn't seem to be working for some reason - so you will have to replace it with an SVG version. Here is something that works. Note that the shape is rotated, but feOffset applies dx and dy pre-rotation, so adding a dx = 2 doesn't move the shadow to the right.
body {
padding: 1rem;
background: #bbb;
text-align: center;
}
svg:not(:root) {
overflow: visible;
}
svg {
height: 280px;
width: 280px;
border: 20px solid white;
border-radius: 50%;
}
<!-- 4 Elements -->
<svg height="20" width="20" viewBox="0 0 20 20">
<defs>
<filter id="dshadow" x="-100%" y="-100%" width="300%" height="300%">
<feGaussianBlur stdDeviation="1"/>
<feOffset dx="-1" result="shadow"/>
<feFlood flood-color="black" flood-opacity="0.75"/>
<feComposite operator="in" in2="shadow"/>
<feComposite operator="over" in="SourceGraphic"/>
</filter>
</defs>
<circle id="1" r="5" cx="10" cy="10"
stroke="tomato"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform="rotate(-90)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="blue"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="green"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform="rotate(180)"
transform-origin="center center"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="yellow"
stroke-width="10"
stroke-dasharray="calc(90 * 31.42 / 360) 31.42"
transform="rotate(90) scale(1.15)"
transform-origin="center center"
filter="url(#dshadow)"
/>
</svg>

Related

scale a svg element which is inside an other svg

I would like to scale up on hover 3 svgs nested in an other svg. These 3 svgs are planets visible on the first graph at this address : http://68.183.74.150:3000/planet.
So, to sum up, the code looks like this :
<svg id="a">
<g>
...
</g>
<g>
<svg id="b"></svg>
</g>
</svg>
I tried the code below but it doesn't work as b is nested inside a. It works if I apply this code to the "a" svg.
svg#b:hover {
transform: scale(3);
}
svg#b {
transition: all 1s;
transform-origin: 50% 50%;
}
How would you solve this ?
Apparently chromium seems to have issues with scaling nested svg elements.
/* example layout */
.wrap {
display: inline-block;
width: 20em;
}
.svgParent {
width: 10em;
border: 2px solid #ccc;
}
.svgParent:hover {
border: 2px solid green;
}
/* set transformorigin */
.svgChild,
.childNodes {
transition: 0.3s;
transform-origin: center;
}
/* ensure scaled element don't get cropped when scaled */
.svgChild {
overflow: visible;
}
.hoverElement:hover {
transform: scale(1.3);
opacity: 0.5;
}
<div class="wrap">
<p>Scale nested svg on hover –<br />not working in chrome</p>
<svg class="svgParent" viewBox="0 0 100 100">
<svg class="svgChild hoverElement" x="20" y="20" width="48" height="48" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="12" fill="#ccc" />
</svg>
</svg>
</div>
<div class="wrap">
<p>Scale group in nested svg on hover</p>
<svg class="svgParent" viewBox="0 0 100 100">
<svg class="svgChild" x="20" y="20" width="48" height="48" viewBox="0 0 24 24">
<g class="childNodes hoverElement">
<circle cx="12" cy="12" r="12" fill="#ccc" />
</g>
</svg>
</svg>
</div>
For a consistent display in both firefox and chromium you could wrap your planets' child elements an additional group like so:
<svg x="129.2" y="62.1" width="26" height="26" viewBox="0 0 36 36">
<g class="planetwrap">
<circle fill="#88C9F9" cx="18" cy="18" r="18" />
<path fill="#5C913B" d="M25.716 1.756c-1.022.568-1.872 1.528-3.028 1.181-1.875-.562-4.375-1.812-6-.25s-2 3 0 2.938 3.375-2.438 4.375-1.438.749 1.813-1.625 2.125S14.5 7 13.125 7s-1.688.812-.75 1.688-.563.937-2.125 1.812.375 1.25 1.688 2 2.312-.188 2.875-1.438 2.981-2.75 3.99-2.562c1.01.188 1.01.688.822 1.562s.75.625.812-.375 1.188-1.75 2.062-1.812 1.625 1.188.625 1.812-2 1.125-.75 1.438 2.125 1.938.688 2.625-3.937 1.125-5.062.562-3.688-1.375-4.375-.938-1.062.89-1.875 1.195c-.812.305-4.125 1.805-4.188 3.743S7.438 22.438 8.75 22.5s4.5-.812 5.5-1.625 2.375-.625 2.812.312.125 1.5-.312 3 .286 2.25.987 3.562c.701 1.312 1.263 2.062 1.263 3s1 1.875 2.5.312 2.875-4.625 3.5-5.75 1.125-3.625 1.875-4.125 1.938-1.688 1.062-1.5-2.625-.062-3.062-1.312-2.312-3.625-1.438-3.875 1.875 1.39 2.25 2.164c.375.774.875 1.711 1.625 1.961s2.375-1.673 2.875-1.961c.5-.289.125-1.476-.875-1.351s-2.312 0-2.312-.624 1.25-1.438 2.25-1.25 1.75.5 2.375 1.25 1.875 2.125 2.375 3 .875 1 1.125-.562c.166-1.038.387-1.609.59-2.222-1.013-5.829-4.82-10.683-9.999-13.148z" />
</g>
</svg>
Example grouped
If you can't optimize and save your tweaked planet assets statically you could use some js to do the wrapping job.
let planets = document.querySelectorAll('.recharts-reference-dot svg');
// wrap planet svg elements
planets.forEach(function(planet, i){
planet.innerHTML = '<g class="planetwrap">'+ planet.innerHTML +'</g>';
})
.recharts-reference-dot svg{
overflow:visible;
}
.planetwrap{
transform-origin:center;
transition: 0.3s transform
}
.planetwrap:hover{
transform:scale(1.5)
}
<div class="recharts-wrapper" style="position: relative; cursor: default; width: 899px; height: 199.778px;"><svg id="masse_distance" class="recharts-surface" width="899" height="199.77777777777777" viewBox="0 0 899 199.77777777777777" version="1.1">
<defs>
<clipPath id="masse_distance-clip">
<rect x="70" y="20" height="139.77777777777777" width="809"></rect>
</clipPath>
</defs>
<g class="recharts-layer recharts-cartesian-axis recharts-xAxis xAxis">
<line name="masse" type="number" orientation="bottom" width="809" height="30" x="70" y="159.77777777777777" class="recharts-cartesian-axis-line" stroke="#666" fill="none" x1="70" y1="159.77777777777777" x2="879" y2="159.77777777777777"></line>
<g class="recharts-cartesian-axis-ticks">
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="masse" type="number" orientation="bottom" width="809" height="30" x="70" y="159.77777777777777" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="231.8" y1="165.77777777777777" x2="231.8" y2="159.77777777777777"></line><text name="masse" type="number" orientation="bottom" width="809" height="30" x="231.8" y="167.77777777777777" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="231.8" dy="0.71em">0.01 Mjup</tspan>
</text>
</g>
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="masse" type="number" orientation="bottom" width="809" height="30" x="70" y="159.77777777777777" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="308.99821901364135" y1="165.77777777777777" x2="308.99821901364135" y2="159.77777777777777"></line><text name="masse" type="number" orientation="bottom" width="809" height="30" x="308.99821901364135" y="167.77777777777777" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="308.99821901364135" dy="0.71em">0.03 Mjup</tspan>
</text>
</g>
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="masse" type="number" orientation="bottom" width="809" height="30" x="70" y="159.77777777777777" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="393.6" y1="165.77777777777777" x2="393.6" y2="159.77777777777777"></line><text name="masse" type="number" orientation="bottom" width="809" height="30" x="393.6" y="167.77777777777777" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="393.6" dy="0.71em">0.1 Mjup</tspan>
</text>
</g>
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="masse" type="number" orientation="bottom" width="809" height="30" x="70" y="159.77777777777777" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="555.4" y1="165.77777777777777" x2="555.4" y2="159.77777777777777"></line><text name="masse" type="number" orientation="bottom" width="809" height="30" x="555.4" y="167.77777777777777" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="555.4" dy="0.71em">1 Mjup</tspan>
</text>
</g>
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="masse" type="number" orientation="bottom" width="809" height="30" x="70" y="159.77777777777777" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="717.2" y1="165.77777777777777" x2="717.2" y2="159.77777777777777"></line><text name="masse" type="number" orientation="bottom" width="809" height="30" x="717.2" y="167.77777777777777" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="717.2" dy="0.71em">10 Mjup</tspan>
</text>
</g>
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="masse" type="number" orientation="bottom" width="809" height="30" x="70" y="159.77777777777777" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="879" y1="165.77777777777777" x2="879" y2="159.77777777777777"></line><text name="masse" type="number" orientation="bottom" width="809" height="30" x="873.265625" y="167.77777777777777" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="middle">
<tspan x="873.265625" dy="0.71em">100 Mjup</tspan>
</text>
</g>
</g>
</g>
<g class="recharts-layer recharts-cartesian-axis recharts-yAxis yAxis">
<line name="periode orbitale" type="number" orientation="left" width="60" height="139.77777777777777" x="10" y="20" class="recharts-cartesian-axis-line" stroke="#666" fill="none" x1="70" y1="20" x2="70" y2="159.77777777777777"></line>
<g class="recharts-cartesian-axis-ticks">
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="periode orbitale" type="number" orientation="left" width="60" height="139.77777777777777" x="10" y="20" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="64" y1="124.83333333333333" x2="70" y2="124.83333333333333"></line><text name="periode orbitale" type="number" orientation="left" width="60" height="139.77777777777777" x="62" y="124.83333333333333" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="end">
<tspan x="62" dy="0.355em">1 jour</tspan>
</text>
</g>
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="periode orbitale" type="number" orientation="left" width="60" height="139.77777777777777" x="10" y="20" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="64" y1="89.88888888888887" x2="70" y2="89.88888888888887"></line><text name="periode orbitale" type="number" orientation="left" width="60" height="139.77777777777777" x="62" y="89.88888888888887" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="end">
<tspan x="62" dy="0.355em">100 jour</tspan>
</text>
</g>
<g class="recharts-layer recharts-cartesian-axis-tick">
<line name="periode orbitale" type="number" orientation="left" width="60" height="139.77777777777777" x="10" y="20" class="recharts-cartesian-axis-tick-line" stroke="#666" fill="none" x1="64" y1="61.208688458136685" x2="70" y2="61.208688458136685"></line><text name="periode orbitale" type="number" orientation="left" width="60" height="139.77777777777777" x="62" y="61.208688458136685" stroke="none" fill="#666" class="recharts-text recharts-cartesian-axis-tick-value" text-anchor="end">
<tspan x="62" dy="0.355em">4380 jour</tspan>
</text>
</g>
</g>
</g>
<g class="recharts-layer recharts-reference-dot">
<g>
<svg x="129.19821901364134" y="62.06438300713549" width="26" height="26" viewBox="0 0 36 36">
<circle fill="#88C9F9" cx="18" cy="18" r="18"></circle>
<path fill="#5C913B" d="M25.716 1.756c-1.022.568-1.872 1.528-3.028 1.181-1.875-.562-4.375-1.812-6-.25s-2 3 0 2.938 3.375-2.438 4.375-1.438.749 1.813-1.625 2.125S14.5 7 13.125 7s-1.688.812-.75 1.688-.563.937-2.125 1.812.375 1.25 1.688 2 2.312-.188 2.875-1.438 2.981-2.75 3.99-2.562c1.01.188 1.01.688.822 1.562s.75.625.812-.375 1.188-1.75 2.062-1.812 1.625 1.188.625 1.812-2 1.125-.75 1.438 2.125 1.938.688 2.625-3.937 1.125-5.062.562-3.688-1.375-4.375-.938-1.062.89-1.875 1.195c-.812.305-4.125 1.805-4.188 3.743S7.438 22.438 8.75 22.5s4.5-.812 5.5-1.625 2.375-.625 2.812.312.125 1.5-.312 3 .286 2.25.987 3.562c.701 1.312 1.263 2.062 1.263 3s1 1.875 2.5.312 2.875-4.625 3.5-5.75 1.125-3.625 1.875-4.125 1.938-1.688 1.062-1.5-2.625-.062-3.062-1.312-2.312-3.625-1.438-3.875 1.875 1.39 2.25 2.164c.375.774.875 1.711 1.625 1.961s2.375-1.673 2.875-1.961c.5-.289.125-1.476-.875-1.351s-2.312 0-2.312-.624 1.25-1.438 2.25-1.25 1.75.5 2.375 1.25 1.875 2.125 2.375 3 .875 1 1.125-.562c.166-1.038.387-1.609.59-2.222-1.013-5.829-4.82-10.683-9.999-13.148z"></path>
</svg>
</g><text x="167.19821901364134" y="70.06438300713549">Terre</text>
</g>
</svg></div>

How to create an SVG icon consisting of two overlapping shapes, one with a hole?

I have made a progress bar icon from two partially overlapping SVG shapes.
I would like the icon to have the same color as the surrounding text, so I set stroke and fill to currentColor.
The icon is displayed correctly if the color of the surrounding text doesn't have alpha channel e.g. color: black. However, if the color of the surrounding text has alpha channel e.g. color: rgba (0, 0, 0, 0.7), then the icon is darker where the shapes overlap.
How can I get the same color at each point of the icon?
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" fill="currentColor" />
</svg>
Question Prevent overlapping figures with alpha channel from shading each other? is very similar, but the accepted answer doesn't work in this case:
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<defs>
<clipPath id="myClip">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="black" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" />
</clipPath>
</defs>
<rect width="100%" height="100%" fill="currentColor" clip-path="url(#myClip)"/>
</svg>
Update:
I decided to draw the icon without overlapping parts, because it is much easier and it also looks good:
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="4" y="4" width="23" height="7" rx="2" ry="2" fill="currentColor" />
</svg>
One solution is to user a mask. But if you don't change the geometry, you will get the same issue as with #InvisibleGorilla's solution: you will get antialiasing artifacts.
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<defs>
<mask id="cutout">
<rect width="100%" height="100%" fill="white" />
<use xlink:href="#bar" fill="black" />
</mask>
<rect id="bar" x="2" y="2.5" width="24" height="10" />
</defs>
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent"
mask="url(#cutout)" />
<use xlink:href="#bar" fill="currentColor" />
</svg>
To fix the antialiasing artifacts, move your bar so that it is positioned at a whole pixel (y="2") instead of a half pixel (y="2.5"). You still might still see very slight artifacts at some scales. But it should be a lot better.
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
<svg viewBox="0 0 44 18" width="220" height="90">
<defs>
<mask id="cutout">
<rect width="100%" height="100%" fill="white" />
<use xlink:href="#bar" fill="black" />
</mask>
<rect id="bar" x="2" y="2" width="24" height="10" />
</defs>
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent"
mask="url(#cutout)" />
<use xlink:href="#bar" fill="currentColor" />
</svg>
Before the rect where fill has currentColor, add a rect with the exact same attributes but with a white fill directly before it (so that it gets drawn underneath it in the svg).
See snipped below:
<style>
body { background-color: #eee; color: rgba(0, 0, 0, 0.7); }
</style>
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" fill="white" />
<rect x="2" y="2.5" width="24" height="10" fill="currentColor" />
</svg>
You could also change the order of your rects and add a matching white rect under the one where the stroke has currentColor.
Here's the updated snippet using background color and underlying both rects. I've tested on Chrome and Firefox on Mac and I don't see any lines from the background color rects.
<style>
body { background-color: #232b32; color: rgba(240, 240, 240, 0.7); }
</style>
<svg viewBox="0 0 44 18" width="220" height="90">
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="#232b32" stroke-width="2" fill="transparent" />
<rect x="2" y="2" width="40" height="11" rx="3" ry="3"
stroke="currentColor" stroke-width="2" fill="transparent" />
<rect x="2" y="2.5" width="24" height="10" fill="#232b32" />
<rect x="2" y="2.5" width="24" height="10" fill="currentColor" />
</svg>
<p>Some text</p>
Here's a screenshot of when I run this snippet.

Move a div to specific spots on an svg path

I have an SVG path that currently has an image travelling around it. I need to make it so that when you click on a button on the path, the image will travel to that specific spot?
Anyone have any ideas? Thanks in advance.
My HTML is:
<div class="route">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" x="0px" y="0px" width="500px" viewBox="0 0 500 1920" xml:space="preserve">
<path class="cls-1" d="M288.56,7.45c1,1.17,13.77,15.18,14,16.67a8.66,8.66,0,0,1-.65,4.21,117.08,117.08,0,0,1-8.09,18.43c-.36.66-.82,1.39-1.56,1.55a2.71,2.71,0,0,1-1.88-.59L282.72,43a2.5,2.5,0,0,0-4.09.88C270.79,54.35,263,65.09,253.14,73.73c-3,2.61-6.16,5-8.71,8.06-.88,1-1.71,2.38-1.25,3.65a4.35,4.35,0,0,0,1.1,1.49,53.93,53.93,0,0,1,14.12,25.72,4.5,4.5,0,0,1,.12,2.12c-.59,2.2-3.69,2.33-5.41,3.84s-1.75,4.08-1.68,6.34a90,90,0,0,0,1.24,14.12c2,10.3,7.81,19.93,8.07,30.43-2.28,24.14-22.77,45.32-46.87,48.1-2.7.32-5.5.44-8,1.57a20.09,20.09,0,0,0-5,3.7c-32.78,29.91-57.73,67.22-82.35,104.13-2.88,4.32-5.79,8.7-7.48,13.61-2,5.91-2.2,12.26-2.35,18.5-.21,8.75-.38,17.73,2.58,26,3.67,10.22,11.8,18.29,15.91,28.34,4.49,10.93,3.91,23.44,8.47,34.35,1.61,3.85,3.84,7.44,5.16,11.4,2.32,6.94,1.68,14.52,3.28,21.65,2.18,9.7,8.12,20.64,3,29.16a373.16,373.16,0,0,0-36.31,54.7c-4.78,8.8-9.24,17.89-11.68,27.62-2.81,11.19-2.85,22.86-2.88,34.4,0,16.77,0,34,5.78,49.7,2.39,6.51,5.73,12.65,8,19.19,10.3,29.32-1.45,61.63,1,92.61.42,5.43,1.34,11,4,15.71,3.57,6.34,9.92,10.64,16.46,13.82,22.55,10.94,48.91,11,72.34,19.86,12.93,4.92,25.1,12.27,36.75,19.73,5.54-6.69,15.43-8.71,24.11-8.93s17.66.7,25.86-2.17a42.79,42.79,0,0,0,12.9-7.74c15.09-12.46,25-30,33.81-47.45,11.51-22.93,21.95-47.81,20.86-73.43-4.91-2.19-5.89-9.21-10.41-12.13-5.16-3.32-11.87-.21-18,0-7.93.27-15.06-4.5-21.47-9.19a604.83,604.83,0,0,1-70.37-60.38,24.51,24.51,0,0,1-5.05-6.35c-.8-1.66-1.24-3.5-2.27-5-2.1-3.15-6.11-4.31-9.77-5.27-35.8-9.32-70.81-22-104.91-36.35-4.52-7.11-4-16.94-4.71-25.34A85.91,85.91,0,0,0,99,520.19c-1.78-2.94-3.82-6-3.68-9.44a51.33,51.33,0,0,1,1-5.32c1-6.63-3.85-12.53-8-17.74-31.63-39.15-45.62-90.53-74.78-131.56a15.88,15.88,0,0,1-.82-14,14.43,14.43,0,0,1,10.56-8.1c2-.33,4.36-.43,5.38-2.16A5.54,5.54,0,0,0,28.8,328a120,120,0,0,0-3-11.95,21.64,21.64,0,0,0-2-4.93c-1.06-1.75-2.55-3.19-3.73-4.86a33.42,33.42,0,0,1-3.84-8.23c-3.28-9.13-6.58-18.33-8.06-27.92-1-6.17-1.14-12.44-2-18.62A86.93,86.93,0,0,0,.69,231a64.48,64.48,0,0,1,18.11-1.35c-14.94-40.19-3.59-88.94,27-119A156.85,156.85,0,0,1,64.48,95.09C80,83.88,96.75,74.38,113.42,64.9A46.07,46.07,0,0,1,124,60.05c5-1.35,10.31-.95,15.45-1.72C155.85,55.86,168,42.22,182.28,33.7c10.7-6.38,22.85-10,33.83-15.87,7.68-4.14,14.75-9.41,22.7-13s17.61-6.19,25.39-2.24c4.19,2.12,14.08-1.11,15-2.26"; />
<circle id="one" cx="295" cy="48" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" onclick="testFunc"/>
<circle id="two" cx="263" cy="65" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="three" cx="258" cy="103" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="four" cx="252" cy="135" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="five" cx="131" cy="305" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="six" cx="147" cy="502" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="seven" cx="125" cy="538" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="eight" cx="110" cy="563" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="nine" cx="96" cy="619" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="ten" cx="110" cy="791" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="eleven" cx="216" cy="841" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twelve" cx="287" cy="846" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="thirteen" cx="323" cy="817" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="fourteen" cx="349" cy="766" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="fifteen" cx="355" cy="720" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="sixteen" cx="320" cy="705" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="seventeen" cx="265" cy="660" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="eighteen" cx="102" cy="528" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="nineteen" cx="96" cy="498" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twenty" cx="22" cy="306" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twentyone" cx="133" cy="59" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twentytwo" cx="230" cy="8" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
</svg>
<div class="ship"></div>
</div>
Each circle needs to have a click function and the ship needs to move to that circle from where ever it is currently positioned. I currently have basic animation of the ship moving around the svg path using css but understand I'll need to use javascript/jquery.
It's actually quite easy to do. The simplest way is with a javascript animation using window.requestAnimationFrame().
See below. I've documented what I'm doing, so hopefully it should be quite easy to follow.
A couple of notes:
I've only configured the pathOffsets for the first five circles. I've left the rest up to you.
This code assumes that you are going to display the SVG at 1:1 scale. If you change that (ie. you change the SVG width), then the code will have to be modified, because otherwise the ship won't be positioned in the right place.
const ship = document.querySelector(".ship");
const routePath = document.querySelector("svg .cls-1");
// The distance along the path that each circle lies
const pathOffsets = {
"one": 45,
"two": 90,
"three": 141,
"four": 176,
"five": 407,
"six": 0,
"seven": 0,
"eight": 0,
"nine": 0,
"ten": 0,
"eleven": 0,
"twelve": 0,
"thirteen": 0,
"fourteen": 0,
"fifteen": 0,
"sixteen": 0,
"seventeen": 0,
"eighteen": 0,
"nineteen": 0,
"twenty": 0,
"twentyone": 0,
"twentytwo": 0
}
const shipSpeed = 1; // How far along the path to move for each animation step
var currentShipOffset = 0; // Where the ship is now
var shipTarget = 0; // The offset of where the ship is currently heading
var shipMoving = false;
// Position the ship at a particular offset along the path
function setShipOffset(offset) {
var pos = routePath.getPointAtLength(offset);
ship.style.left = pos.x + 'px';
ship.style.top = pos.y + 'px';
currentShipOffset = offset;
}
// Start the ship moving to a particular circle
function startShipMovement(evt) {
// Get the 'id' attribute of the circle we clicked on
var circleId = evt.target.id;
// Get the corresponding offset value
shipTarget = pathOffsets[circleId];
// If the ship isn't already moving, then begin the animation by requesting the first animation step
if (!shipMoving) {
window.requestAnimationFrame(doShipStep);
shipMoving = true;
}
}
function doShipStep() {
// If we are within one step of the target, then stop there.
if (Math.abs(shipTarget - currentShipOffset) <= shipSpeed) {
setShipOffset(shipTarget);
shipMoving = false;
return;
}
// Otherwise move one step in the correct direction
if (shipTarget > currentShipOffset) {
setShipOffset(currentShipOffset + shipSpeed);
} else {
setShipOffset(currentShipOffset - shipSpeed);
}
// and request another animation step
window.requestAnimationFrame(doShipStep);
}
// Set the initial ship position to the start of the path
setShipOffset(0);
// If you want to set it to a particular "port", then you can use:
//setShipOffset(pathOffsets["one"]);
// Add click hadlers to all the circles
var allCircles = document.querySelectorAll("svg circle");
allCircles.forEach(function(circle) {
circle.addEventListener("click", startShipMovement);
});
.route {
position: relative;
background-color: linen;
}
.ship {
position: absolute;
width: 16px;
height: 16px;
border-radius: 50%;
border: solid 1px white;
background-color: limegreen;
transform: translate(-50%, -50%);
}
<div class="route">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" x="0px" y="0px" width="500px" viewBox="0 0 500 1920" xml:space="preserve">
<path class="cls-1" d="M288.56,7.45c1,1.17,13.77,15.18,14,16.67a8.66,8.66,0,0,1-.65,4.21,117.08,117.08,0,0,1-8.09,18.43c-.36.66-.82,1.39-1.56,1.55a2.71,2.71,0,0,1-1.88-.59L282.72,43a2.5,2.5,0,0,0-4.09.88C270.79,54.35,263,65.09,253.14,73.73c-3,2.61-6.16,5-8.71,8.06-.88,1-1.71,2.38-1.25,3.65a4.35,4.35,0,0,0,1.1,1.49,53.93,53.93,0,0,1,14.12,25.72,4.5,4.5,0,0,1,.12,2.12c-.59,2.2-3.69,2.33-5.41,3.84s-1.75,4.08-1.68,6.34a90,90,0,0,0,1.24,14.12c2,10.3,7.81,19.93,8.07,30.43-2.28,24.14-22.77,45.32-46.87,48.1-2.7.32-5.5.44-8,1.57a20.09,20.09,0,0,0-5,3.7c-32.78,29.91-57.73,67.22-82.35,104.13-2.88,4.32-5.79,8.7-7.48,13.61-2,5.91-2.2,12.26-2.35,18.5-.21,8.75-.38,17.73,2.58,26,3.67,10.22,11.8,18.29,15.91,28.34,4.49,10.93,3.91,23.44,8.47,34.35,1.61,3.85,3.84,7.44,5.16,11.4,2.32,6.94,1.68,14.52,3.28,21.65,2.18,9.7,8.12,20.64,3,29.16a373.16,373.16,0,0,0-36.31,54.7c-4.78,8.8-9.24,17.89-11.68,27.62-2.81,11.19-2.85,22.86-2.88,34.4,0,16.77,0,34,5.78,49.7,2.39,6.51,5.73,12.65,8,19.19,10.3,29.32-1.45,61.63,1,92.61.42,5.43,1.34,11,4,15.71,3.57,6.34,9.92,10.64,16.46,13.82,22.55,10.94,48.91,11,72.34,19.86,12.93,4.92,25.1,12.27,36.75,19.73,5.54-6.69,15.43-8.71,24.11-8.93s17.66.7,25.86-2.17a42.79,42.79,0,0,0,12.9-7.74c15.09-12.46,25-30,33.81-47.45,11.51-22.93,21.95-47.81,20.86-73.43-4.91-2.19-5.89-9.21-10.41-12.13-5.16-3.32-11.87-.21-18,0-7.93.27-15.06-4.5-21.47-9.19a604.83,604.83,0,0,1-70.37-60.38,24.51,24.51,0,0,1-5.05-6.35c-.8-1.66-1.24-3.5-2.27-5-2.1-3.15-6.11-4.31-9.77-5.27-35.8-9.32-70.81-22-104.91-36.35-4.52-7.11-4-16.94-4.71-25.34A85.91,85.91,0,0,0,99,520.19c-1.78-2.94-3.82-6-3.68-9.44a51.33,51.33,0,0,1,1-5.32c1-6.63-3.85-12.53-8-17.74-31.63-39.15-45.62-90.53-74.78-131.56a15.88,15.88,0,0,1-.82-14,14.43,14.43,0,0,1,10.56-8.1c2-.33,4.36-.43,5.38-2.16A5.54,5.54,0,0,0,28.8,328a120,120,0,0,0-3-11.95,21.64,21.64,0,0,0-2-4.93c-1.06-1.75-2.55-3.19-3.73-4.86a33.42,33.42,0,0,1-3.84-8.23c-3.28-9.13-6.58-18.33-8.06-27.92-1-6.17-1.14-12.44-2-18.62A86.93,86.93,0,0,0,.69,231a64.48,64.48,0,0,1,18.11-1.35c-14.94-40.19-3.59-88.94,27-119A156.85,156.85,0,0,1,64.48,95.09C80,83.88,96.75,74.38,113.42,64.9A46.07,46.07,0,0,1,124,60.05c5-1.35,10.31-.95,15.45-1.72C155.85,55.86,168,42.22,182.28,33.7c10.7-6.38,22.85-10,33.83-15.87,7.68-4.14,14.75-9.41,22.7-13s17.61-6.19,25.39-2.24c4.19,2.12,14.08-1.11,15-2.26"; />
<circle id="one" cx="295" cy="48" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="two" cx="263" cy="65" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="three" cx="258" cy="103" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="four" cx="252" cy="135" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="five" cx="131" cy="305" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="six" cx="147" cy="502" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="seven" cx="125" cy="538" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="eight" cx="110" cy="563" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="nine" cx="96" cy="619" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="ten" cx="110" cy="791" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="eleven" cx="216" cy="841" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twelve" cx="287" cy="846" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="thirteen" cx="323" cy="817" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="fourteen" cx="349" cy="766" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="fifteen" cx="355" cy="720" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="sixteen" cx="320" cy="705" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="seventeen" cx="265" cy="660" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="eighteen" cx="102" cy="528" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="nineteen" cx="96" cy="498" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twenty" cx="22" cy="306" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twentyone" cx="133" cy="59" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
<circle id="twentytwo" cx="230" cy="8" r="6" stroke="#c7374f" stroke-width="4.5" fill="white" />
</svg>
<div class="ship"></div>
</div>

Rotate SVG group indefinitely 360 degrees without CSS or Java

This is my first time diving into SVG. Is it possible to rotate this group 360 indefinitely without css or javascript/jquery? So far I have it rotating in the top left corner but I cannot seem to figure out how to center it.
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="576" height="576" viewBox="0 0 288 288" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id="seed" transform="translate(144,144)" stroke-width="2" stroke="black" fill="none" >
<circle cx="0" r="64" />
<circle cx="64" r="64" />
<circle cx="64" r="64" transform="rotate(60)" />
<circle cx="64" r="64" transform="rotate(120)" />
<circle cx="64" r="64" transform="rotate(180)" />
<circle cx="64" r="64" transform="rotate(240)" />
<circle cx="64" r="64" transform="rotate(300)" />
<circle cx="0" r="128" />
<animateTransform attributeType="xml" attributeName="transform" type="rotate" values="0 0 0; 360 0 0" dur="5s" repeatCount="indefinite" />
</g>
</svg>
Your animateTransform overwrites the transform on the <g> element. Looks like you want to provide an additional transform which you would with the attribute additive="sum"
<svg width="576" height="576" viewBox="0 0 288 288" xmlns="http://www.w3.org/2000/svg" version="1.1">
<g id="seed" transform="translate(144,144)" stroke-width="2" stroke="black" fill="none" >
<circle cx="0" r="64" />
<circle cx="64" r="64" />
<circle cx="64" r="64" transform="rotate(60)" />
<circle cx="64" r="64" transform="rotate(120)" />
<circle cx="64" r="64" transform="rotate(180)" />
<circle cx="64" r="64" transform="rotate(240)" />
<circle cx="64" r="64" transform="rotate(300)" />
<circle cx="0" r="128" />
<animateTransform attributeType="xml" attributeName="transform" type="rotate" values="0 0 0; 360 0 0" dur="5s" additive="sum" repeatCount="indefinite" />
</g>
</svg>
PaEDIT: My bad you probally mean JavaScript.
Okay you can calculate the center with JavaScript and a nice SVG-method called getBBox();
A method to return center of SVG-elements so your should also be possible. Okay piece of code
var svg = {
getCenterPosition: function(elem) {
// use the native SVG interface to get it's boundingBox
var bbox = elem.getBBox();
// return the center of the bounding box
return {
px: (bbox.x + bbox.width / 2).toFixed(2),
py: (bbox.y + bbox.height / 2).toFixed(2)
};
}
}
svg.getCenterPosition(yourGElementAsParameter); will return the center-coordinates. (web developer console or Firebug or something) Then you can set these coordinates in your attributes but don't alter the viewbox or anything it will now rotate around it's center.

SVG connect two points with a line

Is there any way to connect two point using a line in SVG .I am having the following to create point in SVG.
<?xml version="1.0" standalone="no"?>
<svg width="200px" height="200px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 10"/>
<!-- Points -->
<circle cx="10" cy="10" r="2" fill="red"/>
<circle cx="90" cy="90" r="2" fill="red"/>
<circle cx="90" cy="10" r="2" fill="red"/>
<circle cx="10" cy="90" r="2" fill="red"/>
</svg>
I need to draw a line between points using jquery functions.
You can use a line:
<line x1="10" y1="10" x2="90" y2="90" stroke-width="1" stroke="black"/>
Or a path:
<path d="M10 10 90 90" stroke-width="1" stroke="black"/>
Why do you need jQuery?
If you want to allow the user to connect the dots you need to dynamically change the points of the line or path. There are a few ways to do this however it can be done by tracking the start point then updating the line on mouse move.
var line = $("line");
var svg = $("svg");
var isDown = false;
var startX = 0;
var startY = 0;
$("circle").on("mousedown", function(event){
isDown = true;
var pOffset = svg.offset();
startX = event.clientX - pOffset.left,
startY = event.clientY - pOffset.top;
})
$("circle").on("mouseup", function(){
isDown = false;
})
svg.on("mousemove", function(event){
if(isDown){
var pOffset = svg.offset(),
px = event.clientX - pOffset.left,
py = event.clientY - pOffset.top;
line.attr("x1",startX)
line.attr("x2",px)
line.attr("y1",startY)
line.attr("y2",py)
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<svg width="200px" height="200px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="10" cy="10" r="10" fill="red"/>
<circle cx="90" cy="90" r="10" fill="red"/>
<circle cx="90" cy="10" r="10" fill="red"/>
<circle cx="10" cy="90" r="10" fill="red"/>
<line id="line" x1="10" y1="10" x2="90" y2="90" stroke="red" />
</svg>

Resources