Append children to inline SVG using javascript - javascript

I have the following document, where I plan to add some horizontal lines, one for each line of a textbox, where lines should have a "name: number" structure.
<!DOCTYPE html>
<html lang="pt-br" xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
<head>
<meta charset="UTF-8" />
<meta http-equiv="pragma" content="no-cache"/>
<title>Diagrama Audax</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js"></script>
<style type="text/css">
#sidebar {float: left; display: inline-block;}
#drawing {left: 330px; position: relative; display: inline-block}
#Locais {width: 300px; height: 500px;}
svg {background: #ddd; width: 500px; height: 500px;}
td, textarea {margin: 0; padding: 0;}
</style>
</head>
<body>
<table>
<tr id="tabela" cols="2">
<td>
<textarea id="Locais"></textarea>
</td>
<td>
<svg id="svg">
<circle stroke="black" fill="red" cx="200" cy="200" r="100" opacity="0.1"/>
<line id="path" x1="0" y1="0" x2="200" y2="200" stroke="black"/>
</svg>
</td>
</tr>
</table>
</body>
<script>
// A função abaixo pega a caixa de texto e associa o evento "draw" a ela
$(function () {
$("#Locais").keyup(function() {
valueString = $("#Locais").val();
if (valueString != "") {
lines = valueString.replace("\r","").split("\n");
CPs = [];
for (i in lines) {
eachLine = lines[i];
tmpDict = {};
values = eachLine.split(":");
for (j in values) {
eachVal = values[j];
tmpDict[j] = eachVal;
}
CPs.push(tmpDict);
}
DrawUsing(CPs);
}
})
});
function DrawUsing (lista) {
var svg = document.getElementById("svg");
for (element in lista) {
refname = lista[element][0];
refdist = lista[element][1];
var line = document.createElement ("line");
line.setAttribute('stroke', "black");
line.setAttribute('stroke-width', 1);
line.setAttribute('x1', 0);
line.setAttribute('x2', 100);
line.setAttribute('y1', refdist);
line.setAttribute('y2', refdist);
svg.appendChild(line);
console.log(document.getElementsByTagName("line").length);
}
}
</script>
</html>
As a "warm up", I tried to manipulate the SVG adding lines to it each time I press a key. Having pasted the following text (just pasting it with control+V is enough to trigger keyup event), but although the svg child list increases, no additional line is seen.
What am I doing wrong? (a lot, I suppose, since I am very n00b with javascript, and direct manipulation of inline <svg> elements (as opposed to <object>) is very poorly documented, it seems...
Any help is most welcome, thanks for reading!

SVG elements go in the http://www.w3.org/2000/svg namespace so instead of
var line = document.createElement ("line");
use
var line = document.createElementNS ("http://www.w3.org/2000/svg","line");

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

foreignObject overflow:visible not working in firefox

I am trying to make my drawing application work well in Firefox.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.list {
background-color: blanchedalmond;
}
.list-item {
width: 50px;
height: 25px;
background-color: coral;
}
foreignObject {
overflow: visible;
}
</style>
</head>
<body>
<svg width="300" height="200" fill="blue">
<foreignObject width="300" height="25">
<div class="list">
<div class="list-item">a</div>
<div class="list-item">b</div>
<div class="list-item">c</div>
</div>
</foreignObject>
</svg>
<svg class="svg2" width="300" height="200" fill="blue">
<foreignObject width="300" height="25">
<div class="list">
</div>
</foreignObject>
</svg>
<script>
let svg = document.querySelector('.svg2');
svg.addEventListener('mousemove', handleMouseMove)
function handleMouseMove(e) {
console.log(e.offsetX, e.offsetY);
}
setTimeout(() => {
let el = document.querySelector('.svg2 .list');
let a = document.createElement('div')
let b = document.createElement('div');
let c = document.createElement('div');
a.innerHTML = 'a';
b.innerHTML = 'b';
c.innerHTML = 'c';
a.classList.add('list-item')
b.classList.add('list-item')
c.classList.add('list-item')
el.appendChild(a);
el.appendChild(b);
el.appendChild(c);
}, 1000);
</script>
</body>
</html>
In Chrome, both svg show all 3 items.
In Firefox(developer version 78.0b4 (64-bit)), in the first svg, all 3 items are visible, in the second svg, only the first item is visible. Why does the second svg not show all 3 items?
Setting style="overflow: visible" on <svg> solved the same issue for me.
SVG and sub-elements also support overflow="visible" as an attribute (so you can try <foreignObject overflow="visible ... >).

How do I make free movement of an svg element with the Shift+Left button Mouse pressed?

Hello I need a circle that is created when you click on a free area to be able to move freely throughout the page when the Shift+Left button Mouse is pressed.
Simply put I need to be able to move this circle around the entire page area while holding down Shift+Left button Mouse.
Before trying to respond run the code and click on an empty area.
let svg = document.querySelector("svg")
let bg = document.querySelector("svg rect")
function click(e) {
svg.innerHTML += `
<g transform="translate(${e.clientX},${e.clientY})">
<circle onclick="split(this)" r="50"></circle>
</g>
`;
}
function split(el){
el.parentNode.innerHTML = [...Array(4)].map((_,i) => `
<path d="M-50,0A50,50,0,0,0,0,50L0,0z"
onclick=merge(this)
transform="rotate(${-45+i*90})"></path>
`);
}
function merge(el){
el.parentNode.innerHTML = `<circle onclick="split(this)" r="50"></circle>`;
}
function resize() {
svg.setAttribute("viewBox", [0, 0, innerWidth, innerHeight]);
}
resize();
addEventListener("resize", resize);
body{
margin: 0;
overflow: hidden
}
path, circle {
transition: 100ms;
fill: #0001;
stroke: black;
}
path:hover, circle:hover {
fill: rgba(15, 250, 113, 0.133);
}
<!DOCTYPE HTML>
<html lang="ru">
<head>
<title>Redactor marshrutov</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="menu1.css">
</head>
<body>
<svg>
<rect fill="white" width="1440" height="900" onclick="click(event)"></rect>
</svg>
<script type="text/javascript" src="menu1.js"></script>
</body>
</html>

Greensock - DrawSVG

I am trying to make the search bar animate. I was able to make it draw in when you click and when you click again it goes back to the original position (using greensock - drawSVG).
I want to be able to click again without refreshing the page, and have everything work correctly. So far, only the drawSVG is the only thing not reanimating.
I am also not sure why the drawSVG property is not working here, it does work on my own computer. (I am attaching a gif of the animation from my computer)
var $SearchBar = $('#SearchBar');
var $searchIcon = $('#searchIcon');
var $drawSearch = $ ('#drawSearch');
var $leftX = $('#leftX');
var $rightX = $('#rightX');
var $changeColor = $('#changeColor');
//this is my variable for when to draw the search bar
var searchVisible = false;
var $black = ('#000');
TweenMax.set($SearchBar, {stroke:'#000'});
TweenMax.set([$searchIcon, $leftX, $rightX, $changeColor],{transformOrigin: '50% 50%'});
TweenMax.set([$drawSearch, $leftX, $rightX, $changeColor], {alpha:0});
TweenMax.set([$leftX], {rotation:-45, scale:0.75});
TweenMax.set([$rightX], {rotation:45, scale:0.75});
searchVisible = false;
//funciton to click the searchIcon
function clickSearch(){
console.log("click");
if (searchVisible === true) {
searchVisible = false;
console.log("Yes i see the search draw");
TweenMax.to($changeColor, 2, {alpha:0,scale:0});
TweenMax.to([$leftX],0.25, {rotation:-45});
TweenMax.to([$rightX],0.25, {rotation:45});
TweenMax.to([$rightX,$leftX],0.25, {alpha:0,delay:0.25});
TweenMax.to($drawSearch,1,{drawSVG: 0, delay:0.5});
TweenMax.to($searchIcon, 0.5, {rotation: 0, delay:1.5});
}
else {
console.log("No i dont see the searchdraw");
searchVisible = true;
TweenMax.to($changeColor, 2, {alpha:1,scale:100});
TweenMax.to($searchIcon, 0.25, {rotation: -20});
TweenMax.to($searchIcon, 0.25, {rotation: 88, delay:0.25});
TweenMax.set([$drawSearch],{alpha:1});
TweenMax.from($drawSearch,0.75,{drawSVG:0, delay:0.50});
TweenMax.to([$leftX, $rightX], 0.25,{alpha:1,delay:1});
TweenMax.to([$leftX],0.25, {rotation:0, delay:1});
TweenMax.to([$rightX],0.25, {rotation:0,delay:1});
}
}
//listener for clickSearch function
$SearchBar.on("click", clickSearch);
section {
background-color: #900C3F;
display: flex;
align-content: center;
justify-content: center;
cursor: pointer; }
section svg {
height: 100vh;
width: 100vw; }
<!DOCTYPE html>
<html lang="en">
<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">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
<link rel="stylesheet" href="css/styles.css">
<title>SCSS template</title>
</head>
<body>
<section>
<svg id="SearchBar" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<style>
.st0 {
fill: #41718e;
stroke: #900C3F;
}
.st1 {
stroke-linecap: round
}
.st1,
.st2 {
fill: none;
stroke: #fff;
stroke-width: 8;
stroke-miterlimit: 10
}
</style>
<circle id="changeColor" class="st0" cx="390.24" cy="178.54" r="24.04" />
<g id="searchIcon">
<path class="st1" d="M409.27 199.36l21.05 21.21" />
<circle class="st2" cx="390.38" cy="178.62" r="24.72" />
</g>
<path class="st1" d="M365.47 220.65l-325.13 1.56.32-66.54 289.96-1.16" id="drawSearch" />
<path id="leftX" class="st1" d="M58.31 175.9l24.62 24.61" />
<path id="rightX" class="st1" d="M82.49 175.77l-24.61 24.62" />
</svg>
</section>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Greensock -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<!-- Greensock Draw SVG -->
<script src="http://dugraphicdesign.com/winterWeb3/DrawSVGPlugin.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/plugins/ScrollToPlugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/plugins/TextPlugin.min.js"></script>
<script src="js/scripts.js"></script>
</body>
</html>
The DrawSVGPlugin.js plugin isn't loading. Without this plugin, the DrawSVG functionality won't work.
A page loaded using https will not load javascript using http. This is known as "mixed content" and is prevented by the browser for security reasons.
As for the animation, I think it's because you're trying to use .from() without having properly initialized the element's state.
Instead of using integers for the drawSVG property, use percentages, as in "100%". When you use integers, these are interpreted as a raw length which can take some effort to figure out. When using percentages, DrawSVG will figure it out for you.
Rather than messing around with prior states, animate to "0%" or "100%" as needed.
So initialize with
TweenMax.set([$drawSearch], {drawSVG:"0%"});
Then switch between states with
TweenMax.to($drawSearch, 1, {drawSVG:"0%", delay:0.5});
and
TweenMax.to($drawSearch, 0.75, {drawSVG:"100%", delay:0.50});
as shown in https://repl.it/#ouroborus/GrubbyFuzzyDatalog

add image in the svg

INDEX.HTML
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
width: 960px;
padding-top: 40px;
margin: auto;
position: relative;
}
svg {
width: 100%;
max-height: 400px;
}
</style>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script type='text/javascript'>
window.addEventListener('load', function () {
d3.xml('iPhone.svg', 'image/svg+xml', function (error, data) {
d3.select('body').node().appendChild(data.documentElement);
var svg = d3.select('svg');
var appScreen = svg.select('#ScreenBackground');
var screenWidth = +appScreen.attr('width'),
screenHeight = +appScreen.attr('height');
var appButton = svg.select('#AppButton')
.on('mouseenter', function () {
appButton.style('fill', '#AB69C6');
})
.on('mouseleave', function () {
appButton.style('fill', '#9B59B6')
})
.on('click', function () {
var x = Math.random() * screenWidth;
var y = Math.random() * screenHeight;
appButton
.transition()
.duration(1000)
.ease('bounce')
.attr('cx', x)
.attr('cy', y);
});
});
});
</script>
iPhone.svg
<?xml version='1.0' encoding='utf-8'?>
<svg width='400px' height='800px' viewBox='0 0 400 800'
version='1.1' xmlns='http://www.w3.org/2000/svg'>
<title> SafeSignal </title>
<description>Created with Sketch (http:/ / www.bohemiancoding.com / sketch) </description>
<defs>
<!-- Define a clipping path the size of the screen -->
</defs>
<!-- iPhone frame -->
<rect id='iPhone' fill='#000000'
x='0' y='0' width='400' height='800' rx='50' ry='50'></rect>
<!-- iPhone home button -->
<circle id='HomeButton' fill='#202020'
cx='200' cy='730' r='40'></circle>
<!-- Apply the clipping path to the screen group -->
<g id='ScreenGroup' transform='translate(20, 80)'
clip-path='url(#ScreenMask)'>
<!-- Screen background -->
<rect id = "ScreenBackground" x ="214" y ="0" width ="102" height ="568" style = "pointer-events: all;" ></rect>
<!-- An interactive button in the app -->
<circle id='AppButton' fill='#9B59B6' cx='180' cy='290' r='50' style='cursor:pointer;'></circle>
</g>
</svg>
taking help from the google , i have made this SVG . now I am trying to make have background as image but i have tried all the ways but everytime i done this ya add any image I have get this error Uncaught TypeError: Cannot read property 'documentElement' of null I dont know where i am going wrong because i am new to this svg
<object type="image/svg+xml"
width="100" height="100" style="float:right"
data="http://blog.codedread.com/clipart/apple.svgz">
<span/></object>
<object id="E" type="image/svg+xml" data="http://srufaculty.sru.edu/david.dailey/svg/ovals.svg" width="320" height="240">
alt : Your browser has no SVG support. Please install Adobe SVG Viewer
plugin (for Internet Explorer) or use Firefox, Opera or Safari instead.
</object>
<!DOCTYPE html>
<html>
<head>
<title>HTML5 SVG demo</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>
<body>
<h1>HTML5 SVG Demo (embed with iframe)</h1>
<p> A nice green circle that was embeded using the HTML "iframe" tag:
<iframe src="green-circle.svg"
width="64" height="64" style="border:1;"></iframe>
</p>
<p>
Tips:
<iframe src="green-circle.svg" style="float:left;margin-right:1cm;"
width="64" height="40" style="border:1;"></iframe>
</p>
</body>
</html>

Categories

Resources