Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
kahnos

Update Bezier Points Dynamically

Recommended Posts

Hello,

I'm new to SVG animations and i'm very impressed with GSAP, it's fantastic.

Currently, i'm trying to get an SVG to follow the mouse pointer with the Bezier Plugin, in order to make it autorotate and add some reality to it's movement (it's going to be a humanoid shape flying and following the pointer). So far, i've managed to keep track of the mouse pointer every second, but have been unable to update the established Bezier path.

Should i create a new path every iteration or is there a way to add more points on update to the Bezier path?

Thank you.

See the Pen rJweJY by kahnos (@kahnos) on CodePen

Link to comment
Share on other sites

Are you wanting it to have a linear speed and the mouse just plots the points? So if you wiggle your mouse around really fast and crazy around the screen, it might take 10 seconds to arrive at where your mouse ended? Or do you want it to just kinda lag behind the mouse slightly? Help us understand exactly the type of animated effect you're going for. Do you need to be able to reverse() it at some point? Any particular reason you don't want to use tick-based physics? @OSUblake is probably right about that type of motion, but maybe we're misunderstanding your goal here. 

  • Like 2
Link to comment
Share on other sites

I believe you're correct actually, tick based physics in a canvas would work better. I'm going for the "just kinda lag behind the mouse slightly" with rotation so it looks like it's following it. No need to reverse it.

 

http://lamberta.github.io/html5-animation/examples/ch05/04-follow-mouse-1.html

 

That example comes close, although it goes crazy when it reaches the mouse.

 

Thank you for your time. If you've any recommendations, i'll gladly accept them, i'm quite new to both canvas and animation.

Link to comment
Share on other sites

It is doable with SVG but if you want to learn such interactive and physics based animation that book is best way to go.

 

The 'going crazy' can be fixed easily, it happens because arrow never reaches at it's center and it keeps calculating the angle and causes that crazy behavior.

 

See the Pen WMddqd?editors=0010 by Sahil89 (@Sahil89) on CodePen

 

  • Like 4
Link to comment
Share on other sites

Amazing!

 

Thank you, this taught me a lot.

 

I'll definitely check out the book as well.

Link to comment
Share on other sites

Nice work @Sahil

 

One problem though. Adding a viewBox to your <svg> element will throw all your calculations off. You actually don't need to calculate anything. You just need to get the local coordinates, much like @Dipscom was showing with offsetX/offsetY. But that doesn't work with SVG, so you have to do it manually. It's not hard to do, but remembering the syntax is.

 

Start out by creating a point using the createSVGPoint() method on any <svg> element.

 

var mouse = svg.createSVGPoint();

 

 

On events, just set the point to clientX and clientY. DO NOT adjust for the element's position by subtracting something like getBoundingClientRect from it.

 

function someEvent(event) {
  mouse.x = event.clientX;
  mouse.y = event.clientY;
}

 

 

To get the local coordinates for some svg element, run this code. It returns a new point, so don't worry about it changing the x and y values of the point you call matrixTransform on.

 

var localPoint = mouse.matrixTransform(someElement.getScreenCTM().inverse());

 

 

Rinse and repeat.

 

See the Pen RQxOxw by osublake (@osublake) on CodePen

 

 

  • Like 5
Link to comment
Share on other sites

Thanks Blake. Actually I was assuming that viewbox won't be used for this particular scenario but I also didn't know proper approach if viewbox is used. I remember some other thread where you used similar method to to calculate screen coordinates, at the time I didn't really understand what was going on in your demo. But it is actually really simple to understand.

 

I found this article that explains all the math behind it which was pretty easy to understand. What throws me off is the name of function  that takes CTM as argument and returns new coordinates. I didn't find any docs/articles that will explain it. If they had named it something like mapCoordinates, that would have made more sense to me. :D

  • Like 3
Link to comment
Share on other sites

There's usually a viewBox because people want the SVG to scale, but what I did will work without a viewBox.

 

17 hours ago, Sahil said:

I found this article that explains all the math behind it which was pretty easy to understand. What throws me off is the name of function  that takes CTM as argument and returns new coordinates. I didn't find any docs/articles that will explain it. If they had named it something like mapCoordinates, that would have made more sense to me. :D

 

 

A matrix transform is a common method in vector, canvas and WebGL libraries, so the name isn't too far out there. But you're right, there is not a lot of information out there.

 

I covered a lot about how SVG coordinates and the viewBox works in this thread.

 

 

 

You can see how a matrix works in this demo.

 

See the Pen RLPOyj by osublake (@osublake) on CodePen

 

 

Resize the screen and pay attention to the matrix values and the size and position of the gray box. When there is no rotation, this is how the values matrix values will map out.

 

matrix.a = scaleX;
matrix.b = 0; 
matrix.c = 0;
matrix.d = scaleY;
matrix.e = x;
matrix.f = y;

 

 

And this is how the matrixTransform method converts a point using a matrix.

 

var x = matrix.a * point.x + matrix.c * point.y + matrix.e;
var y = matrix.b * point.x + matrix.d * point.y + matrix.f;

 

 

If you want to get the bounding box of an element you could do this. The getBBox value will not change unless the element's geometry changes, or the element has children like a group <g> element. See this post - https://greensock.com/forums/topic/13681-svg-gotchas/?page=2&tab=comments#comment-72060

 

 

// This won't change the bbox value if it's not a <g> element
TweenLite.set(someElement, { scale: 0.5, x: 100, y: 200 });

var bounds = getBounds(someElement);

function getBounds(element, toElement) {
  
  var svg = element.ownerSVGElement;
  
  if (!svg) {
    return { x: 0, y: 0, width: 0, height: 0 };
  }
    
  var p = svg.createSVGPoint();
  var r = element.getBBox();     
      
  var matrix = (toElement || svg).getScreenCTM().inverse().multiply(element.getScreenCTM()); 

  p.x = r.x;
  p.y = r.y;
  var a = p.matrixTransform(matrix);

  p.x = r.x + r.width;
  p.y = r.y;
  var b = p.matrixTransform(matrix);

  p.x = r.x + r.width;
  p.y = r.y + r.height;
  var c = p.matrixTransform(matrix);

  p.x = r.x;
  p.y = r.y + r.height;
  var d = p.matrixTransform(matrix);

  var minX = Math.min(a.x, b.x, c.x, d.x);
  var maxX = Math.max(a.x, b.x, c.x, d.x);
  var minY = Math.min(a.y, b.y, c.y, d.y);
  var maxY = Math.max(a.y, b.y, c.y, d.y);
  
  return {
    x: minX,
    y: minY,
    width: maxX - minX,
    height: maxY - minY
  };
}

 

  • Like 3
  • Thanks 1
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.
×