How can I animated multiple svg paths? - javascript

How can I animate multiple paths at the same time using an svg and javascript.
Here is the javascript I am using:
var path = document.querySelector('#Layer_1 path');
var length = path.getTotalLength();
// Clear any previous transition
path.style.transition = path.style.WebkitTransition = 'none';
// Set up the starting positions
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
// Trigger a layout so styles are calculated & the browser
// picks up the starting position before animating
path.getBoundingClientRect();
// Define our transition
path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset 2s ease-in-out';
// Go!
path.style.strokeDashoffset = '0';
Link to jsfiddle

The problem is that you are only getting one path with document.querySelector()
So if we change that to document.querySelectorAll() and iterate over it for all paths it works.
Like this:
var paths = document.querySelectorAll('#Layer_1 path');
[].forEach.call(paths, function(path) {
var length = path.getTotalLength();
// Clear any previous transition
path.style.transition = path.style.WebkitTransition =
'none';
// Set up the starting positions
path.style.strokeDasharray = length + ' ' + length;
path.style.strokeDashoffset = length;
// Trigger a layout so styles are calculated & the browser
// picks up the starting position before animating
path.getBoundingClientRect();
// Define our transition
path.style.transition = path.style.WebkitTransition =
'stroke-dashoffset 2s ease-in-out';
// Go!
path.style.strokeDashoffset = '0';
})
<body>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="196.039px" height="185.064px" viewBox="0 0 196.039 185.064" enable-background="new 0 0 196.039 185.064" xml:space="preserve">
<g>
<g>
<path fill="none" stroke="#651D79" stroke-width="3.7953" stroke-miterlimit="10" d="M91.93,59.704
c3.347-5.793,3.347-15.27,0-21.063l-16.5-28.594c-3.347-5.79-10.823-7.791-16.616-4.448l-16.493,9.525
c-5.789,3.347-7.791,10.815-4.447,16.615l16.504,28.576c3.343,5.79,0.604,10.534-6.078,10.534H15.298
c-6.69,0-12.161,5.478-12.161,12.157v19.043c0,6.69,5.471,12.164,12.161,12.164h33.004c6.687,0,14.896-4.744,18.239-10.533
L91.93,59.704z" />
</g>
<g>
<g>
<path fill="none" stroke="#651D79" stroke-width="3.7953" stroke-miterlimit="10" d="M72.631,114.213
c-6.69,0-14.899,4.737-18.247,10.526l-16.508,28.594c-3.343,5.793-1.342,13.269,4.455,16.616l16.486,9.514
c5.796,3.347,13.269,1.345,16.615-4.448l16.5-28.583c3.347-5.8,8.817-5.8,12.165,0l16.497,28.576
c3.343,5.789,10.822,7.791,16.612,4.448l16.489-9.518c5.793-3.343,7.798-10.822,4.451-16.612l-16.5-28.576
c-3.347-5.8-11.556-10.537-18.239-10.537H72.631z" />
</g>
<g>
<path fill="none" stroke="#651D79" stroke-width="3.7953" stroke-miterlimit="10" d="M129.479,103.68
c3.347,5.789,11.556,10.526,18.246,10.526h33.012c6.69,0,12.164-5.467,12.164-12.157V83.006
c-0.007-6.69-5.478-12.164-12.168-12.164l-33.005,0.007c-6.686,0-9.421-4.744-6.078-10.534l16.497-28.576
c3.347-5.8,1.346-13.269-4.451-16.615l-16.489-9.525c-5.79-3.343-13.269-1.334-16.608,4.459l-16.5,28.576
c-3.347,5.789-3.347,15.27,0,21.07L129.479,103.68z" />
</g>
</g>
</g>
</svg>
</body>

You can loop over all paths
var paths = document.querySelectorAll('#Layer_1 path');
for (i = 0; i < paths.length; i++) {
var length = paths[i].getTotalLength();
// Clear any previous transition
paths[i].style.transition = paths[i].style.WebkitTransition ='none';
// Set up the starting positions
paths[i].style.strokeDasharray = length + ' ' + length;
paths[i].style.strokeDashoffset = length;
// Trigger a layout so styles are calculated & the browser
// picks up the starting position before animating
paths[i].getBoundingClientRect();
// Define our transition
paths[i].style.transition = paths[i].style.WebkitTransition = 'stroke-dashoffset 3s ease-in-out';
// Go!
paths[i].style.strokeDashoffset = '0';
}
JSFiddle
Notice: You can try also Vivus library, is light and easy to maintain

Related

How do i set position of scroll trigger on SVG?

I have a SVG line that triggers on scroll and goes down the page as i scroll. I want the trigger to be at a specific location on the page, but for now, even though the SVG is located further down the page, it starts "growing" as soon as the user starts scrolling (which result in no animation when i arrive at that location, since the SVG is already all scrolled out).
Here's the js of that particular SVG:
var path = document.querySelector('#star-path');
var pathLength = path.getTotalLength();
path.style.strokeDasharray = pathLength + ' ' + pathLength;
path.style.strokeDashoffset = pathLength;
window.addEventListener('scroll', () => {
var scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
var drawLength = pathLength * scrollPercentage;
path.style.strokeDashoffset = pathLength - drawLength;
});
And here is the html snippet...
<svg class="svg" width="10" viewBox="0 0 2 150" id="star-svg">
<path id="star-path" fill="none" stroke="black" stroke-width="2" d="M1 0V150" />
</svg>
... as well as the css:
.svg {
position: absolute;
top: 2900px;
left: 1400px;
text-align: center;
overflow: visible;
}
Which element corresponds to that trigger, and what should i do to "delay" it (i am quite new at SVG animations)?
Thanks in advance for your help

My svg draw on scroll from middle, I want to start from top

<svg id="route "xmlns="http://www.w3.org/2000/svg" version="1.1" width="712px" height="2018px" viewBox="0 0 712 2018" class="hidden-xs hidden-sm">
<path id="triangle" fill="none" stroke="red" stroke-width="5" d="M-3.215,2030.921
c8.816-23.698,1.293-50.813,11.855-74.949c13.239-30.25,36.07-52.368,63.675-68.83c39.115-23.327,200.048-39.239,241.599-39.239 c85.812,0,169.935-1.5,251.667-17.933c74.616-15.001,99.381-62.185,103.271-132.082c7.2-129.404-162.375-182.709-261.459-210.021 c-66.561-18.348-117.888-37.01-175.849-77.998c-40.217-28.439-112.694-81.217-96.218-141.023
c35.773-129.859,256.615-74.554,349.684-99.021c67.062-17.629,147.101-35.616,189.606-92.854
c45.659-61.482,39.673-120.866-5.028-180.841c-37.314-50.064-126.141-67.693-184.915-80.39
c-90.278-19.498-192.558-10.397-279.444-44.865c-74.021-29.363-167.793-73.691-193.513-156.378
c-17.428-56.03-20.716-143.802,36.015-181.982c58.886-39.631,148.526-40.825,216.305-49.425
c71.297-9.047,146.186-9.725,215.652-23.335c74.498-14.597,140.473-30.115,189.976-93.165
c32.844-41.83,53.193-89.854,24.771-156.016C641.086-13.609,557.179,7.892,440.83,7.892"/>
</svg>
Above is my SVG code its simple curve line path.
And my javascript code I want to run, but it draws from middle:
var triangle = document.getElementById("triangle");
var length = triangle.getTotalLength();
triangle.style.strokeDasharray = length;
triangle.style.strokeDashoffset = length;
window.addEventListener("scroll", myFunction);
function myFunction() {
var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
var draw = length * scrollpercent;
triangle.style.strokeDashoffset = length - draw;
}
In order to make it begin at the top I've reversed the path. I hope this is what you need.
var triangle = document.getElementById("triangle");
var length = triangle.getTotalLength();
triangle.style.strokeDasharray = length;
triangle.style.strokeDashoffset = length;
window.addEventListener("scroll", myFunction);
function myFunction(e) {
var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);
var draw = length * scrollpercent;
triangle.style.strokeDashoffset = length - draw;
}
<svg id="route "xmlns="http://www.w3.org/2000/svg" version="1.1" width="712px" height="2018px" viewBox="0 0 712 2018" class="hidden-xs hidden-sm">
<path id="triangle" fill="none" stroke="red" stroke-width="5" d="M440.83,7.892C557.179,7.892 641.086,-13.609 694.435,110.574C722.857,176.736 702.508,224.76 669.664,266.59C620.161,329.64 554.186,345.158 479.688,359.755C410.222,373.365 335.333,374.043 264.036,383.09C196.257,391.69 106.617,392.884 47.731,432.515C-9,470.695 -5.712,558.467 11.716,614.497C37.436,697.184 131.208,741.512 205.229,770.875C292.115,805.343 394.395,796.242 484.673,815.74C543.447,828.437 632.274,846.066 669.588,896.13C714.289,956.105 720.275,1015.489 674.616,1076.971C632.111,1134.209 552.072,1152.196 485.01,1169.825C391.941,1194.292 171.09,1138.987 135.326,1268.846C118.85,1328.652 191.327,1381.43 231.544,1409.869C289.505,1450.857 340.832,1469.519 407.393,1487.867C506.477,1515.179 676.052,1568.484 668.852,1697.888C664.962,1767.785 640.197,1814.969 565.581,1829.97C483.849,1846.403 399.726,1847.903 313.914,1847.903C272.363,1847.903 111.43,1863.815 72.315,1887.142C44.71,1903.604 21.879,1925.722 8.64,1955.972C-1.922,1980.108 5.601,2007.223 -3.215,2030.921"/>
</svg>

Call JavaScript function from SVG file

I have a SVG file and a JavaScript file.
In my SVG file I have some code, but it is this small amount of code I'm wondering about:
<g id="zoomButton">
<g onclick="zoom()" transform="scale(x,y)">
<rect x="640" y="20" width="140" height="40"
style="fill:white;stroke:red;stroke-width:2" />
<text x="710" y="49"
style="fill:red;font-size:25px;text-anchor:middle">Zoom</text>
</g>
</g>
You see that I want the function zoom() to be called when this button is clicked.
Now, in my JavaScript file, I have this function called zoom():
function zoom() {
alert("heyho");
}
However, this function is not triggered when I press the button created in the SVG file. I only get the error message:
Uncaught ReferenceError: zoom is not defined
I just want to be able to make that JavaScript function to be called when I press this button.
Furthermore, since this is a zoom-function after all and I want to do some scaling, how do I access the x and y inside transform="scale(x,y) in the zoomButton in the SVG file from the JavaScript file?
Edit:
The full code in the SVG file is as follows (game.svg):
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="600px"
xmlns="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:a="http://www.adobe.com/svg10-extensions" a:timeline="independent"
onload="top.load(evt)">
<defs>
<clipPath id="gameareaclip">
<rect x="20" y="20" width="600" height="560"/>
</clipPath>
<pattern id="background_pattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<rect width="20" height="20" style="fill:purple"/>
<circle cx="10" cy="10" r="8" style="fill:black"/>
</pattern>
<radialGradient id="player_color">
<stop offset="0.0" style="stop-color:yellow;stop-opacity:1"/>
<stop offset="0.8" style="stop-color:yellow;stop-opacity:1"/>
<stop offset="1.0" style="stop-color:orange;stop-opacity:1"/>
</radialGradient>
</defs>
<rect width="100%" height="100%" style="fill:url(#background_pattern);stroke:orange;stroke-width:4" />
<rect x="20" y="20" width="600" height="560" style="fill:black;stroke:red;stroke-width:5" />
<!-- Add your button here -->
<g id="zoomKnapp">
<g onclick="zoom()" transform="scale(x,y)">
<rect x="640" y="20" width="140" height="40"
style="fill:white;stroke:red;stroke-width:2" />
<text x="710" y="49"
style="fill:red;font-size:25px;text-anchor:middle">Zoom</text>
</g>
</g>
<g style="clip-path:url(#gameareaclip)">
<g transform="translate(20,20)">
<g id="gamearea" transform="translate(0,0)" width="600" height="560">
<rect x="0" y="0" width="600" height="560" style="fill:lightgrey" />
<g id="platforms">
<!-- Add your platforms here -->
<rect id="svg_37" height="20" width="300" y="100" x="0" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
<rect id="svg_38" height="20" width="300" y="170" x="300" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
<rect id="svg_39" height="20" width="300" y="240" x="0" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
<rect id="svg_40" height="20" width="300" y="310" x="300" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
<rect id="svg_41" height="20" width="300" y="380" x="0" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
<rect id="svg_42" height="20" width="300" y="450" x="300" stroke-linecap="null" stroke-linejoin="null" stroke-width="0" stroke="#000000" fill="#5fbf00"/>
</g>
<g id="player">
<circle cx="20" cy="20" r="20" style="fill:url(#player_color);stroke:black;stroke-width:2"/>
<ellipse cx="15" cy="15" rx="3" ry="6" style="fill:black"/>
<ellipse cx="25" cy="15" rx="3" ry="6" style="fill:black"/>
<path d="M10,25 l20,0 q0,8 -10,8 t-10,-8" style="fill:orange;stroke:black;stroke-black:2"/>
</g>
</g>
</g>
</g>
</svg>
The HTML file (game.html):
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SVG Game</title>
<script language="JavaScript" src="game.js"></script>
</head>
<body style="text-align: center">
<embed src="game.svg" type="image/svg+xml" width="800" height="600" />
</body>
</html>
The JavaScript (game.js) code:
// The point and size class used in this program
function Point(x, y) {
this.x = (x)? parseFloat(x) : 0.0;
this.y = (y)? parseFloat(y) : 0.0;
}
function Size(w, h) {
this.w = (w)? parseFloat(w) : 0.0;
this.h = (h)? parseFloat(h) : 0.0;
}
// Helper function for checking intersection between two rectangles
function intersect(pos1, size1, pos2, size2) {
return (pos1.x < pos2.x + size2.w && pos1.x + size1.w > pos2.x &&
pos1.y < pos2.y + size2.h && pos1.y + size1.h > pos2.y);
}
function zoom() {
alert("heiho");
}
// The player class used in this program
function Player() {
this.node = svgdoc.getElementById("player");
this.position = PLAYER_INIT_POS;
this.motion = motionType.NONE;
this.verticalSpeed = 0;
}
Player.prototype.isOnPlatform = function() {
var platforms = svgdoc.getElementById("platforms");
for (var i = 0; i < platforms.childNodes.length; i++) {
var node = platforms.childNodes.item(i);
if (node.nodeName != "rect") continue;
var x = parseFloat(node.getAttribute("x"));
var y = parseFloat(node.getAttribute("y"));
var w = parseFloat(node.getAttribute("width"));
var h = parseFloat(node.getAttribute("height"));
if (((this.position.x + PLAYER_SIZE.w > x && this.position.x < x + w) ||
((this.position.x + PLAYER_SIZE.w) == x && this.motion == motionType.RIGHT) ||
(this.position.x == (x + w) && this.motion == motionType.LEFT)) &&
this.position.y + PLAYER_SIZE.h == y) return true;
}
if (this.position.y + PLAYER_SIZE.h == SCREEN_SIZE.h) return true;
return false;
}
Player.prototype.collidePlatform = function(position) {
var platforms = svgdoc.getElementById("platforms");
for (var i = 0; i < platforms.childNodes.length; i++) {
var node = platforms.childNodes.item(i);
if (node.nodeName != "rect") continue;
var x = parseFloat(node.getAttribute("x"));
var y = parseFloat(node.getAttribute("y"));
var w = parseFloat(node.getAttribute("width"));
var h = parseFloat(node.getAttribute("height"));
var pos = new Point(x, y);
var size = new Size(w, h);
if (intersect(position, PLAYER_SIZE, pos, size)) {
position.x = this.position.x;
if (intersect(position, PLAYER_SIZE, pos, size)) {
if (this.position.y >= y + h)
position.y = y + h;
else
position.y = y - PLAYER_SIZE.h;
this.verticalSpeed = 0;
}
}
}
}
Player.prototype.collideScreen = function(position) {
if (position.x < 0) position.x = 0;
if (position.x + PLAYER_SIZE.w > SCREEN_SIZE.w) position.x = SCREEN_SIZE.w - PLAYER_SIZE.w;
if (position.y < 0) {
position.y = 0;
this.verticalSpeed = 0;
}
if (position.y + PLAYER_SIZE.h > SCREEN_SIZE.h) {
position.y = SCREEN_SIZE.h - PLAYER_SIZE.h;
this.verticalSpeed = 0;
}
}
//
// Below are constants used in the game
//
var PLAYER_SIZE = new Size(40, 40); // The size of the player
var SCREEN_SIZE = new Size(600, 560); // The size of the game screen
var PLAYER_INIT_POS = new Point(0, 0); // The initial position of the player
var MOVE_DISPLACEMENT = 5; // The speed of the player in motion
var JUMP_SPEED = 15; // The speed of the player jumping
var VERTICAL_DISPLACEMENT = 1; // The displacement of vertical speed
var GAME_INTERVAL = 25; // The time interval of running the game
//
// Variables in the game
//
var motionType = {NONE:0, LEFT:1, RIGHT:2}; // Motion enum
var svgdoc = null; // SVG root document node
var player = null; // The player object
var gameInterval = null; // The interval
var zoom = 1.0; // The zoom level of the screen
//
// The load function for the SVG document
//
function load(evt) {
// Set the root node to the global variable
svgdoc = evt.target.ownerDocument;
// Attach keyboard events
svgdoc.documentElement.addEventListener("keydown", keydown, false);
svgdoc.documentElement.addEventListener("keyup", keyup, false);
// Remove text nodes in the 'platforms' group
cleanUpGroup("platforms", true);
// Create the player
player = new Player();
// Start the game interval
gameInterval = setInterval("gamePlay()", GAME_INTERVAL);
}
//
// This function removes all/certain nodes under a group
//
function cleanUpGroup(id, textOnly) {
var node, next;
var group = svgdoc.getElementById(id);
node = group.firstChild;
while (node != null) {
next = node.nextSibling;
if (!textOnly || node.nodeType == 3) // A text node
group.removeChild(node);
node = next;
}
}
//
// This is the keydown handling function for the SVG document
//
function keydown(evt) {
var keyCode = (evt.keyCode)? evt.keyCode : evt.getKeyCode();
switch (keyCode) {
case "N".charCodeAt(0):
player.motion = motionType.LEFT;
break;
case "M".charCodeAt(0):
player.motion = motionType.RIGHT;
break;
// Add your code here
case "Z".charCodeAt(0):
if (player.isOnPlatform()) {
//Jump
player.verticalSpeed = JUMP_SPEED;
}
break;
}
}
//
// This is the keyup handling function for the SVG document
//
function keyup(evt) {
// Get the key code
var keyCode = (evt.keyCode)? evt.keyCode : evt.getKeyCode();
switch (keyCode) {
case "N".charCodeAt(0):
if (player.motion == motionType.LEFT) player.motion = motionType.NONE;
break;
case "M".charCodeAt(0):
if (player.motion == motionType.RIGHT) player.motion = motionType.NONE;
break;
}
}
//
// This function updates the position and motion of the player in the system
//
function gamePlay() {
// Check whether the player is on a platform
var isOnPlatform = player.isOnPlatform();
// Update player position
var displacement = new Point();
// Move left or right
if (player.motion == motionType.LEFT)
displacement.x = -MOVE_DISPLACEMENT;
if (player.motion == motionType.RIGHT)
displacement.x = MOVE_DISPLACEMENT;
// Fall
if (!isOnPlatform && player.verticalSpeed <= 0) {
displacement.y = -player.verticalSpeed;
player.verticalSpeed -= VERTICAL_DISPLACEMENT;
}
// Jump
if (player.verticalSpeed > 0) {
displacement.y = -player.verticalSpeed;
player.verticalSpeed -= VERTICAL_DISPLACEMENT;
if (player.verticalSpeed <= 0)
player.verticalSpeed = 0;
}
// Get the new position of the player
var position = new Point();
position.x = player.position.x + displacement.x;
position.y = player.position.y + displacement.y;
// Check collision with platforms and screen
player.collidePlatform(position);
player.collideScreen(position);
// Set the location back to the player object (before update the screen)
player.position = position;
updateScreen();
}
//
// This function updates the position of the player's SVG object and
// set the appropriate translation of the game screen relative to the
// the position of the player
//
function updateScreen() {
// Transform the player
player.node.setAttribute("transform", "translate(" + player.position.x + "," + player.position.y + ")");
// Calculate the scaling and translation factors
// Add your code here
}
The script tag needs to go in the SVG file (game.svg) and not in the html file. Note that SVG script tags use xlink:href instead of src as the attribute that holds the script source.
<script xlink:href="game.js"></script>
You should also change onload="top.load(evt)" to just onload="load(evt)" in the root <svg> element.
And your third and main issue is that you have a function zoom() and a variable called zoom on line 114. Remove the variable as it isnt used and the zoom method will get called.

Dragging SVG element over another SVG element

Is there any way i can drag an SVG element over another SVG element? I tried but like in this tutorial i can only drag the one i placed the second over the first one. There is no way i can drag first one over the second without problems.
Does anyone know how to solve this?
Here is the whole tutorial: http://www.petercollingridge.co.uk/book/export/html/437
I was writing it before I saw that #Strat-O gave you the same approach.
So here is a commented example of that :
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="200">
<style>
.draggable {
cursor: move;
}
</style>
<script type="text/ecmascript"><![CDATA[
var selectedElement = 0;
var currentX = 0;
var currentY = 0;
var currentMatrix = 0;
function cloneToTop(oldEl){
// already at top, don't go farther…
if(oldEl.atTop==true) return oldEl;
// make a copy of this node
var el = oldEl.cloneNode(true);
// select all draggable elements, none of them are at top anymore
var dragEls= oldEl.ownerDocument.documentElement.querySelectorAll('.draggable');
for(i=0; i<dragEls.length; i++){
dragEls[i].atTop=null;
}
var parent = oldEl.parentNode;
// remove the original node
parent.removeChild(oldEl);
// insert our new node at top (last element drawn is first visible in svg)
parent.appendChild(el);
// Tell the world that our new element is at Top
el.atTop= true;
return el;
}
function selectElement(evt) {
selectedElement = cloneToTop(evt.target);
currentX = evt.clientX;
currentY = evt.clientY;
currentMatrix = selectedElement.getAttributeNS(null, "transform").slice(7,-1).split(' ');
for(var i=0; i<currentMatrix.length; i++) {
currentMatrix[i] = parseFloat(currentMatrix[i]);
}
selectedElement.setAttributeNS(null, "onmousemove", "moveElement(evt)");
selectedElement.setAttributeNS(null, "onmouseout", "deselectElement(evt)");
selectedElement.setAttributeNS(null, "onmouseup", "deselectElement(evt)");
}
function moveElement(evt) {
var dx = evt.clientX - currentX;
var dy = evt.clientY - currentY;
currentMatrix[4] += dx;
currentMatrix[5] += dy;
selectedElement.setAttributeNS(null, "transform", "matrix(" + currentMatrix.join(' ') + ")");
currentX = evt.clientX;
currentY = evt.clientY;
}
function deselectElement(evt) {
if(selectedElement != 0){
selectedElement.removeAttributeNS(null, "onmousemove");
selectedElement.removeAttributeNS(null, "onmouseout");
selectedElement.removeAttributeNS(null, "onmouseup");
selectedElement = 0;
}
}
]]> </script>
<g>
<circle/>
</g>
<rect x="0.5" y="0.5" width="399" height="199" fill="none" stroke="black"/>
<rect class="draggable" id="blue" x="30" y="30" width="80" height="80" fill="blue" transform="matrix(1 0 0 1 46 18)" onmousedown="selectElement(evt)"/>
<rect class="draggable" id="green" x="160" y="50" width="50" height="50" fill="green" transform="matrix(1 0 0 1 51 11)" onmousedown="selectElement(evt)"/>
</svg>
Unfortunately, there is only one way to make an element appear in front of another element in SVG and that is to remove the lower element then turn around and redraw it. There is no z-index or other helpful attribute that you can set. I spent a bit of time on this and that is my conclusion.
There is one upside and that is by removing and redrawing it, it ensures that the display order of all of the elements is maintained whereas if you have to maintain z-indexes, managing the numbers can cause its own set of issues.

Get width/height of SVG element

What is the proper way to get the dimensions of an svg element?
http://jsfiddle.net/langdonx/Xkv3X/
Chrome 28:
style x
client 300x100
offset 300x100
IE 10:
stylex
client300x100
offsetundefinedxundefined
FireFox 23:
"style" "x"
"client" "0x0"
"offset" "undefinedxundefined"
There are width and height properties on svg1, but .width.baseVal.value is only set if I set the width and height attributes on the element.
The fiddle looks like this:
HTML
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="1" fill="red" />
<circle cx="150" cy="50" r="40" stroke="black" stroke-width="1" fill="green" />
<circle cx="250" cy="50" r="40" stroke="black" stroke-width="1" fill="blue" />
</svg>
JS
var svg1 = document.getElementById('svg1');
console.log(svg1);
console.log('style', svg1.style.width + 'x' + svg1.style.height);
console.log('client', svg1.clientWidth + 'x' + svg1.clientHeight);
console.log('offset', svg1.offsetWidth + 'x' + svg1.offsetHeight);
CSS
#svg1 {
width: 300px;
height: 100px;
}
Use the getBBox function:
The SVGGraphicsElement.getBBox() method allows us to determine the coordinates of the smallest rectangle in which the object fits. [...]
http://jsfiddle.net/Xkv3X/1/
var bBox = svg1.getBBox();
console.log('XxY', bBox.x + 'x' + bBox.y);
console.log('size', bBox.width + 'x' + bBox.height);
FireFox have problemes for getBBox(), i need to do this in vanillaJS.
I've a better Way and is the same result as real svg.getBBox() function !
With this good post : Get the real size of a SVG/G element
var el = document.getElementById("yourElement"); // or other selector like querySelector()
var rect = el.getBoundingClientRect(); // get the bounding rectangle
console.log( rect.width );
console.log( rect.height);
I'm using Firefox, and my working solution is very close to obysky. The only difference is that the method you call in an svg element will return multiple rects and you need to select the first one.
var chart = document.getElementsByClassName("chart")[0];
var width = chart.getClientRects()[0].width;
var height = chart.getClientRects()[0].height;
SVG has properties width and height. They return an object SVGAnimatedLength with two properties: animVal and baseVal. This interface is used for animation, where baseVal is the value before animation. From what I can see, this method returns consistent values in both Chrome and Firefox, so I think it can also be used to get calculated size of SVG.
This is the consistent cross-browser way I found:
var heightComponents = ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth'],
widthComponents = ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'];
var svgCalculateSize = function (el) {
var gCS = window.getComputedStyle(el), // using gCS because IE8- has no support for svg anyway
bounds = {
width: 0,
height: 0
};
heightComponents.forEach(function (css) {
bounds.height += parseFloat(gCS[css]);
});
widthComponents.forEach(function (css) {
bounds.width += parseFloat(gCS[css]);
});
return bounds;
};
From Firefox 33 onwards you can call getBoundingClientRect() and it will work normally, i.e. in the question above it will return 300 x 100.
Firefox 33 will be released on 14th October 2014 but the fix is already in Firefox nightlies if you want to try it out.
Use .getAttribute()!
var height = document.getElementById('rect').getAttribute("height");
var width = document.getElementById('rect').getAttribute("width");
var x = document.getElementById('rect').getAttribute("x");
alert("height: " + height + ", width: " + width + ", x: " + x);
<svg width="500" height="500">
<rect width="300" height="100" x="50" y="50" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" id="rect"/>
</svg>
A save method to determine the width and height unit of any element (no padding, no margin) is the following:
let div = document.querySelector("div");
let style = getComputedStyle(div);
let width = parseFloat(style.width.replace("px", ""));
let height = parseFloat(style.height.replace("px", ""));

Categories

Resources