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");
Related
I would add a rectangle as on each Node element
the rect is added only in the last element.
ngAfterViewInit() {
let rect : NodeList = this.synoptic.nativeElement.querySelectorAll("#stops g");
let rect2 = document.createElementNS('','rect');
rect2.setAttribute("fill","none");
rect.forEach((elm : Node) => {
console.log(elm.firstChild) #### Well selecting the first element
elm.insertBefore(rect2,elm.firstChild);
console.log(elm) ####rect added
})
### rect is awailable only in the last elm
}
Edit I'm using angular And my code is running inside ngAfterViewInit() hook
Here a stackblitz demo
Try it this way by adding namespace and attributes required for rect
(function() {
let rect = document.querySelectorAll("#stops g");
rect.forEach(e => {
let rect2 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect2.setAttribute("fill", "#000");
rect2.setAttribute('x', e.getAttribute('x'));
rect2.setAttribute('y', e.getAttribute('y'));
rect2.setAttribute('height', '50');
rect2.setAttribute('width', '50');
e.appendChild(rect2);
});
})();
<svg id="stops" xmlns="http://www.w3.org/2000/svg">
<g x="0" y="0"></g>
<g x="100" y="100"></g>
</svg>
Angular Working Fiddle
The SVG namespace is 'http://www.w3.org/2000/svg', and not the empty string.
Additionally a rect with fill none won't be visible, it either needs a fill or a stroke and appears to have neither specified.
Finally it needs a non-zero width and height.
I can get the width of my object svg in javascript and save the value in a variable. this is my object
<rect id="cercle1" x="5" y="25" width="50" height="50" stroke-width="1" stroke="#0E0E0E" style="fill:red; stroke:black; stroke-width:2"; />
I try this:
document.getElementById('cercle1').width.value;
thanks for help
You can use the getAttribute function:
document.getElementById('cercle1').getAttribute("width");
That will get you the String from the HTML code. As Phrogz mentioned it, you might want a number instead, or the actual value (that might be different). If so, refer to his answer.
The width attribute is an SVGAnimatedLength property. As such, you need to:
// If you want the original value
var w = document.getElementById('cercle1').width.baseVal.value;
// If it is animated and you want the current animated value
var w = document.getElementById('cercle1').width.animVal.value;
Or, if just want what's in the source code:
var w = document.getElementById('cercle1').getAttribute('width')*1; // convert to num
You can try this:
var obj = document.getElementById("cercle1"); // reference to the object tag
var rect = obj.getBoundingClientRect(); // get the bounding rectangle
alert(rect.width);
alert(rect.height);
Or this:
var obj = document.getElementById("cercle1"); // reference to the object tag
var svgdoc = obj.contentDocument; // reference to the SVG document
var svgelem = svgdoc.documentElement; // reference to the SVG element
alert(svgelem.getAttribute("width"));
Here is a working JSFiddle example.
From the comments from Phrongz: Note that the bounding rect will account for transforms, which may or may not be desired.
Just in case you had created your rect dynamically, then the below solution is valid
var rect = document.createElementNS(svgns, "rect");
rect.setAttribute('width', '200px');
rect.setAttribute('height', '200px');
var width= rect.width.baseVal.value;
var height= rect.width.baseVal.value;
Here is what I want to do :
var a = Snap("#id");
var group = new SnapGroup(); // unfortunatly didnt find how to do it
// for some reasons i dont want to do a.group();
group.circle(5,5,5);
a.add(group);
Here is what I did :
var a = Snap("#id");
s = Snap(); // creates a SVG element instead of a group
s.circle(5,5,5);
a.add(s);
It works, the circle is rendered, but then I cannot move the group :
s.attr({"x":60}); // the group doesnt move
Actually it looks like that when we embed and <svg> elements into an other one. Then it becomes impossible to move the embeded svg element in the parent one.
I would like to know how to create a group element without doing snapInstance.group() ? And then add it to a Snap instance.
I'm still not quite sure from your description what you are after, as I suspect it may depend how you are generating the original group (if its just a bit of svg markup or imported).
Snap.parse('<g></g>'); may be enough to fiddle with, to parse into a fragment.
See if this helps...its an example with two separate SVG elements and Snap instances. It will draw a rect from the original SVG markup string with a group,add a circle from Snap, and on the 2nd instance it will translate the group by 75 as well.
<svg id="svg1" width="200" height="200"></svg><br />
<svg id="svg2" width="200" height="200"></svg>
...
var paper1 = Snap("#svg1");
var paper2 = Snap("#svg2");
var groupMarkup = '<g><rect x="0" y="0" width="70" height="70" opacity="0.3"/><text x="0" y="15">original</text></g>';
var parsedMarkup1 = Snap.parse( groupMarkup ); //parse from a string derived elsewhere
var parsedMarkup2 = Snap.parse( groupMarkup );
// example1 just use the markup with its original group
paper1.add( parsedMarkup1 )
.add( paper1.circle(100,50,50)
.attr('fill', 'red' ) );
// example2, will create a new group and add the existing group to it, and then move it
var outerG = paper2.g()
.transform('t75,0'); //create a group and move it
outerG.add( parsedMarkup2 ); //add the original group/square
outerG.add( paper2.circle(70,50,50) //add a circle
.attr('fill', 'blue' ) );
var clone = outerG.clone(); //lets create a clone
clone.transform('r45t50,50'); //translate and rotate the clone
fiddle here http://jsfiddle.net/v4bJa/
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);
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);