Get position of svg element - javascript

Why i can not get values of cx and cy ?
its print some array. i need only 2 values
<!DOCTYPE html>
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="red" id="cir"/>
</svg>
<script>
console.log(document.getElementById("cir").cx);
console.log(document.getElementById("cir").cy);
</script>
</body>
</html>

The cx and cy properties are SVGAnimatedLength objects, not strings or numbers.
To get the actual value for cx, you need to do:
cx.baseVal.value
<!DOCTYPE html>
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="100" r="50" fill="red" id="cir"/>
</svg>
<script>
console.log(document.getElementById("cir").cx.baseVal.value);
console.log(document.getElementById("cir").cy.baseVal.value);
</script>
</body>
</html>

Use console.log() instead of Console.log()
console is defined by the browser, Console is not (JS, as most languages, is case-sensitive)

Related

How to get the offsetLeft/offsetTop of the <g id="iqaluit"> and <circle id="circle"> elements on the page?

How to get offsetLeft/offsetTop of **<g id="iqaluit"> and <circle id="circle"> elements in javascript.
I tried this: but it gives an error TypeError: bar is null.
JS
let bar = document.getElementById('iqaluit');
console.log(bar.offsetLeft, bar.offsetTop)
let circle = document.getElementById('circle');
console.log(circle.offsetLeft, circle.offsetTop);
HTML
<div class="section-map">
<canvas class="svgfix__canvas" width="500" height="488"> </canvas>
<svg id="MAP" data-name="MAP" data-province="MAP" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 1072.93">
<g id="City_Labels_Canada" data-name="City Labels Canada">
<g id="iqaluit" data-name="Iqaluit" data-province="nunavut" class="city nohover">
<circle id="circle" cx="839.32" cy="390.34" r="3.1"></circle>
<text x="847" y="394" data-name="Iqaluit" class="en de fr es">Iqaluit</text>
</g>
</g>
</svg>
</div>
#Dio, you're on the right track. The svg elements do not support the properties you are looking for but you can access the elements, just a little differently from how you attempted, with the document. See below.
Also, the suggestion from #Syed Qasim Ahmed provides an object, but I'm not sure what you're trying to achieve with offsetLeft/offsetTop, so I can't say if it's equivalent or not.
const map = document.getElementById('MAP');
const bar = map?.querySelector('#iqaluit');
/**
* You can see the available
* methods and properties
* with a for in loop
*/
if (bar) {
for (let i in bar) {
console.log('what is i?', i);
console.log('what is bar[i]?', bar[i]);
}
const getBoundingClientRect = bar.getBoundingClientRect();
console.log({ getBoundingClientRect });
}
<div class="section-map">
<canvas class="svgfix__canvas" width="500" height="488"> </canvas>
<svg id="MAP" data-name="MAP" data-province="MAP" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 1072.93">
<g id="City_Labels_Canada" data-name="City Labels Canada">
<g id="iqaluit" data-name="Iqaluit" data-province="nunavut" class="city nohover">
<circle id="circle" cx="839.32" cy="390.34" r="3.1"></circle>
<text x="847" y="394" data-name="Iqaluit" class="en de fr es">Iqaluit</text>
</g>
</g>
</svg>
</div>

SVG graph and Javascript: Which is the best way to add animation to and SVG file?

I'm new at coding.
I'm studying the way to make an animated portfolio like Sean Halpin or Stephanie Walter one. I want to put a face, in which, blinking eyes and a moving the mouth would be the animated elements. Basically, I want to play with the visibility of the closed eyes and open mouth. As an example, I drew a face as follows:
<svg id="Capa_1" data-name="Capa 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 429 429">
<defs>
<style>
.cls-1 {
fill: #fff;
}
.cls-2 {
fill: none;
stroke: #000;
stroke-miterlimit: 10;
}
</style>
</defs>
<g id="face">
<path class="cls-1" d="M611,608.5a214,214,0,1,1,151.32-62.68A212.6,212.6,0,0,1,611,608.5Z" transform="translate(-396.46 -180)" />
<path d="M611,181a212.9,212.9,0,1,1-83.1,16.78A212.11,212.11,0,0,1,611,181m0-1c-118.46,0-214.5,96-214.5,214.5S492.5,609,611,609s214.5-96,214.5-214.5S729.43,180,611,180Z" transform="translate(-396.46 -180)" />
</g>
<g id="eyes">
<g id="eye_r">
<circle class="cls-1" cx="319.15" cy="128.63" r="48.5" />
<path d="M715.61,260.62a48,48,0,1,1-48,48,48.06,48.06,0,0,1,48-48m0-1a49,49,0,1,0,49,49,49,49,0,0,0-49-49Z" transform="translate(-396.46 -180)" />
</g>
<g id="iris_r">
<circle cx="319.15" cy="128.63" r="19" />
</g>
<g id="eye_l">
<circle class="cls-1" cx="109.85" cy="128.63" r="48.5" />
<path d="M506.32,260.62a48,48,0,1,1-48,48,48.06,48.06,0,0,1,48-48m0-1a49,49,0,1,0,49,49,49,49,0,0,0-49-49Z" transform="translate(-396.46 -180)" />
</g>
<g id="iris_l">
<circle cx="109.85" cy="128.63" r="19" />
</g>
<line id="closed_eye_l" class="cls-2" x1="62.04" y1="128.5" x2="158.04" y2="128.5" />
<line id="closed_eye_r" class="cls-2" x1="270.69" y1="128.23" x2="366.69" y2="128.23" />
</g>
<g id="closed_mouth">
<ellipse cx="214.5" cy="309" rx="108.5" ry="11.5" />
<path d="M611,478c29.08,0,56.41,1.25,77,3.51,30.68,3.38,31,7.32,31,7.49s-.35,4.11-31,7.49C667.37,498.75,640,500,611,500s-56.41-1.25-77-3.51c-30.69-3.38-31-7.32-31-7.49s.35-4.11,31-7.49c20.55-2.26,47.88-3.51,77-3.51m0-1c-60.2,0-109,5.37-109,12s48.8,12,109,12,109-5.37,109-12-48.8-12-109-12Z" transform="translate(-396.46 -180)" />
</g>
</svg>
So, I thought three ways to do this:
Place the svg inside an tag, calling then a function that takes into consideration the loading of the file. An example of what I'm saying is found in the following resource: https://www.petercollingridge.co.uk/tutorials/svg/interactive/javascript/, in the "External SVG + External JavaScript" part. It didn't work. The contentDocument ALWAYS returns "null".
In my example, it would be:
HTML:
<object id="face" data="path/to/face.svg" type="image/svg+xml"></object>
JS:
<script type="text/javascript">
window.addEventListener("load", function() {
var svgObject = document.getElementById('face').contentDocument;
var svg = svgObject.getElementById('closed_eye_r');
svg.style.visibility="hidden";
});
</script>
Inline SVG - call a "transform" property. Sean Halpin does it but I'm not sure what he does.
HTML: https://www.seanhalpin.design/
JS: https://www.seanhalpin.design/js/scripts.js
Inline SVG, use getElementById and apply functions to animate the internal parts of the SVG file.
Questions:
a. Is Inline SVG a good practice?
b. Which is the best way to animate an SVG?
I hope to have been clear. Let me know if something is not well presented, I want to learn to edit questions in order to make them as clear as possible.
Thanks!

onmouseenter event triggered on any movement in an SVG use element

When the "mouseenter" event is triggered on the green circle a 1 is printed in the console, when it is triggered on the blue circle a 2 is printed in the console. Note that when the mouse enters the green circle, 1 is printed exactly once. When the mouse enters the blue circle any mouse movement within the circle causes a 2 to be printed.
var gr = document.getElementById("greenOne");
var bl = document.getElementById("blueOneCopy");
gr.onmouseenter = function() {gr.parentNode.appendChild(gr); console.log(1);};
bl.onmouseenter = function() {bl.parentNode.appendChild(bl); console.log(2);};
<html>
<head>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg height="500px" width="500px">
<defs>
<circle id="blueOne" cx="100" cy="100" r="50" style="fill: #0091EA"></circle>
</defs>
<use id="blueOneCopy" href="#blueOne"></use>
<circle id="greenOne" cx="150" cy="100" r="50" style="fill: #00C853"></circle>
</svg>
</body>
</html>
I've managed to get blueOneCopy to behave similarly to greenOne by checking whether the relatedTarget property of the mouse event isn't blueOne before executing the rest of the function. I'm not sure if this is the best solution, but it appears to work.
var gr = document.getElementById("greenOne");
var bl = document.getElementById("blueOneCopy");
gr.onmouseenter = function() {
gr.parentNode.appendChild(gr);
console.log(1);
};
bl.onmouseenter = function(e) {
if (e.relatedTarget.id !== "blueOne") {
bl.parentNode.appendChild(bl);
console.log(2);
}
};
<html>
<head>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg height="500px" width="500px">
<defs>
<circle id="blueOne" cx="100" cy="100" r="50" style="fill: #0091EA"></circle>
</defs>
<use id="blueOneCopy" href="#blueOne"></use>
<circle id="greenOne" cx="150" cy="100" r="50" style="fill: #00C853"></circle>
</svg>
</body>
</html>
Another option is to check whether the element is the last one in the SVG before moving it there. See below
I expect that this issue will have something to do with how events behave when Shadow DOM elements are attached to the DOM. Since Chrome and Firefox behave the same, I expect it is behaviour described in the spec. I'm just too lazy right now to check :)
Note that, with both mine and RFoxtea's solutions, the mouseenter event is still being fired. We are just detecting the first occurrence. Be careful you don't slow down your app by putting code in the event that unnecessarily runs every time.
var gr = document.getElementById("greenOne");
var bl = document.getElementById("blueOneCopy");
gr.onmouseenter = bringToFront;
bl.onmouseenter = bringToFront;
function bringToFront(evt) {
let el = evt.target;
if (el.nextSibling != null) {
el.parentNode.appendChild(el);
console.log(el.id == 'greenOne' ? 1 : 2);
}
};
<html>
<head>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<svg height="500px" width="500px">
<defs>
<circle id="blueOne" cx="100" cy="100" r="50" style="fill: #0091EA"></circle>
</defs>
<use id="blueOneCopy" href="#blueOne"></use>
<circle id="greenOne" cx="150" cy="100" r="50" style="fill: #00C853"></circle>
</svg>
</body>
</html>

Export style with <svg> to .svg

I have an HTML file, that has a link to export all the <svg> inside to one .SVG. That's perfect, it's what I need and the community helped me a lot.
Now I have a problem that all the SVG inside the file, are clogged on top of each other.
I need them to keep the same 'display' they have on the webpage. I tried using internal, inline and external style... But nothing worked.
The X and Y I have in the <svg> is executed when I open the .SVG file in any program, but it doesn't affect anything on the HTML document.
I'm using the svg-converter.js to get all the .svg inside the <img> and convert to <svg>.
For some reason, inside that JS, something don't let me group all the <svg> inside another <svg>, only inside <div>. I have no idea if that is somehow causing the problem of the style not being exported.
Here is the working link.
Any help will be much appreciated.
Ps: I'd love to know why my question is downvoted.
You need to use x and y attributes to arrange your inner <svg> elements inside your root <svg> element.
Something like this (I've replaced the SVG contents with circles for brevity):
<svg xmlns="http://www.w3.org/3000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%" viewBox="0 0 1224 1224">
<svg x="0" y="0" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="#7AB344" cx="306" cy="306" r="250"/>
</svg>
<svg x="50%" y="0" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="#8DD4F0" cx="306" cy="306" r="250"/>
</svg>
<svg x="0" y="50%" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="orange" cx="306" cy="306" r="250"/>
</svg>
<svg x="50%" y="50%" width="50%" height="50%" viewBox="0 0 612 612">
<circle fill="rebeccapurple" cx="306" cy="306" r="250"/>
</svg>
</svg>
THIS IS THE FINAL WORKING CODE:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/3000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://brand.express/projects/teste/svg-converter.js"></script>
</head>
<body>
<main id="content">
<div id="mySVG" style="width:100%;padding:0;margin:0;">
<img src='img/leafers-sapling.svg' class='svg-convert' x="0" y="0" width="286px">
<img src='img/aqualine-sapling.svg' class='svg-convert' x="286px" y="0" width="286px">
<img src='img/leafers-sapling.svg' class='svg-convert' x="572px" y="0" width="286px">
<img src='img/aqualine-sapling.svg' class='svg-convert' x="858px" y="0" width="286px">
</div>
</main>
<script>
//transforma os .svg para <svg>
jQuery(document).ready(function($) {
$('.svg-convert').svgConvert({
onComplete: function() {
exportSVG(document.getElementById('mySVG'));
},
svgCleanupAttr: []
});
});
</script>
<script>
var exportSVG = function(divContainer) {
var svgContainer = document.createElementNS("http://www.w3.org/1999/xhtml", "svg");
svgContainer.setAttribute('width','1200px');
$('#mySVG').find("svg").clone().appendTo(svgContainer);
var svgData = svgContainer.outerHTML;
var a = document.createElement('a');
a.href = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);
a.download = 'finalSVG.svg';
a.innerHTML = 'download the .SVG file';
document.body.appendChild(a);
};
</script>
</body>
</html>

"ellipse" element created through JS doesn't appear in html

I'm new to svg. What i'm trying to do is to create an ellipse element with JS and append it to the SVG tag. The HTML code is
<svg width="640" height="480">
<ellipse cx="200" cy="100" rx="90" ry="60" stroke-width="10" stroke="orange" fill="none" opacity="0.6"/>
<ellipse cx="200" cy="100" rx="70" ry="40" stroke-width="10" stroke="green" fill="none" opacity="0.6"/>
</svg>
Below is the JS code
<script type="text/javascript">
var el=document.createElement('ellipse');
$(el).attr("cx",300);
$(el).attr("cy",200);
$(el).attr("stroke","red");
$(el).attr("stroke-width","10");
$(el).attr("fill","green");
$(el).attr("rx",120);
$(el).attr("ry",80);
$("svg").append(el);
</script>
But the ellipse didn't appear on the viewport ,but when i inspect HTML i found the ellipse element that i created is appended to SVG. what makes the difference when created this way & what is the correct approach to dynamically add elements to SVG
FYI see the image below
What you have is a custom HTML element instead of an SVG element. Use createElementNS to create the SVG element:
$(function(){
var el = document.createElementNS("http://www.w3.org/2000/svg", 'ellipse');
el.setAttribute('cx', 300);
el.setAttribute('cy', 200);
el.setAttribute('stroke', "red");
el.setAttribute('stroke-width', 10);
el.setAttribute('fill', "green");
el.setAttribute('rx', 120);
el.setAttribute('ry', 80);
$("svg").append(el);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<svg width="640" height="480">
<ellipse cx="200" cy="100" rx="90" ry="60" stroke-width="10" stroke="orange" fill="none" opacity="0.6"/>
<ellipse cx="200" cy="100" rx="70" ry="40" stroke-width="10" stroke="green" fill="none" opacity="0.6"/>
</svg>

Categories

Resources