Transforms
Ripl supports element-level transformations — translate, scale, and rotate — that apply to any element or group. Transforms are set as properties on the element and are automatically applied to the rendering context before the element draws.
Transform Properties
Every element exposes these transform properties:
| Property | Type | Default | Description |
|---|---|---|---|
translateX | number | 0 | Horizontal translation in pixels |
translateY | number | 0 | Vertical translation in pixels |
transformScaleX | number | 1 | Horizontal scale factor |
transformScaleY | number | 1 | Vertical scale factor |
rotation | number | string | 0 | Rotation angle (see below) |
transformOriginX | number | string | 0 | Horizontal origin for rotation/scale |
transformOriginY | number | string | 0 | Vertical origin for rotation/scale |
Rotation
Rotation can be specified as a number (radians) or a string with a unit suffix:
// Radians (number)
rect.rotation = Math.PI / 4;
// Degrees (string)
rect.rotation = '45deg';
// Radians (string)
rect.rotation = '0.785rad';When no unit suffix is provided on a string value, it is treated as radians.
Transform Origin
Transform origin defines the pivot point for rotation and scale. It can be a number (pixels) or a percentage string relative to the element's bounding box:
// Pixel values
rect.transformOriginX = 50;
rect.transformOriginY = 50;
// Percentage of element dimensions
rect.transformOriginX = '50%';
rect.transformOriginY = '50%';When set to '50%', the element rotates and scales around its center. The percentage is resolved relative to the element's width and height properties.
Application Order
Transforms are applied to the rendering context in the following order:
- Translate to the origin point (
transformOriginX,transformOriginY) - Translate by
translateX,translateY - Rotate by
rotation - Scale by
transformScaleX,transformScaleY - Translate back from the origin point
This order ensures that rotation and scaling happen around the specified origin.
Group Inheritance
When transforms are applied to a group, all children inherit the transformation. The context is saved before the group renders and restored afterward, so transforms compose naturally:
import {
createCircle,
createGroup,
createRect,
} from '@ripl/core';
const group = createGroup({
children: [
createRect({ x: 0,
y: 0,
width: 80,
height: 80,
fillStyle: '#3a86ff' }),
createCircle({ cx: 120,
cy: 40,
radius: 30,
fillStyle: '#ff006e' }),
],
});
// Both children will be translated and rotated together
group.translateX = 100;
group.translateY = 50;
group.rotation = '15deg';Animating Transforms
All transform properties are fully animatable using renderer.transition(). String values (degrees, percentages) are interpolated smoothly:
// Animate rotation from 0 to 360 degrees
await renderer.transition(rect, {
duration: 1000,
ease: easeOutCubic,
state: {
rotation: '360deg',
},
});
// Animate translation
await renderer.transition(rect, {
duration: 800,
state: {
translateX: 200,
translateY: 100,
},
});
// Animate scale
await renderer.transition(rect, {
duration: 600,
state: {
transformScaleX: 2,
transformScaleY: 2,
},
});SVG Support
Transforms work identically for both Canvas and SVG contexts. In the SVG context, transforms are serialised as SVG transform attribute values (e.g., translate(10,20) rotate(45) scale(2,2)), and the transform state is saved and restored alongside the context state stack.