gpt4 book ai didi

javascript - KonvaJS - 在不使用偏移的情况下围绕光标旋转矩形

转载 作者:行者123 更新时间:2023-11-30 19:05:01 34 4
gpt4 key购买 nike

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

我试过旋转矩形,然后在鼠标下移动它。由于用户仍在拖动它,这似乎没有按我的计划工作。

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

这是一个显示问题的 fiddle - 可以通过将第一个变量设置为 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/konva@4.0.18/konva.min.js"></script>

<body>
<div id="container"></div>
<div id="desc">
<button onclick="spawnRectangle(0)">spawn rectangle</button>
</div>
</body>

最佳答案

这是一个简单的函数,可以在不使用 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>

关于javascript - KonvaJS - 在不使用偏移的情况下围绕光标旋转矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59074176/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com