Both Shape and Scene components support transformation properties that control positioning, rotation, and scaling.
All transform props are optional and have sensible defaults. See the type definitions in the source code for the complete definition.
X-axis translation in pixels. Moves the element horizontally.
Y-axis translation in pixels. Moves the element vertically.
Rotation angle in degrees. Positive values rotate clockwise.
Horizontal scale factor. Values > 1 enlarge, values < 1 shrink.
Vertical scale factor. Values > 1 enlarge, values < 1 shrink.
Translation (Position)
Use x and y props to position elements:
import { SwCanvas , Shape , Rect } from '@thorvg/react-fiber' ;
function App () {
return (
< SwCanvas width = { 400 } height = { 300 } >
< Shape fill = { [ 255 , 100 , 100 , 255 ] } x = { 50 } y = { 50 } >
< Rect x = { 0 } y = { 0 } width = { 100 } height = { 100 } />
</ Shape >
< Shape fill = { [ 100 , 100 , 255 , 255 ] } x = { 200 } y = { 150 } >
< Rect x = { 0 } y = { 0 } width = { 100 } height = { 100 } />
</ Shape >
</ SwCanvas >
);
}
The x and y props on Shape are separate from the x and y props on geometry children like Rect. The Shape transform moves the entire shape, while geometry coordinates are relative to the shape’s origin.
Rotation
Rotate elements using the rotation prop (in degrees):
< Shape
fill = { [ 200 , 100 , 255 , 255 ] }
x = { 150 }
y = { 150 }
rotation = { 45 }
>
< Rect x = { - 50 } y = { - 50 } width = { 100 } height = { 100 } />
</ Shape >
Rotation is applied around the element’s origin (0, 0). To rotate around the center of a rectangle, position it with negative offsets equal to half its dimensions.
Rotation Example: Spinning Square
import { useState , useEffect } from 'react' ;
import { SwCanvas , Shape , Rect } from '@thorvg/react-fiber' ;
function SpinningSquare () {
const [ rotation , setRotation ] = useState ( 0 );
useEffect (() => {
const interval = setInterval (() => {
setRotation ( r => ( r + 2 ) % 360 );
}, 16 ); // ~60fps
return () => clearInterval ( interval );
}, []);
return (
< SwCanvas width = { 400 } height = { 300 } >
< Shape
fill = { [ 100 , 200 , 255 , 255 ] }
x = { 200 }
y = { 150 }
rotation = { rotation }
>
{ /* Center the rect on the rotation point */ }
< Rect x = { - 50 } y = { - 50 } width = { 100 } height = { 100 } />
</ Shape >
</ SwCanvas >
);
}
Scaling
Scale elements using scaleX and scaleY:
< Shape
fill = { [ 100 , 255 , 100 , 255 ] }
x = { 100 }
y = { 100 }
scaleX = { 1.5 }
scaleY = { 0.8 }
>
< Circle x = { 0 } y = { 0 } radius = { 50 } />
</ Shape >
Uniform Scaling Use the same value for both scaleX and scaleY to scale proportionally.
Non-uniform Scaling Use different values to stretch or squash in one direction.
Transforms are applied in a specific order: Scale → Rotate → Translate .
This is implemented in the matrix utility in the source code:
// Order: Scale -> Rotate -> Translate
// Matrix multiplication: T * R * S
Scale
The element is first scaled by scaleX and scaleY.
Rotate
Then rotated by rotation degrees around the origin.
Translate
Finally moved to position (x, y).
You can combine all transform properties:
< Shape
fill = { [ 255 , 150 , 50 , 255 ] }
x = { 200 }
y = { 150 }
rotation = { 30 }
scaleX = { 1.2 }
scaleY = { 0.8 }
>
< Rect x = { - 50 } y = { - 25 } width = { 100 } height = { 50 } rx = { 5 } ry = { 5 } />
</ Shape >
Scene components support the same transform props and apply them to all children:
import { SwCanvas , Scene , Shape , Rect , Circle } from '@thorvg/react-fiber' ;
function App () {
return (
< SwCanvas width = { 600 } height = { 400 } >
< Scene x = { 100 } y = { 100 } rotation = { 15 } scaleX = { 1.5 } scaleY = { 1.5 } >
< Shape fill = { [ 255 , 100 , 100 , 255 ] } >
< Rect x = { 0 } y = { 0 } width = { 50 } height = { 50 } />
</ Shape >
< Shape fill = { [ 100 , 100 , 255 , 255 ] } >
< Circle x = { 75 } y = { 25 } radius = { 25 } />
</ Shape >
</ Scene >
</ SwCanvas >
);
}
Transforms on a Scene apply to all its children. Each child can also have its own transforms, which are combined with the parent’s.
Transforms accumulate when nesting Scene components:
< Scene x = { 100 } y = { 100 } rotation = { 45 } >
< Scene x = { 50 } y = { 0 } scaleX = { 2 } >
< Shape fill = { [ 200 , 100 , 200 , 255 ] } >
< Rect x = { 0 } y = { 0 } width = { 30 } height = { 30 } />
</ Shape >
</ Scene >
</ Scene >
In this example:
The inner Scene is positioned at (50, 0) relative to the outer Scene
The inner Scene is scaled 2x
The outer Scene rotates both scenes by 45 degrees
The outer Scene moves everything to (100, 100)
Interactive Example: Draggable Shape
import { useState } from 'react' ;
import { SwCanvas , Shape , Circle } from '@thorvg/react-fiber' ;
function DraggableCircle () {
const [ position , setPosition ] = useState ({ x: 200 , y: 150 });
const [ isDragging , setIsDragging ] = useState ( false );
const handleMouseDown = () => setIsDragging ( true );
const handleMouseUp = () => setIsDragging ( false );
const handleMouseMove = ( e : React . MouseEvent < HTMLCanvasElement >) => {
if ( ! isDragging ) return ;
const rect = e . currentTarget . getBoundingClientRect ();
setPosition ({
x: e . clientX - rect . left ,
y: e . clientY - rect . top
});
};
return (
< div
onMouseDown = { handleMouseDown }
onMouseUp = { handleMouseUp }
onMouseMove = { handleMouseMove }
>
< SwCanvas width = { 400 } height = { 300 } >
< Shape
fill = { [ 100 , 200 , 255 , 255 ] }
x = { position . x }
y = { position . y }
>
< Circle x = { 0 } y = { 0 } radius = { 30 } />
</ Shape >
</ SwCanvas >
</ div >
);
}
Common Patterns
To center a rectangle, offset its geometry by half its dimensions: < Shape x = { 200 } y = { 150 } fill = { [ 255 , 100 , 100 , 255 ] } >
< Rect x = { - 50 } y = { - 50 } width = { 100 } height = { 100 } />
</ Shape >
Position geometry so (0,0) is at the desired rotation point: < Shape x = { 200 } y = { 150 } rotation = { 45 } fill = { [ 100 , 255 , 100 , 255 ] } >
< Rect x = { - 60 } y = { - 40 } width = { 120 } height = { 80 } />
</ Shape >
Use negative scale: < Shape scaleX = { - 1 } x = { 200 } y = { 100 } fill = { [ 100 , 100 , 255 , 255 ] } >
< Circle x = { 0 } y = { 0 } radius = { 40 } />
</ Shape >
Group and transform together
Remember that geometry coordinates (like x and y on Rect) are separate from transform props on Shape. Geometry coordinates define the shape itself, while transform props position and manipulate the entire shape.