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

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>

Related

How to modify the width of SVGs with JQuery

I'm using Articulate Storyline and I want to modify the width of a line that I've created in the software using Javascript.
I already know that I can select any items (every item export to SVGs in Storyline's output) using This line of code:
var item = $('[aria-label="Ourline"] svg')
Then we should be able to do some jQuery animations...
The problem is I can't modify the width attribute of the selected line using code below:
$(item).attr("width","500");
It just changes the position of the line 500 px to the right! What?!
Any suggestions would be appreciated.
Please note: The question has nothing to do with Storyline, It's all about SVGs and jquery.
https://jsfiddle.net/whLf02n8/
html:
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
<button id="7">7</button>
<button id="3">3</button>
javascript:
$('button').click(function() {
const id = $(this).attr('id');
$('svg circle').attr('stroke-width', id);
})

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

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.

onclick not working when removing/appending child element

I have a simple *.svg file with some javascript code inside.
There are 6 circles and they partially overlay each other.
When a mousover event occurs for one of the circle, this circle should appear at the top.
This works just fine. Here is my code:
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
width="400" height="300">
<script>
function mouseOver(evt) {
var parent = evt.target.parentNode;
parent.removeChild(evt.target);
parent.appendChild(evt.target);
}
function click(evt) {
alert("CLICKED");
}
</script>
<g id="myCircles" stroke="none" onclick="click(evt)" onmouseover="mouseOver(evt)">
<circle id="circ1" cx="150" cy="100" r="50" fill="red"/>
<circle id="circ2" cx="100" cy="60" r="30" fill="yellow"/>
<circle id="circ3" cx="200" cy="150" r="80" fill="blue"/>
<circle id="circ4" cx="160" cy="190" r="70" fill="green"/>
<circle id="circ5" cx="100" cy="220" r="10" fill="gray"/>
<circle id="circ6" cx="80" cy="90" r="20" fill="black"/>
</g>
</svg>
However if I use this mouseOver function the onclick event doesn't work anymore. I guess this has something to do with the removing and appinding of the Element inside the DOM structure.
If i uncomment the code in mouseOver(evt), the onclick event gets fired.
Anyone knows how to solve this?
EDIT: Interestingly, when I am using onmousedown instead of onclick event, everything works fine! Can anybody explain why?
You could use the z-index property to bring the selected circle to the top. If you use a .css file, add the z-index and set the initial value to the same value (say, '1')
z-index:1;
on the mouseover event, change the z-index to a higher value (say, '5') to pop it to the top of the circle stack. on the mouseout event, reset z-index to 1 and, finally, use the mousedown event to produce your alert, "Clicked."

visibility is not working for svg g tag

I'm using svg in my application and i using g tag to group the all elements. The first g tag contain more than g tag's, all g tag have their own different visibility style. If i set visibility hidden to the parent g tag it will affect the other g tag elements. I need to hide all the g tag elements by setting visibility to the parent but child elements visibility style should not change.
Here the sample svg
<svg height: "200" width="200">
<g style="visibility:hidden">
<g style="visibility:visible">
<circle cx="100" cy="100" fill="green" r="15" />
</g>
</g>
</svg>
Here is the working Sample.
How can set visibility to the parent g tag without changing it child elements visibility?
Try to use opacity:0 instead of visibility:hidden.
Also, you should look at this example http://svg-whiz.com/svg/HideShow.svg
Hard to understand quite what you are after as the others have said.
I had deleted this answer, as it feels I'm missing your point, but thought it may still help http://jsfiddle.net/rnZss/5/ , it will still display the rect, but hide the circle, so I have left the answer for the moment. What else do you want to happen ?
<svg height:"200" width="200">
<g style="visibility:hidden">
<g style="visibility:hidden">
<circle style="visibility: hidden"cx="100" cy="100" fill="green" r="15"/>
<rect style="visibility: visible" x="50" y="50" width="50" height="50"/>
</g>
</g>
</svg>

How to create SVG animation tag using javascript

I have this SVG circle with an animation.
<circle cx="30" cy="50" r="15" fill="blue" stroke="black" stroke-width="1">
<animateMotion path="M 0 0 H 300 Z" dur="8s" repeatCount="indefinite" />
</circle>
It works fine. I want to make the exact same thing using javascript so if I click a button, it would create the same circle with the same animation.
here is my try:
var animateMotion = document.createElementNS("http://www.w3.org/2000/svg", "animateMotion");
animateMotion.setAttribute("dur","8s");
animateMotion.setAttribute("d", "M 0 0 H 300 Z");
animateMotion.setAttribute("repeatCount","indefinite");
//assuming that I already created my circle
myCircle.appendChild(animateMotion);
var animateMotion = document.createElementNS('http://www.w3.org/2000/svg','animateMotion');
animateMotion.setAttribute("dur","3s");
animateMotion.setAttribute("repeatCount","1");
var mpath = document.createElementNS('http://www.w3.org/2000/svg','mpath');
mpath.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#YourPath");
animateMotion.appendChild(mpath);
Looks like animateMotion elements are bugged in Webkit, when dinamically created (see SVG elements will not Animate when added dynamically), and unsupported in IE. I think you're better off using pure javascript animation using a library like d3.
Maybe this is your problem:
In XML:
<animateMotion path= ... />
In JS:
animateMotion.setAttribute("d", ... ); //Should this be "path"?
Hope it helps,
regards m93a.
If just the click is important, it can be solved by using the begin attribute in your animateMotion:
<svg height="500" width="500" id="foo">
<circle cx="30" cy="50" r="15" fill="blue" stroke="black" stroke-width="1">
<animateMotion path="M 0 0 H 300 Z" dur="8s" repeatCount="indefinite" begin="foo.click"/>
</circle>
</svg>
Should work with a button as well, if the button has an identifier, e.g. id="startbutton", then it should be begin="startbutton.click
Another alternative with inline javascript can be found here: http://svg-whiz.com/svg/PausePlay.svg
cheers
if you want the animate as soon as <animateMotion> element append page,
set <animateMotion> 'begin' to 'indefinite' and begin the animate call its .beginElement();
var animateMotion = document.createElementNS(SVG_NS, 'animateMotion');
animateMotion.setAttribute('begin', 'indefinite');
//append animateMotion to the page
animateMotion.beginElement();
Here you can get number of examples regarding svg using javascript.
You can get help from there.

Categories

Resources