I have an SVG file embedded into an HTML document inside . I can javascript access the elements in the html and svg using ids and classes. However, I want to perform some drag and drop on the embedded svg. I have been using the following example at http://svg-whiz.com/svg/DragAndDrop.svg separating the SVG from the javascript, but it gives me trouble when I embed the SVG in HTML. The init function in the SVG doesn't work when embedded
onload="initSVG(evt)"
I need to access the root of the SVG in the HTML so that I can get the drag and drop routines working. The original code for a standalone svg is written thus:
function initSVG(evt)
{
SVGDocument = evt.target.ownerDocument;
SVGRoot = SVGDocument.documentElement;
TrueCoords = SVGRoot.createSVGPoint();
GrabPoint = SVGRoot.createSVGPoint();
}
My rewrite is like such, so that it can be run without an onload event call:
function initSVG()
{
SVGRoot = document.getElementsByTagName("svg");
TrueCoords = SVGRoot.createSVGPoint();
GrabPoint = SVGRoot.createSVGPoint();
}
Which gives the the error: "Object # has no method 'CreateSVGPoint'". So it doesn't seem to be treating the imported SVG in the same way as a stand alone svg. How can I get the SVGRoot?
Thanks!
P.S. I know i should probably be using jquery, but I wanted to learn raw DOM.
The getElementsByTagName function returns a NodeList, not an element. Try:
SVGRoot = document.getElementsByTagName("svg")[0];
Related
I know I can use an inline <svg> element to load snap svg. However I would like to use an non-inlined file via an <img> element:
<img alt="comparison" src={arcStatic('/images/comparison.svg')} />
var diagram = Snap('img'),
group = diagram.select('#someGroup')
Where someGroup is an svg g element, fails. group is null.
Additionally:
console.log('diagram.constructor.name);
Shows this is an Element rather than a Snap instance.
How can I use snap.svg with external files?
Use the Paper.image function: http://snapsvg.io/docs/#Paper.image and put the images into the page with snap, so that you can access them.
Say you have this in your HTML:
<img src='example.svg' />
How would you access the contents ( ie. <rect>, <circle>, <ellipse>, etc.. ) of the example.svg via JavaScript?
It's not possible to get the DOM of a referenced svg from the img element.
If you use <object>, <embed> or <iframe> however then you can use .contentDocument (preferred) to get the referenced svg, or .getSVGDocument which may be more compatible with old svg plugins.
Here's an example showing how to get the DOM of a referenced svg.
I'm pretty sure this isn't possible. The external SVG is not part of the DOM in the way an inline SVG is, and I don't believe you can access the SVG DOM tree from the loading document.
What you can do is load the SVG as XML, using an AJAX request, and insert it into the DOM as an inline SVG you can then walk and manipulate. This D3 example demonstrates the technique. I think the d3.xml() function used here is more or less equivalent to jQuery's $.ajax() with dataType: "xml".
No, not possible but you can convert <img> to <svg> as mentioned HERE (same code available below) and you can access the nodes of svg in the DOM.
<script type="text/javascript">
$(document).ready(function() {
$('#img').each(function(){
var img = $(this);
var image_uri = img.attr('src');
$.get(image_uri, function(data) {
var svg = $(data).find('svg');
svg.removeAttr('xmlns:a');
img.replaceWith(svg);
}, 'xml');
});
});
</script>
<img id='img' src="my.svg" />
If you are using inlining of SVG into CSS url(data:...) or just using url(*.svg) background, you can embed them into DOM with svg-embed.
Support Chrome 11+, Safari 5+, FireFox 4+ and IE9+.
If you’re using a back end language that can go fetch the file and insert it, at least you can clean up the authoring experience. Like:
<?php echo file_get_contents("kiwi.svg"); ?>
A little PHP-specific thing here… it was demonstrated to me that file_get_contents() is the correct function here, not include() or include_once() as I have used before. Specifically because SVG sometimes is exported with that as the opening line, which will cause the PHP parser to choke on it.
(Information taken out of CSS-tricks)
Is there a way to just generate an svg and get it as a string without actually drawing it? I thought about render svg to a hidden div and then reading the inner html, but is there a cleaner way?
I would think you could do this:
var svg = d3.select("body").append("svg")
svg = d3.select(svg).remove()
Append the svg to the body, but immediately remove it. This will, of course, give you the 'd3 selection' object, not a string.
You can create a whole other DOM tree in javascript using createDocumentFragment(). This is commonly used to create a complex section of the document and then add it all to the page in one step, so the browser only has to re-calculate layout once.
I haven't tested it, but you should also be able to use .innerHTML() to extract everything you've created as a string that can be saved to file. Answers to this SO Question suggest that you can't call innerHTML() directly on the document fragment itself, so you would have to add a body element to the fragment, add your SVG to it, and then get the inner HTML from the body node.
One way to approach this problem is by checking how it would be done on the server side -- where there is no DOM.
As it turns out, the way to do this on the server side involves more or less the same "hack" used in the question. This is because d3 expects to work on a DOM; writing that DOM to HTML is really the only way to render it to a string.
Brief example:
var svg = window.d3.select('body')
.append('div').attr('class','container')
.append('svg'); // and lots of other stuff
//etc etc
svg.selectAll('.arc').doSomething('blah blah');
var svgAsString = d3.select('.container').html();
im having a problem highlighting states in map using jquery.i have implemented it using javascript. `
SVG Illustrator Test
<object data="map_with_hover.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(){
var svgDoc = a.contentDocument; //get the inner DOM of alpha.svg
var delta = svgDoc.getElementById("states"); //get the inner element by id
delta.addEventListener("mouseover",function(evt){ evt.target.setAttributeNS(null,"opacity","0.5");},false); //add behaviour
delta.addEventListener("mouseout",function(evt){ evt.target.setAttributeNS(null,"opacity","1");},false); //add behaviour
},false);
</script>
</body>
</html>
`
by this code states get highlighted easily but i want to do it in jquery as i also wanna add tooltip,so that on mouseover state name will also be displayed.
so basically i wanna know how to use SVG's id or class or tags to perfrom different action by using jquery.
There is a library called jQuery SVG this might help you.
You should embed the file directly into your HTML, (using SVG tags). This will allow you to select the different SVG elements using plain jQuery. See here
Feel free to use this code as it is very basic, and I pulled the map from Wikipedia.
I've got an SVG map of the world (based on a public domain file from wikipedia), with generated CSS to highlight individual countries.
I need to a add mouseover tooltips containing additional data about each country, the data will be provided by PHP.
I'm an experienced web programmer, but have never worked with SVG until now. What is the best approach to display a text tooltip under the user's mouse, with info about the specific SVG node under the mouse cursor?
Note this SVG is full of nice id and class attributes designed to facilitate this kind of use.
I need this to be as cross browser as practical, but am happy to disable the feature for some browsers (old versions of Internet Explorer).
Detect the mouseover event
Access the title information
Create-or-show a group of title elements
Append them to the end of the SVG document so that they draw above all other content
Populate the elements with the appropriate data based on title
Position the elements accordingly
You'll want to transform the cursor point from screen space to SVG space, or calculate the bounding box of your source element and transform that from possibly-transformed object space to global SVG space.
Detect the mouseout event
Hide-or-destroy the title elements.
Is there any part of the above that you cannot do?
Edit: Answering the wealth of questions from the comment below:
You can place your script inside the SVG or outside in an embedding HTML; if they are self-contained to the SVG (as yours would be) it's better to place them here, so that you can embed your SVG externally and have it still work.
Finding a list of anything is easiest of you place a common class="foo" attribute on them, via one of:
var foos = document.querySelectorAll('.foo');
var foos = document.getElementsByClassName('foo');
Or you can query based on structure; for example, if every country is a <path> contained within a <g id="countries"> then you can use:
var countries = document.querySelectorAll('#countries path');
But if all you have is an array of IDs, then you'll need to do something like:
var countryIDs = [ "usa", "brazil", … ];
// Old school
var countries = [];
for (var i=countryIDs.length; i--; ){
countries[i]=document.getElementById(countryIDs[i]);
}
// New school
var countries = countryIDs.map(function(id){
return document.getElementById(id);
});
To attach an event handler to each:
function showTooltip(evt){
var element = evt.target;
// your code here
}
countries.forEach(function(el){
el.addEventListener('mouseover',showTooltip,false);
});
Alternatively, you can just attach the event handler to a common ancestor once, and handle it there:
svg.addEventListener('mouseover',function(evt){
var element = evt.target;
if (element.hasAttribute('title')){
// your code here
}
}
The <script> is easiest when placed right before the </svg>, but you can put it at the top if you want and it only do its work when the file is done loading, for example:
window.addEventListener('load',function(){
// Put all your code here
},false);
It's easy to find information on embedding SVG, and you are right, there are many ways to do it. Here's one nice article about it. I personally advocate either SVG in XHTML or, if you must, SVG in HTML5.
You can use append svg title to view additional data.
// Here we add an SVG title element the contents of which is effectively rendered in a tooltip
.append("svg:title")
.text(function(d) {return "Name:"+d.Name;});
We can use this tooltip along with all svg element. Here d is a json object form this we are parsing the data.
https://gist.github.com/ilyabo/1339996