I have an HTML file that looks somehow like this:
<html>
<div id="test"> ... </div>
<object data="pic.svg" [...]></object>
</html>
Inside pic.svg, I have an element, let's say, a circle, and I want to realize something like that:
<circle onClick="doSomething()" [...]>
Now, in the js function doSomething() (i.e. when someone clicks on the circle) I want to change my "test"-div. How to do this?
You can access the parent document (and consequently the elements there) from inside the svg like this:
var divInParentDocument = window.parent.document.getElementById('test');
Here's a (slightly more complex) example showing how to call a function in the parent html document from inside an svg.
If you want the SVG to live in the same DOM as the HTML, best to use an embedded <svg> element. It's pretty well supported.
Something like
<svg id="svgroot" width="600" height="600"
version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script type="text/ecmascript">//<![CDATA[
function doSomething() {
document.getElementById('test').appendChild(...);
}
//]]></script>
<circle onClick="doSomething()" />
</svg>
Related
The problem space:
I have an SVG map that I embed inline to html using JQUERY Ajax. Then I use java script to address many elements in the svg object to change attributes and add event listeners based on data series. The data and the maps are interactive. Users can change state over many permutations.
I am also using JQUERY UI 1.10.3 Tabs
There are numerous categories. Therefore depending on the presentation there could be multiple copies of the svg map on the same Tab and many different Tabs having the same svg map.
Each copy of the svg document has the same element IDs. The problem I am experiencing is that the element IDs are conflicting with each other in the HTML DOM. So that the only elements that are addressable are the elements from the svg object that occurs first in the HTML document.
My question is:
Do I need to make the elements IDs unique for each instance of the svg object? Or is there a way to set scope and context to the svg object in the HTML DOM?
Example:
Each containing div has a unique ID that I use to insert the svg document and retrieve the SVG document.
<div id="svgMap_div_1" class="cIG" style="height: 500px; width: 750px"></div>
Code used to load the svg document that is received from ajax (mimeType = "image/svg+xml"):
document.getElementById('svgMap_div_1').appendChild(svgXMLObject.documentElement)
Code used to retrieve the svg document. The declaration for svgDoc is local to the function it is implemented in and is unique.
var svgDoc = document.getElementById('svgMap_div_1').ownerDocument;
Code used to update the individual elements. When the identical svg objects (child elements have the same IDs) are in the same HTML DOM, then this javascript will always address the svg object that occurs first in the HTML DOM even if it is retrieved from a discrete div for example id='svgMap_div_2'.
var svgElem = svgDoc.getElementById('elemID');
svgElem.setAttribute("fill", '#0000FF');
I believe that the root of the problem is that svgDoc is retrieved using ownerDocument. Rather than create a discrete object with scope and context, it reaches through to the entire DOM so that the DOM is the context. See the code reference from the IDE:
HTMLDocument Node.ownerDocument
Property ownerDocument http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
See Also:
Document
Since:
Standard ECMA-262 3rd. Edition
Level 2 Document Object Model Core Definition.
#type
Document
I can develop a working algorithm to make all of the ids unique if I have to but I sure would like to find a better way. I have experimented with other methods and properties to get a working svg document object but none of these are working for me.
Below is a working example to demonstrate what happens when both svg objects are in different div on the same page. All four combinations change the color of the first rectangle. If you change the ID for the rect in the second object to 'box-b' and address it accordingly ('bbox_div', 'box-b'), then both rectangles are operated on independent from one another.
<script type='text/javascript'>
function colorBox(divID, svgElem, colorHex) {
/* DOM This is the original solution that did not work !!!*/
// var svgDoc = document.getElementById(divID).ownerDocument.
// var svgBox = svgDoc.getElementById(svgElem);
// svgBox.setAttribute("fill", colorHex);
/* querySelector */
// document.querySelector("#"+divID + " ."+svgElem).setAttribute("fill", colorHex);
/* jquery div */
// var svgBox = $('#'+divID+' svg').find('#'+svgElem);
// svgBox.css("fill", colorHex);
/* jquery class */
$('#'+divID+' svg').find('.'+svgElem).css("fill", colorHex);
}
</script>
<div style="height: 100px; width: 100px">
Box A Red<br>
Box A Blue<br>
Box B Red<br>
Box B Blue<br -->
</div>
<div id="abox_div" style="height: 100px; width: 100px">
<svg xmlns="http://www.w3.org/2000/svg"
width="0.990919in"
height="0.597218in"
viewBox="0 0 71.3461 42.9997">
<style type="text/css">
<![CDATA[
.allboxes {fill:#00FF00}
]]>
</style>
<g class="box-a allboxes" transform="translate(0.24,-0.24)" fill="#e8eef7">
<rect x="0" y="0.48" width="70.8661" height="42.5197" ><title>Box A</title></rect>
</g>
</svg>
</div>
<div id="bbox_div" style="height: 100px; width: 100px">
<svg xmlns="http://www.w3.org/2000/svg"
width="0.990919in"
height="0.597218in"
viewBox="0 0 71.3461 42.9997">
<g class="box-a allboxes" transform="translate(0.24,-0.24)" fill="#e8eef7">
<rect x="0" y="0.48" width="70.8661" height="42.5197" ><title>Box B</title></rect>
</g>
</svg>
</div>
I believe it's strictly speaking invalid HTML if you have duplicate IDs. I'd suggest using some other mechanism of identifying the elements, either using classes instead of IDs or data- attributes. Then you could move from .getElemntById() to either .querySelector() (try on JS Bin):
<html>
<head>
<title></title>
</head>
<body>
<div id="div1">
<svg xmlns="http://www.w3.org/2000/svg" width="50px" height="50px">
<rect class="rect1" width="50px" height="50px"/>
</svg>
</div>
<div id="div2">
<svg xmlns="http://www.w3.org/2000/svg" width="50px" height="50px">
<rect class="rect1" width="50px" height="50px"/>
</svg>
</div>
<script type="text/javascript">
document.querySelector("#div1 .rect1").setAttribute("fill","red");
document.querySelector("#div2 .rect1").setAttribute("fill","green");
</script>
</body>
</html>
or .getElementsByClassName() (try on JS Bin):
<html>
<head>
<title></title>
</head>
<body>
<div id="div1">
<svg xmlns="http://www.w3.org/2000/svg" width="50px" height="50px">
<rect class="rect1" width="50px" height="50px"/>
</svg>
</div>
<div id="div2">
<svg xmlns="http://www.w3.org/2000/svg" width="50px" height="50px">
<rect class="rect1" width="50px" height="50px"/>
</svg>
</div>
<script type="text/javascript">
document.getElementById("div1").getElementsByClassName("rect1")[0].setAttribute("fill","red");
document.getElementById("div2").getElementsByClassName("rect1")[0].setAttribute("fill","green");
</script>
</body>
</html>
Probably .querySelector() would also work if you leave the ID attributes as they are, like:
document.querySelector("#div1 [id=rect1]")
but I'd still suggest using data- attributes as this avoids any potential ID pitfalls.
Since you are already using jQuery, you can use jQuery's selectors, which don't care about duplicate ids.
function colorBox(divID, svgElem, colorHex) {
var svgBox = $('#'+divID+' svg').find('#'+svgElem);
svgBox.css("fill", colorHex);
}
Demo here: http://jsfiddle.net/w9KA3/1/
I'm trying to create an SVG-based menu. I'm completely new to SVG, and have been searching for 1.5 days for a simple example of interaction between JS and SVG. My document structure is:
/LOCAL_FOLDER (not on a server yet)
+index.html
/CSS
+global.css
/JS
+navigation.js
/IMAGES
+navigation.svg
I have a simple html body
<body>
<div id="outer-container">
<div id="navigation-container" onclick="javascript:changeColor();" >
<object id="navigation" type="image/svg+xml" data="images/test.svg" >Your browser does not support SVG</object>
</div>
</div>
</body>
My SVG looks like this (for now)
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle id="test" cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>
This is the general structure I want to use. As you can see, it has JS from the html head (linked) interacting with my SVG #test. For now, I'd deal with having it change opacity on load just so I can start figuring out HOW to interact.
I've tried JQuerySVG, Raphael, straight JS, JS within SVG, etc, and I can't seem to connect. What I'm looking for (and can't seem to find an operational snippet of) is a super basic example that I can then learn from...
From what I've tried, I rarely had success using data="", however using something like container.load(your.svg), I could then modify to my hearts content.
another issue is to make sure that the svg data was standard.
from there (I used jQuery) jQuery('#test').attr('style','stroke:#ff0000') should change the stroke to red.
How would I modify an SVG file after it has been loaded by the browser, preferably through jquery? A simple example would be pressing a button and the color of the SVG element changes. Any documentation would help as well.
EDIT: This link helped a great deal:
w3.org/Graphics/SVG/IG/resources/svgprimer.html#SVG_in_HTML
You can't "modify" SVG files (except by changing them on the server). SVG files define a collection of SVG objects, each of which can be identified with an ID, if you wish. These objects can be manipulated with JavaScript like you would any DOM element (e.g. setAttribute, etc). Check http://www.w3.org/TR/SVG11/types.html#BasicDOMInterfaces for the DOM interfaces. Notice that SVGElement extends Element, which is the basic DOM element type.
EDIT: simple example:
<html>
<body>
<input type="button" onclick="doSVGThing()" value="change">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="aRect" x="10" y="10" height="100" width="100"
style="stroke:#ff0000; fill: #9999ff"></rect>
</svg>
<script type="text/javascript">
function doSVGThing() {
var r = document.getElementById('aRect');
r.setAttribute('style', 'stroke: #00ff00; fill: #99ff99');
}
</script>
</body>
</html>
I have a SVG document where three circles are drawn:
<?xml version="1.0"?>
<svg width="450" height="80" xmlns="http://www.w3.org/2000/svg">
<script>
document.fillCircle = function(id) {
var circles = document.getElementsByTagName('circle'),
circle = document.getElementById(id);
[].forEach.call(circles, function(circle) {
circle.setAttribute('fill','#ffffff');
});
circle.setAttribute('fill', '#000000');
}
</script>
<g>
<line y1="35" x1="35" y2="35" x2="375" stroke-width="3" stroke="#000000"/>
<circle id="state1" r="30" cy="35" cx="35" stroke-width="3" stroke="#000000" fill="#ffffff" onclick="fillCircle(this.id);"/>
<circle id="state2" r="30" cy="35" cx="205" stroke-width="3" stroke="#000000" fill="#ffffff" onclick="fillCircle(this.id);"/>
<circle id="state3" r="30" cy="35" cx="375" stroke-width="3" stroke="#000000" fill="#ffffff" onclick="fillCircle(this.id);"/>
</g>
</svg>
For testing purposes I have the onclick="" method, but actually this document is an object in my html document:
<object id="test" data="test-vector.svg" width="100px" height="100px"></object>
I have a dataset and these three circles show the "progress" of every item. I regularly update the JSON set by pulling the new list from the server. For every item changed, I want to update the filled circle.
I would like to update the svg based on some javascript. However, I can't make it to get into the DOM of the SVG. I do not really care if the fillCircle() is inside the svg or not and if I have to use <embed>, <object> or something else, but this kind of javascript does not work for me.
<html>
<body>
<object id="test" data="test-vector.svg"></object>
<script>
var svg = document.getElementById('test');
console.log(svg);
svg.fillCircle('state2');
</script>
</body>
</html>
I tried several things I found on SO, like this one and this one, but whatever I test, the exception is always:
Uncaught TypeError: Object #<HTMLObjectElement> has no method 'fillCircle'
var object = document.getElementById("test") will get you the object element but you can't call that till the object has loaded. Once you have that you can use object.contentDocument to do things with the embedded svg document.
<html>
<body>
<object id="test" data="test-vector.svg" onload="f()" ></object>
<script>
function f() {
var svg = document.getElementById('test');
svg.contentDocument.fillCircle('state2');
}
</script>
</body>
</html>
Why don't you embed the SVG directly in your HTML code (using SVG tags)? According to W3, this works in all modern browsers (and IE >= 9). Accessing and changing the circles' properties with JS is then trivial...
<html>
<body>
<svg>...</svg>
</body>
</html>
If you want to keep your HTML/SVG structure though, you can do the following:
var svg = document.getElementById("test");
svg.onload = function(){
svg.contentDocument.fillCircle("state2");
};
The trick is to wait for the SVG object to load (onload event); not till then you can safely use the contentDocument property. Btw, this is also described in this solution on SO (you posted a link to it). ;)
I have a .svg file that has the following code:
<svg version="1.1" x="0" y="0" width="256" height="256" viewBox="0 0 335 394">
plus a ton more code (namespaces etc) that is unnecessary to this situation, but the problem I have is that I need to somehow alter that width and height (from 256px to arbitrary size) using JavaScript. The .svg is being used like this:
<html>
<body>
<div style="background: url(example.svg);"></div>
</body>
</html>
I would really need to accomplish this somehow. Any ideas?
Update: I need this because I want a user to be able to set the base size for my user interface via a JavaScript control.
How about putting an <img> tag inside the div, and setting the width and the height on that?
<html>
<body>
<div>
<img src="example.svg" width="10px" height="10px" />
</div>
</body>
</html>
This will allow your browser to automatically scale the image based on the given dimensions.