JavaScript Accessing Inner Dom of Svg

JavaScript accessing inner DOM of SVG

You need to wait until the SVG is loaded and than you can access the contentDocument:

 var mySVG = document.getElementById("SVG");
var svgDoc;
mySVG.addEventListener("load",function() {
svgDoc = mySVG.contentDocument;
alert("SVG contentDocument Loaded!");
}, false);

How to access SVG elements with Javascript

Is it possible to do it this way, as opposed to using something like Raphael or jQuery SVG?

Definitely.

If it is possible, what's the technique?

This annotated code snippet works:

<!DOCTYPE html>
<html>
<head>
<title>SVG Illustrator Test</title>
</head>
<body>

<object data="alpha.svg" type="image/svg+xml"
id="alphasvg" width="100%" height="100%"></object>

<script>
var a = document.getElementById("alphasvg");

// It's important to add an load event listener to the object,
// as it will load the svg doc asynchronously
a.addEventListener("load",function(){

// get the inner DOM of alpha.svg
var svgDoc = a.contentDocument;
// get the inner element by id
var delta = svgDoc.getElementById("delta");
// add behaviour
delta.addEventListener("mousedown",function(){
alert('hello world!')
}, false);
}, false);
</script>
</body>
</html>

Note that a limitation of this technique is that it is restricted by the same-origin policy, so alpha.svg must be hosted on the same domain as the .html file, otherwise the inner DOM of the object will be inaccessible.

Important thing to run this HTML, you need host HTML file to web server like IIS, Tomcat

How to get Inner tags in g tags in svg?

Grabbing a Child (er, can I write that?)

First, to grab all of the children of a <g> tag, you could use the childNodes attribute (big example here):

var allGs = document.getElementsByTagName('g');
var firstG = allGs[0];
var firstChild = firstG.childNodes[0];

Then you could grab each child's bounding box to grab the width/height. I'd use the getBBox method (source):

var boundingBox= firstChild.getBBox();
var width = boundingBox.width

For more on bounding boxes, check out the docs.

Here's an example Fiddle showing how to get the attribute from a child.


Multiple Children

And here's another example Fiddle that grabs the widths of all the children of each <g> tag -- or see the relevant code below:

var allGs = document.getElementsByTagName('g');

for (var i=0; i<allGs.length; i++) {
var gElem = allGs[i];
var children = gElem.children;

// `children` is an array of the form [child, child, ...].

for (var j=0; j < children.length; j++){
var child = children[j];
var box = child.getBBox();
var width = box.width;

//... Now do whatever you wanted to do with the width.

}
}

Note: element.childNodes will collect unwanted whitespace between children elements; element.children only selects the children (Docs). Thanks, Eric!


Setting Attributes

A quick note that if all you want to do is change the width, you don't need to grab the bound box; you can just use the setAttribute method (source). For example, if you wanted to set the width of the first child to 100px:

//A condensed version of the "firstChild" retrieval from before:
var firstChild = document.getElementsByTagName('g')[0].childNodes[0];
var newWidth = 100;
firstChild.setAttribute("width", newWidth)

Example Fiddle


Retrieving Attributes

Regarding retrieving other "values" -- that depends on what you mean. If you want an attribute, then you could just use the getAttribute method (documentation) of each child instead of grabbing the BBox's width (SO post with examples). That is done in a similar way to how we sets an attribute in the code snippet above:

//A condensed version of the "firstChild" retrieval from before:
var firstChild = document.getElementsByTagName('g')[0].childNodes[0];
var value = firstChild.getAttribute("src")
// ... Now do what you will with that value.

Example Fiddle

How do I select an SVG inside an `object` tag?

You need to access the <object> contentDocument in order to access its contained elements.

To do this, you also need to wait until your <object> has loaded its content.

I'm not too much into d3, so it might not be the best d3 way of doing, but at least it works:

(but not in StackSnippet's null origined iframes...)

fetch('https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg')
.then(r => r.blob())
.then(b => obj.data = URL.createObjectURL(b));

obj.onload = function() { // wait for the svg has loaded

var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("Hello");

var obj = this; // we're in the object's load event handler.
var svg = d3.select(obj.contentDocument) // get the contentDocument
.select("svg"); // then get the svg inside
svg.selectAll('g')
.on("mouseover", function() {
return tooltip.style("visibility", "visible");
})
.on("mousemove", function() {
var event = d3.event;
var offset = 20;
var topPosition = (event.pageY - offset) + "px";
var leftPosition = (event.pageX + offset) + "px";
return tooltip.style("top", topPosition).style("left", leftPosition);
})
.on("mouseout", function() {
return tooltip.style("visibility", "hidden");
});

};
<script src="https://d3js.org/d3.v4.min.js"></script>
<object id="obj" type="image/svg+xml"></object>

Fiddle

Access an element by class name from SVG using JavaScript

Your javascript function gets called right after loading the window. At that time, the svg picture has not been loaded, and its inner elements do not exist. According to this answer, you might find the elements by changing the script to:

const el = document.getElementById('container2');
el.addEventListener("load", () => {
console.log(document.getElementsByClassName('ads'));
});

The script should be called after loading #container2. You can just add the script after the html code or run the script after loading the page.



Related Topics



Leave a reply



Submit