Jump to content
Search Community

Animating SVG Polygon Points using attrPlugin

John Blazek test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

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
Link to comment
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 6
Link to comment
Share on other sites

  • 1 year later...
  • 2 months later...

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
Link to comment
Share on other sites

  • 7 months later...

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
Link to comment
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
Link to comment
Share on other sites

  • 1 year later...
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 :

?????

 

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...