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.
Related
I've drawn a line before with this exact code but when reimplementing it into another project something isn't working.
let main = document.getElementById('main');
let svg = document.createElement('svg');
let newLine = document.createElement('line');
svg.setAttribute('style', `position: fixed;display: block;`);
newLine.setAttribute('x1', 0);
newLine.setAttribute('y1', 0);
newLine.setAttribute('x2', 500);
newLine.setAttribute('y2', 500);
newLine.setAttribute('style', `stroke:red;stroke-width:100;`);
svg.appendChild(newLine);
main.appendChild(svg);
Before I was running an express server and JSDOM to fill a div in the document with svg's then sending the innerhtml of the document element as the body when routing to '/', not the most performant way to do it but I was just playing around around with tools we were learning in class. When I put the code below into my html a black line is displayed as it should so I feel I'm missing some small piece...
<svg width="500" height="500">
<line x1="50" y1="50" x2="350" y2="350" stroke="black" />
</svg>
You need to use createElementNS when creating your svg and line elements, otherwise it just thinks they're made up tags and not actual SVG.
Also, since you're not using variables in your setAttribute, you should avoid string interpolation and just use single-quotes instead of backticks.
Solution
let main = document.getElementById('main');
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
let newLine = document.createElementNS('http://www.w3.org/2000/svg','line');
svg.setAttribute('style', 'position: fixed;display: block;');
newLine.setAttribute('x1', 0);
newLine.setAttribute('y1', 80);
newLine.setAttribute('x2', 100);
newLine.setAttribute('y2', 20);
newLine.setAttribute('style', 'stroke:red;stroke-width:100;');
svg.appendChild(newLine);
main.appendChild(svg);
<div id="main"></div>
Documentation
https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
Figured it out, needed to use the code below when declaring my svg
const svgTop = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
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'm trying to create a new <img> with the <svg> tag with JavaScript every time I click on the button. When I see the result in the console firebug it works correctly, but nothing on screen displays.
What I want is for an image <svg> to appear after the last one every time you click the button.
Thanks in advance.
var svgNS = "http://www.w3.org/2000/svg";
mybtn.addEventListener("click", createCircleSVG);
function createCircleSVG(){
var d = document.createElement('svg');
d.setAttribute('id','mySVG');
document.getElementById("svgContainer").appendChild(d);
createCircle();
}
function createCircle(){
var myCircle = document.createElementNS(svgNS,"circle"); //to create a circle."
myCircle.setAttributeNS(null,"id","mycircle" + opCounter++);
myCircle.setAttributeNS(null,"cx",25);
myCircle.setAttributeNS(null,"cy",25);
myCircle.setAttributeNS(null,"r",100);
myCircle.setAttributeNS(null,"fill","black");
myCircle.setAttributeNS(null,"stroke","blue");
document.getElementById("mySVG").appendChild(myCircle);
}
Create a SVG:
var svg = document.createElementNS(ns, 'svg');
First function:
function createSVG() { ... }
Second function:
function createSVGCircle() { createSVG() ... }
Or separated:
createSVG();
createSVGCircle();
Example
You need to create the svg element in the SVG namespace using createElementNS (like you already do for the circle) e.g.
var d = document.createElementNS(svgNS, 'svg');
giving the SVG element a width and height is also necessary
d.setAttribute("width", "100%");
d.setAttribute("height", "100%");
Note here we can use setAttribute as the attributes are in the null namespace. You can convert the circle setAttributeNS calls too if you want.
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/