I have a Konva.Group
with a few nodes to which I have set clip properties to limit what is seen. I'm applying Konva.Transformer
to the group and the problem I'm facing is that the Transformer encloses the entire group, even the unclipped portion. This is not looking good even if it is fully functional and does the job. Is there any way to set the initial width and height of the transformer so that it only encloses the clipped portion?
This is the group before applying clip and transform
This is what it looks like after applying clip and transform
import React, {useRef, useEffect} from 'react';
import { render } from 'react-dom';
import { Stage, Layer, Rect, Circle, Line, Group, Transformer } from 'react-konva';
const App = () => {
const trRef = useRef(null)
const grpRef = useRef(null)
useEffect(()=>{
const transformNode = trRef.current;
transformNode.enabledAnchors(["top-left",
"top-right",
"bottom-left",
"bottom-right"])
transformNode.nodes([grpRef.current])
},[trRef])
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Group ref={grpRef} clipX={0} clipY={0} clipWidth={200} clipHeight={200}>
<Rect
x={20}
y={50}
width={100}
height={100}
fill="red"
shadowBlur={10}
/>
<Circle x={200} y={100} radius={50} fill="green" />
<Line
x={20}
y={200}
points={[0, 0, 100, 0, 100, 100]}
tension={0.5}
closed
stroke="black"
fillLinearGradientStartPoint={{ x: -50, y: -50 }}
fillLinearGradientEndPoint={{ x: 50, y: 50 }}
fillLinearGradientColorStops={[0, 'red', 1, 'yellow']}
/>
</Group>
<Transformer rotateEnabled={false} ref={trRef} />
</Layer>
</Stage>
);
};
render(<App />, document.getElementById('root'));
This is the default behavior of Konva.Transform
and it can't be altered. One workaround would be to create a transparent rectangle around the clipped portion, apply the transform to it and then copy the changes to the group.
import React, {useRef, useEffect} from 'react';
import { render } from 'react-dom';
import { Stage, Layer, Rect, Circle, Line, Group, Transformer } from 'react-konva';
const App = () => {
const trRef = useRef(null)
const grpRef = useRef(null)
const rectRef = useRef(null)
// To copy the transform matrix from the rectangle to the group
function handleTransform(e){
const shape1 = e.target;
const transform = shape1.getTransform().copy();
const attrs = transform.decompose();
grpRef.current.setAttrs(attrs);
}
useEffect(()=>{
const transformNode = trRef.current;
transformNode.enabledAnchors(["top-left",
"top-right",
"bottom-left",
"bottom-right"])
transformNode.nodes([rectRef.current])
},[trRef])
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Group draggable>
{/* Transparent rectangle to which the transform is now applied to */}
<Rect
ref={rectRef}
x={0}
y={0}
width={200}
height={200}
id="invisible-rect"
/>
<Group ref={grpRef} clipX={0} clipY={0} clipWidth={200} clipHeight={200}>
<Rect
x={20}
y={50}
width={100}
height={100}
fill="red"
shadowBlur={10}
/>
<Circle x={200} y={100} radius={50} fill="green" />
<Line
x={20}
y={200}
points={[0, 0, 100, 0, 100, 100]}
tension={0.5}
closed
stroke="black"
fillLinearGradientStartPoint={{ x: -50, y: -50 }}
fillLinearGradientEndPoint={{ x: 50, y: 50 }}
fillLinearGradientColorStops={[0, 'red', 1, 'yellow']}
/>
</Group>
</Group>
<Transformer onTransform={handleTransform} rotateEnabled={false} ref={trRef} />
</Layer>
</Stage>
);
};
render(<App />, document.getElementById('root'));
Here's the demo of the above code. Thanks to Anton, the creator of this wonderful library for suggesting this solution.
Reference - Konva shape transform sharing is simple