Why won't dynamic SVG work if not handled via createElementNS - javascript

I was trying to manipulate SVG in plain JS and found that it won't behave as intended if I don't use methods like createElementNS and setAttributeNS.
<svg id="mydsvg" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
The above markup works perfectly. But if you try to add another circle via the following code, you won't see it.
var circle = createElement('circle');
circle.setAttribute('cx', 50);
....
document.getElementById('mysvg').appendChild(circle);
But if you use createElementNS and setAttributeNS, it will work as expected.
To be worst, both createElement and createElementNS create identical DOM text.

It doesn't work because the specifications say that SVG elements must exist in the SVG namespace and createElement creates elements in the html namepace. How would a parser know otherwise whether you wanted to create an html <a> element which works with a src attribute or a SVG <a> element for which an `xlink:href attribute is required.
In html where namespaces are not serialized things look the same. In XML where namespaces are serialized they don't.
SVG in html looks like this...
<svg id="mydsvg" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
SVG as a standalone document would look like this
<svg xmlns="https://www.w3.org/2000/svg" id="mydsvg" width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
The circle inherits the namespace of its parent.

Related

Javascript - change r attribute of circle wrapped in #shadow-root

My html tree looks as follows:
<svg id="floating-button-svg" style={{fill: `${floatingButton.backgroundColor}`}}>
<use id="use-tag" href="
<svg>
<circle id="semi-circle" class="cls-1" cx="500" cy="500" r="50"/>
</svg>"
/>
</svg>
Afer compilation the href dissolves to data:image/svg+xml;base64,PCEtLSA8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtOCI/Pgo8c3ZnIHZlcnNpb249IjEuMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxMDAwIDUwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CjxjaXJjbGUgaWQ9InNlbWktY2lyY2xlIiBjeD0iNTAwIiBjeT0iNTAwIiByPSI1MDAiLz4KPC9zdmc+IC0tPgoKCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTAwMCIgaGVpZ2h0PSI1MDAiIHZpZXdCb3g9IjAgMCAxMDAwIDUwMCI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogIzAwMDsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPGNpcmNsZSBpZD0ic2VtaS1jaXJjbGUiIGNsYXNzPSJjbHMtMSIgY3g9IjUwMCIgY3k9IjUwMCIgcj0iNTAiLz4KPC9zdmc+Cgo=#semi-circle
If anyone wants to test it, please replace the value in the href above with this link.
I am trying to change the radius of the circle through
document.getElementById('use-tag').setAttribute('r', '25')
but instead it only gives use an attribute of r=25. Is there any way I can change the radius of the circle? I have tried to fetch it using
getElementById
but it just gives me null (I'm assuming because it's wrapped in a shadow root).
edit: The gist of the problem here I believe is that I am trying to change the attributes of a closed shadow root which is impossible to achieve. So can someone please tell me why am I get a closed root instead of an open one? And how can I get an open one?
edit: Here is a demo of this situation: https://codesandbox.io/embed/smoosh-sun-nnevd?fontsize=14&hidenavigation=1&theme=dark
Since you have direct access to circle with id semi-circle, you can update it as the below snippet.
The snippet is running under a setTimeout to show the difference.
setTimeout(function() {
var circle = document.getElementById('semi-circle');
circle.setAttribute('r', 60)
}, 3000)
<svg id="floating-button-svg" height="100" width="100">
<circle id="semi-circle" class="cls-1" cx="50" cy="50" r="40" fill="red" />
</svg>
You can also do it in another way, check the snippet
setTimeout(function() {
var circle = document.getElementById('floating-button-svg');
circle.firstElementChild.setAttribute('r', 60)
}, 1500)
<svg id="floating-button-svg" height="400" width="400">
<circle id="semi-circle" class="cls-1" cx="80" cy="80" r="40" fill="red" />
</svg>

SVG - Draw shapes along the circle path

How to draw shapes as a stroke for Circle in SVG ?
Something like this:
Try this
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="blue" stroke-width="5" stroke-dasharray="3" fill="transparent" />
Sorry, your browser does not support inline SVG.
</svg>
Adjust the stroke-width and stroke-dasharray

How to avoid shadow-root in MathJax?

I want to access the SVG code created by MathJax via javascript. Apparently, MathJax put the SVG <path> under shadow-root, which is not directly accessible by javascript. Here is a picture of the elements given by Chrome
If I get the <svg> element by any javascript method, the <path> children will not be included.
You cannot avoid shadow-root. It is not put there by MathJax renderer. It is because of the use tag.
From MDN:
The <use> element takes nodes from within the SVG document, and duplicates them somewhere else.
So MathJax creates svg pathes and gives them ids and reuses them. Say the letter a is rendered into svg, and MathJax stores it in the svg with an id and use it when the letter a is needed to be rendered.
Below example from MDN speaks better.
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg">
<style>
.classA {
fill: red;
}
</style>
<defs>
<g id="Port">
<circle style="fill: inherit;" r="10"/>
</g>
</defs>
<text y="15">black</text>
<use x="50" y="10" href="#Port" />
<text y="35">red</text>
<use x="50" y="30" href="#Port" class="classA"/>
<text y="55">blue</text>
<use x="50" y="50" href="#Port" style="fill: blue;"/>
</svg>

Create graphical element with selectable portions

I'm looking to create something like this using CSS:
As I hover over each colored section, I want to be able to change the color of the section and have a popup appear.
I know that using a canvas with an image map & clickable area coords is one way to tackle this, but I'm wondering if there is perhaps an easier way that would allow me to create the graphic with CSS and set a class for each piece of it.
You should use an SVG. The actual SVG markup can be embedded into your HTML as several grouped elements.
You can then wire up javascript events or target the elements with CSS :hover. Because the browser knows their exact shape, you can get pixel-accurate mouse overs.
circle:hover {
opacity: 0.5;
}
<svg width="500" height="500">
<circle id="circle1" cx="50" cy="50" r="20" fill="red"/>
<circle id="circle2" cx="150" cy="50" r="40" fill="green"/>
<circle id="circle3" cx="200" cy="50" r="30" fill="blue"/>
</svg>
Plenty of vector editing packages like Adobe Illustrator or Sketch can output SVG artwork. There are also online SVG editors.

Discover clipped elements

If I clip a bunch of SVG elements, is there some way to use the SVG API to determine whether each of those elements is affected by the clip?
In other words, given the following:
<svg>
<defs>
<clipPath id="aClip">
<rect x="10" y="10" width="90" height="90"/>
</clipPath>
</defs>
<circle cx="50" cy="50" r="10" clip-path="url(#aClip)" />
<circle cx="150" cy="50" r="10" clip-path="url(#aClip)" />
<circle cx="150" cy="150" r="10" clip-path="url(#aClip)" />
</svg>
..is there any way I can tell which circle elements are clipped without resorting to drawing the elements and using canvas to check for raster overlap?

Categories

Resources