Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
328 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 Reply

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...