使用 Rotate Group Konvajs 时保持在界限内

问题描述 投票:0回答:1

我正在调整图像大小并将其放入组中进行裁剪,并且我正在限制图像的拖动。 当组轮换为 0 时效果非常好。 但是,当我旋转组时,拖动限制无法正常工作。 这可能需要一些数学知识,不幸的是,我在这方面不是很熟练。 您能帮我限制旋转组时图像的拖动吗? 这是演示

let stage = new Konva.Stage({
  container: "container",
  width: 800,
  height: 600
});
var layer = new Konva.Layer();
stage.add(layer);

var background = new Konva.Rect({
  width: stage.width(),
  height: stage.height(),
  fill: "lightgray"
});
layer.add(background);

var blockPhoto = new Konva.Group({
  x: 200,
  y: 100,
  width: 200,
  height: 200,
  draggable: true,
  rotation: 0,
  clip: {
    x: 0,
    y: 0,
    width: 200,
    height: 200
  }
});
var rect = new Konva.Rect({
  width: 200,
  height: 200,
  fill: "lightblue"
});

blockPhoto.add(rect);

var itemUrl =
  "https://images.unsplash.com/photo-1683009686716-ac2096a5a73b?ixlib=rb-.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80";
Konva.Image.fromURL(itemUrl, function (image) {
  resizeImgDimToOccupateAllGroup(blockPhoto, image);
  image.draggable(true);
  image.dragBoundFunc(function (pos) {
    var newX = pos.x;
    var newY = pos.y;
    var posRotatedGroup = getRectPosition(blockPhoto);
    if (newX + image.width() < posRotatedGroup.maxX) {
      newX = posRotatedGroup.maxX - image.width();
    }

    if (newX > posRotatedGroup.minX) {
      newX = posRotatedGroup.minX;
    }

    if (newY > posRotatedGroup.minY) {
      newY = posRotatedGroup.minY;
    }

    if (newY + image.height() < posRotatedGroup.maxY) {
      newY = posRotatedGroup.maxY - image.height();
    }
    return {
      x: newX,
      y: newY
    };
  });

  blockPhoto.add(image);
});

layer.add(blockPhoto);

function resizeImgDimToOccupateAllGroup(group, image) {
  var widthRatio = group.width() / image.width();
  var heightRatio = group.height() / image.height();

  var maxRatio = Math.max(widthRatio, heightRatio);

  var newImageWidth = image.width() * maxRatio;
  var newImageHeight = image.height() * maxRatio;

  image.width(newImageWidth);
  image.height(newImageHeight);
  return image;
}

function getRectPosition(rectangle) {
  const rectRotation = rectangle.rotation();
  const rectWidth = rectangle.width();
  const rectHeight = rectangle.height();
  const rectPosition = rectangle.getAbsolutePosition();

  // Convertir l'angle de rotation en radians
  const radians = (rectRotation * Math.PI) / 180;

  // Coordonnées des coins non tournés
  const x1 = rectPosition.x;
  const y1 = rectPosition.y;
  const x2 = x1 + rectWidth;
  const y2 = y1;
  const x3 = x1;
  const y3 = y1 + rectHeight;
  const x4 = x2;
  const y4 = y3;

  // Calcul des nouvelles coordonnées après rotation
  const rotatedX1 =
    rectPosition.x +
    (x1 - rectPosition.x) * Math.cos(radians) -
    (y1 - rectPosition.y) * Math.sin(radians);
  const rotatedY1 =
    rectPosition.y +
    (x1 - rectPosition.x) * Math.sin(radians) +
    (y1 - rectPosition.y) * Math.cos(radians);

  const rotatedX2 =
    rectPosition.x +
    (x2 - rectPosition.x) * Math.cos(radians) -
    (y2 - rectPosition.y) * Math.sin(radians);
  const rotatedY2 =
    rectPosition.y +
    (x2 - rectPosition.x) * Math.sin(radians) +
    (y2 - rectPosition.y) * Math.cos(radians);

  const rotatedX3 =
    rectPosition.x +
    (x3 - rectPosition.x) * Math.cos(radians) -
    (y3 - rectPosition.y) * Math.sin(radians);
  const rotatedY3 =
    rectPosition.y +
    (x3 - rectPosition.x) * Math.sin(radians) +
    (y3 - rectPosition.y) * Math.cos(radians);

  const rotatedX4 =
    rectPosition.x +
    (x4 - rectPosition.x) * Math.cos(radians) -
    (y4 - rectPosition.y) * Math.sin(radians);
  const rotatedY4 =
    rectPosition.y +
    (x4 - rectPosition.x) * Math.sin(radians) +
    (y4 - rectPosition.y) * Math.cos(radians);

  // Trouver les coordonnées minimales et maximales
  const minX = Math.min(rotatedX1, rotatedX2, rotatedX3, rotatedX4);
  const minY = Math.min(rotatedY1, rotatedY2, rotatedY3, rotatedY4);
  const maxX = Math.max(rotatedX1, rotatedX2, rotatedX3, rotatedX4);
  const maxY = Math.max(rotatedY1, rotatedY2, rotatedY3, rotatedY4);

  return {
    minX: minX,
    maxX: maxX,
    minY: minY,
    maxY: maxY
  };
}

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
function 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;

  node.rotation(rotation);
  node.x(node.x() + dx);
  node.y(node.y() + dy);
}
$("#rotation").on("keyup", function () {
  var rotation = $("#rotation").val();
  rotateAroundCenter(blockPhoto, rotation);
});
<div id="container"></div>
Rotation: <input type="text" id="rotation" name="rotation" value="0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script src="https://unpkg.com/[email protected]/konva.min.js"></script>

javascript geometry rotation konvajs konva
1个回答
0
投票

您可以通过将其视为边界矩形是否完全在图像矩形内的问题来解决此问题。如果图像正在旋转,就像您的情况一样,则更容易将图像视为多边形。现在,您可以对边界矩形的每个角点使用多边形内的点检查 - 如果所有这些点都在多边形内部,则接受该位置,或者如果有任何点在多边形外部,则拒绝移动。

这里有一个很好的多边形点算法和解释

请注意,这是一个基于数学的解决方案,并且速度非常快。 Konva 提供了一些碰撞检查,但速度会较慢,因为它们需要构建离屏画布和像素矩阵采样来检测碰撞。不要误会我的意思,有时这种稍微慢一点的方法效果很好或者是救星,但在你的情况下,你想在拖动过程中检查矩形的重叠,因此性能是焦点。

另请注意,这种方法取决于您能否获得旋转图像的角点。在这个SO答案中有一种方法。

© www.soinside.com 2019 - 2024. All rights reserved.