Apply on focus css when click on svg element - javascript

I have an svg file.
I would that when I click on a station name, the station stay scaled.
For that I used focus method and then in CSS with the selector :focused apply the effect
But that's not working , nothing is happening.
ps: you can ignore forEach loop it's not so important to understand
let stops = document.querySelector("#stops");
// all the g elements in the stops
let gs = stops.querySelectorAll("g");
// for each g in the gs
gs.forEach(g=>{
// the rectangle in this g element
let thisRect = g.querySelector("rect");
// the circle in this g element
let thisCircle = g.querySelector("circle");
// the coords of the circle's center used for the transform-origin
let x = thisCircle.getAttribute("cx");
let y = thisCircle.getAttribute("cy");
// the bounding box of the group
let bb = g.getBBox();
// set the rect's attributes
thisRect.setAttributeNS(null, "x", bb.x);
thisRect.setAttributeNS(null, "y", bb.y);
thisRect.setAttributeNS(null, "width", bb.width);
thisRect.setAttributeNS(null, "height", bb.height);
// set the value for the transform-origin for this group
g.style.transformOrigin = `${x}px ${y}px`;
})
document.getElementById('g3670').focus()
function showmessage() {
alert("heloo");
}
text{
font-family: Lato;
font-size:16px;
}
g * {pointer-events:none;}
g rect{pointer-events:all;}
#stops g{transform: scale(1);cursor: pointer;}
#stops g:hover {
transform: scale(2);
}
#stops g:active {
transform: scale(2)
}
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 775.43 469.98">
<defs>
<style>.cls-1{fill:none;stroke-width:5px;}.cls-1,.cls-2{stroke:#a15256;}.cls-2{fill:#fff;}.cls-3{isolation:isolate;font-size:42.79px;font-family:ArialMT, Arial;}</style>
</defs>
<title>line</title>
<path id="path7" class="cls-1" d="M202,67.72,329.33,215.86" transform="translate(-200.1 -66.09)" />
<path id="path8" class="cls-1" d="M329.35,215.87,449,355" transform="translate(-200.1 -66.09)" />
<path id="path9" class="cls-1" d="M449,355c41.53,51.11,96.22,63.08,117.9,69.28" transform="translate(-200.1 -66.09)" />
<path id="path10" class="cls-1" d="M566.86,424.29C655.43,460.48,977.38,391.48,973,536" transform="translate(-200.1 -66.09)" />
<g id="stops">
<g id="g3670">
<rect fill="none"/>
<circle class="cls-2" cx="129.24" cy="149.78" r="13.58" />
<text id="text3668" class="cls-3" transform="translate(145 160)">Station1</text>
</g>
<g id="g3700">
<rect fill="none"/>
<circle class="cls-2" cx="248.91" cy="288.93" r="13.58" />
<text id="text3698" class="cls-3" transform="translate(270 300)">Station2</text>
</g>
<g id="g3750">
<rect fill="none"/>
<circle class="cls-2" cx="366.75" cy="358.2" r="13.58" />
<text id="text3748" class="cls-3" transform="translate(200 400)">Station3</text>
</g>
</g>
</svg>

Add tabindex to stations:
let stops = document.querySelector("#stops");
// all the g elements in the stops
let gs = stops.querySelectorAll("g");
// for each g in the gs
gs.forEach((g, i) => {
g.setAttribute('tabindex', i);
// the rectangle in this g element
let thisRect = g.querySelector("rect");
// the circle in this g element
let thisCircle = g.querySelector("circle");
// the coords of the circle's center used for the transform-origin
let x = thisCircle.getAttribute("cx");
let y = thisCircle.getAttribute("cy");
// the bounding box of the group
let bb = g.getBBox();
// set the rect's attributes
thisRect.setAttributeNS(null, "x", bb.x);
thisRect.setAttributeNS(null, "y", bb.y);
thisRect.setAttributeNS(null, "width", bb.width);
thisRect.setAttributeNS(null, "height", bb.height);
// set the value for the transform-origin for this group
g.style.transformOrigin = `${x}px ${y}px`;
})
document.getElementById('g3670').focus()
function showmessage() {
alert("heloo");
}
text{
font-family: Lato;
font-size:16px;
}
g * {pointer-events:none;}
g rect{pointer-events:all;}
#stops g{transform: scale(1);cursor: pointer;transition:.3s}
#stops g:hover {
transform: scale(2);
}
#stops g:focus {
outline: 0;
transform: scale(2)
}
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 775.43 469.98">
<defs>
<style>.cls-1{fill:none;stroke-width:5px;}.cls-1,.cls-2{stroke:#a15256;}.cls-2{fill:#fff;}.cls-3{isolation:isolate;font-size:42.79px;font-family:ArialMT, Arial;}</style>
</defs>
<title>line</title>
<path id="path7" class="cls-1" d="M202,67.72,329.33,215.86" transform="translate(-200.1 -66.09)" />
<path id="path8" class="cls-1" d="M329.35,215.87,449,355" transform="translate(-200.1 -66.09)" />
<path id="path9" class="cls-1" d="M449,355c41.53,51.11,96.22,63.08,117.9,69.28" transform="translate(-200.1 -66.09)" />
<path id="path10" class="cls-1" d="M566.86,424.29C655.43,460.48,977.38,391.48,973,536" transform="translate(-200.1 -66.09)" />
<g id="stops">
<g id="g3670">
<rect fill="none"/>
<circle class="cls-2" cx="129.24" cy="149.78" r="13.58" />
<text id="text3668" class="cls-3" transform="translate(145 160)">Station1</text>
</g>
<g id="g3700">
<rect fill="none"/>
<circle class="cls-2" cx="248.91" cy="288.93" r="13.58" />
<text id="text3698" class="cls-3" transform="translate(270 300)">Station2</text>
</g>
<g id="g3750">
<rect fill="none"/>
<circle class="cls-2" cx="366.75" cy="358.2" r="13.58" />
<text id="text3748" class="cls-3" transform="translate(200 400)">Station3</text>
</g>
</g>
</svg>

This is how I would do it: on click I would toggle a class active for the clicked group. In your code I've added this:
g.addEventListener("click",()=>{
g.classList.toggle("active")
})
inside the forEach.
let stops = document.querySelector("#stops");
// all the g elements in the stops
let gs = stops.querySelectorAll("g");
// for each g in the gs
gs.forEach(g=>{
// the rectangle in this g element
let thisRect = g.querySelector("rect");
// the circle in this g element
let thisCircle = g.querySelector("circle");
// the coords of the circle's center used for the transform-origin
let x = thisCircle.getAttribute("cx");
let y = thisCircle.getAttribute("cy");
// the bounding box of the group
let bb = g.getBBox();
// set the rect's attributes
thisRect.setAttributeNS(null, "x", bb.x);
thisRect.setAttributeNS(null, "y", bb.y);
thisRect.setAttributeNS(null, "width", bb.width);
thisRect.setAttributeNS(null, "height", bb.height);
// set the value for the transform-origin for this group
g.style.transformOrigin = `${x}px ${y}px`;
g.addEventListener("click",()=>{
g.classList.toggle("active")
})
})
document.getElementById('g3670').focus()
function showmessage() {
console.log("heloo");
}
text{
font-family: Lato;
font-size:16px;
}
g * {pointer-events:none;}
g rect{pointer-events:all;}
#stops g{transform: scale(1);cursor: pointer;}
#stops g:hover {
transform: scale(2);
}
#stops g.active {
transform: scale(2)
}
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 775.43 469.98">
<defs>
<style>.cls-1{fill:none;stroke-width:5px;}.cls-1,.cls-2{stroke:#a15256;}.cls-2{fill:#fff;}.cls-3{isolation:isolate;font-size:42.79px;font-family:ArialMT, Arial;}</style>
</defs>
<title>line</title>
<path id="path7" class="cls-1" d="M202,67.72,329.33,215.86" transform="translate(-200.1 -66.09)" />
<path id="path8" class="cls-1" d="M329.35,215.87,449,355" transform="translate(-200.1 -66.09)" />
<path id="path9" class="cls-1" d="M449,355c41.53,51.11,96.22,63.08,117.9,69.28" transform="translate(-200.1 -66.09)" />
<path id="path10" class="cls-1" d="M566.86,424.29C655.43,460.48,977.38,391.48,973,536" transform="translate(-200.1 -66.09)" />
<g id="stops">
<g id="g3670">
<rect fill="none"/>
<circle class="cls-2" cx="129.24" cy="149.78" r="13.58" />
<text id="text3668" class="cls-3" transform="translate(145 160)">Station1</text>
</g>
<g id="g3700">
<rect fill="none"/>
<circle class="cls-2" cx="248.91" cy="288.93" r="13.58" />
<text id="text3698" class="cls-3" transform="translate(270 300)">Station2</text>
</g>
<g id="g3750">
<rect fill="none"/>
<circle class="cls-2" cx="366.75" cy="358.2" r="13.58" />
<text id="text3748" class="cls-3" transform="translate(200 400)">Station3</text>
</g>
</g>
</svg>

Related

Javascript to perform custom placement of svg text

I am working with a SVG element as following. In this I am using <textPath></textPath> to place a text on a path.
The svg is following
<!DOCTYPE html>
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="vBoxRect" width="1280" height="720" fill="green" rx="35" style="overflow: visible;"></rect>
<rect class="boundRect" x="70" y="70" width="1090" height="500" fill="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<path id="WorldAvg" class="WorldAvg" fill="none" stroke="white" stroke-width="5" opacity="1" d="M0,418.8448266855795L45.416666666666664,414.575606092466L90.83333333333333,411.52106545918446L136.25,407.6362492744353L181.66666666666666,404.77160362539087L227.08333333333334,393.4071256244998L272.5,391.02044947895274L317.9166666666667,386.66829128561017L363.3333333333333,379.8367479839252L408.75,378.1893224105598L454.1666666666667,369.95354728799214L499.5833333333333,368.77725419172447L545,363.8472517451793L590.4166666666666,363.6062134379884L635.8333333333334,357.4943259634553L681.25,351.27652154825586L726.6666666666666,344.34458188257486L772.0833333333334,342.18836536625594L817.5,338.5473949587725L862.9166666666666,336.1670218633692L908.3333333333334,332.6090887556393L953.75,328.1112436453848L999.1666666666666,321.4448005003716L1044.5833333333335,312.9573561957251L1090,306.4131526885112"></path>
<g class="avgLbl">
<text text-anchor="start" stroke="red">
<textPath href="#WorldAvg" startOffset="0%">10.3%</textPath>
</text>
<text text-anchor="end" stroke="red">
<textPath href="#WorldAvg" startOffset="100%">24.7%</textPath>
</text>
</g>
</svg>
</body>
</html>
My end goal is to place each text just above the path so that the text is clearly visible.
To achieve that, I tried the following which did not work. the label for 24.7% is pushed far down.
Is there a way to programatically achieve this?
const element = document.querySelectorAll('.avgLbl>text');
const comp = document.querySelector(`.bound>#WorldAvg`);
element.forEach(
(a, i) => {
const diff = comp.getBoundingClientRect().bottom - a.getBoundingClientRect().bottom;
a.setAttribute('transform', `translate(0,${diff})`)
}
);
<!DOCTYPE html>
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="vBoxRect" width="1280" height="720" fill="green" rx="35" style="overflow: visible;"></rect>
<rect class="boundRect" x="70" y="70" width="1090" height="500" fill="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<path id="WorldAvg" class="WorldAvg" fill="none" stroke="white" stroke-width="5" opacity="1" d="M0,418.8448266855795L45.416666666666664,414.575606092466L90.83333333333333,411.52106545918446L136.25,407.6362492744353L181.66666666666666,404.77160362539087L227.08333333333334,393.4071256244998L272.5,391.02044947895274L317.9166666666667,386.66829128561017L363.3333333333333,379.8367479839252L408.75,378.1893224105598L454.1666666666667,369.95354728799214L499.5833333333333,368.77725419172447L545,363.8472517451793L590.4166666666666,363.6062134379884L635.8333333333334,357.4943259634553L681.25,351.27652154825586L726.6666666666666,344.34458188257486L772.0833333333334,342.18836536625594L817.5,338.5473949587725L862.9166666666666,336.1670218633692L908.3333333333334,332.6090887556393L953.75,328.1112436453848L999.1666666666666,321.4448005003716L1044.5833333333335,312.9573561957251L1090,306.4131526885112"></path>
<g class="avgLbl">
<text text-anchor="start" stroke="red">
<textPath href="#WorldAvg" startOffset="0%">10.3%</textPath>
</text>
<text text-anchor="end" stroke="red">
<textPath href="#WorldAvg" startOffset="100%">24.7%</textPath>
</text>
</g>
</svg>
</body>
</html>
You could achieve a baseline offset by adjusting dominant-baseline and dy values like so:
svg {
display: block;
height: 100vmin;
}
text {
font-size: 30px
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect class="vBoxRect" width="1280" height="720" fill="green" rx="35" style="overflow: visible;"></rect>
<rect class="boundRect" x="70" y="70" width="1090" height="500" fill="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<path id="WorldAvg" class="WorldAvg" fill="none" stroke="white" stroke-width="5" opacity="1" d="M 0 418.8 L 45.4 414.6 L 90.8 411.5 L 136.3 407.6 L 181.7 404.8 L 227.1 393.4 L 272.5 391 L 317.9 386.7 L 363.3 379.8 L 408.8 378.2 L 454.2 370 L 499.6 368.8 L 545 363.8 L 590.4 363.6 L 635.8 357.5 L 681.3 351.3 L 726.7 344.3 L 772.1 342.2 L 817.5 338.5 L 862.9 336.2 L 908.3 332.6 L 953.8 328.1 L 999.2 321.4 L 1044.6 313 L 1090 306.4"></path>
<g class="avgLbl">
<text text-anchor="start" dominant-baseline="hanging" dy="10" stroke="red">
<textPath href="#WorldAvg" startOffset="0%">10.3%</textPath>
</text>
<text text-anchor="end" dominant-baseline="hanging" dy="10" stroke="red">
<textPath href="#WorldAvg" startOffset="100%">24.7%</textPath>
</text>
</g>
</svg>
dominant-baseline="hanging"
will position your text under your <textPath>
dy="10"
allows you to finetune the vertical alignment further:
Quite often capital letters ascenders will collide with your <textPath>.

How to reverse the order of svg elements

I am working with a svg element which is following
<svg class="layer1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150">
<rect class="bg" id="bg" width="150" height="150" fill="#e6e6e6"></rect>
<circle class="circ0" id="circ0" cx="75" cy="75" r="72" fill="none" stroke="blue" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle class="circ1" id="circ1" cx="75" cy="75" r="69" fill="none" stroke="green" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle class="circ2" id="circ2" cx="75" cy="75" r="66" fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round"></circle>
<script href="index.js"></script>
</svg>
I want to reverse the order of these circles with javascript, which I am currently doing by this way
const svg = document.querySelector("svg");
var x = document.querySelectorAll("[class^='circ']");
var bucket = [];
x.forEach((a, i) => {
bucket.push(a)
});
bucket.reverse();
x.forEach(
(a, i) => a.parentNode.removeChild(a)
);
bucket.forEach(
(a, i) => {
a.setAttribute("class", 'circ' + [i]);
a.setAttribute("id", "circ" + [i]);
svg.appendChild(a);
}
)
<svg class="layer1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150">
<rect class="bg" id="bg" width="150" height="150" fill="#e6e6e6"></rect>
<circle class="circ0" id="circ0" cx="75" cy="75" r="72" fill="none" stroke="blue" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle class="circ1" id="circ1" cx="75" cy="75" r="69" fill="none" stroke="green" stroke-linecap="round" stroke-linejoin="round"></circle>
<circle class="circ2" id="circ2" cx="75" cy="75" r="66" fill="none" stroke="red" stroke-linecap="round" stroke-linejoin="round"></circle>
<script href="index.js"></script>
</svg>
It gives me this
Is there a better way of doing this?
append(child) by itself moves DOM Nodes. So your code can be simplified.
But for complexer SVG you probably want to swap DOM positions, because there could be other Elements in between you don't want to affect.
Hold CTRL key to see what happens with append
Click to see the swapping version,
a matter of processing an Array and swapping the first with the last element.
Note: append was not available in Internet Explorer, that is why you see most posts using appendChild.
Modern browsers have loads more DOM goodies: replaceWith after , before etc.
<svg viewBox="0 0 10 10" style="height:200px">
<style>
text { font-size: 2px }
[y="3"]{ fill:yellow }
.first { stroke: black; stroke-width: 0.5 }
</style>
<rect class="bg" id="bg" width="10" height="10" fill="grey"></rect>
<circle class="first" id="c0" cx="2" cy="5" r="2" fill="red" />
<text x="0" y="3">R</text>
<circle class="second" id="c1" cx="4" cy="5" r="3" fill="green" />
<text x="1" y="3">G</text>
<circle class="last" id="c2" cx="6" cy="5" r="4" fill="blue" />
<text x="2" y="3">B</text>
<text x="1" y="6">Click Me!</text>
</svg>
<script>
let svg = document.querySelector("svg");
function append() {
[...svg.querySelectorAll("circle")]
.reverse().forEach((c, i) => {
c.parentNode.append(c);
c.setAttribute("class", c.id = 'c' + i);
});
}
function swap() {
function swapElements(e1, e2) {
let {id,previousSibling,className:{baseVal:c2}} = e2;
e1.after(e2); // put e2 after e1
e2.id = e1.id; e2.setAttribute("class", e1.getAttribute("class"));
previousSibling.after(e1); // put e1 after where e2 WAS
e1.id = id; e1.setAttribute("class", c2);
}
let circles = [...svg.querySelectorAll("circle")];
while (circles.length) {
let c1 = circles.shift();
if (circles.length) swapElements(c1, circles.pop())
}
}
svg.onclick = (e) => (e.ctrlKey && append()) || swap();
</script>

Fill Percentage area in a custom Oval SVG image

I would like to fill a custom SVG to a specific percentage.
Here is my initial SVG
<svg width="202" height="195" viewBox="0 0 202 195" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" d="M96.8166 4.06964C16.0794 8.40606 -20.4645 94.8546 20.2957 157.019C54.6867 204.16 143.361 202.123 184.273 150.807C226.464 97.5789 163.505 0.38025 96.8166 4.06964Z" stroke="#313848" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Suppose there is a progress of x% so I would like to fill this SVG like
<svg width="207" height="203" viewBox="0 0 207 203" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" d="M99.8166 12.0696C19.0794 16.4061 -17.4645 102.855 23.2957 165.019C57.6867 212.16 146.361 210.123 187.273 158.807C229.464 105.579 166.505 8.38025 99.8166 12.0696Z" stroke="#313848" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M99.8142 12.0736C166.502 8.38527 229.463 105.585 187.273 158.812" stroke="#EA7052" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M96.1683 2.4287C88.1789 2.85671 84.5529 11.2658 88.579 17.3074C91.9765 21.8887 100.751 21.6836 104.805 16.6905C108.986 11.5113 102.768 2.06471 96.1683 2.4287Z" fill="#EDEDEE" stroke="#EA7052" stroke-width="4.76054" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M171.545 162.236C169.583 169.548 177.007 175.33 184.329 173.522C189.985 171.84 192.408 163.889 188.57 158.747C184.582 153.434 173.156 156.193 171.545 162.236Z" fill="#EDEDEE" stroke="#EA7052" stroke-width="4.76054" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
I am not able to figure out how to achieve this.
I want it to be dynamic so that I can make it for any percentage.
Also, I need to animate it from the starting point to the endpoint in a circular motion.
Any help would be highly appreciatable.
As I've commented:
You can calculate the length of the path using the getTotalLength() method. This represents 100%.
Next you can get the length representing the x% (xperc in the code).
Now you can use stroke-dasharray to represent the partial path.
You can calculate the position of the last point using the getPointAtLength() method.
Please read the comments in my code.
//the desired percentege
let xperc = .35;
//the total length of the path
let tl = base.getTotalLength();
//the partial length at the given percentage xperc
let partial = tl * xperc;
//set the stroke-dasharray of the second use element
perc.setAttribute("stroke-dasharray", `${partial} ${tl -partial}`)
//calculate the position of the point marking the end position
let theEnd = base.getPointAtLength(partial);
// set the cx and the cy attributes for the end point
end.setAttribute("cx", theEnd.x);
end.setAttribute("cy", theEnd.y);
circle {
stroke: red;
fill:white;
stroke-width: 6.87634;
}
<svg width="207" height="203" viewBox="0 0 207 203" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="base" d="M99.8166,12.0696L99.8166,12.0696C166.505,8.38025 229.464,105.579 187.273,158.807C146.361,210.123 57.6867,212.16 23.2957,165.019C-17.4645,102.855 19.0794,16.4061 99.8166,12.0696Z" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</defs>
<use xlink:href="#base" stroke="silver" />
<use xlink:href="#base" stroke="red" id="perc" />
<circle cx="99.8166" cy="12.0696" r="10" />
<circle id="end" r="10" />
</svg>
OBSERVATION: since your path goes counter clockwise I had to reverse the path to get the desired result
And this is an example where I'm using an input type range to change the percent value:
let xperc = itr.value;
onInput();
itr.addEventListener("input", onInput)
function onInput() {
xperc = itr.value;
let tl = base.getTotalLength();
let partial = tl * xperc;
perc.setAttribute("stroke-dasharray", `${partial} ${tl - partial}`);
let theEnd = base.getPointAtLength(partial);
end.setAttribute("cx", theEnd.x);
end.setAttribute("cy", theEnd.y);
}
circle {
stroke: red;
fill:white;
stroke-width: 6.87634;
}
<input id="itr" type="range" min="0" max="1" step=".001" value=".35" /><br>
<svg width="207" viewBox="-5 -5 220 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="base" d="M99.8166,12.0696L99.8166,12.0696C166.505,8.38025 229.464,105.579 187.273,158.807C146.361,210.123 57.6867,212.16 23.2957,165.019C-17.4645,102.855 19.0794,16.4061 99.8166,12.0696Z" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</defs>
<use xlink:href="#base" stroke="silver" />
<use xlink:href="#base" stroke="red" id="perc" />
<circle cx="99.8166" cy="12.0696" r="10" />
<circle id="end" r="10" />
</svg>
And another demo where I'm using javascript to animate it from 0 to 1:
//the animation begins at 0
let xperc = 0;
//get the total length of the path
let tl = base.getTotalLength();
//the request animation id
let rid = null;
function Animation() {
rid = window.requestAnimationFrame(Animation);
// while xperc < 1 increase it's value by 0.001. Else stop the animation
if (xperc < 1) {
xperc += 0.001;
}else{window.cancelAnimationFrame(rid)}
//the same as in the first example
let partial = tl * xperc;
perc.setAttribute("stroke-dasharray", `${partial} ${tl - partial}`);
let theEnd = base.getPointAtLength(partial);
end.setAttribute("cx", theEnd.x);
end.setAttribute("cy", theEnd.y);
}
Animation();
circle {
stroke: red;
fill:white;
stroke-width: 6.87634;
}
<svg width="207" viewBox="-5 -5 220 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="base" d="M99.8166,12.0696L99.8166,12.0696C166.505,8.38025 229.464,105.579 187.273,158.807C146.361,210.123 57.6867,212.16 23.2957,165.019C-17.4645,102.855 19.0794,16.4061 99.8166,12.0696Z" stroke-width="6.87634" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</defs>
<use xlink:href="#base" stroke="silver" />
<use xlink:href="#base" stroke="red" id="perc" />
<circle cx="99.8166" cy="12.0696" r="10" />
<circle id="end" r="10" />
</svg>

Random Color to SVG rect

How can I make this possible? It's not working. I would like that the color of the rect changes after reload to one of the colors in the array.
This method isn't working. Can anybody help?
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<defs>
<style>
.cls-1 {
fill: #ff0000;
}
.cls-2 {
fill: #fff;
}
</style>
</defs>
<title>Logo MC</title>
<g id="Ebene_2" data-name="Ebene 2">
<g id="Ebene_1-2" data-name="Ebene 1">
<rect class="cls-1" width="72" height="72" />
<path class="cls-2" d="M12,20.41h4.62l7.61,13.17h.28l7.61-13.17h4.66V45.29H32.15V33l.28-4.17h-.28L25.83,40H23L16.65,28.85h-.28L16.65,33V45.29H12Z" />
<path class="cls-2" d="M63.22,41.29a12.21,12.21,0,0,1-4.34,3.39,13.84,13.84,0,0,1-10.76.16,13.18,13.18,0,0,1-6.86-17.12,12.54,12.54,0,0,1,6.86-6.86,13.15,13.15,0,0,1,5.16-1,11.75,11.75,0,0,1,9.32,4.07l-3.31,3.19a8.93,8.93,0,0,0-2.55-2.05,7.19,7.19,0,0,0-3.42-.76,8.68,8.68,0,0,0-3.27.61,7.82,7.82,0,0,0-2.66,1.72,8.17,8.17,0,0,0-1.79,2.69,9.77,9.77,0,0,0,0,7.06,8.17,8.17,0,0,0,1.79,2.69,8,8,0,0,0,2.66,1.72,8.88,8.88,0,0,0,3.27.61,7.92,7.92,0,0,0,3.7-.85,9.09,9.09,0,0,0,2.86-2.42Z" />
<path class="cls-2" d="M14,53.11h0a1.33,1.33,0,0,1-.14.19,1,1,0,0,1-.2.16,1.23,1.23,0,0,1-.26.12,1.65,1.65,0,0,1-.32,0,1,1,0,0,1-.45-.1,1,1,0,0,1-.36-.27,1.13,1.13,0,0,1-.25-.41,1.32,1.32,0,0,1-.1-.53,1.27,1.27,0,0,1,.1-.52,1.13,1.13,0,0,1,.25-.41,1,1,0,0,1,.36-.27A1,1,0,0,1,13,51a1.06,1.06,0,0,1,.58.15,1,1,0,0,1,.34.35h0l0-.34V50h.32v3.58H14Zm-.89.22a.8.8,0,0,0,.34-.07.69.69,0,0,0,.28-.2.87.87,0,0,0,.2-.32,1.14,1.14,0,0,0,.07-.43,1.18,1.18,0,0,0-.07-.43,1,1,0,0,0-.2-.32.77.77,0,0,0-.28-.19.8.8,0,0,0-.34-.07.83.83,0,0,0-.34.07.9.9,0,0,0-.28.2,1.16,1.16,0,0,0-.2.32,1.33,1.33,0,0,0,0,.85,1,1,0,0,0,.2.32.9.9,0,0,0,.28.2A.83.83,0,0,0,13.08,53.33Z" />
<path class="cls-2" d="M18.49,53a1.38,1.38,0,0,1-.17.25.93.93,0,0,1-.23.21,1.4,1.4,0,0,1-.3.15,1.52,1.52,0,0,1-.38,0,1.16,1.16,0,0,1-.49-.1.94.94,0,0,1-.38-.27,1.25,1.25,0,0,1-.26-.41,1.51,1.51,0,0,1-.09-.53,1.69,1.69,0,0,1,.08-.5,1.38,1.38,0,0,1,.24-.41,1.2,1.2,0,0,1,.38-.29,1.1,1.1,0,0,1,.49-.1,1.21,1.21,0,0,1,.48.09,1,1,0,0,1,.36.26,1.13,1.13,0,0,1,.23.4,1.46,1.46,0,0,1,.09.52v0a0,0,0,0,0,0,0v0h-2a1,1,0,0,0,.3.73.79.79,0,0,0,.29.17.89.89,0,0,0,.31.06.79.79,0,0,0,.49-.14,1.22,1.22,0,0,0,.3-.37Zm-.29-.86a.85.85,0,0,0-.05-.26.73.73,0,0,0-.14-.26.71.71,0,0,0-.25-.2.9.9,0,0,0-.39-.08,1,1,0,0,0-.29.05,1,1,0,0,0-.25.15.79.79,0,0,0-.19.25,1,1,0,0,0-.1.35Z" />
<path class="cls-2" d="M21.36,53.62a1.15,1.15,0,0,1-.37-.06,1.32,1.32,0,0,1-.29-.15,1.2,1.2,0,0,1-.22-.23.87.87,0,0,1-.14-.27l.28-.12a.92.92,0,0,0,.3.41.8.8,0,0,0,.44.13.75.75,0,0,0,.47-.13.38.38,0,0,0,.17-.3.37.37,0,0,0,0-.15.24.24,0,0,0-.09-.12.55.55,0,0,0-.17-.1l-.28-.09-.34-.08-.24-.08a.78.78,0,0,1-.22-.12,1,1,0,0,1-.17-.19.53.53,0,0,1-.06-.26.61.61,0,0,1,.08-.3.73.73,0,0,1,.21-.22,1,1,0,0,1,.3-.13,1.41,1.41,0,0,1,.35-.05,1,1,0,0,1,.3,0,1.08,1.08,0,0,1,.27.1,1.24,1.24,0,0,1,.22.18,1,1,0,0,1,.15.25l-.28.11a.63.63,0,0,0-.28-.3.81.81,0,0,0-.39-.1.78.78,0,0,0-.22,0l-.19.08a.44.44,0,0,0-.14.13.26.26,0,0,0-.05.17.25.25,0,0,0,.13.24,1.18,1.18,0,0,0,.37.15l.36.09a1.09,1.09,0,0,1,.55.27.58.58,0,0,1,.18.42.59.59,0,0,1-.07.29.72.72,0,0,1-.19.24,1,1,0,0,1-.31.16A1.14,1.14,0,0,1,21.36,53.62Z" />
<path class="cls-2" d="M24.41,50.45a.21.21,0,0,1-.17-.07.23.23,0,0,1-.08-.17.25.25,0,0,1,.08-.18.21.21,0,0,1,.17-.07.24.24,0,0,1,.18.07.29.29,0,0,1,.07.18.26.26,0,0,1-.07.17A.24.24,0,0,1,24.41,50.45Zm-.16,3.09V51.09h.32v2.45Z" />
<path class="cls-2" d="M27.71,54.7a1.09,1.09,0,0,1-.42-.07,1,1,0,0,1-.31-.16,1,1,0,0,1-.22-.23,1.49,1.49,0,0,1-.13-.25l.3-.12a.72.72,0,0,0,.29.39.84.84,0,0,0,.49.15.84.84,0,0,0,.67-.26,1,1,0,0,0,.22-.71v-.32h0a1.06,1.06,0,0,1-.35.35,1,1,0,0,1-.55.15,1,1,0,0,1-.45-.1,1,1,0,0,1-.36-.27,1.48,1.48,0,0,1-.35-.94,1.3,1.3,0,0,1,.1-.52,1.22,1.22,0,0,1,.25-.41,1,1,0,0,1,.36-.27,1,1,0,0,1,.45-.1,1,1,0,0,1,.55.15,1,1,0,0,1,.35.34h0v-.41h.31v2.37a1.45,1.45,0,0,1-.09.54,1,1,0,0,1-.26.39,1,1,0,0,1-.38.23A1.4,1.4,0,0,1,27.71,54.7Zm0-1.37a.8.8,0,0,0,.34-.07.76.76,0,0,0,.28-.2,1,1,0,0,0,.2-.31,1.2,1.2,0,0,0,.07-.44,1.18,1.18,0,0,0-.07-.43,1.16,1.16,0,0,0-.2-.32.87.87,0,0,0-.28-.19.8.8,0,0,0-.34-.07.78.78,0,0,0-.33.07,1,1,0,0,0-.47.52,1.08,1.08,0,0,0-.08.42,1.18,1.18,0,0,0,.08.43,1,1,0,0,0,.47.52A.78.78,0,0,0,27.72,53.33Z" />
<path class="cls-2" d="M31.31,51.55h0l.14-.21.2-.17a1,1,0,0,1,.25-.12.88.88,0,0,1,.29,0,.94.94,0,0,1,.39.07.78.78,0,0,1,.29.21.83.83,0,0,1,.16.31,1.29,1.29,0,0,1,.06.4v1.54h-.32V52.06a.81.81,0,0,0-.18-.58.64.64,0,0,0-.49-.18.72.72,0,0,0-.32.08.82.82,0,0,0-.25.21,1.08,1.08,0,0,0-.16.3,1,1,0,0,0-.06.35v1.3H31V51.09h.3Z" />
<path class="cls-2" d="M37.86,51.09h.3v.46h0a1.2,1.2,0,0,1,.13-.21,1.54,1.54,0,0,1,.19-.17,1.34,1.34,0,0,1,.24-.12A.78.78,0,0,1,39,51a.73.73,0,0,1,.5.16.84.84,0,0,1,.27.4,1.09,1.09,0,0,1,.34-.4.89.89,0,0,1,.54-.16.86.86,0,0,1,.38.07.75.75,0,0,1,.26.2.81.81,0,0,1,.15.31,1.6,1.6,0,0,1,.05.39v1.56h-.32V52a.93.93,0,0,0-.14-.55.54.54,0,0,0-.46-.19.61.61,0,0,0-.3.08.74.74,0,0,0-.23.2.85.85,0,0,0-.15.3,1,1,0,0,0-.06.34v1.32h-.32V52.05a.87.87,0,0,0-.14-.56.52.52,0,0,0-.45-.19.61.61,0,0,0-.3.08.69.69,0,0,0-.24.21.89.89,0,0,0-.15.31,1.49,1.49,0,0,0,0,.36v1.28h-.32Z" />
<path class="cls-2" d="M45.2,53.1h0a1,1,0,0,1-.35.37.88.88,0,0,1-.51.15,1.06,1.06,0,0,1-.37-.06,1,1,0,0,1-.3-.17.79.79,0,0,1-.19-.26.72.72,0,0,1-.07-.33.67.67,0,0,1,.08-.35.78.78,0,0,1,.22-.26A1.26,1.26,0,0,1,44,52a1.75,1.75,0,0,1,.4-.05,1.53,1.53,0,0,1,.45.06,1.33,1.33,0,0,1,.33.13V52a.73.73,0,0,0-.06-.3.63.63,0,0,0-.16-.23.7.7,0,0,0-.24-.15.87.87,0,0,0-.28-.05.85.85,0,0,0-.4.1.78.78,0,0,0-.29.28l-.28-.17a1,1,0,0,1,.39-.36,1.2,1.2,0,0,1,.57-.13,1.23,1.23,0,0,1,.44.07.93.93,0,0,1,.33.21.84.84,0,0,1,.22.31,1.07,1.07,0,0,1,.07.41v1.53H45.2Zm0-.65a1.66,1.66,0,0,0-.33-.15,1.2,1.2,0,0,0-.4-.06,1.36,1.36,0,0,0-.3,0,.9.9,0,0,0-.24.12.52.52,0,0,0-.16.17.5.5,0,0,0-.06.24.54.54,0,0,0,0,.22.57.57,0,0,0,.15.16.64.64,0,0,0,.2.11.85.85,0,0,0,.23,0,.71.71,0,0,0,.32-.07.77.77,0,0,0,.28-.19.92.92,0,0,0,.19-.28A.8.8,0,0,0,45.2,52.45Z" />
<path class="cls-2" d="M48.11,52.85a.43.43,0,0,0,.11.32.28.28,0,0,0,.24.11h.12l.12,0,.1.27a.49.49,0,0,1-.17.06l-.21,0a.64.64,0,0,1-.44-.17.6.6,0,0,1-.14-.2.85.85,0,0,1-.05-.3V51.38h-.44v-.29h.44v-.75h.32v.75h1.12v-.75h.32v.75h.61v.29h-.61v1.47a.43.43,0,0,0,.11.32.28.28,0,0,0,.24.11H50l.12,0,.1.27a.49.49,0,0,1-.17.06l-.21,0a.64.64,0,0,1-.44-.17.6.6,0,0,1-.14-.2.85.85,0,0,1-.05-.3V51.38H48.11Z" />
<path class="cls-2" d="M54.27,53a1.38,1.38,0,0,1-.17.25.93.93,0,0,1-.23.21,1.4,1.4,0,0,1-.3.15,1.52,1.52,0,0,1-.38,0,1.16,1.16,0,0,1-.49-.1,1.05,1.05,0,0,1-.39-.27,1.41,1.41,0,0,1-.25-.41,1.51,1.51,0,0,1-.09-.53,1.69,1.69,0,0,1,.08-.5,1.38,1.38,0,0,1,.24-.41,1.2,1.2,0,0,1,.38-.29,1.1,1.1,0,0,1,.49-.1,1.21,1.21,0,0,1,.48.09,1,1,0,0,1,.36.26,1.13,1.13,0,0,1,.23.4,1.46,1.46,0,0,1,.09.52v0a0,0,0,0,0,0,0v0h-2a1,1,0,0,0,.3.73.79.79,0,0,0,.29.17.89.89,0,0,0,.31.06.79.79,0,0,0,.49-.14,1.22,1.22,0,0,0,.3-.37ZM54,52.1a.85.85,0,0,0,0-.26.73.73,0,0,0-.14-.26.71.71,0,0,0-.25-.2.9.9,0,0,0-.39-.08,1,1,0,0,0-.29.05,1,1,0,0,0-.25.15.79.79,0,0,0-.19.25,1,1,0,0,0-.1.35Z" />
<path class="cls-2" d="M56.26,53.54V51.09h.3v.43h0a.78.78,0,0,1,.11-.2.9.9,0,0,1,.18-.16.7.7,0,0,1,.21-.11.51.51,0,0,1,.2,0l.19,0,.15,0-.1.29a.7.7,0,0,0-.28,0,.59.59,0,0,0-.25.07.68.68,0,0,0-.21.17.72.72,0,0,0-.14.26,1,1,0,0,0-.06.34v1.38Z" />
<path class="cls-2" d="M60.19,53.62a1,1,0,0,1-.36-.06,1,1,0,0,1-.52-.38.87.87,0,0,1-.14-.27l.28-.12a.92.92,0,0,0,.3.41.8.8,0,0,0,.44.13.75.75,0,0,0,.47-.13.38.38,0,0,0,.17-.3.37.37,0,0,0,0-.15.24.24,0,0,0-.09-.12.55.55,0,0,0-.17-.1l-.28-.09-.34-.08-.24-.08a.78.78,0,0,1-.22-.12,1,1,0,0,1-.17-.19.53.53,0,0,1-.06-.26.61.61,0,0,1,.08-.3.73.73,0,0,1,.21-.22,1,1,0,0,1,.3-.13,1.41,1.41,0,0,1,.35-.05,1,1,0,0,1,.3,0,1.08,1.08,0,0,1,.27.1,1.24,1.24,0,0,1,.22.18,1,1,0,0,1,.15.25l-.28.11a.67.67,0,0,0-.27-.3.88.88,0,0,0-.4-.1.78.78,0,0,0-.22,0l-.19.08a.58.58,0,0,0-.14.13.34.34,0,0,0,0,.17.25.25,0,0,0,.13.24,1.18,1.18,0,0,0,.37.15l.36.09a1.17,1.17,0,0,1,.56.27.61.61,0,0,1,.17.42.59.59,0,0,1-.07.29.61.61,0,0,1-.19.24.91.91,0,0,1-.31.16A1.14,1.14,0,0,1,60.19,53.62Z" />
</g>
</g>
<script type="text/javascript">
var colors = ['#ff0000', '#00ff00', '#0000ff'];
var random_color = colors[Math.floor(Math.random() * colors.length)];
document.getElementsByClassName('cls-1').fill = random_color;
</script>
Try:
<script type="text/javascript">
var colors = ['#ff0000', '#00ff00', '#0000ff'];
var random_color = colors[Math.floor(Math.random() * colors.length)];
document.getElementsByClassName('cls-1')[0].style.fill = random_color;
</script>
https://jsfiddle.net/ibowankenobi/knkg5gss/3/
In addition to ibowankenobi's answer:
You may want to loop through all your getElementsByClassName selections, in case you have more than one match:
var colors = ['#ff0000', '#00ff00', '#0000ff'];
var random_color = colors[Math.floor(Math.random() * colors.length)];
var myElements = document.getElementsByClassName('cls-1');
for(var i = 0; i < myElements.length; i++)
{
myElements[i].style.fill = random_color;
}
Full working example, with a color changing interval of 5 seconds:
function setColor(){
var colors = ['#ff0000', '#00ff00', '#0000ff'];
var random_color = colors[Math.floor(Math.random() * colors.length)];
var myElements = document.getElementsByClassName('cls-1');
for(var i = 0; i < myElements.length; i++)
{
myElements[i].style.fill = random_color;
}
}
setInterval(function(){
setColor();
}, 5000);
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72 72">
<defs>
<style>
.cls-1 {
fill: #ff0000;
}
.cls-2 {
fill: #fff;
}
</style>
</defs>
<title>Logo MC</title>
<g id="Ebene_2" data-name="Ebene 2">
<g id="Ebene_1-2" data-name="Ebene 1">
<rect class="cls-1" width="72" height="72" />
<path class="cls-2" d="M12,20.41h4.62l7.61,13.17h.28l7.61-13.17h4.66V45.29H32.15V33l.28-4.17h-.28L25.83,40H23L16.65,28.85h-.28L16.65,33V45.29H12Z" />
<path class="cls-2" d="M63.22,41.29a12.21,12.21,0,0,1-4.34,3.39,13.84,13.84,0,0,1-10.76.16,13.18,13.18,0,0,1-6.86-17.12,12.54,12.54,0,0,1,6.86-6.86,13.15,13.15,0,0,1,5.16-1,11.75,11.75,0,0,1,9.32,4.07l-3.31,3.19a8.93,8.93,0,0,0-2.55-2.05,7.19,7.19,0,0,0-3.42-.76,8.68,8.68,0,0,0-3.27.61,7.82,7.82,0,0,0-2.66,1.72,8.17,8.17,0,0,0-1.79,2.69,9.77,9.77,0,0,0,0,7.06,8.17,8.17,0,0,0,1.79,2.69,8,8,0,0,0,2.66,1.72,8.88,8.88,0,0,0,3.27.61,7.92,7.92,0,0,0,3.7-.85,9.09,9.09,0,0,0,2.86-2.42Z" />
<path class="cls-2" d="M14,53.11h0a1.33,1.33,0,0,1-.14.19,1,1,0,0,1-.2.16,1.23,1.23,0,0,1-.26.12,1.65,1.65,0,0,1-.32,0,1,1,0,0,1-.45-.1,1,1,0,0,1-.36-.27,1.13,1.13,0,0,1-.25-.41,1.32,1.32,0,0,1-.1-.53,1.27,1.27,0,0,1,.1-.52,1.13,1.13,0,0,1,.25-.41,1,1,0,0,1,.36-.27A1,1,0,0,1,13,51a1.06,1.06,0,0,1,.58.15,1,1,0,0,1,.34.35h0l0-.34V50h.32v3.58H14Zm-.89.22a.8.8,0,0,0,.34-.07.69.69,0,0,0,.28-.2.87.87,0,0,0,.2-.32,1.14,1.14,0,0,0,.07-.43,1.18,1.18,0,0,0-.07-.43,1,1,0,0,0-.2-.32.77.77,0,0,0-.28-.19.8.8,0,0,0-.34-.07.83.83,0,0,0-.34.07.9.9,0,0,0-.28.2,1.16,1.16,0,0,0-.2.32,1.33,1.33,0,0,0,0,.85,1,1,0,0,0,.2.32.9.9,0,0,0,.28.2A.83.83,0,0,0,13.08,53.33Z" />
<path class="cls-2" d="M18.49,53a1.38,1.38,0,0,1-.17.25.93.93,0,0,1-.23.21,1.4,1.4,0,0,1-.3.15,1.52,1.52,0,0,1-.38,0,1.16,1.16,0,0,1-.49-.1.94.94,0,0,1-.38-.27,1.25,1.25,0,0,1-.26-.41,1.51,1.51,0,0,1-.09-.53,1.69,1.69,0,0,1,.08-.5,1.38,1.38,0,0,1,.24-.41,1.2,1.2,0,0,1,.38-.29,1.1,1.1,0,0,1,.49-.1,1.21,1.21,0,0,1,.48.09,1,1,0,0,1,.36.26,1.13,1.13,0,0,1,.23.4,1.46,1.46,0,0,1,.09.52v0a0,0,0,0,0,0,0v0h-2a1,1,0,0,0,.3.73.79.79,0,0,0,.29.17.89.89,0,0,0,.31.06.79.79,0,0,0,.49-.14,1.22,1.22,0,0,0,.3-.37Zm-.29-.86a.85.85,0,0,0-.05-.26.73.73,0,0,0-.14-.26.71.71,0,0,0-.25-.2.9.9,0,0,0-.39-.08,1,1,0,0,0-.29.05,1,1,0,0,0-.25.15.79.79,0,0,0-.19.25,1,1,0,0,0-.1.35Z" />
<path class="cls-2" d="M21.36,53.62a1.15,1.15,0,0,1-.37-.06,1.32,1.32,0,0,1-.29-.15,1.2,1.2,0,0,1-.22-.23.87.87,0,0,1-.14-.27l.28-.12a.92.92,0,0,0,.3.41.8.8,0,0,0,.44.13.75.75,0,0,0,.47-.13.38.38,0,0,0,.17-.3.37.37,0,0,0,0-.15.24.24,0,0,0-.09-.12.55.55,0,0,0-.17-.1l-.28-.09-.34-.08-.24-.08a.78.78,0,0,1-.22-.12,1,1,0,0,1-.17-.19.53.53,0,0,1-.06-.26.61.61,0,0,1,.08-.3.73.73,0,0,1,.21-.22,1,1,0,0,1,.3-.13,1.41,1.41,0,0,1,.35-.05,1,1,0,0,1,.3,0,1.08,1.08,0,0,1,.27.1,1.24,1.24,0,0,1,.22.18,1,1,0,0,1,.15.25l-.28.11a.63.63,0,0,0-.28-.3.81.81,0,0,0-.39-.1.78.78,0,0,0-.22,0l-.19.08a.44.44,0,0,0-.14.13.26.26,0,0,0-.05.17.25.25,0,0,0,.13.24,1.18,1.18,0,0,0,.37.15l.36.09a1.09,1.09,0,0,1,.55.27.58.58,0,0,1,.18.42.59.59,0,0,1-.07.29.72.72,0,0,1-.19.24,1,1,0,0,1-.31.16A1.14,1.14,0,0,1,21.36,53.62Z" />
<path class="cls-2" d="M24.41,50.45a.21.21,0,0,1-.17-.07.23.23,0,0,1-.08-.17.25.25,0,0,1,.08-.18.21.21,0,0,1,.17-.07.24.24,0,0,1,.18.07.29.29,0,0,1,.07.18.26.26,0,0,1-.07.17A.24.24,0,0,1,24.41,50.45Zm-.16,3.09V51.09h.32v2.45Z" />
<path class="cls-2" d="M27.71,54.7a1.09,1.09,0,0,1-.42-.07,1,1,0,0,1-.31-.16,1,1,0,0,1-.22-.23,1.49,1.49,0,0,1-.13-.25l.3-.12a.72.72,0,0,0,.29.39.84.84,0,0,0,.49.15.84.84,0,0,0,.67-.26,1,1,0,0,0,.22-.71v-.32h0a1.06,1.06,0,0,1-.35.35,1,1,0,0,1-.55.15,1,1,0,0,1-.45-.1,1,1,0,0,1-.36-.27,1.48,1.48,0,0,1-.35-.94,1.3,1.3,0,0,1,.1-.52,1.22,1.22,0,0,1,.25-.41,1,1,0,0,1,.36-.27,1,1,0,0,1,.45-.1,1,1,0,0,1,.55.15,1,1,0,0,1,.35.34h0v-.41h.31v2.37a1.45,1.45,0,0,1-.09.54,1,1,0,0,1-.26.39,1,1,0,0,1-.38.23A1.4,1.4,0,0,1,27.71,54.7Zm0-1.37a.8.8,0,0,0,.34-.07.76.76,0,0,0,.28-.2,1,1,0,0,0,.2-.31,1.2,1.2,0,0,0,.07-.44,1.18,1.18,0,0,0-.07-.43,1.16,1.16,0,0,0-.2-.32.87.87,0,0,0-.28-.19.8.8,0,0,0-.34-.07.78.78,0,0,0-.33.07,1,1,0,0,0-.47.52,1.08,1.08,0,0,0-.08.42,1.18,1.18,0,0,0,.08.43,1,1,0,0,0,.47.52A.78.78,0,0,0,27.72,53.33Z" />
<path class="cls-2" d="M31.31,51.55h0l.14-.21.2-.17a1,1,0,0,1,.25-.12.88.88,0,0,1,.29,0,.94.94,0,0,1,.39.07.78.78,0,0,1,.29.21.83.83,0,0,1,.16.31,1.29,1.29,0,0,1,.06.4v1.54h-.32V52.06a.81.81,0,0,0-.18-.58.64.64,0,0,0-.49-.18.72.72,0,0,0-.32.08.82.82,0,0,0-.25.21,1.08,1.08,0,0,0-.16.3,1,1,0,0,0-.06.35v1.3H31V51.09h.3Z" />
<path class="cls-2" d="M37.86,51.09h.3v.46h0a1.2,1.2,0,0,1,.13-.21,1.54,1.54,0,0,1,.19-.17,1.34,1.34,0,0,1,.24-.12A.78.78,0,0,1,39,51a.73.73,0,0,1,.5.16.84.84,0,0,1,.27.4,1.09,1.09,0,0,1,.34-.4.89.89,0,0,1,.54-.16.86.86,0,0,1,.38.07.75.75,0,0,1,.26.2.81.81,0,0,1,.15.31,1.6,1.6,0,0,1,.05.39v1.56h-.32V52a.93.93,0,0,0-.14-.55.54.54,0,0,0-.46-.19.61.61,0,0,0-.3.08.74.74,0,0,0-.23.2.85.85,0,0,0-.15.3,1,1,0,0,0-.06.34v1.32h-.32V52.05a.87.87,0,0,0-.14-.56.52.52,0,0,0-.45-.19.61.61,0,0,0-.3.08.69.69,0,0,0-.24.21.89.89,0,0,0-.15.31,1.49,1.49,0,0,0,0,.36v1.28h-.32Z" />
<path class="cls-2" d="M45.2,53.1h0a1,1,0,0,1-.35.37.88.88,0,0,1-.51.15,1.06,1.06,0,0,1-.37-.06,1,1,0,0,1-.3-.17.79.79,0,0,1-.19-.26.72.72,0,0,1-.07-.33.67.67,0,0,1,.08-.35.78.78,0,0,1,.22-.26A1.26,1.26,0,0,1,44,52a1.75,1.75,0,0,1,.4-.05,1.53,1.53,0,0,1,.45.06,1.33,1.33,0,0,1,.33.13V52a.73.73,0,0,0-.06-.3.63.63,0,0,0-.16-.23.7.7,0,0,0-.24-.15.87.87,0,0,0-.28-.05.85.85,0,0,0-.4.1.78.78,0,0,0-.29.28l-.28-.17a1,1,0,0,1,.39-.36,1.2,1.2,0,0,1,.57-.13,1.23,1.23,0,0,1,.44.07.93.93,0,0,1,.33.21.84.84,0,0,1,.22.31,1.07,1.07,0,0,1,.07.41v1.53H45.2Zm0-.65a1.66,1.66,0,0,0-.33-.15,1.2,1.2,0,0,0-.4-.06,1.36,1.36,0,0,0-.3,0,.9.9,0,0,0-.24.12.52.52,0,0,0-.16.17.5.5,0,0,0-.06.24.54.54,0,0,0,0,.22.57.57,0,0,0,.15.16.64.64,0,0,0,.2.11.85.85,0,0,0,.23,0,.71.71,0,0,0,.32-.07.77.77,0,0,0,.28-.19.92.92,0,0,0,.19-.28A.8.8,0,0,0,45.2,52.45Z" />
<path class="cls-2" d="M48.11,52.85a.43.43,0,0,0,.11.32.28.28,0,0,0,.24.11h.12l.12,0,.1.27a.49.49,0,0,1-.17.06l-.21,0a.64.64,0,0,1-.44-.17.6.6,0,0,1-.14-.2.85.85,0,0,1-.05-.3V51.38h-.44v-.29h.44v-.75h.32v.75h1.12v-.75h.32v.75h.61v.29h-.61v1.47a.43.43,0,0,0,.11.32.28.28,0,0,0,.24.11H50l.12,0,.1.27a.49.49,0,0,1-.17.06l-.21,0a.64.64,0,0,1-.44-.17.6.6,0,0,1-.14-.2.85.85,0,0,1-.05-.3V51.38H48.11Z" />
<path class="cls-2" d="M54.27,53a1.38,1.38,0,0,1-.17.25.93.93,0,0,1-.23.21,1.4,1.4,0,0,1-.3.15,1.52,1.52,0,0,1-.38,0,1.16,1.16,0,0,1-.49-.1,1.05,1.05,0,0,1-.39-.27,1.41,1.41,0,0,1-.25-.41,1.51,1.51,0,0,1-.09-.53,1.69,1.69,0,0,1,.08-.5,1.38,1.38,0,0,1,.24-.41,1.2,1.2,0,0,1,.38-.29,1.1,1.1,0,0,1,.49-.1,1.21,1.21,0,0,1,.48.09,1,1,0,0,1,.36.26,1.13,1.13,0,0,1,.23.4,1.46,1.46,0,0,1,.09.52v0a0,0,0,0,0,0,0v0h-2a1,1,0,0,0,.3.73.79.79,0,0,0,.29.17.89.89,0,0,0,.31.06.79.79,0,0,0,.49-.14,1.22,1.22,0,0,0,.3-.37ZM54,52.1a.85.85,0,0,0,0-.26.73.73,0,0,0-.14-.26.71.71,0,0,0-.25-.2.9.9,0,0,0-.39-.08,1,1,0,0,0-.29.05,1,1,0,0,0-.25.15.79.79,0,0,0-.19.25,1,1,0,0,0-.1.35Z" />
<path class="cls-2" d="M56.26,53.54V51.09h.3v.43h0a.78.78,0,0,1,.11-.2.9.9,0,0,1,.18-.16.7.7,0,0,1,.21-.11.51.51,0,0,1,.2,0l.19,0,.15,0-.1.29a.7.7,0,0,0-.28,0,.59.59,0,0,0-.25.07.68.68,0,0,0-.21.17.72.72,0,0,0-.14.26,1,1,0,0,0-.06.34v1.38Z" />
<path class="cls-2" d="M60.19,53.62a1,1,0,0,1-.36-.06,1,1,0,0,1-.52-.38.87.87,0,0,1-.14-.27l.28-.12a.92.92,0,0,0,.3.41.8.8,0,0,0,.44.13.75.75,0,0,0,.47-.13.38.38,0,0,0,.17-.3.37.37,0,0,0,0-.15.24.24,0,0,0-.09-.12.55.55,0,0,0-.17-.1l-.28-.09-.34-.08-.24-.08a.78.78,0,0,1-.22-.12,1,1,0,0,1-.17-.19.53.53,0,0,1-.06-.26.61.61,0,0,1,.08-.3.73.73,0,0,1,.21-.22,1,1,0,0,1,.3-.13,1.41,1.41,0,0,1,.35-.05,1,1,0,0,1,.3,0,1.08,1.08,0,0,1,.27.1,1.24,1.24,0,0,1,.22.18,1,1,0,0,1,.15.25l-.28.11a.67.67,0,0,0-.27-.3.88.88,0,0,0-.4-.1.78.78,0,0,0-.22,0l-.19.08a.58.58,0,0,0-.14.13.34.34,0,0,0,0,.17.25.25,0,0,0,.13.24,1.18,1.18,0,0,0,.37.15l.36.09a1.17,1.17,0,0,1,.56.27.61.61,0,0,1,.17.42.59.59,0,0,1-.07.29.61.61,0,0,1-.19.24.91.91,0,0,1-.31.16A1.14,1.14,0,0,1,60.19,53.62Z" />
</g>
</g>
</svg>

Calculate SVG.Text Length before drawing [duplicate]

I want to color the background of svg text similar to background-color in css
I was only able to find documentation on fill, which colors the text itself
Is it even possible?
You could use a filter to generate the background.
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" result="bg" />
<feMerge>
<feMergeNode in="bg"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">solid background</text>
</svg>
No this is not possible, SVG elements do not have background-... presentation attributes.
To simulate this effect you could draw a rectangle behind the text attribute with fill="green" or something similar (filters). Using JavaScript you could do the following:
var ctx = document.getElementById("the-svg"),
textElm = ctx.getElementById("the-text"),
SVGRect = textElm.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", SVGRect.x);
rect.setAttribute("y", SVGRect.y);
rect.setAttribute("width", SVGRect.width);
rect.setAttribute("height", SVGRect.height);
rect.setAttribute("fill", "yellow");
ctx.insertBefore(rect, textElm);
The solution I have used is:
<svg>
<line x1="100" y1="100" x2="500" y2="100" style="stroke:black; stroke-width: 2"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.6em">Hello World!</text>
<text x="150" y="105" style="fill:black">Hello World!</text>
</svg>
A duplicate text item is being placed, with stroke and stroke-width attributes. The stroke should match the background colour, and the stroke-width should be just big enough to create a "splodge" on which to write the actual text.
A bit of a hack and there are potential issues, but works for me!
Instead of using a <text> tag, the <foreignObject> tag can be used, which allows for XHTML content with CSS.
No, you can not add background color to SVG elements. You can do it programmatically with d3.
var text = d3.select("text");
var bbox = text.node().getBBox();
var padding = 2;
var rect = self.svg.insert("rect", "text")
.attr("x", bbox.x - padding)
.attr("y", bbox.y - padding)
.attr("width", bbox.width + (padding*2))
.attr("height", bbox.height + (padding*2))
.style("fill", "red");
Answer by Robert Longson (#RobertLongson) with modifications:
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow"/>
<feComposite in="SourceGraphic" operator="xor"/>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50"> solid background </text>
<text x="20" y="50" font-size="50">solid background</text>
</svg>
and we have no bluring and no heavy "getBBox" :)
Padding is provided by white spaces in text-element with filter.
It's worked for me
Going further with #dbarton_uk answer, to avoid duplicating text you can use paint-order=stroke style:
<svg>
<line x1="100" y1="100" x2="350" y2="100" style="stroke:grey; stroke-width: 100"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.5em; fill:black; paint-order:stroke; stroke-linejoin:round">Hello World!</text>
</svg>
Note the stroke-linejoin:round which is needed to avoid seeing spikes for the W sharp angle.
You can combine filter with the text.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>SVG colored patterns via mask</title>
</head>
<body>
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter x="0" y="0" width="1" height="1" id="bg-text">
<feFlood flood-color="white"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<!-- something has already existed -->
<rect fill="red" x="150" y="20" width="100" height="50" />
<circle cx="50" cy="50" r="50" fill="blue"/>
<!-- Text render here -->
<text filter="url(#bg-text)" fill="black" x="20" y="50" font-size="30">text with color</text>
<text fill="black" x="20" y="50" font-size="30">text with color</text>
</svg>
</body>
</html>
For those wondering how to apply padding to a text element when it has a background like in the Robert's answer, do the following:
<svg>
<defs>
<filter x="-0.1" y="-0.1" width="1.2" height="1.2" id="solid">
<feFlood flood-color="#171717"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">Hello</text>
</svg>
In the example above, filter's x and y positions can be used as transform: translate(-10%, -10%) would, and width and height values can be read as 120% and 120%. So we made background 20% bigger, and offsetted it -10%, so background is now 10% bigger on each side of the text.
this is my favorite hack (not sure it should work). It refer an element that is not yet displayed, and it works pretty well
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 620 40" preserveAspectRatio="xMidYMid meet">
<defs>
<filter x="-0.02" y="0" width="1.04" height="1.1" id="removebackground">
<feFlood flood-color="#00ffff"/>
</filter>
</defs>
<!--Draw the text-->
<use xlink:href="#mygroup" filter="url(#removebackground)" />
<g id="mygroup">
<text id="text1" x="9" y="20" style="text-anchor:start;font-size:14px;">custom text with background</text>
<line x1="200" y1="18" x2="200" y2="36" stroke="#000" stroke-width="5"/>
<line x1="120" y1="27" x2="203" y2="27" stroke="#000" stroke-width="5"/>
</g>
</svg>
The previous answers relied on doubling up text and lacked sufficient whitespace.
By using atop and I was able to get the results I wanted.
This example also includes arrows, a common use case for SVG text labels:
<svg viewBox="-105 -40 210 234">
<title>Size Guide</title>
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="white"></feFlood>
<feComposite in="SourceGraphic" operator="atop"></feComposite>
</filter>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z"></path>
</marker>
</defs>
<g id="garment">
<path id="right-body" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 0 l30 0 l0 154 l-30 0"></path>
<path id="right-sleeve" d="M30 0 l35 0 l0 120 l-35 0" fill="none" stroke-linejoin="round" stroke="black" stroke-width="1"></path>
<use id="left-body" href="#right-body" transform="scale(-1,1)"></use>
<use id="left-sleeve" href="#right-sleeve" transform="scale(-1,1)"></use>
<path id="collar-right-top" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 -6.5 l11.75 0 l6.5 6.5"></path>
<use id="collar-left-top" href="#collar-right-top" transform="scale(-1,1)"></use>
<path id="collar-left" fill="white" stroke="black" stroke-width="1" stroke-linejoin="round" d="M-11.75 -6.5 l-6.5 6.5 l30 77 l6.5 -6.5 Z"></path>
<path id="front-right" fill="white" stroke="black" stroke-width="1" d="M18.25 0 L30 0 l0 154 l-41.75 0 l0 -77 Z"></path>
<line x1="0" y1="0" x2="0" y2="154" stroke="black" stroke-width="1" stroke-dasharray="1 3"></line>
<use id="collar-right" href="#collar-left" transform="scale(-1,1)"></use>
</g>
<g id="dimension-labels">
<g id="dimension-sleeve-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="85" y1="0" x2="85" y2="120" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="85" y="60" class="dimension" text-anchor="middle" dominant-baseline="middle"> 120 cm</text>
</g>
<g id="dimension-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-85" y1="0" x2="-85" y2="154" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="-85" y="77" text-anchor="middle" dominant-baseline="middle" class="dimension"> 154 cm</text>
</g>
<g id="dimension-sleeve-to-sleeve">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-65" y1="-20" x2="65" y2="-20" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="-20" text-anchor="middle" dominant-baseline="middle" class="dimension"> 130 cm </text>
</g>
<g title="Back Width" id="dimension-back-width">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-30" y1="174" x2="30" y2="174" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="174" text-anchor="middle" dominant-baseline="middle" class="dimension"> 60 cm </text>
</g>
</g>
</svg>
An obvious workaround to the problem of the blur produced by the filter effect is to render the <text> two times: once for the background (with transparent characters) and once for the characters (without a background filter).
For me, this was the only way to make the text readable in Safari.
<svg width="100%" height="100%">
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" />
</filter>
<g transform="translate(20, 50)" font-size="50">
<text aria-hidden="true" fill="none" filter="url(#solid)">solid background</text>
<text fill="blue">solid background</text>
</g>
</svg>
The aria-hidden="true" attribute is there to prevent screen readers from speaking the text twice, if the user uses a screen reader.
You can add style to your text:
style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
text-shadow: rgb(255, 255, 255) -2px -2px 0px, rgb(255, 255, 255) -2px 2px 0px,
rgb(255, 255, 255) 2px -2px 0px, rgb(255, 255, 255) 2px 2px 0px;"
White, in this example.
Does not work in IE :)

Categories