Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Konva继续跟踪舞台外的鼠标_Javascript_Html_Reactjs_Konvajs_React Konva - Fatal编程技术网

Javascript Konva继续跟踪舞台外的鼠标

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

我正在尝试使用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>
  );
}
import React,{useState,useContext}来自“React”;
从“react konva”导入{Stage,Layer,Circle};
导出默认功能操纵杆(道具){
常量{size}=props;
const[x,setX]=useState(0);
const[y,setY]=useState(0);
const[down,setDown]=使用状态(false);
常数x=向下?x:大小/2;
const joyY=向下?y:尺寸/2;
返回(
{
setX(ev.evt.layerX);
setY(ev.evt.layerY);
}}
onMouseDown={(ev)=>setDown(true)}
onMouseUp={(ev)=>setDown(false)}
>
);
}

因此,我想知道的是,我可以扩展它的最简单和最干净的方式是什么,以便在鼠标离开舞台时仍能跟踪鼠标?

根据@VanquishedWombat的建议,从中获得灵感,我想出了以下代码

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>
    );
  }
}
功能偏移量(el){
var rect=el.getBoundingClientRect(),
scrollLeft=window.pageXOffset | | document.documentElement.scrollLeft,
scrollTop=window.pageYOffset | | document.documentElement.scrollTop;
返回{
顶部:rect.top+滚动顶部,
左:rect.left+scrollLeft,
};
}
导出默认类。组件{
建造师(道具){
超级(道具);
此.state={
下跌:0,,
x:0,,
y:0,
偏移量:{top:0,left:0},
};
this.handleMouseMove=this.handleMouseMove.bind(this);
this.handleMouseUp=this.handleMouseUp.bind(this);
}
更新位置(ev,o){
const{size}=this.props;
const offset=o | | this.state.offset;
设x=ev.clientX-offset.left;
设y=ev.clientY-offset.top;
设右=(x/尺寸-0.5)*2;
松弛=(y/尺寸-0.5)*-2;
常量mag=Math.sqrt(右*右+上*上);
const newMag=数学最小值(mag,1);
右=(右/mag)*新mag;
上升=(上升/上升)*新上升;
x=(1+右)*(大小/2);
y=(1-向上)*(尺寸/2);
这个.setState({x,y});
}
手推式移动(ev){
本次更新位置(ev);
}
手推车(ev){
document.removeEventListener(“mousemove”,this.handleMouseMove);
document.removeEventListener(“mouseup”,this.handleMouseUp);
this.setState({down:false});
}
render(){
常数{x,y,down}=this.state;
const{size}=this.props;
常数x=向下?x:大小/2;
const joyY=向下?y:尺寸/2;
返回(
{
常数o=偏移量(ev.currentTarget);
this.setState({offset:o,down:true});
此更新位置(ev,o);
document.addEventListener(“mousemove”,this.handleMouseMove);
文件。添加的列表(“鼠标”,此为。handleMouseUp);
}}
样式={{宽度:大小,高度:大小}
>
ctx.arc(大小/2,大小/2,大小/2,0,数学PI*2)
}
>
);
}
}
这段代码有点令人讨厌,因为它必须计算光标相对于舞台的位置,但我已尝试使其尽可能简单,并且它似乎工作得相当好。stage需要包装在相同大小的div中才能使用getBoundingClientRect函数,该函数允许计算相对鼠标位置。我还必须将React组件从一个函数组件更改为一个类组件,因为我需要常量回调函数引用,以便在释放鼠标后可以正确地注销它们


我相信,如果鼠标按下时包装div的位置发生变化(从滚动或其他方式),这仍然会失败,因为它只计算初始mousedown事件时的偏移量。这在我的应用程序中不是问题,但如果这会影响到你的应用程序,请注意。

最终所有内容都在浏览器文档中,因此你可以移动侦听器,使其在最高级别上进行侦听,也许?@VanquishedWombat我可以,但如果尝试并计算鼠标相对于Konva元素的位置,将会变得非常糟糕,或者有一个简单的方法吗?不完全相同,但非常相似:@VanquishedWombat thanksNice work。出于兴趣,如果画布被缩放,会有任何问题吗?它可能不是你的用例,它可能不是一个问题-我只是一直认为缩放是一个潜在的问题,因为画布阶段可以与周围的文档隔离。请注意其他人-如果你使用这个代码,发现它在移植时不起作用,请注意您可能拥有的任何cancelbubble样式代码,这些代码会阻止事件沿树向上移动到文档级别。@VanquishedWombat缩放可能会导致一些痛苦,因为屏幕坐标被假定为与画布中的坐标具有相同的比例。它很可能需要进行一些修改以支持缩放。