I'm trying to generate an svg icon to use as Leaflet map markers. There's a circle which should be partially filled (vertically) based on a percentage variable between 0 and 1 (0 = no fill, 1 = full circle). I managed to accomplish what I need using a linear gradient, and that was working fine in Google Maps. Now I'm migrating to Leaflet, and apparently Leaflet doesn't support linear gradients in icons, as it doesn't render it properly. Or maybe it just doesn't support referencing elements with url().
This is what I have been using, using 0.4 as the fill percentage:
<svg width="25px" height="25px" viewBox="0 0 100 100" version="1.1">
<linearGradient id="perc" x1="0.4" y1="1" x2="0.4" y2="0">
<stop stop-color="#80C000" offset="0.4"/>
<stop stop-color="#fff" />
</linearGradient>
<ellipse id="outsideCircle" fill="#80C000" cx="50" cy="50" rx="42.8" ry="42.8"/>
<ellipse id="middleCircle" fill="url(#perc)" cx="50" cy="50" rx="41.2" ry="41.2"/>
<ellipse id="insideCircle" stroke="#80C000" fill="#EFFADC" stroke-width="1.6" cx="50" cy="50" rx="32" ry="32"/>
<text text-anchor="middle" font-family="Verdana" font-size="320%" font-weight="bold" dominant-baseline="central" x="50" y="48" fill="#80C000">A</text>
</svg>
Which renders as (enlarged for clarity):
However, using the exact same code in Leaflet always renders the full green circle, and I'm not sure why. So I'm looking for another way to accomplish this, maybe using Arcs? It would be great if I could generate the icons based on the same percentage variable, but I'm also open to just using 11 static icons (0, 0.1, 0.2, ..., 0.9, 1) and selecting one to use based on the percentage, rounding it.
I've found this question with some promising results, but I've been unable to adapt it to my use case.
CodePudding user response:
An alternative solution would be using a line path that you clip with the circle. Now you can use the stroke-dasharray attribute to set the stroke and the gap length of the path.
I'm using an input type range only to show how the result for different values.
let len = line.getTotalLength();
itr.addEventListener("input",()=>{
let dash = itr.value * len/100;
line.setAttribute("stroke-dasharray",`${dash},${100 - dash}`);
console.clear();console.log(itr.value)
})
<P><input type="range" value="25" id="itr"/></p>
<svg width="100" viewBox="0 0 100 100" version="1.1">
<text text-anchor="middle" font-family="Verdana" font-size="320%" font-weight="bold" dominant-baseline="central" x="50" y="48" fill="#80C000">A</text>
<clipPath id="clip">
<path id="circ" d="M92.8,50A42.8, 42.8 0 1 1 7.2,50A42.8,42.8 0 1 1 92.8,50 M82,50A32,32 0 1 0 18,50 A32,32 0 1 0 82,50" />
</clipPath>
<path id="line" stroke="#80C000" stroke-width="86" d="M50,92.8V7.2" clip-path="url(#clip)" stroke-dasharray="25 75" />
<use href="#circ" fill="none" stroke="#80C000" />
</svg>
Observation: I'm rewriting thecircle as a path with a hole in the middle like so:
<svg width="100" viewBox="0 0 100 100" version="1.1">
<path id="circ" d="M92.8,50A42.8, 42.8 0 1 1 7.2,50A42.8,42.8 0 1 1 92.8,50 M82,50A32,32 0 1 0 18,50 A32,32 0 1 0 82,50" />
</svg>
In order to draw a hole into the circle I'm drawing first the outer circle clockwise and nextnthe inner circle counterclockwise. I will use this shape for the clipPath but also for a <use>
element to draw the green stroke of the circle.