Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select multiple paths with Snap.svg

Background: I'm using snap.svg to animate paths in an inline svg, and I'm trying to animate several paths in one function.

Problem: using the code below, I'm only able to select a single path in one grab function. In the code below, I've used multiple selectors, but the animation only affects rect#rect-one. How can I select multiple paths in Snap.svg?

Thanks for the help!

HTML/Inline SVG:

<a id="one">link</a>

<svg>
<rect  id="rect-one" fill="#231F20" width="39" height="14"/>
<rect id="rect-two" x="54" fill="#231F20" width="39" height="14"/>
<rect id="rect-three" x="104" fill="#231F20" width="39" height="14"/>
</svg>

Snap:

window.onload = function () {
    var grabLink = Snap.select('body a#one'),
        grabPathRectangles = Snap.select('#rect-one, #rect-two, #rect-three');

    function colorPathRectangles(){
        grabPathRectangles.animate({fill: 'red'}, 100, mina.ease);
    } 
    function resumePathRectangles(){
        grabPathRectangles.animate({fill: 'green'}, 100, mina.ease);
    }   
    grabLink.hover(colorPathRectangles, resumePathRectangles);  
};
like image 406
Marcatectura Avatar asked Oct 13 '25 03:10

Marcatectura


2 Answers

I think the problem is that you can't apply animations to a set (edit: possible now), so you would have to apply it to each element. For this you could use the forEach command, so...

 grabPathRectangles.forEach( function(elem,i) {
        elem.animate({fill: 'red'}, 1000, mina.ease);
  });

Jsfiddle here... http://jsfiddle.net/DZ4wZ/3/

Or I suspect you could put them into a group and animate the group as one if that makes more sense. Here is an example http://jsfiddle.net/DZ4wZ/5/ however, I had to remove the original fill.

Edit: Looks like you can apply animations to a set now, I think this feature didn't used to work, or was buggy, so not historically used. So you may want to make sure you have the latest version of Snap if using it.

like image 50
Ian Avatar answered Oct 14 '25 16:10

Ian


@Ian's answer is unfortunately incorrect, although his fiddle silently fixed the actual issue.

The problem is that you have used Snap.select instead of Snap.selectAll to query for multiple elements. Select will only ever bring back the first instance that satisfies the selector, whereas selectAll will grab all of them and return as a set or array of Element objects. That's why only a single element was responding to the animation.

Further, you definitely can call animate on a set of elements simultaneous, so there's no need to complicate things with an additional for loop.

From the docs on Set.animate():

Animates each element in set in sync.

Here's a working demo using Stack Snippets.

It starts by logging the different outputs of select and SelectAll

console.log("select:    ", Snap.select(   '#rect-1, #rect-2, #rect-3'));
console.log("selectAll: ", Snap.selectAll('#rect-1, #rect-2, #rect-3'));

var grabLink = Snap.select('#one'),
    grabPathRectangles = Snap.selectAll('#rect-1, #rect-2, #rect-3');

function colorPathRectangles(){
  grabPathRectangles.animate({fill: 'red'}, 1000, mina.ease);
} 
function resumePathRectangles(){
  grabPathRectangles.animate({fill: 'green'}, 1000, mina.ease);
}   

grabLink.hover(colorPathRectangles, resumePathRectangles);  
a#one {
  display: block;
  border: 1px solid blue;
  margin-bottom: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>

<a id="one">Hover Me</a>

<svg>
  <rect id="rect-1" fill="#231F20" width="39" height="14"/>
  <rect id="rect-2" fill="#231F20" width="39" height="14" x="54" />
  <rect id="rect-3" fill="#231F20" width="39" height="14" x="104" />
</svg>
like image 31
KyleMit Avatar answered Oct 14 '25 16:10

KyleMit