Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
329 views
in Technique[技术] by (71.8m points)

konvajs - How to set the initial dimensions of a transformer when applying it on a group having clip properties in Konva?

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

enter image description here

This is what it looks like after applying clip and transform

enter image description here

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'));
question from:https://stackoverflow.com/questions/66046417/how-to-set-the-initial-dimensions-of-a-transformer-when-applying-it-on-a-group-h

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...