SVG is accessible when embedded but not when included - javascript

I have a map with SVG and I am going to create an Area Map with that. It works well when I embed that SVG file in my HTML page, but not when I include it by
This is my SVG:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="595.28px" height="841.89px" viewBox="0 0 595.28 841.89" enable-background="new 0 0 595.28 841.89" xml:space="preserve">
<g id="Layer_1">
<rect x="106.429" y="86.429" fill="#D32A2A" stroke="#000000" stroke-miterlimit="10" width="311.429" height="194.286"/>
</g>
<g id="Layer_2">
<rect x="127.144" y="261.143" fill="#1F5785" stroke="#000000" stroke-miterlimit="10" width="311.428" height="194.287"/>
</g>
</svg>
And this is my javascript:
$(function(){
$('#Layer_2').click(function() {
alert('Thanks');
});
});
This works well and when I click on blue square, an alert shows. DEMO
But I need to include it like this:
<object data="map.svg" type="image/svg+xml" id="map-id" width="100%" height="100%"></object>
and when I include it, I don't have access to that. DEMO

You right this don't work...
You need for use "live" bind, because when you include it directly it
load in not same time as your script:
$('#Layer_2').live('click', function() {
alert('Thanks');
});
I have found this solutions first for read, second for read
To access svg.contentDocument it must be loaded from the same domain, and it will be null otherwise.
There working DEMO.
for simlify your use svg as inside you must start your code after loading all svg objects:
<object id="mysvg1" data="./test.svg" type="image/svg+xml" width="100%" height="100%"></object>
<object id="mysvg2" data="./test.svg" type="image/svg+xml" width="100%" height="100%"></object>
...
var my_start_function = function(){
// start your code here
}
...
var svg_objects = ['mysvg1','mysvg2'], load_counter = 0;
for (var i in svg_objects) {
document.getElementById(svg_objects[i]).addEventListener("load",function() {
load_counter++;
if (load_counter == svg_objects.length) my_start_function();
}, false);
}
and access to svg elements throught a little function:
var svg_inside = function(svg_id,elem_id) {
return $($(document.getElementById(svg_id.substr(1)).contentDocument).find(elem_id)[0]);
}
...
svg_inside('#mysvg1','#Layer_2').click(function() {
alert('Thanks');
});

Related

Added svg image into canvas using fabric.js not visible in firefox

I am adding background svg image to my canvas using fabric.js in my angular.js application, the background is visible perfectly in chrome but not in firefox, I have provided js code and svg.
I am using firefox 47.0.1 on OSX 10.11.5
Why it is not visible in firefox?
Any help will be appreciated.
var image="mysvg.svg";
$window.fabric.Image.fromURL(image, function(oImg) {
oImg.width = width;
oImg.height = height;
oImg.lockMovementX = true;
oImg.lockMovementY = true;
oImg.lockRotation = true;
oImg.lockScalingX = true;
oImg.lockScalingY = true;
oImg.selectable = false;
oImg.selectable = false;
oImg.id = 'bg_image';
canvas.centerObject(oImg)
.add(oImg)
.sendToBack(oImg)
.renderAll();
});
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="mysvg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" viewBox="0 0 921.3 921.3" style="enable-background:new 0 0 921.3 921.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#DEDEDE;}
.st1{fill:none;stroke:#000000;stroke-width:0.75;stroke-miterlimit:10;}
</style>
<g id="Jacket_Spine">
<g id="jacket">
<g>
<polygon class="st0" points="719.3,420.1 200.7,420.1 17,471.7 903,471.7 "/>
</g>
</g>
<rect id="Spine_1_" x="17" y="471.8" class="st1" width="887.2" height="11.3"/>
</g>
</svg>
You are hitting a firefox bug wher a svg without specified width and height cannot be drawn on canvas.
You should modify your SVG and add a width and height to it.
Also the code to add the image as background could be made simpler, unless you have some reason to have it in that way.
Here is the firefox BUG just as a reference:
https://bugzilla.mozilla.org/show_bug.cgi?id=700533
Probably the image will not show on internet explorer 11 also.
var image="mysvg.svg";
fabric.Image.fromURL(image, function(oImg) {
canvas.bakgroundImage = oImg;
canvas.renderAll();
});
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="mysvg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="922" height="922" viewBox="0 0 921.3 921.3" style="enable-background:new 0 0 921.3 921.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#DEDEDE;}
.st1{fill:none;stroke:#000000;stroke-width:0.75;stroke-miterlimit:10;}
</style>
<g id="Jacket_Spine">
<g id="jacket">
<g>
<polygon class="st0" points="719.3,420.1 200.7,420.1 17,471.7 903,471.7 "/>
</g>
</g>
<rect id="Spine_1_" x="17" y="471.8" class="st1" width="887.2" height="11.3"/>
</g>
</svg>

How to morph one SVG path element into another on a click command?

I am trying to make a play and stop button. I don't know how to morph the triangle shape (it is a path) into the square shape (it is a path) when it has been clicked. Only showing one shape at a time. Can anyone help?
<svg class="playStop" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
</style>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</svg>
I think one way is to define your two paths in defs and then use a use xlink:href="#shapeName" with an onclick handler that toggles that attribute or the corresponding DOM property, if supported..
A use element object with fully implemented SVG DOM has a href property with a baseVal property that can be read and set, so inside browsers as far as I have tested (with Firefox, Chrome, IE and Edge on Window) we can simply toggle that property, see https://jsfiddle.net/4x0gnkob/ for an online sample.
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
<svg class="playStop" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<defs>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</defs>
<use xlink:href="#playTriangle" pointer-events="all" onclick="this.href.baseVal = this.href.baseVal == '#playTriangle' ? '#stopSquare' : '#playTriangle';"></use>
</svg>
An alternative is to toggle the DOM attribute, it seems a bit complicated in an HTML5 environment as I thought I could solve it with setAttributeNS and getAttributeNS in one line, after some testing it seems that within HTML5 getAttribute('xlink:href') works better, so the full code tries to test which function returns a value.
function toggleLink(element, value1, value2) {
var xlinkNS = 'http://www.w3.org/1999/xlink';
var linkName = 'xlink:href';
var oldValue = element.getAttributeNS(xlinkNS, linkName) || element.getAttribute(linkName);
if (element.hasAttributeNS(xlinkNS, 'href')) {
element.setAttributeNS(xlinkNS, linkName, oldValue == value1 ? value2 : value1)
}
else {
element.setAttribute(linkName, oldValue == value1 ? value2 : value1);
}
}
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
<svg class="playStop" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<defs>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</defs>
<use xlink:href="#playTriangle" pointer-events="all" onclick="toggleLink(this, '#stopSquare', '#playTriangle')"></use>
</svg>
Online at https://jsfiddle.net/w36k21uz/1/.
You cannot do all the things just like that, you can either use SMIL, which is to become deprecated, or use a dedicated animation engine. I developed KUTE.js with a SVG Plugin that does most of the things you probably need for SVG.
A quick demo (should work in Firefox only due to some Stackoverflow XSS issue):
<div style="width: 220px">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="rectangle" fill="indigo" d="M38.01,5.653h526.531c17.905,0,32.422,14.516,32.422,32.422v526.531
c0,17.905-14.517,32.422-32.422,32.422H38.01c-17.906,0-32.422-14.517-32.422-32.422V38.075C5.588,20.169,20.104,5.653,38.01,5.653z"></path>
<path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808
l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"></path>
</svg>
</div>
<script id="core" src="https://cdn.jsdelivr.net/kute.js/1.5.5/kute.min.js"></script>
<script id="svg" src="https://cdn.jsdelivr.net/kute.js/1.5.5/kute-svg.min.js"></script>
<script>
var tween = KUTE.to('#rectangle', { path: '#star' }, {duration: 1500, yoyo: true, repeat: 1}).start();
document.addEventListener('click', function(){
!tween.playing && tween.start();
}, false);
</script>

How to change SVG pattern image dynamically with javascript on hyperlink click

I have looked and not found a suitable answer for this. I have found answers for changing fill color but not the pattern images.
Fiddle
JAVASCRIPT
$("a#changePattern").click(function(){
var value = $('#pattern');
value.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://3.bp.blogspot.com/-zX0zs-7rHOM/UJ2halaWKlI/AAAAAAAACXg/2rape7g5Y6c/s320/tiling7small.jpg');
});
HTML
<a href='#' id='changePattern'>change pattern</a>
<svg version="1.1" id="レイヤー_1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="105.513px"
height="80.789px" viewBox="0 0 105.513 80.789" style="enable-background:new 0 0 105.513 80.789;" xml:space="preserve">
<defs>
<pattern id='pattern' patternUnits='userSpaceOnUse' width='10' height='10'>
<image xlink:href='http://3.bp.blogspot.com/--4FM7pgC20Q/UKSCRo5QaII/AAAAAAAACa8/uh8wEsX7naM/s1600/new-tiling-1.jpeg' x='0'y='0'width='10px'height='10px' />
</pattern>
</defs>
<polygon style="fill:url(#pattern); stroke:#060001;stroke-width:0.15;" points="64.392,52.845 0.878,79.872 23.175,20.413 104.256,0.818 "/>
</svg>
I need to be able to change multiple patterns in a svg image without reloading the page.
Is this possible?
You can do this with jQuery (which I think you were already trying to use but did not import it in jsFiddle):
Link to fiddle
Js code
$("#changePattern").click(function(){
var value = $('#pattern image'); // select 'image' tag inside element with id 'pattern'
value.attr('xlink:href', 'http://3.bp.blogspot.com/-zX0zs-7rHOM/UJ2halaWKlI/AAAAAAAACXg/2rape7g5Y6c/s320/tiling7small.jpg');
});

Interactive SVG with JavaScript | embed or not embed SVG?

I am trying to change the attribute of a circle in an SVG via javascript. When I have the SVG directly embeded in the HTML file, it works: 'kreis1' is changing color upon clicking a button. But when I have the SVG in an extra file (which I would like to have ultimatly when the SVG will have more than two circles), 'kreis1' doesn't react.
The is my SVG file, two circles:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<circle id="kreis1" fill="#8CC63F" stroke="#000000" cx="53.318" cy="55.5" r="50"/>
<circle id="kreis2" fill="#C44741" stroke="red" cx="138.786" cy="130" r="30" stroke-width="0"
onmouseover="evt.target.setAttribute('stroke-width','10');"
onmouseout="evt.target.setAttribute('stroke-width','0');"/>
</svg>
... and here is my HTML:
<!DOCTYPE html>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<circle id="kreis1" fill="#8CC63F" stroke="#000000" cx="53.318" cy="55.5" r="50"/>
<circle id="kreis2" fill="#C44741" stroke="red" cx="138.786" cy="130" r="30" stroke-width="0"
onmouseover="evt.target.setAttribute('stroke-width','10');"
onmouseout="evt.target.setAttribute('stroke-width','0');"/>
</svg>
<button onclick="getElementById('kreis1').innerHTML=changeColor()">Change!</button>
<object type="image/svg+xml" data="test.svg">
<html>
<head>
<script>
var htmlDocument = document;
function changeColor()
{
document.getElementById("kreis1").setAttribute("fill", "blue");
}
</script>
</head>
</html>
test.svg is a different document to the html document. Fortunately you can get the test.svg document via the contentDocument field on the <object> tag.
<!DOCTYPE html>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
<circle id="kreis1" fill="#8CC63F" stroke="#000000" cx="53.318" cy="55.5" r="50"/>
<circle id="kreis2" fill="#C44741" stroke="red" cx="138.786" cy="130" r="30" stroke-width="0"
onmouseover="evt.target.setAttribute('stroke-width','10');"
onmouseout="evt.target.setAttribute('stroke-width','0');"/>
</svg>
<button onclick="getElementById('kreis1').innerHTML=changeColor()">Change!</button>
<object id="object1" type="image/svg+xml" data="test.svg">
<html>
<head>
<script>
var htmlDocument = document;
function changeColor()
{
document.getElementById("object1").contentDocument.getElementById("kreis1").setAttribute("fill", "blue");
}
</script>
</head>
</html>
It's a limitation of browser layout engines. External SVGs can't be styled by CSS. They have to be embedded in the HTML directly. JavaScript does permit interaction via the object tag per Robert's answer.
If you'd like to go down the embedding route (in my opinion it is more flexible) I've developed a script to automate this embedding, I've got a couple of hours so I'll bundle it up into something reusable this morning and update the question when it's done.
EDIT: Here's the embedding plugin, with docs: http://sakurasvg.appsondemand.com.au/

Show multiple SVG layers from HTML document

I have an SVG file containing 3 vector shapes:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="800px" height="1500px" viewBox="0 0 1500 1500" enable-background="new 0 0 1500 1500" xml:space="preserve">
<svg:style xmlns:svg="http://www.w3.org/2000/svg" type="text/css">
g { display: none; }
g:target { display: block; }
</svg:style>
<g id="svgRed">
<rect x="301" y="344" fill="#DB1919" stroke="#000000" stroke-width="10" stroke-miterlimit="10" width="286" height="314"/>
</g>
<g id="svgGreen">
<circle fill="#1AD84B" cx="692.143" cy="1007.381" r="180.953"/>
</g>
<g id="svgBlue">
<path fill="#1A7ED8" d="M1271,1052c0,1.657-1.343,3-3,3h-251c-1.657,0-3-1.343-3-3V347c0-1.657,1.343-3,3-3h251 c1.657,0,3,1.343,3,3V1052z"/>
</g>
</svg>
As you see, I have each shape in a separate group. I've set all groups to display:none unless they are targeted. Now I can show the blue shape in an HTML document like so:
<object data="test.svg#svgBlue" type="image/svg+xml" width="600" height="860">
My question is, what if I want to show two of the shapes? I can't seem to target more than one shape in the HTML.
I'll be using javascript alongside this, so that is also acceptable to use.
Firstly, you must insert the SVG inline in your HTML5 Document. The object is not accessible via local javascript. Then it's possible to show/hide and change all elements via the DOM. You can load inline svg as xml using XMLHttpRequest
and then have the response fill the innerHTML of a DIV.
Try the files below. Once it is loaded you can use the buttons to toggle display.
Assume you have an svg file(my.svg)
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1500 1500">
<g id="svgRed" display="inline">
<rect x="301" y="344" fill="#DB1919" stroke="#000000" stroke-width="10" stroke-miterlimit="10" width="286" height="314"/>
</g>
<g id="svgGreen" display="inline">
<circle fill="#1AD84B" cx="692.143" cy="1007.381" r="180.953"/>
</g>
<g id="svgBlue" display="inline">
<path fill="#1A7ED8" d="M1271,1052c0,1.657-1.343,3-3,3h-251c-1.657,0-3-1.343-3-3V347c0-1.657,1.343-3,3-3h251 c1.657,0,3,1.343,3,3V1052z"/>
</g>
</svg>
And your HTML5 document is as below:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<center>
<div id="svgInlineDiv" style='background-color:lightgreen;width:300px;height:300px;'></div>
<button onClick=toggleDisplay(svgRed)>toggle red</button>
<button onClick=toggleDisplay(svgBlue)>toggle blue</button>
<button onClick=toggleDisplay(svgGreen)>toggle green</button>
</center>
<script id=myScript>
function toggleDisplay(me)
{
if(me.getAttribute("display")=="inline")
me.setAttribute("display","none")
else
me.setAttribute("display","inline")
}
</script>
<script>
document.addEventListener("onload",inlineSVG(),false)
function inlineSVG()
{
var SVGFile="my.svg"
var loadXML = new XMLHttpRequest;
function handler(){
if(loadXML.readyState == 4 && loadXML.status == 200)
svgInlineDiv.innerHTML=loadXML.responseText
}
if (loadXML != null){
loadXML.open("GET", SVGFile, true);
loadXML.onreadystatechange = handler;
loadXML.send();
}
}
</script>
</body>
</html>

Categories