JavaScript function to draw SVG elements - javascript

Hello I would like to write a simple function that creates svgcircles where I only have to specify the x, y coordinates.
JavaScript code is:
function cir(x, y){
<circle cx="x" cy="y" r="10" fill="blue" />;
}
HTML code is:
<!DOCTYPE html>
<html>
<head>
<script src="script.js"></script>
</head>
<body>
<svg width="1024" height="768">
cir(50, 50);
</svg>
</body>
</html>
What am I doing wrong?

You can return some HTML using a template literal and add it to your SVG element.
function cir(x, y) {
return `<circle cx=${x} cy=${y} r="10" fill="blue" />`;
}
document.querySelector('svg').insertAdjacentHTML('beforeend', cir(50, 50));
<svg width="1024" height="768"></svg>
Note: you should move your script to just before your </body> tag. That way the document will have time to load before the script is executed.
<script src="script.js"></script>
</body>
DOM resources on MDN:
querySelector
insertAdjacentHTML
EDIT
Now, if you wanted to include a form from which you can get the coordinates, you can do something like this.
function cir(x, y) {
return `<circle cx=${x} cy=${y} r="10" fill="blue" />`;
}
// Grab all the elements
const button = document.querySelector('.submit');
const svg = document.querySelector('svg');
const x = document.querySelector('.x');
const y = document.querySelector('.y');
// Add an event listener to the button
button.addEventListener('click', addShape, false);
function addShape(e) {
// Prevent the form from submitting
e.preventDefault();
svg.insertAdjacentHTML('beforeend', cir(x.value, y.value));
}
<form>
<input class="x" type="text" placeholder="X coord" />
<input class="y" type="text" placeholder="Y coord" />
<button class="submit">Submit</button>
</form>
<svg width="1024" height="768"></svg>
You can add more inputs for the radius and colour if you wanted.

Related

Insert SVG file into HTML

I've got 3 files: test.html, test.js and test.svg
I'm trying to call the different files into HTML but the file svg don't work
test.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Using SVG as an object</title>
<link href="index.css" rel="stylesheet" />
</head>
<body>
<h1>Test</h1>
<script type="text/javascript" src="test.js"></script>
<object data="test.svg" width="300" height="300"> </object> <!-- Not working -->
<input type="button" value="Start Animation" onclick="startAnimation();">
<input type="button" value="Stop Animation" onclick="stopAnimation();">
</body>
</html>
test.js
var timerFunction = null;
function startAnimation() {
if(timerFunction == null) {
timerFunction = setInterval(animate, 20);
}
}
function stopAnimation() {
if(timerFunction != null){
clearInterval(timerFunction);
timerFunction = null;
}
}
function animate() {
var circle = document.getElementById("circle1");
var x = circle.getAttribute("cx");
var newX = 2 + parseInt(x);
if(newX > 500) {
newX = 20;
}
circle.setAttribute("cx", newX);
}
test.svg
<svg width="500" height="100">
<circle id="circle1" cx="20" cy="20" r="10"
style="stroke: none; fill: #ff0000;"/>
</svg>
I don't understand why I can't insert svg file with object
Thanks for your help
See Dev.To Post: <load-file> Web Component
Use a modern, native W3C standard Web Component <load-svg>
it reads the SVG as text
adds SVG to shadowDOM as DOM element
moves the style element from lightDOM to shadowDOM
So style is only applied to one SVG
<load-svg shadowRoot src="//graphviz.org/Gallery/directed/fsm.svg">
<style>
svg { height:150px } text { stroke: green } path { stroke: red ; stroke-width:3 }
</style>
</load-svg>
<load-svg src="//graphviz.org/Gallery/directed/fsm.svg">
<!-- all HTML here is overwritten -->
</load-svg>
<script>
customElements.define('load-svg', class extends HTMLElement {
async connectedCallback() {
this.style.display = 'none'; // prevent FOUC (provided Custom Element is defined ASAP!)
let src = this.getAttribute("src");
let svg = await (await fetch(src)).text();
if (this.hasAttribute("shadowRoot")) {
this.attachShadow({mode:"open"}).innerHTML = svg;
this.shadowRoot.append(this.querySelector("style") || []);
} else {
this.innerHTML = svg;
}
this.style.display = 'inherit';
}
});
</script>
More complex example: How to make an svg interactive to gather comments/annotations on depicted elements
You can use svgs directly in the HTML. Easiest is to just use the SVG inside the HTML. You can also re-use an svg shape on a page but then the icons have a shadow-dom boundary.
If you use an object or svg tag, it will render just fine but you will lose all information about classes, IDs and so on in the SVG.
Further Information on SVG on css-tricks
More information about how to group and re-use shapes in SVG on css-tricks (and one more, also on css-tricks)
var timerFunction = null;
function startAnimation() {
if (timerFunction == null) {
timerFunction = setInterval(animate, 20);
}
}
function stopAnimation() {
if (timerFunction != null) {
clearInterval(timerFunction);
timerFunction = null;
}
}
function animate() {
var circle = document.getElementById("circle1");
var x = circle.getAttribute("cx");
var newX = 2 + parseInt(x);
if (newX > 500) {
newX = 20;
}
circle.setAttribute("cx", newX);
}
<svg width="500" height="100">
<circle id="circle1" cx="20" cy="20" r="10"
style="stroke: none; fill: #ff0000;"/>
</svg>
<input type="button" value="Start Animation" onclick="startAnimation();">
<input type="button" value="Stop Animation" onclick="stopAnimation();">
<object> tags can be used on many elements, including SVG files, and therefore not recognized as image elements, So:
It's not available on image search. So you can use an <img> tag as fallback (optional but recommended)
You should specify the type of the object
So you can change it like this:
<object type="image/svg+xml" data="test.svg" width="300" height="300">
<img src="test.svg" />
</object>
And another problem is the SVG file. Based on MDN documents :
The xmlns attribute is only required on the outermost SVG element of SVG documents. It is unnecessary for inner SVG elements or inside HTML documents.
so you need to add xmlns parameters to the SVG tag on SVG file like this :
<svg width="500" height="100" xmlns="http://www.w3.org/2000/svg">
<circle id="circle1" cx="20" cy="20" r="10"
style="stroke: none; fill: #ff0000;"/>
</svg>
I made a small simple example that works, checkout this sandBox link

How to redraw SVG after change from javascript (Internet Explorer and Edge)

Does anyone know how to force IE and Edge to display/refresh embedded SVG after changing its content (see code below)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Title</title>
<script type="text/javascript">
function onClick() {
document.getElementById('svg').innerHTML = '<circle r="50" cx="50" cy="50" fill="red" />';
}
</script>
</head>
<body>
<button type="button" onclick="onClick()" >Display red circle</button>
<svg id="svg"/>
</body>
</html>
Modify your markup as
<div id="container">
Your svg here
</div>
and add
document.getElementById("container").innerHTML += "";
at the end of your script.
As it was mentioned by #rzelek, SVG image will get updated on it's own if you add elements with svg.appendChild() rather than by assigning to svg.innerHTML.
One caveat, though: you must specify the http://www.w3.org/2000/svg namespace on the element you create using document.createElementNS(), instead of the normal createElement().
Example:
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('r', '50');
circle.setAttribute('cx', '50');
circle.setAttribute('cy', '50');
circle.setAttribute('fill', 'red');
document.getElementById('svg').appendChild(circle);
JSFiddle
Basically, you do not need to reload anything. Actually, the problem is different. You will not able to interact with SVG using standard innerHTML method. Your SVG is not updated after calling to innerHTML. This method is suitable for editing HTML elements only.
Plase take a look at this:
update SVG dynamically
Plunker
JS:
var x = 0;
function onClick() {
var div = document.getElementById('svg');
Update(div);
}
function Update(div){
x++;
div.innerHTML = '<svg><circle r="' + x + '" cx="' + x +'" cy="' + x + '" fill="red" /></svg>';
if (x < 100)
{
setTimeout(function() {
Update(div);
}, 100);
}
console.log(div.innerHTML);
}
HTML:
<body>
<button type="button" onclick="onClick();" >Display red circle</button>
<div id="svg">
</div>
</body>
Wrapping the SVG in a container and then updating the content of the container seems to work.

How to create a clickable shape with SVG and Javascript?

HTML
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src='draw.js'></script>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="200"></svg>
</body>
</html>
draw.js
function draw() {
var svg = document.getElementsByTagName('svg')[0];
var svgNS = svg.namespaceURI;
var rect = document.createElementNS(svgNS,'rect');
rect.setAttribute('x',5);
rect.setAttribute('y',5);
rect.setAttribute('width',100);
rect.setAttribute('height',36);
rect.setAttribute('fill','#95B3D7');
var link = document.createElement('a');
link.setAttribute('xlink:href', 'http://www.google.com');
link.appendChild(rect);
svg.appendChild(link);
}
$( document ).ready( draw );
The generated HTML looks correct, but the rectangle does not appear:
<a xlink:href="http://www.google.com">
<rect x="5" y="5" width="100" height="36" fill="#95B3D7"></rect>
</a>
In fact, the generated HTML does work, when pasted into an HTML file. So, is there some limitation of the browser using SVG, Javascript and links?
Using Chrome 39.
You need to create an SVG link element and not a html link element i.e. in the SVG namespace
var link = document.createElementNS(svgNS, 'a');
link.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'http://www.google.com');
You get it right for the rect itself!

appending entire svg to dom element leads to Exception... "String contains an invalid character" code: "5"

I'd like to appending an entire svg element to an childless element of the DOM. I tried the d3-style and the common style and both lead me to this error:
[Exception... "String contains an invalid character" code: "5" nsresult: "0x80530005 (InvalidCharacterError)" location: "<unknown>"]
How do I append it correct?
// with d3
var dropTargetsDiv = d3.select(".droptargets").html("");
dropTargetsDiv.append(svgPic);
// without d3
var dropTargetsDiv = window.document.getElementById("canvas").parentNode;
dropTargetsDiv.innerHTML="";
dropTargetsDiv.appendChild(window.document.createElement(svgPic));
//the svg content is taken from a text area...
var svgPic = scope.$parent.export;
//and looks fine
<svg id="canvas"><g id="dashboard-content"><rect id="dropPanel"></rect></g></svg>
// the structure
<div class="droptargets"...
<svg id="canvas"...
<g id="dashboard-content...
D3's .append() doesn't take the contents of the element to be appended. To quote the documentation:
Appends a new element with the specified name as the last child of each element in the current selection [...] The name may be specified either as a constant string or as a function that returns the DOM element to append.
So to append an SVG element, you should do
var svg = dropTargetsDiv.append("svg");
and then populate the contents of the node, i.e. add the g element and anything else that may be there.
Insert svg text into your SVG DIV by dropTargetsDiv.innerHTML=mySVGText. This will completely replace the previous.
Example 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 style='font-family:arial'>
<center>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
Replace DIV.innerHTML with new SVG text
</div>
<br />New SVG Source:<br />
<textarea id=svgNewSourceValue style='font-size:110%;font-family:lucida console;width:90%;height:100px'>
<svg id="mySVG2" width="400" height="400" xmlns="http://www.w3.org/2000/svg" >
<rect width=150 height=100 x=100 y=100 fill=blue />
</svg>
</textarea>
<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'>
<svg id="mySVG1" width="400" height="400" xmlns="http://www.w3.org/2000/svg" >
<circle r=150 cx=200 cy=200 fill=red />
</svg>
</div>
<center><button onClick=replaceSVG()>Replace SVG</button></center>
<br />SVG Source:<br />
<textarea id=svgSourceValue style='font-size:110%;font-family:lucida console;width:90%;height:100px'>
</textarea>
<br />Javascript:<br />
<textarea id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:200px'></textarea>
</center>
<script id=myScript>
function replaceSVG()
{
svgDiv.innerHTML=svgNewSourceValue.value
svgSourceValue.value=svgDiv.innerHTML
}
</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
svgSourceValue.value=svgDiv.innerHTML
jsValue.value=myScript.text
}
</script>
</body>
</html>

input button to resize shape

Hi can someone please help me with getting the buttons to resize the shape. I have had a go myself but cannot get it to work. Below is the code I have so far thanks in advance
<html>
<head>
<script>
function Smaller()
{
document.getElementById("rectangle1").height="50";
document.getElementById("rectangle1").width="50";
}
function resetsize()
{
document.getElementById("rectangle1").height="200";
document.getElementById("rectangle1").width="300";
}
</script>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 500px; height: 500px">
<rect id="rectangle1" x="150" y="0" width="300" height="200" />
</svg>
<input type="button" onclick="Smaller" value="Smaller" />
<input type="button" onclick="resetsize" value="ResetSize" />
</body>
</html>
<html>
<head>
<script>
function smaller() {
document.getElementById("rectangle1").style.height="50px";
document.getElementById("rectangle1").style.width="50px";
}
function resetsize() {
document.getElementById("rectangle1").style.height="200px";
document.getElementById("rectangle1").style.width="300px";
}
</script>
</head>
<body>
<div style="min-height:500px">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 500px; height: 500px" id="rectangle1">
<rect x="150" y="0" width="300" height="200" />
</svg>
</div>
<input type="button" onclick="smaller()" value="smaller" />
<input type="button" onclick="resetsize()" value="ResetSize" />
</body>
</html>
Please look at the on click propery of the buttons. And there is no id for yor svg element. :- )
You can access a DOM element's CSS properties with the style attribute, like this:
function smaller() {
document.getElementById("rectangle1").style.height="50";
document.getElementById("rectangle1").style.width="50";
}
function resetsize() {
document.getElementById("rectangle1").style.height="200";
document.getElementById("rectangle1").style.width="300";
}
A few notes about your coding conventions: You typically want to having opening function brackets on the same line as the name of the function. Function names should be camelCase at all times; save UpperCase for class names only. Finally, make sure you tab in stuff inside of functions, if statements, etc. Your fellow developers will thank you. =)
Edit: make sure your HTML looks like this:
<input type="button" onclick="smaller()" value="Smaller" />
<input type="button" onclick="resetsize()" value="ResetSize" />
use jQuery to avoid this DOM abomination document.getElementById("fooo")

Categories

Resources