我想做一个小绘画应用程序使用画布。所以我需要找到鼠标在画布上的位置。


当前回答

对于那些为移动设备和/或笔记本电脑/触摸屏显示器开发常规网站或PWAs(渐进式Web应用程序)的人来说,你可能已经登陆这里了,因为你可能已经习惯了鼠标事件,对触摸事件的痛苦体验还不熟悉……耶!

只有3条规则:

在鼠标移动或触摸移动事件期间尽可能少做。 在鼠标按下或触摸启动事件期间尽可能多地进行操作。 取消传播并防止触摸事件的默认值,以防止鼠标事件也在混合设备上触发。

不用说,触摸事件更复杂,因为可以有多个触摸事件,它们比鼠标事件更灵活(复杂)。这里我只讲一个触碰。是的,我很懒,但这是最常见的触摸方式。

var posTop; var posLeft; function handleMouseDown(evt) { var e = evt || window.event; // Because Firefox, etc. posTop = e.target.offsetTop; posLeft = e.target.offsetLeft; e.target.style.background = "red"; // The statement above would be better handled by CSS // but it's just an example of a generic visible indicator. } function handleMouseMove(evt) { var e = evt || window.event; var x = e.offsetX; // Wonderfully var y = e.offsetY; // Simple! e.target.innerHTML = "Mouse: " + x + ", " + y; if (posTop) e.target.innerHTML += "<br>" + (x + posLeft) + ", " + (y + posTop); } function handleMouseOut(evt) { var e = evt || window.event; e.target.innerHTML = ""; } function handleMouseUp(evt) { var e = evt || window.event; e.target.style.background = "yellow"; } function handleTouchStart(evt) { var e = evt || window.event; var rect = e.target.getBoundingClientRect(); posTop = rect.top; posLeft = rect.left; e.target.style.background = "green"; e.preventDefault(); // Unnecessary if using Vue.js e.stopPropagation(); // Same deal here } function handleTouchMove(evt) { var e = evt || window.event; var pageX = e.touches[0].clientX; // Touches are page-relative var pageY = e.touches[0].clientY; // not target-relative var x = pageX - posLeft; var y = pageY - posTop; e.target.innerHTML = "Touch: " + x + ", " + y; e.target.innerHTML += "<br>" + pageX + ", " + pageY; e.preventDefault(); e.stopPropagation(); } function handleTouchEnd(evt) { var e = evt || window.event; e.target.style.background = "yellow"; // Yes, I'm being lazy and doing the same as mouseout here // but obviously you could do something different if needed. e.preventDefault(); e.stopPropagation(); } div { background: yellow; height: 100px; left: 50px; position: absolute; top: 80px; user-select: none; /* Disable text selection */ -ms-user-select: none; width: 100px; } <div onmousedown="handleMouseDown()" onmousemove="handleMouseMove()" onmouseout="handleMouseOut()" onmouseup="handleMouseUp()" ontouchstart="handleTouchStart()" ontouchmove="handleTouchMove()" ontouchend="handleTouchEnd()"> </div> Move over box for coordinates relative to top left of box.<br> Hold mouse down or touch to change color.<br> Drag to turn on coordinates relative to top left of page.

更喜欢使用Vue.js?我做!然后你的HTML看起来是这样的:

<div @mousedown="handleMouseDown"
     @mousemove="handleMouseMove"
     @mouseup="handleMouseUp"
     @touchstart.stop.prevent="handleTouchStart"
     @touchmove.stop.prevent="handleTouchMove"
     @touchend.stop.prevent="handleTouchEnd">

其他回答

canvas.onmousedown = function(e) {
    pos_left = e.pageX - e.currentTarget.offsetLeft;
    pos_top = e.pageY - e.currentTarget.offsetTop;
    console.log(pos_left, pos_top)
}

HTMLElement.offsetLeft

HTMLElement。offsetLeft read-only属性返回当前元素的左上角在HTMLElement中向左偏移的像素数。offsetParent节点。

对于块级元素,offsetTop, offsetLeft, offsetWidth和offsetHeight描述了一个元素相对于offsetParent的边界框。

However, for inline-level elements (such as span) that can wrap from one line to the next, offsetTop and offsetLeft describe the positions of the first border box (use Element.getClientRects() to get its width and height), while offsetWidth and offsetHeight describe the dimensions of the bounding border box (use Element.getBoundingClientRect() to get its position). Therefore, a box with the left, top, width and height of offsetLeft, offsetTop, offsetWidth and offsetHeight will not be a bounding box for a span with wrapped text.

HTMLElement.offsetTop

HTMLElement。offsetTop只读属性返回当前元素相对于offsetParent节点顶部的距离。

MouseEvent.pageX

pageX只读属性返回事件相对于整个文档的X(水平)坐标(像素)。此属性考虑页面的任何水平滚动。

MouseEvent.pageY

鼠标事件。pageY只读属性返回事件相对于整个文档的Y(垂直)像素坐标。此属性考虑页面的任何垂直滚动。

如需进一步解释,请参阅Mozilla开发者网络:

https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop

在我看来,上述答案都不令人满意,所以我用的是:

// Cross-browser AddEventListener
function ael(e, n, h){
    if( e.addEventListener ){
        e.addEventListener(n, h, true);
    }else{
        e.attachEvent('on'+n, h);
    }
}

var touch = 'ontouchstart' in document.documentElement; // true if touch device
var mx, my; // always has current mouse position IN WINDOW

if(touch){
    ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY} );
}else{
    ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY} );
}

// local mouse X,Y position in element
function showLocalPos(e){
    document.title = (mx - e.getBoundingClientRect().left)
        + 'x'
        + Math.round(my - e.getBoundingClientRect().top);
}

如果你需要知道页面当前的Y轴滚动位置:

var yscroll = window.pageYOffset
        || (document.documentElement && document.documentElement.scrollTop)
        || document.body.scrollTop; // scroll Y position in page

因为我没有找到一个解决方案,可以帮助你得到它,如果你把它附加到一个父母元素,你有一个例如选择。

这就是我所做的:

let positions = {
  x: event.pageX,
  y: event.pageY - event.currentTarget.getBoundingClientRect().top + event.currentTarget.offsetTop
}

你可以买到它

var element = document.getElementById(canvasId);
element.onmousemove = function(e) {
    var xCoor = e.clientX;
    var yCoor = e.clientY;
}

我实现了另一个解决方案,我认为很简单,所以我想和你们分享一下。

所以,对我来说,问题是拖动的div将跳转到0,0的鼠标光标。所以我需要捕捉鼠标在div上的位置来调整div的新位置。

我读取的divs PageX和PageY,并设置的顶部和左侧的根据,然后得到的值,调整坐标,以保持光标在div的初始位置,我使用onDragStart监听器和存储e.nativeEvent.layerX和e.nativeEvent.layerY,只有在初始触发器给你的鼠标位置在可拖动的div。

示例代码:

 onDrag={(e) => {
          let newCoords;
          newCoords = { x: e.pageX - this.state.correctionX, y: e.pageY - this.state.correctionY };
          this.props.onDrag(newCoords, e, item.id);
        }}
        onDragStart={
          (e) => {
            this.setState({
              correctionX: e.nativeEvent.layerX,
              correctionY: e.nativeEvent.layerY,
            });
          }

我希望这能帮助那些和我经历过同样问题的人:)