How to center an SVG element based on another element using js? - javascript

I made an SVG face and want to center each pupil in their respective eye.
I tried doing this by getting the center of the eye using getBoundingClientRect(). However when I set the position of the pupil this way it didn't work as expected (it did not center, and changes location based on size of page).
I'm guessing getBoundingClientRect() is related to a global position and the cx, cy attributes are local, but it's not clear to me what the attributes are local to or how I would fix it
Any ideas why this doesn't work and what approach might fix it?
Code
// Center the pupil in the eye. Side param is "left" or "right"
function center_pupil(side) {
let eye = document.querySelector(`#${side}-eye`).getBoundingClientRect()
let pupil = document.querySelector(`#${side}-pupil`)
let pupil_radius = pupil.getAttribute("r")
pupil.setAttribute("cx", eye.left + eye.width / 2 - pupil_radius)
pupil.setAttribute("cy", eye.top + eye.height / 2 - pupil_radius)
}
center_pupil("left")
center_pupil("right")
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 645.72 579.45">
<defs>
<clipPath id="clip-path" transform="translate(-114.91 -242.55)">
<path d="M544,377s9-21,54-25c0,0,114-7,150,25s-43,86-43,86-33.77,18.6-79.06,11.62C615.11,473,587.67,468.87,563,448c-10.53-8.91-25.76-21.79-27-42C535.2,393.05,540.49,382.61,544,377Z"
fill="none" />
</clipPath>
<clipPath id="clip-path-2" transform="translate(-114.91 -242.55)">
<path d="M117.5,397.5a38.69,38.69,0,0,1,8-11c6.89-6.57,14.55-8.78,19-10,32.47-8.93,45-10,45-10,34.68-2.95,53.54-4.56,81-1,33.83,4.38,50.79,6.54,61,21,13.58,19.24,5,45.13,4,48-6.94,20.08-23.19,30.46-35,38a106,106,0,0,1-29.07,12.82,108,108,0,0,1-39.93,3.18c-4.63.72-54.1,7.55-88.32-28.91C120.39,435.31,117.91,406.25,117.5,397.5Z"
fill="none" />
</clipPath>
</defs>
<title>face</title>
<g id="eyes">
<g id="right-eye">
<path d="M540.89,375.37A28.23,28.23,0,0,1,548.4,367a24,24,0,0,1,2.19-1.6c.76-.5,1.5-1,2.26-1.48,1.56-.86,3.07-1.81,4.67-2.55s3.14-1.57,4.76-2.23c.8-.34,1.6-.69,2.39-1.06l2.42-.94c.81-.31,1.61-.65,2.42-1s1.64-.56,2.46-.85l2.46-.81a25.18,25.18,0,0,1,2.49-.73c1.68-.43,3.34-.91,5-1.36s3.38-.71,5.07-1.07l2.54-.55,2.56-.41,5.14-.82c1.81-.26,3.45-.36,5.17-.53l5.12-.43q5.12-.4,10.23-.65a289.41,289.41,0,0,1,41,.71c6.82.65,13.62,1.57,20.39,2.63s13.51,2.37,20.23,3.71,13.41,2.9,20.15,4.54c1.69.38,3.36.86,5,1.36l2.51.73c.83.26,1.65.58,2.48.87l2.47.9c.82.3,1.61.71,2.42,1.05a49,49,0,0,1,4.78,2.33,52.84,52.84,0,0,1,4.63,2.72l2.26,1.48c.75.49,1.44,1.12,2.16,1.68l2.12,1.72c.67.65,1.37,1.27,2,2a30,30,0,0,1,3.57,4.42c.57.78,1,1.65,1.5,2.47s.88,1.73,1.21,2.64a25.41,25.41,0,0,1,1.57,5.59,29.78,29.78,0,0,1-.37,11.31c-4.58,14.09-13,25.18-22.33,35.35a178.89,178.89,0,0,1-14.84,14.31q-3.88,3.39-8,6.53c-2.72,2.11-5.44,4.15-8.32,6.15l-.11.08-.1.05c-2.33,1.23-4.54,2.18-6.86,3.13s-4.62,1.77-7,2.58c-4.68,1.57-9.43,2.87-14.23,4a151.83,151.83,0,0,1-29.28,3.67c-2.46,0-4.93.12-7.39.07l-7.41-.31-7.38-.71c-2.46-.23-4.85-.58-7.3-.93a131.55,131.55,0,0,1-28.88-7.35,114.07,114.07,0,0,1-13.69-6.28c-2.25-1.13-4.38-2.49-6.55-3.78-1.08-.65-2.09-1.41-3.14-2.11s-2.12-1.4-3.1-2.19a143.74,143.74,0,0,1-11.34-9.74,83.58,83.58,0,0,1-10.05-11.51A57.13,57.13,0,0,1,535.46,420a53.51,53.51,0,0,1-2.89-15.38,48.4,48.4,0,0,1,2-15.44,50,50,0,0,1,2.7-7.28c.54-1.17,1.12-2.32,1.76-3.44.31-.56.64-1.11,1-1.65S540.59,375.83,540.89,375.37Zm6.22,3.26c-.75,1.3-1.25,2.21-1.77,3.23s-1,2-1.52,3a56.3,56.3,0,0,0-2.49,6.29,41.51,41.51,0,0,0-2,13.2,34.3,34.3,0,0,0,2.84,12.95,45.72,45.72,0,0,0,7.15,11.32,91.37,91.37,0,0,0,9.77,9.7c3.46,3.07,7.29,6.18,10.83,9a112.56,112.56,0,0,0,23.73,14.54,121.21,121.21,0,0,0,13.15,5,135,135,0,0,0,13.72,3.63c2.31.47,4.7,1,7,1.32s4.69.73,7,1l7.1.56c2.37.13,4.75.12,7.13.18a128.42,128.42,0,0,0,28.29-3.39,135,135,0,0,0,13.69-4c2.23-.81,4.46-1.64,6.63-2.57s4.39-1.91,6.33-3l-.21.13c5.43-3.8,10.71-8.06,15.86-12.34s10.1-8.85,14.78-13.63a103.24,103.24,0,0,0,12.64-15.43,47.41,47.41,0,0,0,4.69-8.65,40.34,40.34,0,0,0,2.28-9.25,33.29,33.29,0,0,0,.35-4.54,22.19,22.19,0,0,0-.46-4.4,20.11,20.11,0,0,0-1.34-4.15c-.25-.67-.64-1.3-1-1.95s-.74-1.27-1.2-1.86a29.21,29.21,0,0,0-6.38-6.48c-.62-.47-1.2-1-1.86-1.44l-2-1.34a46,46,0,0,0-4.12-2.49c-11.39-6-24.05-11.23-37.37-13.24-13.25-2.37-26.77-3-40.22-3.48s-26.92-1-40.43-1.38l-10.13-.24-5.07-.07c-1.66,0-3.42,0-5,0a108.23,108.23,0,0,0-19.78,2.72,24.43,24.43,0,0,0-2.41.65l-2.39.72a43.68,43.68,0,0,0-4.71,1.63c-.77.32-1.55.6-2.3.94s-1.48.75-2.21,1.14-1.47.74-2.17,1.18l-2.06,1.35-1,.68c-.33.24-.64.51-1,.76l-1.9,1.53c-.6.54-1.18,1.11-1.76,1.65a20.72,20.72,0,0,0-1.67,1.71c-.54.58-1.07,1.17-1.54,1.78a21.79,21.79,0,0,0-1.41,1.83l-.66.93-.59.93c-.21.31-.34.62-.52.93-.09.15-.15.29-.22.43Z"
transform="translate(-114.91 -242.55)" />
</g>
<path d="M505,327" transform="translate(-114.91 -242.55)" />
<g id="left-eye">
<path d="M114.91,397a8.77,8.77,0,0,1,.41-1.29c.07-.21.14-.43.22-.65.15-.43.33-.85.52-1.27a23.67,23.67,0,0,1,1.3-2.43,33.63,33.63,0,0,1,3.35-4.38,39.68,39.68,0,0,1,8.37-7.14,45.38,45.38,0,0,1,9.88-4.59c3.45-1.11,6.75-1.8,10-2.64,6.64-1.59,13.29-3.11,20-4.49,3.35-.68,6.71-1.32,10.08-1.9,1.69-.29,3.38-.58,5.08-.84l2.56-.36,1.29-.16.66-.08.33,0,.17,0,.34,0h-.15l10-.79c3.36-.27,6.71-.48,10.05-1s6.66-1.26,10-1.68,6.74-.55,10.13-.72c6.78-.27,13.6-.4,20.41-.06s13.6.93,20.33,1.86,13.33,1.84,20,2.91a156,156,0,0,1,20.08,4.29c.83.26,1.66.55,2.49.83s1.65.56,2.47.91l2.45,1,2.4,1.19a37.88,37.88,0,0,1,8.79,6.29,39.43,39.43,0,0,1,6.43,8.62,19,19,0,0,1,1.21,2.38l1.11,2.43.86,2.52a18.46,18.46,0,0,1,.77,2.53,57.7,57.7,0,0,1,1.39,20.78,77.82,77.82,0,0,1-1.71,10.2c-.41,1.68-.84,3.35-1.38,5s-1.2,3.27-1.82,4.9a80.14,80.14,0,0,1-10.73,18l-.83,1-.87,1c-.6.64-1.17,1.32-1.79,1.94-1.24,1.23-2.49,2.46-3.82,3.59a93.34,93.34,0,0,1-8.31,6.24c-1.42.95-2.85,1.9-4.28,2.81s-2.82,1.81-4.32,2.74q-4.45,2.71-9.14,5a111.57,111.57,0,0,1-19.45,7.27,109.85,109.85,0,0,1-41.18,3l.81,0a96.63,96.63,0,0,1-10.64.84c-3.53.09-7.06,0-10.58-.18a118,118,0,0,1-20.88-3.16A104.42,104.42,0,0,1,170,482a97.9,97.9,0,0,1-18-11.15,94.11,94.11,0,0,1-26.21-32.74,104.55,104.55,0,0,1-7.36-19.73q-1.36-5.09-2.24-10.3c-.28-1.74-.57-3.48-.77-5.23-.12-.87-.2-1.75-.29-2.63l-.07-.66-.07-.86C114.94,398.15,114.92,397.55,114.91,397Zm5.18,1.08a7,7,0,0,1,.08.79l0,1.06c.05.83.09,1.67.17,2.5.11,1.68.31,3.34.51,5,.46,3.33,1.1,6.63,1.88,9.91.39,1.63.86,3.25,1.32,4.86s1,3.21,1.62,4.78c1.17,3.15,2.48,6.25,4,9.27a87.88,87.88,0,0,0,42.45,41.16,99.57,99.57,0,0,0,19,6.34,112.17,112.17,0,0,0,19.92,2.62c3.35.14,6.71.15,10.05,0a89,89,0,0,0,9.9-.94l.38-.06.43,0a105.31,105.31,0,0,0,19.53.1A110.47,110.47,0,0,0,270.55,482a104.55,104.55,0,0,0,18.21-6.92,96.58,96.58,0,0,0,8.52-4.71c1.36-.84,2.79-1.77,4.18-2.67s2.76-1.83,4.12-2.75c2.72-1.85,5.3-3.82,7.85-5.8s5-4,7.4-6.21a51.27,51.27,0,0,0,6.53-7.12,42.86,42.86,0,0,0,4.84-8.38,61.67,61.67,0,0,0,4.57-18.91,52.32,52.32,0,0,0-1.7-19.18,18.18,18.18,0,0,0-.76-2.26l-.84-2.22-1.06-2.12a16.05,16.05,0,0,0-1.13-2.08,35,35,0,0,0-5.82-7.29,34.22,34.22,0,0,0-7.68-5.19l-2.14-1-2.23-.86c-.73-.3-1.5-.55-2.27-.78s-1.53-.49-2.31-.71a160.49,160.49,0,0,0-19.39-3.74c-6.59-.93-13.26-1.73-19.92-2.52a264.5,264.5,0,0,0-39.7-1.74c-3.33.07-6.65.33-10,.27s-6.72-.28-10.08-.29a96.26,96.26,0,0,0-10.05.57l-10,.9h-.16l-2.26.33-2.48.41c-1.65.29-3.3.61-4.95.95-3.3.7-6.59,1.48-9.87,2.28-6.56,1.62-13.08,3.42-19.58,5.32-3.23,1-6.56,1.86-9.53,3a39,39,0,0,0-8.42,4.28,34.43,34.43,0,0,0-6.92,6.22,46.51,46.51,0,0,0-2.8,3.73l-1.37,1.92-.7,1-.37.48A.39.39,0,0,0,120.09,398Z"
transform="translate(-114.91 -242.55)" />
</g>
</g>
<g clip-path="url(#clip-path)">
<circle id="right-pupil" cx="532.09" cy="125.45" r="31" />
</g>
<g clip-path="url(#clip-path-2)">
<circle id="left-pupil" cx="116.59" cy="139.95" r="31" />
</g>
<g id="Layer_4" data-name="Layer 4">
<path d="M505,264s120-29,194-10" transform="translate(-114.91 -242.55)" fill="none" stroke="#000"
stroke-miterlimit="10" stroke-width="10" />
<path d="M154,280s116-27,179,0" transform="translate(-114.91 -242.55)" fill="none" stroke="#000"
stroke-miterlimit="10" stroke-width="10" />
<path d="M390,401c9.15,143.49,6.63,190.63,2,205,0,0-6.53,20.28-2,41a35.35,35.35,0,0,0,4,10s1.3,2.14,8,10"
transform="translate(-114.91 -242.55)" fill="none" stroke="#000" stroke-miterlimit="10"
stroke-width="10" />
<line x1="321.09" y1="415.45" x2="329.09" y2="424.45" fill="none" stroke="#000" stroke-miterlimit="10"
stroke-width="10" />
<path d="M363,774l146-4s-1,47-73,47S363,774,363,774Z" transform="translate(-114.91 -242.55)" fill="none"
stroke="#000" stroke-miterlimit="10" stroke-width="10" />
</g>
</svg>
What I'm currently seeing
Note: pupil location changes based on screen size

Related

how to increase loading percentage in SVG?

I am very new to SVG, I have a SVG already in my theme, it looks like something this.
The SVG Html looks like this
<div id="apexcharts1q6mbbep" class="apexcharts-canvas apexcharts1q6mbbep apexcharts-theme-light" style="width: 40px; height: 41px;"><svg id="SvgjsSvg1099" width="40" height="41" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev" class="apexcharts-svg" xmlns:data="ApexChartsNS" transform="translate(0, 0)" style="background: transparent;">
<g id="SvgjsG1101" class="apexcharts-inner apexcharts-graphical" transform="translate(0, 0)">
<defs id="SvgjsDefs1100">
<clipPath id="gridRectMask1q6mbbep">
<rect id="SvgjsRect1103" width="46" height="42" x="-3" y="-1" rx="0" ry="0" opacity="1" stroke-width="0" stroke="none" stroke-dasharray="0" fill="#fff"></rect>
</clipPath>
<clipPath id="forecastMask1q6mbbep"></clipPath>
<clipPath id="nonForecastMask1q6mbbep"></clipPath>
<clipPath id="gridRectMarkerMask1q6mbbep">
<rect id="SvgjsRect1104" width="44" height="44" x="-2" y="-2" rx="0" ry="0" opacity="1" stroke-width="0" stroke="none" stroke-dasharray="0" fill="#fff"></rect>
</clipPath>
</defs>
<g id="SvgjsG1105" class="apexcharts-radialbar">
<g id="SvgjsG1106">
<g id="SvgjsG1107" class="apexcharts-tracks">
<g id="SvgjsG1108" class="apexcharts-radialbar-track apexcharts-track" rel="1">
<path id="apexcharts-radialbarTrack-0" d="M 20 4.146341463414631 A 15.85365853658537 15.85365853658537 0 1 1 19.99723301461454 4.1463417048796565" fill="none" fill-opacity="1" stroke="rgba(242,242,242,0.85)" stroke-opacity="1" stroke-linecap="butt" stroke-width="2.3658536585365857" stroke-dasharray="0" class="apexcharts-radialbar-area" data:pathOrig="M 20 4.146341463414631 A 15.85365853658537 15.85365853658537 0 1 1 19.99723301461454 4.1463417048796565"></path>
</g>
</g>
<g id="SvgjsG1110">
<g id="SvgjsG1112" class="apexcharts-series apexcharts-radial-series" seriesName="series-1" rel="1" data:realIndex="0">
<path id="SvgjsPath1113" d="M 20 4.146341463414631 A 15.85365853658537 15.85365853658537 0 1 1 14.061114982430661 34.699256230936875" fill="none" fill-opacity="0.85" stroke="rgba(47,179,68,0.85)" stroke-opacity="1" stroke-linecap="butt" stroke-width="2.439024390243903" stroke-dasharray="0" class="apexcharts-radialbar-area apexcharts-radialbar-slice-0" data:angle="202" data:value="56" index="0" j="0" data:pathOrig="M 20 4.146341463414631 A 15.85365853658537 15.85365853658537 0 1 1 14.061114982430661 34.699256230936875"></path>
</g>
<circle id="SvgjsCircle1111" r="14.670731707317076" cx="20" cy="20" class="apexcharts-radialbar-hollow" fill="transparent"></circle>
</g>
</g>
</g>
<line id="SvgjsLine1114" x1="0" y1="0" x2="40" y2="0" stroke="#b6b6b6" stroke-dasharray="0" stroke-width="1" stroke-linecap="butt" class="apexcharts-ycrosshairs"></line>
<line id="SvgjsLine1115" x1="0" y1="0" x2="40" y2="0" stroke-dasharray="0" stroke-width="0" stroke-linecap="butt" class="apexcharts-ycrosshairs-hidden"></line>
</g>
<g id="SvgjsG1102" class="apexcharts-annotations"></g>
</svg>
<div class="apexcharts-legend"></div>
</div>
I played around <cicle> tag but I failed to increase the percentage. Currently you can see the loading icon is around 50% I want to make it dynamic.
Can anyone help me out?

How to position an SVG circle along another circle's path

I'm building a Gauge chart in a presentational component in React.
I just need to pass it a percentage and let the component do the rest. I can't use any animations because I'm taking a screenshot of the component to place the image in a Powerpoint presentation.
Here's a screenshot of what I'm trying to do:
As you can see in my code snippet, the circle <marker> is being positioned at the end of the grey <path> instead of at the end of the green <path>. How could I position the circle so it sits at the stroke-linecap of the green <path> as in the image above?
Here's the HTML code I have so far:
<div style="width:400px">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker
id="dot"
viewBox="0 0 10 10"
refX="4"
refY="4"
markerWidth="4"
markerHeight="4"
>
<circle
cx="4"
cy="4"
r="2"
fill="#FFFFFF"
stroke="#008000"
stroke-width="2"
/>
</marker>
</defs>
<path d="M20,60a35,35 0 1,1 60,0" stroke="#D3D7DB" stroke-width="4" fill="none" stroke-linecap="round"></path>
<path d="M20,60a35,35 0 1,1 60,0" stroke="#008000" stroke-width="6" pathLength="100" fill="none" stroke-linecap="round" stroke-dasharray="75 35" marker-end="url(#dot)"></path>
</svg>
</div>
You can do it all in SVG by setting pathLength and using animationMotion to position the circle.
Some JavaScript and a W3C standard Web Component (supported in all modern Browsers) help in putting multiple gauges on screen and making them dynamic.
customElements.define("svg-gauge", class extends HTMLElement {
connectedCallback() {
let speed = 0.5; // set to 0.0001 for instant display!
let arc = "M20,60a35,35 0 1,1 60,0";
let col = this.getAttribute("color") || "green";
this.innerHTML =
`<input type="range" min="0" max="100" step="5" value="0"`+ // delete 2 lines
` oninput="this.parentNode.percent=this.value" /><br>`+ // just for demo
`<svg viewbox="0 0 100 100">
<path d="${arc}" stroke="grey" stroke-width="6" fill="none" stroke-linecap="round"></path>
<path id="P" d="${arc}" stroke="${col}" stroke-width="8" pathLength="100" fill="none" stroke-linecap="round" stroke-dasharray="75 35"/>
<circle stroke="${col}" cx="0" cy="0" fill="#fff" r="4" stroke-width="3">
<animateMotion dur="${speed}s" path="${arc}" keyPoints="0;0.75" fill="freeze" keyTimes="0;1" calcMode="linear"/>
</circle>
<text x="50%" y="40%" text-anchor="middle">XXX</text>
</svg>`;
this.style.display='inline-block';
this.percent = this.getAttribute("value") || "50";
}
set percent(val = 0) {
this.setAttribute("value", val);
let dash = val + " " + (105 - val);
this.querySelector("#P").setAttribute('stroke-dasharray', dash);
this.querySelector("animateMotion").setAttribute('keyPoints', '0;'+val/100);
this.querySelector("text").innerHTML =`${val} %`;
this.querySelector("animateMotion").beginElement();
this.querySelector("input").value = val;
}
})
<svg-gauge value="35" color="red" ></svg-gauge>
<svg-gauge value="50" color="orange"></svg-gauge>
<svg-gauge value="75" color="green" ></svg-gauge>
I went ahead and accepted Danny '365CSI' Engelman's answer above, but just in case anyone wants to do this without the animations here is how I ended up implementing it:
<div style="width:400px">
<svg viewBox="0 -10 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="M20,60a35,35 0 1,1 60,0" stroke="#D3D7DB" stroke-width="4" fill="none" stroke-linecap="round"></path>
<path d="M20,60a35,35 0 1,1 60,0" stroke="#008000" stroke-width="6" pathLength="100" fill="none" stroke-linecap="round" stroke-dasharray="50 85"></path>
<circle
cx="0"
cy="0"
r="6"
stroke-width="6"
fill="#FFFFFF"
stroke="#008000"
>
<animateMotion
begin="0s"
dur="infinite"
repeatCount="infinite"
keyPoints="0.5;0.5"
fill="freeze"
keyTimes="0;1"
calcMode="linear"
path="M20,60a35,35 0 1,1 60,0"
></animateMotion>
</circle>
</svg>
</div>

How to change fill color SVG object for specific path id via AngularJS

svg:
<path id="svg_1" stroke-width="0.5" stroke="black" fill="none" d="m50.610001,63.470001l12.869999,0m0,0l0,464.709991m0,0l-12.869999,0m0,0l0,-464.709991"/>
<path id="svg_2" stroke-width="0.5" stroke="black" fill="none" d="m66.529999,260.670013l12.870003,0m0,0l-0.029999,267.519989m0,0l-12.870003,0m0,0l0.029999,-267.519989"/>
<path id="svg_3" stroke-width="0.5" stroke="black" fill="none" d="m66.519997,275.440002l-3.039997,0"/>
html:
<div ng-include="'example.svg'"></div>
I would like to change fill color for id="svg_2" for example on button click, How to do it?
The problem are your paths. After every line you are using a move to command (m) where you are moving to the last point. I've rewritten the first 2 paths bu removing the move to (m0,0) Now the paths can be filled. The third path is just a line.
Now you can fill the paths using css or bu resetting the value of the attribute fill
path{fill:red}
<svg viewBox="0 0 130 600" width="100">
<path id="svg_1" stroke-width="0.5" stroke="black" fill="none" d="M50.610001,63.470001l12.869999,0
l0,464.709991
l-12.869999,0
l0,-464.709991"/>
<path id="svg_2" stroke-width="0.5" stroke="black" fill="none" d="M66.529999,260.670013l12.870003,0
l-0.029999,267.519989
l-12.870003,0
l0.029999,-267.519989"/>
<path id="svg_3" stroke-width="0.5" stroke="black" fill="none" d="m66.519997,275.440002l-3.039997,0"/>
</svg>

How to add text on click SVG rectangle using JS

I have this SVG file... I want to add some text when clicking to rectangles and it shouldn't for the black one... Like when i click on any rectangle then it should be >> g rectangle text /g
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1200px" height="800px" viewBox="0 0 1200 800" enable-background="new 0 0 1200 800" xml:space="preserve">
<!-- <rect x="50.683" y="111.41" fill="#FFFFFF" stroke="#231F20" stroke-width="3" stroke-miterlimit="10" width="1116.428" height="578.514"/> -->
<rect x="76.564" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="173.42" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="270.276" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="367.133" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="463.989" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="667.414" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="764.27" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="861.126" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="957.983" y="132.216" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.681" height="84.682"/>
<rect x="1054.839" y="132.216" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="41.042" y="351.442" fill="#FFFFFF" width="23.851" height="112.15"/>
<rect x="31.853" y="375.293" fill="#494849" width="1118.006" height="65.463"/>
<rect x="76.564" y="252.552" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="173.42" y="252.552" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
</svg>
You will need to create the text node. The x and y of the text - in this case - is the center of the rect.
Please read the comments in my code.
const SVG_NS = 'http://www.w3.org/2000/svg';
//the array of the rects with a white fill
let rects = Array.from(svg.querySelectorAll("rect[fill='#FFFFFF']"));
//an array of true values as long as the rects array
let arr = Array(rects.length).fill(true);
//for each rect in the rects array
rects.forEach((r,i)=>{
//get the position end the size of the rect (the bounding box)
let bb = r.getBBox();
//the center of the rect
let x = bb.x + bb.width/2;
let y = bb.y + bb.height/2;
//on click
r.addEventListener("click", ()=>{
//if there isn't already a text element there
if(arr[i]){
//add a text element
let txt = drawSVGelmt({x:x,y:y},"text", svg)
txt.textContent = i;
arr[i] = false;
}
})
})
// a function to create a new svg element
function drawSVGelmt(o,tag, parent) {
let elmt = document.createElementNS(SVG_NS, tag);
for (var name in o) {
if (o.hasOwnProperty(name)) {
elmt.setAttributeNS(null, name, o[name]);
}
}
parent.appendChild(elmt);
return elmt;
}
text{text-anchor:middle; dominant-baseline:middle}
<svg id="svg" width="1200px" height="800px" viewBox="0 0 1200 800" >
<rect x="76.564" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="173.42" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="270.276" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="367.133" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="463.989" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="667.414" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="764.27" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="861.126" y="133.804" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="957.983" y="132.216" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.681" height="84.682"/>
<rect x="1054.839" y="132.216" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
<rect x="41.042" y="351.442" fill="#FFFFFF" width="23.851" height="112.15"/>
<rect x="31.853" y="375.293" fill="#494849" width="1118.006" height="65.463"/>
<rect x="76.564" y="252.552" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.682" height="84.682"/>
<rect x="173.42" y="252.552" fill="#FFFFFF" stroke="#231F20" stroke-width="2" stroke-miterlimit="10" width="84.683" height="84.682"/>
</svg>
Observation: since the user can click many time on one rect I needed to add a condition. If there is no text node there create one, else don't.

Change an inline SVG's x and y with ecmascript

I am using an inline SVG in an SVG and have set some default x and y values. When I change them, the inline SVG moves accordingly. I am trying to change it with
var inlineSVG = document.getElementById("inlineSVG");
inlineSVG.style.x = "90";
and that adds style="x:90px;" but that doesn't actually affect the element.
It's weird (in my head) because this works with a rect but not with an svg.
Here is my actual code:
<?xml version='1.0' encoding='UTF-8'?>
<svg width='1000' height='360'
xmlns='http://www.w3.org/2000/svg'
xmlns:xlink="http://www.w3.org/1999/xlink"
onload='init(evt)'
>
<script type='text/ecmascript'>
function init(event){
var wing1 = document.getElementById("wing1");
wing1.style.x = "90";
}
</script>
<circle cx="200" cy="140" r="5" fill="red" />
<circle cx="220" cy="170" r="5" fill="red" />
<circle cx="180" cy="170" r="5" fill="red" />
<circle cx="220" cy="220" r="5" fill="red" />
<circle cx="180" cy="220" r="5" fill="red" />
<svg id="wing1" x="280" y="100" viewBox="0 0 350 300">
<g>
<g>
<g>
<ellipse fill="#E6E7E8" cx="229.505" cy="117.813" rx="5.862" ry="4.547"/>
</g>
<g>
<ellipse fill="#E6E7E8" cx="265.931" cy="117.819" rx="5.862" ry="4.547"/>
</g>
</g>
<g>
<g>
<ellipse fill="#E6E7E8" cx="229.191" cy="125.538" rx="5.862" ry="4.547"/>
</g>
<g>
<ellipse fill="#E6E7E8" cx="265.617" cy="125.531" rx="5.861" ry="4.547"/>
</g>
</g>
</g>
<ellipse fill="#E6E7E8" cx="247.244" cy="121.796" rx="20.635" ry="38.017"/>
</svg>
<rect id="square" x="0" y="470" width="50" height="50" fill="#BADA55" style="fill-opacity : 0.5" />
<line x1="0" y1="0" x2="1000" y2="360" style="stroke: yellowgreen;
stroke-width: 1;
stroke-dasharray: 10 1;"></line>
<line x1="0" y1="360" x2="1000" y2="0" style="stroke: yellowgreen;
stroke-width: 1;
stroke-dasharray: 10 1;"></line>
I tried adding !important to the value but it didn't work ( because I guess it doesn't count it as a valid number? ).
The solution is to directly change the x attribute like so:
selector.setAttribute("attr",val);

Categories

Resources