Рисование и поворот изображений с помощью KonvaJS - PullRequest
0 голосов
/ 20 марта 2020

Итак, я пытался использовать Konva для рисования количества изображений, текста и фигур, все в порядке, пока я не попытался добавить вращение в микс. Я понимаю, что Konva использует источник (верхний левый по умолчанию, который может быть перемещен по смещению), чтобы повернуть изображение, но мне нужно, чтобы положение всегда было верхним левым.

Поэтому я попытался вычислить, повернуть ре -положить объект в mimi c, что я хочу, но это всегда приводит к тому, что положение изображения будет отличаться от моего исходного состояния, что является нежелательным поведением.

поэтому мой вопрос: может ли Konva вращать изображения из их центра, сохраняя исходное положение слева вверху после поворота?

* Редактировать с примером кода: зеленое поле / текст поворачивается, но позиция все неверная. Мне нужно, чтобы позиция была слева.

const stage = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight
});

const layer = new Konva.Layer();
stage.add(layer);


const rotatePoint= (x, y , rad)=> {
  const rcos = Math.cos(rad);
  const rsin = Math.sin(rad);
  return {
    x: x * rcos - y * rsin,
    y: y * rcos + x * rsin
  }
}

const rotateAroundCenter = (node, rotation) => {  
  const topLeft = { x: -node.width() / 2, y: -node.height() / 2 };
  const current = rotatePoint(topLeft.x, topLeft.y, Konva.getAngle(node.rotation()));
  const rotated = rotatePoint(topLeft.x, topLeft.y, Konva.getAngle(rotation));
  const dx = rotated.x - current.x,
        dy = rotated.y - current.y;
  
  node.rotation(rotation); 
  
  node.x(node.x() + dx);
  node.y(node.y() + dy);
  
  return node;
}

let x = 100,
    y = 50, 
    width = 50,
    height = 50;
    

const rotation = 90;

const text = { width, height, fontSize: 15, fontFamily: 'Calibri', text: 'Simple Text', opacity: 0.5 };
const rect = { width, height, strokeWidth: 2}
let pos = {x, y};
layer.add(new Konva.Circle({ ...pos, radius:5, fill: 'black' })); 
layer.add(new Konva.Text({ ...pos, ...text, fill: 'black' })); 
layer.add(new Konva.Rect({ ...pos, ...rect, stroke: 'purple' })); 
layer.add(new Konva.Text({ ...pos, ...text, fill: 'purple', rotation: rotation })); 
layer.add(new Konva.Rect({ ...pos, ...rect, stroke: 'purple', rotation: rotation }));

pos = {x, y:150};

layer.add(new Konva.Circle({ ...pos, radius:5, fill: 'black' })); 
layer.add(rotateAroundCenter(new Konva.Text({ ...pos, ...text, fill: 'green' }), rotation)); 
layer.add(rotateAroundCenter(new Konva.Rect({ ...pos, ...rect, stroke: 'green' }), rotation)); 



layer.draw();
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="KonvaJS Template">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/konva/4.2.0/konva.min.js"></script>
  <meta charset="utf-8">
</head>
<body>
  <div id="container"></div>
</body>
</html>

1 Ответ

0 голосов
/ 26 марта 2020

Хорошо, в основном нужно было сделать то, что сказал Лавртон, поместил фигуру в группу (с правильным положением), затем фигура поворачивается и смещается внутри группы.

const stage = new Konva.Stage({
  container: 'container',
  width: 300,
  height: 700
});

const layer = new Konva.Layer();
stage.add(layer);

const rotatePoint = ({ x, y }, rad) => {
  const rcos = Math.cos(rad);
  const rsin = Math.sin(rad);
  return { x: x * rcos - y * rsin, y: y * rcos + x * rsin };
}

// will work for shapes with top-left origin, like rectangle
const rotateAroundCenter = (node, rotation) => {
  //current rotation origin (0, 0) relative to desired origin - center (node.width()/2, node.height()/2)
  const topLeft = { x: -node.width() / 2, y: -node.height() / 2 };
  const current = rotatePoint(topLeft, Konva.getAngle(node.rotation()));
  const rotated = rotatePoint(topLeft, Konva.getAngle(rotation));
  const dx = rotated.x - current.x,
        dy = rotated.y - current.y;
  
  const r = Math.floor(rotation / 90) % 4;  
  switch(r){
    case 1:
    case 3:
      node.x(node.x() + dx + node.height()/2);
      node.y(node.y() + dy + node.width()/2);
      break;
    case 2:
    default: 
      node.x(node.x() + dx + node.width()/2);
      node.y(node.y() + dy + node.height()/2);
      break;
  }

  node.rotation(rotation);
  
  return node;
}

let x = 200, y = 250, width = 30, height = 75, text = "? ? ? ? ?", opacity = 0.4;

drawShapes = (x, y, width, height, rotation) => {  
  layer.add(new Konva.Text({x:0, y, fill: 'black', text: (rotation+"°").padStart(5,"_")}));
  
  layer.add(new Konva.Rect({x, y, width, height, fill: 'black', rotation}));
  layer.add(new Konva.Text({x, y, width, height, fill: 'white', rotation, text}));

  const group = new Konva.Group({ x, y,/* clip:{x:0,y:0,width:200,height:200}*/})
  
  group.add(rotateAroundCenter(new Konva.Rect({x:-width/2,y:-height/2, width, height,fill: 'grey', opacity}), rotation));
  group.add(rotateAroundCenter(new Konva.Text({x:-width/2,y:-height/2, width, height,fill: 'black', text}), rotation));
  layer.add(group, new Konva.Circle({x, y, radius: 2, fill: 'black'}));
}
drawShapes(x, 50, width, height,   0);
drawShapes(x, 200, width, height,  90);
drawShapes(x, 350, width, height, 180);
drawShapes(x, 500, width, height, 270);


layer.draw();
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="KonvaJS Template">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/konva/4.2.0/konva.min.js"></script>
  <meta charset="utf-8">
</head>
<body>
  <div id="container" style="height:700px"></div>
</body>
</html>
...