gpt4 book ai didi

javascript - Konva 继续在舞台外跟踪鼠标

转载 作者:行者123 更新时间:2023-12-04 09:17:24 26 4
gpt4 key购买 nike

我正在尝试使用 React-Konva 库实现一个操纵杆,该操纵杆可用于控制 React.JS 中的机器人之类的东西。到目前为止,我已经设法通过在较大的圆圈内绘制一个较小的圆圈并让较小的圆圈在鼠标按下时跟踪鼠标相对于舞台的位置来获得某种效果。它的问题在于,一旦鼠标离开舞台,我就会停止获取 onMouseMove 事件,并且圆圈一直停留在最后一个位置,直到鼠标返回舞台。理想情况下,我希望即使在舞台外移动时,圆圈也能继续跟踪鼠标的方向,但显然限制了圆圈从原点实际移动多远以保持在舞台内。
这是我到目前为止的代码

import React, { useState, useContext } from "react";
import { Stage, Layer, Circle } from "react-konva";

export default function Joystick(props) {
const { size } = props;

const [x, setX] = useState(0);
const [y, setY] = useState(0);
const [down, setDown] = useState(false);

const joyX = down ? x : size / 2;
const joyY = down ? y : size / 2;

return (
<Stage
width={size}
height={size}
onMouseMove={(ev) => {
setX(ev.evt.layerX);
setY(ev.evt.layerY);
}}
onMouseDown={(ev) => setDown(true)}
onMouseUp={(ev) => setDown(false)}
>
<Layer>
<Circle x={size / 2} y={size / 2} radius={size / 2} fill="black" />
<Circle x={joyX} y={joyY} radius={size / 4} fill="white" />
</Layer>
</Stage>
);
}
所以我想知道的是,即使鼠标超出舞台,我也可以扩展它以保持跟踪鼠标的最简单和最干净的方法是什么?

最佳答案

根据@VanquishedWombat 的建议,从 fire the div mousemove while on document 中获取灵感我想出了以下代码

function offset(el) {
var rect = el.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return {
top: rect.top + scrollTop,
left: rect.left + scrollLeft,
};
}

export default class Joystick extends React.Component {
constructor(props) {
super(props);

this.state = {
down: 0,
x: 0,
y: 0,
offset: { top: 0, left: 0 },
};

this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
}

updatePosition(ev, o) {
const { size } = this.props;
const offset = o || this.state.offset;

let x = ev.clientX - offset.left;
let y = ev.clientY - offset.top;

let right = (x / size - 0.5) * 2;
let up = (y / size - 0.5) * -2;

const mag = Math.sqrt(right * right + up * up);
const newMag = Math.min(mag, 1);

right = (right / mag) * newMag;
up = (up / mag) * newMag;

x = (1 + right) * (size / 2);
y = (1 - up) * (size / 2);

this.setState({ x, y });
}

handleMouseMove(ev) {
this.updatePosition(ev);
}

handleMouseUp(ev) {
document.removeEventListener("mousemove", this.handleMouseMove);
document.removeEventListener("mouseup", this.handleMouseUp);
this.setState({ down: false });
}

render() {
const { x, y, down } = this.state;
const { size } = this.props;

const joyX = down ? x : size / 2;
const joyY = down ? y : size / 2;

return (
<div
onMouseDown={(ev) => {
const o = offset(ev.currentTarget);
this.setState({ offset: o, down: true });
this.updatePosition(ev, o);

document.addEventListener("mousemove", this.handleMouseMove);
document.addEventListener("mouseup", this.handleMouseUp);
}}
style={{ width: size, height: size }}
>
<Stage width={size} height={size}>
<Layer
clipFunc={(ctx) =>
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2)
}
>
<Circle x={size / 2} y={size / 2} radius={size / 2} fill="black" />
<Circle x={joyX} y={joyY} radius={size / 4} fill="white" />
</Layer>
</Stage>
</div>
);
}
}
这段代码有点讨厌,因为它必须计算光标相对于舞台的位置,但我试图让它尽可能简单,而且它似乎工作得很好。舞台需要包裹在一个相同大小的 div 中,以便能够使用 getBoundingClientRect 函数来计算鼠标的相对位置。我还必须将我的 React 组件从函数组件更改为类组件,因为我需要常量回调函数引用,以便在释放鼠标后可以正确地取消注册。
我相信如果在鼠标按下时包装 div 的位置发生变化(从滚动或其他原因),这仍然会失败,因为它只计算初始 mousedown 事件的偏移量。这在我的应用程序中不是问题,但如果这会影响您的应用程序,请注意。

关于javascript - Konva 继续在舞台外跟踪鼠标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63159928/

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