KonvaJS-围绕光标旋转矩形而不使用偏移量

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

我正在使用KonvaJS将矩形拖放到预定义的插槽中。一些插槽需要旋转90度。我在垂直旋转的插槽周围有一个点击框,因此当用户将矩形拖动到该区域时,它将自动旋转90度(以匹配方向)。旋转时,它会从鼠标下方移出。这可以通过偏移来解决,但是在捕捉后,矩形在外观上不会与框对齐。这可以(可能)用其他代码解决。

我已尝试旋转矩形,然后将其在鼠标下移动。由于用户仍在拖动它,因此这似乎不符合我的计划。

是否可以在不使用偏移的情况下迫使矩形在鼠标下旋转?

这里是显示问题的小提琴-可以通过将第一个变量设置为true来演示偏移问题。https://jsfiddle.net/ChaseRains/1k0aqs2j/78/

var width = window.innerWidth;
var height = window.innerHeight;

var rectangleLayer = new Konva.Layer();
var holdingSlotsLayer = new Konva.Layer();
var controlLayer = new Konva.Layer();
var stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height,
  draggable: true
});
//vertical holding spot
holdingSlotsLayer.add(new Konva.Rect({
  x: 300,
  y: 25,
  width: 130,
  height: 25,
  fill: '#fff',
  draggable: false,
  rotation: 90,
  stroke: '#000'
}));

//horizontal holding spot
holdingSlotsLayer.add(new Konva.Rect({
  x: 25,
  y: 75,
  width: 130,
  height: 25,
  fill: '#fff',
  draggable: false,
  rotation: 0,
  stroke: '#000'
}));

//mask to set boundaries around where we wannt to flip the rectangle
controlLayer.add(new Konva.Rect({
  x: 215,
  y: 15,
  width: 150,
  height: 150,
  fill: '#fff',
  draggable: false,
  name: 'A',
  opacity: 0.5
}));
stage.add(holdingSlotsLayer, controlLayer);

//function for finding intersections
function haveIntersection(placeHolder, rectangle, zone) {
  if (rectangle.rotation == 0 || zone == true) {
    return !(
      rectangle.x > placeHolder.x + placeHolder.width ||
      rectangle.x + rectangle.width < placeHolder.x ||
      rectangle.y > placeHolder.y + placeHolder.height ||
      rectangle.y + rectangle.height < placeHolder.y
    );
  } else {
    return !(
      rectangle.x > placeHolder.x + 25 ||
      rectangle.x + rectangle.width < placeHolder.x ||
      rectangle.y > placeHolder.y + placeHolder.height + 90 ||
      rectangle.y + rectangle.height < placeHolder.y
    );
  }
}

//function to create rectangle group (so we can place text on the rectangle)
function spawnRectangle(angle) {
  var rectangleGroup = new Konva.Group({
    x: 95,
    y: 95,
    width: 130,
    height: 25,
    rotation: angle,
    draggable: true,
  });

  rectangleGroup.add(new Konva.Rect({
    width: 130,
    height: 25,
    fill: 'lightblue'
  }));

  rectangleGroup.add(new Konva.Text({
    text: '123',
    fontSize: 18,
    fontFamily: 'Calibri',
    fill: '#000',
    width: 130,
    padding: 5,
    align: 'center'
  }));

  //function tied to an on drag move event
  rectangleGroup.on('dragmove', (e) => {
    //shrink rectangle hitbox for use in placeholder intersection
    var dimensions = {
      "height": 3,
      "width": 5,
      "x": e.target.attrs.x,
      "y": e.target.attrs.y,
      'rotation': e.target.attrs.rotation
    };
    //loop over holding slots to see if there is an intersection.
    for (var i = 0; holdingSlotsLayer.children.length > i; i++) {
      //if true, change the look of the slot we are hovering
      if (haveIntersection(holdingSlotsLayer.children[i].attrs, dimensions, false)) {
        holdingSlotsLayer.children[i].attrs.fill = '#C41230';
        holdingSlotsLayer.children[i].attrs.dash = [10, 3];
        holdingSlotsLayer.children[i].attrs.stroke = '#000';
        //set attributes back to normal otherwise
      } else {
        holdingSlotsLayer.children[i].attrs.fill = '#fff';
        holdingSlotsLayer.children[i].attrs.dash = null;
        holdingSlotsLayer.children[i].attrs.stroke = null;
      }
    }

    //check to see if we are in a zone that requires the rectangle to be flipped 90 degrees 
    if (haveIntersection(controlLayer.children[0].attrs, dimensions, true)) {
      if (rectangleGroup.attrs.rotation != 90) {
        rectangleGroup.attrs.rotation = 90;
      }
    } else {
      rectangleGroup.attrs.rotation = 0;
    }

    stage.batchDraw();
  });

  rectangleGroup.on('dragend', (e) => {

    for (var i = 0; holdingSlotsLayer.children.length > i; i++) {
      //If the parking layer has an element that is lit up, then snap to position.. 
      if (holdingSlotsLayer.children[i].attrs.fill == '#C41230') {
        rectangleGroup.position({
          x: holdingSlotsLayer.children[i].attrs.x,
          y: holdingSlotsLayer.children[i].attrs.y
        });
        holdingSlotsLayer.children[i].attrs.fill = '#fff';
        holdingSlotsLayer.children[i].attrs.dash = null;
        holdingSlotsLayer.children[i].attrs.stroke = null;
      }
    }

    stage.batchDraw();
  });


  rectangleLayer.add(rectangleGroup);
  stage.add(rectangleLayer);
}
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  background-color: #D3D3D3;
  background-size: cover;
}

#desc {
  position: absolute;
  top: 5px;
  left: 5px;
}
<script src="https://unpkg.com/[email protected]/konva.min.js"></script>

<body>
  <div id="container"></div>
  <div id="desc">
    <button onclick="spawnRectangle(0)">spawn rectangle</button>
  </div>
</body>
javascript konvajs
1个回答
0
投票

这里是一个简单的函数,无需使用konva offset()即可在鼠标下方旋转矩形。我使用补间来应用移动,但是如果您更喜欢在不使用补间的情况下使用它,则只需应用rect.rotate()然后将newPos x&y作为位置即可。

编辑:OP指出,如果单击,则在矩形完成其动画的同时按住鼠标不放,然后拖动该矩形,则矩形将跳开。是什么赋予了 ?好吧,当mousedown事件运行时,Konva会在其内部拖动功能中注意到该形状的初始位置。然后,当我们开始实际拖动鼠标时,Konva会忠实地在其计算位置重绘形状。现在,“我们”知道我们已经将形状移出了代码,但是我们并未让Konva陷入困境。

解决方法是致电

 rect.stopDrag(); 
 rect.startDrag();

立即设置新位置之后。因为我使用补间,所以我在补间之一的onFinish()回调函数中执行了此操作-如果应用多个补间,则需要确保其最终补间。我之所以放弃,是因为我的补间在同一时期内运行。如果您不使用补间,则只需在形状上应用上一个rotate()或position()调用即可立即调用上面的内容。

function rotateUnderMouse(){


  // Get the stage position of the mouse
  var mousePos = stage.getPointerPosition();

  // get the stage position of the mouse
  var shapePos = rect.position();

  // compute the vector for the difference
  var rel = {x: mousePos.x - shapePos.x, y: mousePos.y - shapePos.y} 

  // Now apply the rotation
  angle = angle + 90;


  // and reposition the shape to keep the same point in the shape under the mouse 
  var newPos = ({x: mousePos.x  + rel.y , y: mousePos.y - rel.x}) 

  // Just for fun, a tween to apply the move: See https://konvajs.org/docs/tweens/Linear_Easing.html
  var tween1 = new Konva.Tween({
    node: rect,
    duration: 0.25,
    x:  newPos.x,
    y: newPos.y,
    easing: Konva.Easings.Linear,
    onFinish: function() { rect.stopDrag(); rect.startDrag();}
  });
  
  // and a tween to apply the rotation 
  tween2 = new Konva.Tween({
    node: rect,
    duration: 0.25,
    rotation: angle,
    easing: Konva.Easings.Linear
  });
    
  
  tween2.play();
  tween1.play();


  
}


function setup() {

// Set up a stage and a shape
stage = new Konva.Stage({
  container: 'canvas-container',
  width: 650,
  height: 300
});


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

newPos = {x: 80, y: 40};
rect = new Konva.Rect({
   width: 140, height: 50, x: newPos.x, y: newPos.y, draggable: true, stroke: 'cyan', fill: 'cyan'
  })
layer.add(rect);

stage.draw()

rect.on('mousedown', function(){
  rotateUnderMouse()
})

}

var stage, layer, rect, angle = 0;

setup()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/4.0.13/konva.js"></script>

<p>Click the rectangle - it will rotate under the mouse.</p>

<div id="canvas-container"></div>
© www.soinside.com 2019 - 2024. All rights reserved.