Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
John Blazek

Animating SVG Polygon Points using attrPlugin

Recommended Posts

Hey all,

 

Got a bit of a quandary going here.

 

So what I'd like to be able to do is to move the points of a polygon contained within a mask a variable amount (in this demo, 400 pts).

 

A pen can be found here: (FF only) codepen.io/johnblazek/pen/CqEpd

 

I'm using the attrPlugin, and adjusting the x/y coordinates within the point, but I'm getting no luck. 

 

Could the fact I'm using this as a mask be messin me up?

  • Like 1

Share this post


Link to post
Share on other sites

It's actually not animating anything on that SVG, either fill, stroke, or x/y.

 

Not exactly sure why but in general GSAP doesn't have much problem with path attributes.

Share this post


Link to post
Share on other sites

It looks like the problem is that your value that you're tweening is not a number - it's a bunch of numbers (a comma-delimited list of them). The AttrPlugin can handle animating a number like:

yourAttribute="1"

But you've got:

yourAttribute="949.5,553.1 -5.1,-401.4 1.4,-145.6 961.6,814.6 1923.3,-147 1924.3,-404"

So you're expecting the tweening engine to see that long string and know how to split it apart into individual values and then match them up with the corresponding values in another complex value and then tween them. Nope, sorry, no dice. 

 

You can certainly accomplish what you're after using an onUpdate and a generic object or build your own plugin. For example:

var values = {s1:949.5, m1:-5.1, e1:-401.4, s2:1.4, ...};
TweenLite.to(values, 1, {s1:200, m1:10, e1:-300, s2:6.2, ..., onUpdate:applyValues});
function applyValues() {
    yourElement.setAttribute("points", values.s1 + " " + values.m1 + " " + values.e1 + ", " + s2...);
}
  • Like 5

Share this post


Link to post
Share on other sites

Hi Vanillabass,

 

The good news is that TweenLite and AttrPlugin can now tween complex strings that contain a bunch of numbers.

Please read http://greensock.com/gsap-1-18-0 (Section:  Tween complex string-based values)

 

So to move all the points on a <polyline> you can just do:

TweenMax.to("#hi", 1, {attr:{points:"159.5,400 213.8,209 302. ... "}, repeat:10, yoyo:true})

http://codepen.io/GreenSock/pen/gPGOxL?editors=001

 

Note this path morphing only works if the start path and end path data have the same number of points. 

 

For the most robust SVG morphing imaginable, please see our MorpshSVGPlugin: http://greensock.com/morphSVG

  • Like 6

Share this post


Link to post
Share on other sites

Hello all, I am new here : ), 
 
@carl Is it possible to do TweenMax.to("#hi", 1, {attr:{points:"159.5,400 213.8,209 302. ... "}})

and staggering the animation of the points?

Thank you 

Share this post


Link to post
Share on other sites

Hi francolsromain,

 

Welcome to the GreenSock forums.

 

Yes you could stagger the animation of the points but it isn't something that will happen automatically. You will have to animate your own point objects with x and y properties and then apply those values to your path when the tweens update. Using the cycle feature of staggerTo() it could look something like this:

 

var points= [
  {x:0, y:200, endX:100, endY:50},
  {x:200, y:200, endX:400, endY:0},
  {x:500, y:200, endX:600, endY:100}
]


var tl = new TimelineMax({onUpdate:updateLine})
tl.staggerTo(points, 1, {cycle:{
  x:function(index){
    return points[index].endX;
  },
  y:function(index){
    return points[index].endY;
  }
}}, 1)


function updateLine() {
  TweenLite.set("#hi", {attr:{points:points[0].x + ", " + points[0].y + " " + points[1].x + ", " + points[1].y + " " + points[2].x + ", " + points[2].y}}); 
}

http://codepen.io/GreenSock/pen/rrVEEx?editors=0011

 

There is definitely a more dynamic way to code it where you might have a start path and end path and you can loop through the values to create your points Array, but that would take me awhile. This is more of a brute-force approach.

 

Read more about stagger and cycle here: http://greensock.com/docs/#/HTML5/GSAP/TimelineLite/staggerTo/

  • Like 1

Share this post


Link to post
Share on other sites

I got curious about this and enjoyed the challenge of making it into a single function that'll handle any number of points for you, so you can just feed in the string you want, the stagger, duration, etc. and it'll automate everything and spit back a TimelineLite instance containing all the animation :)

 

Here's a forked version of Carl's: http://codepen.io/GreenSock/pen/fbb9dd44bf1c98a9842a6c05d6c1be2b?editors=0010

//this one function call does it all:
staggerPoints("#hi", 2, {points:"100,-50 400,0 600,100"}, 0.5);

//the work is done in this one function that spits back a TimelineLite.
function staggerPoints(selector, duration, vars, stagger, onCompleteAll) {
  var numbersExp = /(?:(-)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
      element = document.querySelector(selector),
      startPoints = element.getAttribute("points").match(numbersExp),
      endPoints = vars.points.match(numbersExp),
      applyPoints = function() {
        element.setAttribute("points", startPoints.join(","));
      },
      copy = function(obj) {
        var o = {}, p;
        for (p in obj) {
          if (p !== "points") {
            o[p] = obj[p];
          }
        }
        return o;
      },
      tl = new TimelineLite({onUpdate:applyPoints, onComplete:onCompleteAll}),
      l = startPoints.length,
      obj, i;
  if (l !== endPoints.length) {
    console.log("Error: point quantities don't match");
  }
  for (i = 0; i < l; i+=2) {
    obj = copy(vars);
    obj[i] = parseFloat(endPoints[i]); //note: we need to make sure the values are converted from strings to numbers.
    obj[i+1] = parseFloat(endPoints[i+1]);
    startPoints[i] = parseFloat(startPoints[i]);
    startPoints[i+1] = parseFloat(startPoints[i+1]);
    tl.to(startPoints, duration, obj, stagger * i);
  }
  return tl;
}

Play around with it and let us know if it works okay for you. 

  • Like 5

Share this post


Link to post
Share on other sites
On 9/9/2016 at 12:17 PM, GreenSock said:

I got curious about this and enjoyed the challenge of making it into a single function that'll handle any number of points for you, so you can just feed in the string you want, the stagger, duration, etc. and it'll automate everything and spit back a TimelineLite instance containing all the animation :)

 

Here's a forked version of Carl's: 

See the Pen fbb9dd44bf1c98a9842a6c05d6c1be2b?editors=0010 by GreenSock (@GreenSock) on CodePen


//this one function call does it all:
staggerPoints("#hi", 2, {points:"100,-50 400,0 600,100"}, 0.5);

//the work is done in this one function that spits back a TimelineLite.
function staggerPoints(selector, duration, vars, stagger, onCompleteAll) {
  var numbersExp = /(?-)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
      element = document.querySelector(selector),
      startPoints = element.getAttribute("points").match(numbersExp),
      endPoints = vars.points.match(numbersExp),
      applyPoints = function() {
        element.setAttribute("points", startPoints.join(","));
      },
      copy = function(obj) {
        var o = {}, p;
        for (p in obj) {
          if (p !== "points") {
            o[p] = obj[p];
          }
        }
        return o;
      },
      tl = new TimelineLite({onUpdate:applyPoints, onComplete:onCompleteAll}),
      l = startPoints.length,
      obj, i;
  if (l !== endPoints.length) {
    console.log("Error: point quantities don't match");
  }
  for (i = 0; i < l; i+=2) {
    obj = copy(vars);
    obj[i] = parseFloat(endPoints[i]); //note: we need to make sure the values are converted from strings to numbers.
    obj[i+1] = parseFloat(endPoints[i+1]);
    startPoints[i] = parseFloat(startPoints[i]);
    startPoints[i+1] = parseFloat(startPoints[i+1]);
    tl.to(startPoints, duration, obj, stagger * i);
  }
  return tl;
}

Play around with it and let us know if it works okay for you. 

 

This is many line code .

I want the code class to look like "anime.js"

pls answer me :

👇👇👇👇👇

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×