I'm trying to append a path element to some inline svg using javascript but I'm getting the error: "Uncaught NotFoundError: An attempt was made to reference a Node in a context where it does not exist"
Can anyone explain why this javascript is not working with my HTML?
<body>
<svg height='500' width='500'></svg>
<script>
var svg = document.getElementsByTagName("svg")[0];
var pathElement = svg.appendChild("path");
</script>
</body>
appendChild takes an element and not a string so what you need is something like this...
var svg = document.getElementsByTagName("svg")[0];
var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
// Use path.setAttribute("<attr>", "<value>"); to set any attributes you want
var pathElement = svg.appendChild(path);
Working example for anyone passing by who wants to see it in action:
http://jsfiddle.net/huvd0fju/
HTML
<svg id="mysvg" width="100" height="100">
<circle class="c" cx="50" cy="50" r="40" fill="#fc0" />
</svg>
JS
var mysvg = document.getElementById("mysvg");
//uncomment for example of changing existing svg element attributes
/*
var mycircle = document.getElementsByClassName("c")[0];
mycircle.setAttributeNS(null,"fill","#96f");
*/
var svgns = "http://www.w3.org/2000/svg";
var shape = document.createElementNS(svgns, "rect");
shape.setAttributeNS(null,"width",50);
shape.setAttributeNS(null,"height",80);
shape.setAttributeNS(null,"fill","#f00");
mysvg.appendChild(shape);
Related
I am not able to generate png from svg created in the application because of transform attribute. If there is no value in transformation, I am getting the svg. This problem I am facing in IE11.
let targetElem = <any>document.getElementById('body');
let nodesToRecover = [];
let nodesToRemove = [];
let svgElem = targetElem.querySelector('svg#svg-annotations')
let parentNode = svgElem.parentNode;
// let svg = parentNode.innerHTML.trim();
let svg = '<svg width="100" height="100"> <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" transform="translate(295 157)" fill="yellow" /> </svg>';
this.canvas = document.createElement('canvas');
this.canvas.setAttribute('id', '_canvas' + this.counter);
canvg(this.canvas, svg);
parentNode.appendChild(this.canvas);
let data = this.canvas.toDataURL('image/png', 0.5);
console.log(data);
let blobData = this.base64toBlob(data.split(',')[1], 'image/png');
saveAs(blobData, 'myblob.png');
console.log(blobData);
this.counter++;
Can anyone help me how to resolve this problem with transform? Any help will be much appraciated.
this issue is resolved by putting width and height to the required value. the problem was, translate property value is 297, 195 which is more than width and height given.
Context
I'm using react js and svg.draw.js for draw svg elements inside a div, the user can draw rect or other shapes and he can see shapes drawed in precedent session.
For make the last functionality I stored the entire svg element drawed as string so when ComponentDidMount() method is fired, it can parse it to image/svg+xml element and then it can append the svg node to the svg root.
So to try this solution in ComponentDidMount() I have create a rect node to append.
Issue
When I try to append the rect element, it doesn't visualized but it's present inside the root element.
This is what I see in console, the rect element is what I have to append.
Code
This is what it's present in ComponentDidMount() method.
componentDidMount(){
/*
*
*irrilevant code*/
const scriptDraw = document.createElement("script");
scriptDraw.src = "svgDrawer.js"; //svg.draw.js
scriptDraw.setAttribute("id","drawer")
scriptDraw.async = true;
document.body.appendChild(scriptDraw);
var str = '<rect id="SvgjsRect1008" class="selected" width="124" height="89" stroke="#3399ff" stroke-width="2" fill-opacity="1" fill="#3399ff" x="236" y="160" name="dawdawad"></rect>'
var parser = new DOMParser();
var doc = parser.parseFromString(str, "image/svg+xml");
scriptDraw.addEventListener("load",function(){
var map = document.getElementById("planimetriaSVG"); //svg root
map.appendChild(doc.documentElement);
})
}
Add a namespace attribute to the rect element so parseFromString knows its supposed to be an SVG element i.e.
var str = '<rect xmlns="http://www.w3.org/2000/svg" id="SvgjsRect1008" class="selected" width="124" height="89" stroke="#3399ff" stroke-width="2" fill-opacity="1" fill="#3399ff" x="236" y="160" name="dawdawad"></rect>'
var parser = new DOMParser();
var doc = parser.parseFromString(str, "image/svg+xml");
I am making use of canvg to convert svg present in div into canvas(upto this it's working fine) and then copying the innerHTML of div to another div, but it's not working. Canvas is coming but nothing will be present in that canvas.
Thanks in advance
<div id="k">
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
Sorry, your browser does not support inline SVG.
</svg>
</div>
<div id="kk">
<p>Watch me</p>
</div>
var svgTag = document.querySelectorAll('#k svg');
svgTag = svgTag[0];
var c = document.createElement('canvas');
c.width = svgTag.clientWidth;
c.height = svgTag.clientHeight;
svgTag.parentNode.insertBefore(c, svgTag);
svgTag.parentNode.removeChild(svgTag);
var div = document.createElement('div');
div.appendChild(svgTag);
canvg(c, div.innerHTML);
setTimeout(function(){
var data = $("#k").html();
$("#kk").append($(''+data+''));
},5000);
JSFiddle
The content of a canvas element is held as binary data, much like the content of an image element. Canvas elements do not have an innerHTML text property that can be used to recreate the canvas.
The following example shows a method of cloning a canvas element using standard canvas 2D methods:
function canvasClone(c1) {
var c2 = document.createElement('canvas');
c2.width=c1.width;
c2.height=c1.height;
c2.getContext("2d").drawImage(c1, 0,0);
return c2;
}
You can demonstrate it by including the function in the fiddle and changing the timeout processing to:
setTimeout(function(){
kk.appendChild(canvasClone(c));
},5000);
Feel free to rewrite the timeout code in JQuery if you prefer.
I'm trying to wrap an existing svg element with Snap. When I try to create a circle, I get an error:
var e = document.getElementById("svgId");
var paper = Snap(e);
var button1 = paper.circle(20,20,50);
The above code generates this error:
Uncaught TypeError: Object [object Object] has no method 'circle'
I am very new to js and even more so to svg. Any help regarding this matter is very much appreciated.
The following demo produces the same error:
<!DOCTYPE html>`
<html>
<head lang="en">
<script type="text/javascript" src="snap.svg-min.js"></script>
<script type="text/javascript">
function init(){
var e = document.createElement("svg");
e.id = "demo";
var paper = Snap(e);
console.log(paper);
var button1 = paper.circle(20,20,50);
button1.attr({
fill:"#bbbb55",
stroke:"000",
strokeWidth: 3
});
}
</script>
</head>
<body onload="init()">
</body>
</html>
I'm going to include 3 different examples on the same page, as its sometimes useful to see and compare...
1st example circle, is from a dynamically created svg element similar to your example (note, you needed append the svg element to the body in your example as well, and probably use createElementNS).
2nd example circle, is from svg markup in the body.
3rd example circle, is to let Snap create the element itself (normally the way, or to use an svg element, like Snap("#container")).
jsfiddle here
var e = document.createElementNS("http://www.w3.org/2000/svg", "svg");
e.setAttribute('style', 'border: 1px solid black');
e.setAttribute('width', '600');
e.setAttribute('height', '250');
e.id="svg1";
document.body.appendChild( e );
var paper1 = Snap( "#svg1" ); //use element created above
var button1 = paper1.circle(100,100,100);
button1.attr({
fill:"blue",
stroke:"green",
strokeWidth: 3
});
var paper2 = Snap( "#svg2" ); //use element from markup below
var button2 = paper2.circle(100,100,100);
button2.attr({
fill:"red",
stroke:"yellow",
strokeWidth: 3
});
var paper3 = Snap(200,200); //let Snap create element
var button3 = paper3.circle(100,100,100);
button3.attr({
fill:"purple",
stroke:"silver",
strokeWidth: 3
});
<body onload="init()">
....
<svg id="svg2" width="200" height="200">
<circle r="20" cx="20" cy="20"/>
</svg>
</body>
</html>
How do I create an SVG anchor through JavaScript? Please see relevant section and an example from spec. How do I convert this example to JavaScript (basically, how to dynamically generate the container element a so that when I click the ellipse, it navigates away.
<?xml version="1.0"?>
<svg width="5cm" height="3cm" viewBox="0 0 5 3" version="1.2" baseProfile="tiny"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Example 17_01</title>
<desc>A simple link on an ellipse.</desc>
<rect x=".01" y=".01" width="4.98" height="2.98"
fill="none" stroke="blue" stroke-width=".03"/>
<a xlink:href="http://www.w3.org/">
<ellipse cx="2.5" cy="1.5" rx="2" ry="1"
fill="red" />
</a>
</svg>
This is just basic DOM:
var xlinkNS="http://www.w3.org/1999/xlink", svgNS="http://www.w3.org/2000/svg";
var a = document.createElementNS(svgNS, "a");
a.setAttributeNS(xlinkNS,"href","http://www.w3.org/");
var ellipse = document.createElementNS(svgNS, "ellipse");
ellipse.setAttributeNS(null,"cx","2.5");
ellipse.setAttributeNS(null,"cy","1.5");
ellipse.setAttributeNS(null,"rx","2");
ellipse.setAttributeNS(null,"ry","1");
ellipse.setAttributeNS(null,"fill","red");
a.appendChild(ellipse);
document.documentElement.appendChild(a);
Using my function below, it's as easy as this:
// Find the first SVG element
var svg = document.getElementsByTagName('svg')[0];
var a = createOn(svg,'a',{'xlink:href':'http://www.w3.org/'});
createOn(a,'ellipse',{cx:2.5,cy:1.5,rx:1,ry:1,fill:'red'});
function createOn(root,name,attrs,text){
var doc = root.ownerDocument,
svg = root.ownerSVGElement || root; // In case the root _is_ the <svg>
var svgNS = svg.getAttribute('xmlns');
var el = doc.createElementNS(svgNS,name);
for (var attr in attrs){
if (!attrs.hasOwnProperty(attr)) continue;
var parts = attr.split(':');
if (parts[1]) el.setAttributeNS(
svg.getAttribute('xmlns:'+parts[0]),parts[1],attrs[attr]
);
else el.setAttributeNS(null,attr,attrs[attr]);
}
if (text) el.appendChild(document.createTextNode(text));
return root.appendChild(el);
}
If you already have the ellipse and want to wrap it, then create the 'a' element and:
// Get a reference to the ellipse however you like
var ellipse = document.getElementsByTagName('ellipse')[0];
// Put the anchor node immediately preceding the ellipse
ellipse.parentNode.insertBefore(a,ellipse);
// Move the ellipse to be a child of the anchor
a.appendChild(ellipse);