Dynamically rendered SVG is not displaying - javascript

I have the following svg object which if I put in html page directly without using code(static) it renders properly.
but same svg content if I insert into my html page using JavaScript it is not showing and if I open it in firebug and inspect svg and try to edit svg tag, it displays.
What could be the problem
<svg height="100" width="100">
<rect width="100" height="100" style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)"></rect>
</svg>
I am adding svg dynamically using below code, here container will be my div which is there under body
viewPort = document.createElementNS('http://www.w3.org/2000/svg','svg');
viewPort.setAttribute('height', 100);
viewPort.setAttribute('width', 100);
container.innerHTML = '';
container.appendChild(viewPort);
After this I am adding rect inside this using
boardElement = document.createElement('rect');
boardElement.setAttribute('width', '100');
boardElement.setAttribute('height', '100');
boardElement.setAttribute('y', '1');
boardElement.setAttribute('x', '1');
boardElement.setAttribute('style', "fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)");
viewPort.appendChild(boardElement);

The element boardElement should be declared like so
boardElement = document.createElementNS("http://www.w3.org/2000/svg", "rect");

Related

How to fill a rect tag inside an SVG with image in Javascript

I've made several attempts to insert an image inside a rect tag inside an SVG, but none of them worked. What I want is when I click on a button there is a function that changes the fill of the rect. I tried to use snap.svg but it didn't work either. If anyone has any suggestions I would appreciate it.
Code:
HTML:
<button onclick="changeRect('rect252')">Input</a>
<object type="image/svg+xml" id="main" class="edit-area"></object>
Javascript:
let objectTag = document.getElementById('main').setAttribute('data', 'image.svg')
function changeRect(id){
var obj = document.getElementById("main");
var svgDoc = obj.contentDocument;
let svgRect = svgDoc.getElementById(id);
let pattern = Snap().image('teste.svg', 0, 0, 500, 500).pattern(0, 0, 10, 10);
svgRect.style.setProperty('fill', pattern)
}
SVG:
<rect
style="fill:#00000;"
id="rect252"
width="51.396542"
height="31.275505"
x="120.8588"
y="92.630028"
inkscape:label="Right"
visibility="hidden"/>

How to create a valid svg element with javascript

I was working with SVG and i created an svg element. I added a <rect> element directly into the svg with html and then I created a new element (without namespace) <circle> with javascript and appended it to the svg element. The <rect> element displayed in the svg viewbox but the <circle> element did not display.
I got the <rect> and <circle> on the console and checked the constructor. The <rect> element returned SVGRectElement but the <circle> returned HTMLUnknownElement. I created a new <circle> element (with namespace: https://www.w3.org/2000/svg) and checked the constructor which returned Element.
Whichever way, appending both the namespaced and non-namespaced <circle> element to the svg did not appear in the svg viewbox. So how do i create a recognized svg element with javascript that will return SVGCircleElement?.
var circle = document.createElement('circle');
circle.setAttribute('cx', '10');
circle.setAttribute('cy', '10');
circle.setAttribute('r', '30');
circle.setAttribute('fill', 'red');
var circle_2 = document.createElementNS('https://www.w3.org/2000/svg','circle');
circle.setAttribute('cx', '5');
circle.setAttribute('cy', '20');
circle.setAttribute('r', '30');
circle.setAttribute('fill', 'blue');
var svg = document.getElementById('svgx');
var rect = document.getElementById('svgrect');
svg.appendChild(circle);
svg.appendChild(circle_2);
console.log(svg.constructor); // SVGSVGElement() { [native code] }
console.log(rect.constructor); // HTMLRectElement() { [native code] }
console.log(circle.constructor); // HTMLUnknownElement() { [native code] }
console.log(circle_2.constructor); // Element() { [native code] }
<svg style='width: 100%;' id='svgx'>
<rect x='5' y='5' width='50' height='30' fill='black' id='svgrect'>
</svg>
Remove the "s" from "https".
var circle_2 = document.createElementNS('http://www.w3.org/2000/svg','circle');
Even though it looks like a URL. It is really just a string constant that indicates this XML file is an SVG file. The namespace constant has to be exactly as presented here.
Also you need to change circle to circle_2 for that section of code.
var circle_2 = document.createElementNS('http://www.w3.org/2000/svg','circle');
circle_2.setAttribute('cx', '5');
circle_2.setAttribute('cy', '20');
circle_2.setAttribute('r', '30');
circle_2.setAttribute('fill', 'blue');
var svg = document.getElementById('svgx');
var rect = document.getElementById('svgrect');
svg.appendChild(circle_2);
<svg style='width: 100%;' id='svgx'>
<rect x='5' y='5' width='50' height='30' fill='black' id='svgrect'>
</svg>

Dynamically adding elements to loaded svg file

After loading an svg file from InkScape I want to add new elements to the drawing, created under program control. This seems to work fine if we just change the attributes of already present elements, but new created ones, even if they appear when inspecting the DOM, do not show!
A hand-simplified SVG test file:
<svg id="svg8" width="1e3" height="750" version="1.1"
viewBox="0 0 264.58333 198.43751" xmlns="http://www.w3.org/2000/svg">
<g id="layer"><circle id="cc0" cx="20" cy="20" r="10"/></g>
</svg>
The javascript/html file:
<!doctype html><html><head><meta charset="UTF-8"/>
<script>
function addCircle() {
var svgDoc = document.getElementById("test");
var svg = svgDoc.contentDocument;
var svgns = svgDoc.namespaceURI;
// Ok, this changes the circle to red
var c0 = svg.getElementById("cc0");
c0.setAttribute("fill", "#ff0000");
var layer = svg.getElementById("layer");
// Create a circle inside layer "g"
var cc = document.createElementNS(svgns, "circle");
cc.setAttribute("cx", "50");
cc.setAttribute("cy", "50");
cc.setAttribute("r", "20");
layer.appendChild(cc);
// However it's not updating the screen
// even if DOM shows the circle is there, inside the "g"
}
</script></head>
<body>
<object id="test" data="test.svg" type="image/svg+xml"></object>
<script>
document.onreadystatechange = function(){
if(document.readyState === 'complete') addCircle(); }
</script>
</body>
</html>
What am I doing wrong? Or what am I missing? Thank you!
Its the issue with your svg namespace that you are passing to create the circle. Try this
var cc = document.createElementNS("http://www.w3.org/2000/svg", "circle");
You are getting the namespaceURI of the <object> element.
What you need is the one of the inner document's documentElement :
function addCircle() {
// this is the <object>
var svgDoc = document.getElementById("test");
var svg = svgDoc.contentDocument;
// here get the real svg document
var svgns = svg.documentElement.namespaceURI;
//...
As a plunker since stacksnippetsĀ® won't allow the modification of inner frames...

Dynamically add a full svg shape (with pure Javascript)

I want to draw a square by using path in SVG created with JS. But the browsers do not accept this:
Javascript:
var svg = document.createElement('svg');
svg.width = "200";
svg.height = "200";
document.body.appendChild(svg);
var path = document.createElement('path');
path.setAttribute('d','M100,0 L200,100 100,200 0,100Z');
path.setAttribute('fill','red');
svg.appendChild(path);
HTML (output):
<svg width="200" height="200">
<path d="M100,0 L200,100 100,200 0,100Z" fill="red"/>
</svg>
createElement can only be used to create html elements. To create SVG elements you must use createElementNS and supply the SVG namespace as the first argument.
Also document.body.appendChild('svg'); is presumably a typo as you want to add the svg element and not a string containing the text 'svg'
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('width','200');
svg.setAttribute('height','200');
document.body.appendChild(svg);
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttribute('d','M100,0 L200,100 100,200 0,100Z');
path.setAttribute('fill','red');
svg.appendChild(path);
Use createElementNS instead of createElement.

SVG element inserted into DOM is ignored (its type is changed)

I am using the VivaGraph.js library to render a graph in SVG. I am trying to display an image cropped to a circle, for which I am using a clipPath element - as recommended in this post.
However, when I create a new SVG element of type that has a capital letter in it, e.g. clipPath in my case, the element that is inserted into the DOM is lowercase, i.e. clippath, even though the string I pass in to the constructor is camelCase. Since SVG is case sensitive, this element is ignored. Everything else seems to be okay.
I also tried to change the order in which I append the child elements, in hopes of changing the 'z-index', but it didn't have an impact on this.
I am using the following code inside of the function that creates the visual representation of the node in the graph (the 'addNode' callback) to create the node:
var clipPhotoId = 'clipPhoto';
var clipPath = Viva.Graph.svg('clipPath').attr('id', clipPhotoId);
var ui = Viva.Graph.svg('g');
var photo = Viva.Graph.svg('image').attr('width', 20).attr('height', 20).link(url).attr('clip-path', 'url(#' + clipPhotoId + ')');
var photoShape = Viva.Graph.svg('circle').attr('r', 10).attr('cx', 10).attr('cy', 10);
clipPath.append(photoShape);
ui.append(clipPath);
ui.append(photo);
return ui;
Thank you!
There is a bit of tweaking needed on top of the post you provided.
General idea to solve your issue is this one:
We create a VivaGraph svg graphics (which will create an svg element in the dom)
Into this svg graphic we create only once a clip path with relative coordinates
When we create a node we refer to the clip path
Code is:
var graph = Viva.Graph.graph();
graph.addNode('a', { img : 'a.jpg' });
graph.addNode('b', { img : 'b.jpg' });
graph.addLink('a', 'b');
var graphics = Viva.Graph.View.svgGraphics();
// Create the clipPath node
var clipPath = Viva.Graph.svg('clipPath').attr('id', 'clipCircle').attr('clipPathUnits', 'objectBoundingBox');
var circle = Viva.Graph.svg('circle').attr('r', .5).attr('cx', .5).attr('cy', .5);
clipPath.appendChild(circle);
// Add the clipPath to the svg root
graphics.getSvgRoot().appendChild(clipPath);
graphics.node(function(node) {
return Viva.Graph.svg('image')
.attr('width', 30)
.attr('height', 30)
// I refer to the same clip path for each node
.attr('clip-path', 'url(#clipCircle)')
.link(node.data.img);
})
.placeNode(function(nodeUI, pos){
nodeUI.attr('x', pos.x - 15).attr('y', pos.y - 15);
});
var renderer = Viva.Graph.View.renderer(graph, { graphics : graphics });
renderer.run();
The result in the dom will be like this:
<svg>
<g buffered-rendering="dynamic" transform="matrix(1, 0, 0,1,720,230.5)">
<line stroke="#999" x1="-77.49251279562495" y1="-44.795726056131116" x2="6.447213894549255" y2="-56.29464520347651"></line>
<image width="30" height="30" clip-path="url(#clipCircle)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="a.jpg" x="-92.49251279562495" y="-59.795726056131116"></image>
<image width="30" height="30" clip-path="url(#clipCircle)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="b.jpg" x="-8.552786105450746" y="-71.2946452034765"></image>
</g>
<clipPath id="clipCircle" clipPathUnits="objectBoundingBox">
<circle r="0.5" cx="0.5" cy="0.5"></circle>
</clipPath>
</svg>
Notice the clipPathUnits="objectBoundingBox", since it's the main trick for this solution.

Categories

Resources