Jump to content
GreenSock

mickFli

Rotating Cubic Bezier Control Points and MorphSVG

Go to solution Solved by OSUblake,

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

Just to demonstrate how to rotate two cubic bezier control points from an existing SVG path, and then morph them, I copied the _createSVG goodness from the MorphSVG Plugin Banner Pen (

See the Pen WQjRXE by GreenSock (@GreenSock) on CodePen

), and used the points of the array in the cubic bezier generated from 

var bezier = MorphSVGPlugin.pathDataToRawBezier(pathData)[0];

to then rotate the first two control points along my path.  My rotate function is very simple, as I'm trying to get a handle on rotating control points, and hopefully this post can help someone else.  

function rotate(x, y, angle, bezierPathOrdinalPosition) {
  
  var _DEG2RAD = Math.PI / 180;
  
  angle = angle * _DEG2RAD;
  
  var sin = Math.sin(angle);
  var cos = Math.cos(angle);


  // Rotate by (angle) radians.
  //
  var dx = (x * cos) - (y * sin); 
  var dy = (x * sin) + (y * cos);
  
  return { "dx": dx, "dy": dy, "pos": bezierPathOrdinalPosition };

}

My question is; why are the points not rotated "upwards" and to the left, as in being rotated as if they were in the quadrant of the positive x and positive y axes of the 2d coordinate system?  I don't understand the rotation being applied, vs. the math I used.  Also, I'm not entirely sure which to which anchor (the black dots) these control points are related.

 

Help me, Obi Wan.  

 

-Dan

See the Pen ZbgKMW by dotComb (@dotComb) on CodePen

Link to comment
Share on other sites

What are you trying to do? What is rotating from what? Are the control points rotating from anchor points? And what are the anchor points rotating from, the previous anchor? I think you should draw lines to make sense of points. And I don't think your math is correct. You need to add the x/y coordinates that the points are rotating from... or are you doing that somewhere else?

var dx = someCenterX + (x * cos) - (y * sin); 
var dy = someCenterY + (x * sin) + (y * cos);
  • Like 5
Link to comment
Share on other sites

I see you updated your pen, but it looks like you still aren't doing the rotation correctly. Look at the line update method in this example.

 

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

Link to comment
Share on other sites

Okay, I finally figured out what the problem was.  To clarify, what I want to do is this: rotate the first two control points in the bezier, the ones with pink circles in the pen, counterclockwise 20 degrees using their anchor as a point of origin.  The point of origin is obviously important, and is initially (0,0) in the svg coordinate system.  That single fact threw me off.  

 

So, I basically had to translate the points according to their position relative to the anchor, and rotate using the anchor coordinates as the point of origin.  What I have now seems to work.  Maybe I'm still missing something? 

 

See the Pen ZbgKMW by dotComb (@dotComb) on CodePen

 

Thanks OSUblake for your help and guidance.  That pen is pretty sweet, (off - topic) although I don't normally work with Babel, I like how it implements properties, and how you leveraged the line's property setter to update it's position relative to r.  

 

-Dan

Link to comment
Share on other sites

It looks like you are rotating two control points from the same anchor. If those control points are part of the same segment, they should be rotating around different anchor points.

 

If you are trying to learn Bezier curves, here's a really good place to start. All the examples are interactive.

http://pomax.github.io/bezierjs/

 

And's here the source code of the library used in those examples.

http://pomax.github.io/bezierjs/lib/bezier.js

 

Babel doesn't add anything to JavaScript, it just converts ES6 code to ES5 code. So what I wrote will actually run just fine in Edge browsers without it. Of course you could always write it out the long way. That's the way most canvas libraries do it.

// Constructor 
function Line() {
   
}

// Method
Line.prototype.update = function() {
  
};

// Getter, setter
Object.defineProperty(Line.prototype, "x1", {
  get: function() { return +this.node.getAttribute("x1"); },
  set: function(x) { this.node.setAttribute("x1", x); }
});


  • Like 1
Link to comment
Share on other sites

Yeah, I seem to also be drawing the lines incorrectly for a cubic bezier ... It's my understanding pathDataToRawBezier will return an array representing the bezier as a cubic bezier.  The format of the array returned by pathDataToRawBezier; let's take the simple case where it just has one array because only one "M" command exists.  

 

Okay, so given the above, based on the discussion at this point, it is my understanding the format is this:

 

[ anchor1X, anchor1Y, controlPoint1X, controlPoint1Y, controlPoint2X, controlPoint2Y, anchor2X, anchor2Y, etc ... ]

 

... and the array both starts and ends with anchor point coordinates.  So, if this is correct, then the first control point should be connected to the first anchor point, and the second control point should be connected in a line w/ the next anchor in the array, as I understand it anyway.  

Link to comment
Share on other sites

  • Solution

The first anchor point is not part of a segment. It uses the previous segment's last anchor point. If there isn't a previous segment, then that means the previous command is a move command, which would be used as the anchor. So something like this...

 

[M: anchor point][C: control point, control point, anchor point][C: control point, control point, anchor point]etc...

 

Look at how I'm using the pathDataToRawBezier to draw SVGs on the canvas in this demo. 

 

See the Pen RWeOWX?editors=001 by osublake (@osublake) on CodePen

var beziers = MorphSVGPlugin.pathDataToRawBezier(shape.getAttribute("d"));

// Loop through all the beziers
beziers.forEach(function(p) {
  
  // Move command and first anchor point
  ctx.moveTo(p[0], p[1]);

  // Draw Cubic Bezier segments
  for (var i = 2, len = p.length; i < len;) {

    ctx.bezierCurveTo(
      p[i++], p[i++], // Control Point 1
      p[i++], p[i++], // Control Point 2
      p[i++], p[i++]);// Anchor Point 2, and anchor point 1 for next segment
  }
})
  • Like 2
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.
×