Let's look at rotation in a canvas UI. Rotation is hard. 💀
When we have a single shape selected, we can start dragging on a handle here and then rotate the shape. The shape rotates around its center point.
When more than one item is selected, we do something a little different. We're actually making two changes to these shapes as we rotate the group. I'll show each change separately.
We still get the angle of rotation based on the center of the bounding box, however we rotate each shape by this angle around its own center, just as we would with a single shape.
We also use this rotation to move each shape's center point around the bounding box's center point.
When we do both things at the same time, we get the correct result.
You'll notice that the bounding box isn't rotating. That's good: while shapes have individual rotations, bounding boxes are recalculated on each update.
Rotation adds some complexity to things like hit tests.
It also makes transformations a LOT more complex.
For rotated shapes in a group, we first transform the shape's original bounding box, then center and scale the shape so that it fits within that box.
Individual shapes are the hardest problem. First, we counter-rotate the drag vector (initial click point ➡️ current point) by the shape's rotation, and use that to compute a new bounding box as if it weren't rotated. This creates the correct size but the wrong position.
To fix the position, we then rotate the new bounding box's corners around its center and compare them against the shape's original rotated corners, offsetting the point so that the opposite corner/edge stays fixed.
Different shapes handle rotations differently. Circles are easy, ellipses are harder. It's mostly about finding the new bounding box.
Still some details to add too, like rotating the cursor so that it matches the angle of the dragging edge. 👀
Share this Scrolly Tale with your friends.
A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.