Question

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);  
};
Was it helpful?

Solution

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.

OTHER TIPS

@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>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top