0

I want to control rotate of Line Component. But it doesn't work correctly. When I rotate it or after I rotate and then drag it ==> position of it is not correct.

This is my initial points:

const [points, setPoints] = useState([
  [20, 100],
  [100, 100],
  [100, 200],
  [20, 200]
]);

I have a Line component to draw my points:

 <Line
        ref={shapRef}
        points={flatPoints(points)}
        stroke={"#E90000"}
        strokeWidth={1}
        closed
        strokeScaleEnabled={false}
        draggable={true}
        onDragEnd={handleDragEnd}
        rotationDeg={rotateDeg}
        onTransformEnd={handleTransformEnd}
      />

And I want to transform that Line with rotate, scale and drag options. These values after transform will be saved in state. I have some functions to handle these transform:

const handleDragEnd = (e) => {
    // return how many x,y distance that shape move (from:0)
    const deltaX = e.target.x();
    const deltaY = e.target.y();
    const newPoints = [...points].map((item) => {
      return [item[0] + deltaX, item[1] + deltaY];
    });

    onPointsChange(newPoints);

    // reset
    e.target.x(0);
    e.target.y(0);
  };

  const handleTransformEnd = (e) => {
    if (!shapRef.current) return;
    const node = shapRef.current;
    let newRotationDeg = node.rotation();
    let scaleX = node.scaleX();
    let scaleY = node.scaleY();
    const newPoints = [...points].map((item) => {
      return [item[0] * scaleX + node.x(), item[1] * scaleY + node.y()];
    });
    onPointsChange(newPoints);
    onRotateDegChange(newRotationDeg);
    //reset
    node.rotate(0);
    node.scaleX(1);
    node.scaleY(1);
    node.x(0);
    node.y(0);
  };

When I rotate this Line, I want it rotate in center point, but it jumps to another position in Canvas. How to caculate new points with rotation value after transform ? I just need to save new Points and rotation value.

This is my simple demo: https://codesandbox.io/s/simple-konva-jp54q1?file=/src/DrawArea.js. I handle rotate in handleTransformEnd Function. Thank you for helping me

BachKhoa
  • 1
  • 1
  • 2
  • 1
    Welcome to SO. If you are going to post code examples, and you should, then you need to make it a cut-down example that is a simplified and minimal demo that illustrates the issue. In your demo I don't see any points - just an empty transformer which jumps when rotated. What are you actually aiming to do? – Vanquished Wombat May 11 '23 at 15:47
  • @VanquishedWombat thanks for your response. I updated my question with code. Can you see it again and help me ? – BachKhoa May 11 '23 at 16:03

1 Answers1

1

The konva.Transformer rotates rect-based shapes about their center point - not their position. This has the effect of changing the position. In other words it is not simply a rotation but also a move. The math to calculate where the new location of the points in relation to the layer(0,0) is not difficult but we can escape it altogether by borrowing the konva.Transform (note this is different from the Konva.Transform_er)

I solved a similar question related to getting the corner co-ordinates of a rotated rect in this question. The magic is in using

shape.getAbsoluteTransform().point(pt);

I explained the 'how' in detain in this blog post.

In a nutshell, in case the blog link evaporates, we can get the list of individual steps of position, rotation & scaling applied to the shape. We can the drop into this black-box machine any (x,y) point and we will receive the position of that point if the same transformations are applied on it.

This technique works regardless of the position, rotation & scaling applied to the shape, meaning we can have one function to call after a plain drag AND at the the end of a transformer interaction.

// Function to get position of a point with any 
// position / rotation / scaling applied.
// node = the shape we are using to determine the transform of the pt.
// pt = {x,y} of point to rotate, 
// returns {x, y} giving the new point.
function getTransformedPoint(node, pt){
  return node.getAbsoluteTransform().point(pt);
}
Vanquished Wombat
  • 9,075
  • 5
  • 28
  • 67
  • Thank you for answer. I know node.getAbsoluteTransform().point(pt); will give me new points after scaling, rotate. But i need to rotate my Transform too. So I have to save rotation value without transform points to set this rotation value for Line Component each refresh page. If I use your solution, should I save rotation value by node.rotation() and set it for Transform ? In this case, if I scale or rotate Transform again, does it work correctly ? – BachKhoa May 12 '23 at 06:18
  • No that will not work. Question I should have asked before - why do you need to store the points of the line separate to the line shape itself? – Vanquished Wombat May 12 '23 at 07:31
  • If i use node.getAbsoluteTransform().point(pt) to calculate new points after transform. Then Transform Component does not rotate follow new shape. I want after rotate, Transform can rotate follow shape like this: https://drive.google.com/file/d/1cjRhYGo3EsAxVeTGUUaAfx6V2exC0Ho2/view?usp=share_link . Any solution for me. Note: i have to save new points after transform into database. – BachKhoa May 12 '23 at 07:59
  • So all you need to do is let the user rotate the line and then later store that in the db and be able to re-display the shape later when they come back? In that case, you are making life very complicated for no reason. Store the Konva.Line attributes for x, y, rotation, scale, and the points without any recalculation. When you have to reload set those stored values back into a new Konva.Line. The transfomer will work, everything will work. – Vanquished Wombat May 12 '23 at 08:13
  • Yeah, it's simple if i save all attributes like you say. But i need to send points for another server to cacluate distance between shape without x, y, scale values, Just points. This is the reason why i make everything complicated. Sorry for that and thank you for your answer. – BachKhoa May 12 '23 at 08:39
  • So - you can't have both recalculated points and a Konva.Transformer that shows the rotation. What I would do it this. (1) Store the shape attrs as I have said - this is for the diagram only, (2) Store the points recalculated to 0 degrees rotation for use in any calculations on the server. – Vanquished Wombat May 12 '23 at 09:22