使用原生 JavaScript 在画布中获取鼠标位置的最现代方法 [英] Most modern method of getting mouse position within a canvas in native JavaScript

查看:17
本文介绍了使用原生 JavaScript 在画布中获取鼠标位置的最现代方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我知道这个问题已经被问过很多次了.但是,提供的答案并不一致,并且使用了多种方法来获取鼠标位置.几个例子:

方法一:

canvas.onmousemove = function (event) {//这个对象是指画布对象鼠标 = {x: event.pageX - this.offsetLeft,y: event.pageY - this.offsetTop}}

方法二:

function getMousePos(canvas, evt) {var rect = canvas.getBoundingClientRect();返回 {x: evt.clientX - rect.left,y: evt.clientY - rect.top};}

方法三:

var findPos = function(obj) {var curleft = curtop = 0;如果(obj.offsetParent){做 {curleft += obj.offsetLeft;curtop += obj.offsetTop;} while (obj = obj.offsetParent);}返回 { x : curleft, y : curtop };};

方法四:

var x;各不相同;如果(e.pageX || e.pageY){x = e.pageX;y = e.pageY;}别的 {x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;}x -= gCanvasElement.offsetLeft;y -= gCanvasElement.offsetTop;

等等.

我很好奇的是,就浏览器支持和在画布中获取鼠标位置的便利性而言,哪种方法是最现代的.或者是那些影响很小的东西,以上任何一个都是不错的选择?(是的,我意识到上面的代码并不完全相同)

解决方案

这似乎有效.我想这基本上就是K3N所说的.

function getRelativeMousePosition(event, target) {目标 = 目标 ||事件目标;var rect = target.getBoundingClientRect();返回 {x: event.clientX - rect.left,y: event.clientY - rect.top,}}函数 getStyleSize(style, propName) {返回 parseInt(style.getPropertyValue(propName));}//假设 target 或 event.target 是画布函数 getCanvasRelativeMousePosition(事件,目标){目标 = 目标 ||事件目标;var pos = getRelativeMousePosition(event, target);//如果填充为 0,您可以删除它.//我希望这总是返回px"var style = window.getComputedStyle(target);var nonContentWidthLeft = getStyleSize(style, "padding-left") +getStyleSize(style, "border-left");var nonContentWidthTop = getStyleSize(style, "padding-top") +getStyleSize(style, "border-top");var nonContentWidthRight = getStyleSize(style, "padding-right") +getStyleSize(style, "border-right");var nonContentWidthBottom = getStyleSize(style, "padding-bottom") +getStyleSize(style, "border-bottom");var rect = target.getBoundingClientRect();var contentDisplayWidth = rect.width - nonContentWidthLeft - nonContentWidthRight;var contentDisplayHeight = rect.height - nonContentWidthTop - nonContentWidthBottom;pos.x = (pos.x - nonContentWidthLeft) * target.width/contentDisplayWidth;pos.y = (pos.y - nonContentWidthTop) * target.height/contentDisplayHeight;返回位置;}

如果您运行下面的示例并将鼠标移到蓝色区域上,它将在光标下绘制.边框(黑色)、填充(红色)、宽度和高度都设置为非像素值.蓝色区域是实际的画布像素.画布的分辨率未设置,因此无论拉伸到多大,它都是 300x150.

将鼠标移到蓝色区域上,它会在其下方绘制一个像素.

var canvas = document.querySelector("canvas");var ctx = canvas.getContext("2d");函数 clearCanvas() {ctx.fillStyle = "蓝色";ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);}清除画布();var posNode = document.createTextNode("");document.querySelector("#position").appendChild(posNode);函数 getRelativeMousePosition(事件,目标){目标 = 目标 ||事件目标;var rect = target.getBoundingClientRect();返回 {x: event.clientX - rect.left,y: event.clientY - rect.top,}}函数 getStyleSize(style, propName) {返回 parseInt(style.getPropertyValue(propName));}//假设 target 或 event.target 是画布函数 getCanvasRelativeMousePosition(事件,目标){目标 = 目标 ||事件目标;var pos = getRelativeMousePosition(event, target);//如果填充为 0,您可以删除它.//我希望这总是返回px"var style = window.getComputedStyle(target);var nonContentWidthLeft = getStyleSize(style, "padding-left") +getStyleSize(style, "border-left");var nonContentWidthTop = getStyleSize(style, "padding-top") +getStyleSize(style, "border-top");var nonContentWidthRight = getStyleSize(style, "padding-right") +getStyleSize(style, "border-right");var nonContentWidthBottom = getStyleSize(style, "padding-bottom") +getStyleSize(style, "border-bottom");var rect = target.getBoundingClientRect();var contentDisplayWidth = rect.width - nonContentWidthLeft - nonContentWidthRight;var contentDisplayHeight = rect.height - nonContentWidthTop - nonContentWidthBottom;pos.x = (pos.x - nonContentWidthLeft) * target.width/contentDisplayWidth;pos.y = (pos.y - nonContentWidthTop) * target.height/contentDisplayHeight;返回位置;}函数handleMouseEvent(事件){var pos = getCanvasRelativeMousePosition(event);posNode.nodeValue = JSON.stringify(pos, null, 2);ctx.fillStyle = "白色";ctx.fillRect(pos.x | 0, pos.y | 0, 1, 1);}canvas.addEventListener('mousemove', handleMouseEvent);canvas.addEventListener('click', clearCanvas);

* {box-sizing: 边框框;光标:十字准线;}html,正文{宽度:100%;高度:100%;白颜色;}.外{背景颜色:绿色;显示:弹性;显示:-webkit-flex;-webkit-justify-content:中心;-webkit-align-content:居中;-webkit-align-items:居中;对齐内容:居中;对齐内容:居中;对齐项目:居中;宽度:100%;高度:100%;}.内{边框:1em 纯黑色;背景颜色:红色;填充:1.5em;宽度:90%;高度:90%;}#位置 {位置:绝对;左:1em;顶部:1em;z-索引:2;指针事件:无;}

<canvas class="inner"></canvas>

<pre id="position"></pre>

那么,最好的建议是?,除非您想完成所有这些步骤,否则始终将画布的边框和内边距设为 0.如果边框和内边距为零,你可以在 contentDisplayWidthcontentDisplayHeight 中使用 canvas.clientWidthcanvas.clientHeight下面的示例和所有 nonContextXXX 值都变为 0.

function getRelativeMousePosition(event, target) {目标 = 目标 ||事件目标;var rect = target.getBoundingClientRect();返回 {x: event.clientX - rect.left,y: event.clientY - rect.top,}}//假设 target 或 event.target 是画布函数 getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {目标 = 目标 ||事件目标;var pos = getRelativeMousePosition(event, target);pos.x = pos.x * target.width/canvas.clientWidth;pos.y = pos.y * target.height/canvas.clientHeight;返回位置;}

var canvas = document.querySelector("canvas");var ctx = canvas.getContext("2d");函数 clearCanvas() {ctx.fillStyle = "蓝色";ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);}清除画布();var posNode = document.createTextNode("");document.querySelector("#position").appendChild(posNode);函数 getRelativeMousePosition(事件,目标){目标 = 目标 ||事件目标;var rect = target.getBoundingClientRect();返回 {x: event.clientX - rect.left,y: event.clientY - rect.top,}}//假设 target 或 event.target 是画布函数 getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {目标 = 目标 ||事件目标;var pos = getRelativeMousePosition(event, target);pos.x = pos.x * target.width/canvas.clientWidth;pos.y = pos.y * target.height/canvas.clientHeight;返回位置;}函数handleMouseEvent(事件){var pos = getNoPaddingNoBorderCanvasRelativeMousePosition(event);posNode.nodeValue = JSON.stringify(pos, null, 2);ctx.fillStyle = "白色";ctx.fillRect(pos.x | 0, pos.y | 0, 1, 1);}canvas.addEventListener('mousemove', handleMouseEvent);canvas.addEventListener('click', clearCanvas);

* {box-sizing: 边框框;光标:十字准线;}html,正文{宽度:100%;高度:100%;白颜色;}.外{背景颜色:绿色;显示:弹性;显示:-webkit-flex;-webkit-justify-content:中心;-webkit-align-content:居中;-webkit-align-items:居中;对齐内容:居中;对齐内容:居中;对齐项目:居中;宽度:100%;高度:100%;}.内{背景颜色:红色;宽度:90%;高度:80%;显示:块;}#位置 {位置:绝对;左:1em;顶部:1em;z-索引:2;指针事件:无;}

<canvas class="inner"></canvas>

<pre id="position"></pre>

First, I know this question has been asked many times. However, the answers provided are not consistent and a variety of methods are used to get the mouse position. A few examples:

Method 1:

canvas.onmousemove = function (event) { // this  object refers to canvas object  
    Mouse = {
        x: event.pageX - this.offsetLeft,
        y: event.pageY - this.offsetTop
    }
}

Method 2:

function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
    };
}

Method 3:

var findPos = function(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) { 
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop; 
        } while (obj = obj.offsetParent);
    }
    return { x : curleft, y : curtop };
};

Method 4:

var x;
var y;
if (e.pageX || e.pageY)
{
    x = e.pageX;
    y = e.pageY;
}
else {
    x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
    y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 
} 
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;

and so on.

What I am curious is which method is the most modern in terms of browser support and convenience in getting the mouse position in a canvas. Or is it those kind of things that have marginal impact and any of the above is a good choice? (Yes I realize the codes above are not exactly the same)

解决方案

This seems to work. I think this is basically what K3N said.

function getRelativeMousePosition(event, target) {
  target = target || event.target;
  var rect = target.getBoundingClientRect();

  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  }
}

function getStyleSize(style, propName) {
  return parseInt(style.getPropertyValue(propName));
}

// assumes target or event.target is canvas
function getCanvasRelativeMousePosition(event, target) {
  target = target || event.target;
  var pos = getRelativeMousePosition(event, target);

  // you can remove this if padding is 0. 
  // I hope this always returns "px"
  var style = window.getComputedStyle(target);
  var nonContentWidthLeft   = getStyleSize(style, "padding-left") +
                              getStyleSize(style, "border-left");
  var nonContentWidthTop    = getStyleSize(style, "padding-top") +
                              getStyleSize(style, "border-top");
  var nonContentWidthRight  = getStyleSize(style, "padding-right") +
                              getStyleSize(style, "border-right");
  var nonContentWidthBottom = getStyleSize(style, "padding-bottom") +
                              getStyleSize(style, "border-bottom");

  var rect = target.getBoundingClientRect();
  var contentDisplayWidth  = rect.width  - nonContentWidthLeft - nonContentWidthRight;
  var contentDisplayHeight = rect.height - nonContentWidthTop  - nonContentWidthBottom;

  pos.x = (pos.x - nonContentWidthLeft) * target.width  / contentDisplayWidth;
  pos.y = (pos.y - nonContentWidthTop ) * target.height / contentDisplayHeight;

  return pos;  
}

If you run the sample below and move the mouse over the blue area it will draw under the cursor. The border (black), padding (red), width, and height are all set to non-pixel values values. The blue area is the actual canvas pixels. The canvas's resolution is not set so it's 300x150 regardless of the size it's stretched to.

Move the mouse over the blue area and it will draw a pixel under it.

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");

function clearCanvas() {
  ctx.fillStyle = "blue";
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
clearCanvas();

var posNode = document.createTextNode("");
document.querySelector("#position").appendChild(posNode);

function getRelativeMousePosition(event, target) {
  target = target || event.target;
  var rect = target.getBoundingClientRect();

  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  }
}

function getStyleSize(style, propName) {
  return parseInt(style.getPropertyValue(propName));
}

// assumes target or event.target is canvas
function getCanvasRelativeMousePosition(event, target) {
  target = target || event.target;
  var pos = getRelativeMousePosition(event, target);
  
  // you can remove this if padding is 0. 
  // I hope this always returns "px"
  var style = window.getComputedStyle(target);
  var nonContentWidthLeft   = getStyleSize(style, "padding-left") +
                              getStyleSize(style, "border-left");
  var nonContentWidthTop    = getStyleSize(style, "padding-top") +
                              getStyleSize(style, "border-top");
  var nonContentWidthRight  = getStyleSize(style, "padding-right") +
                              getStyleSize(style, "border-right");
  var nonContentWidthBottom = getStyleSize(style, "padding-bottom") +
                              getStyleSize(style, "border-bottom");
  
  var rect = target.getBoundingClientRect();
  var contentDisplayWidth  = rect.width  - nonContentWidthLeft - nonContentWidthRight;
  var contentDisplayHeight = rect.height - nonContentWidthTop  - nonContentWidthBottom;

  pos.x = (pos.x - nonContentWidthLeft) * target.width  / contentDisplayWidth;
  pos.y = (pos.y - nonContentWidthTop ) * target.height / contentDisplayHeight;
  
  return pos;  
}

  
function handleMouseEvent(event) {
  var pos = getCanvasRelativeMousePosition(event);
  posNode.nodeValue = JSON.stringify(pos, null, 2);
  ctx.fillStyle = "white";
  ctx.fillRect(pos.x | 0, pos.y | 0, 1, 1);
}

canvas.addEventListener('mousemove', handleMouseEvent);
canvas.addEventListener('click', clearCanvas);

* {
  box-sizing: border-box;
  cursor: crosshair;
}
html, body {
  width: 100%;
  height: 100%;
  color: white;
}
.outer {
  background-color: green;
  display: flex;
  display: -webkit-flex;
  
  -webkit-justify-content: center;
  -webkit-align-content: center;
  -webkit-align-items: center;

  justify-content: center;
  align-content: center;
  align-items: center;  
  
  width: 100%;
  height: 100%;
}
.inner {
  border: 1em solid black;
  background-color: red;
  padding: 1.5em;
  width: 90%;
  height: 90%;
}
#position {
  position: absolute;
  left: 1em;
  top: 1em;
  z-index: 2;
  pointer-events: none;
}

<div class="outer">
  <canvas class="inner"></canvas>
</div>
<pre id="position"></pre>

So, best advice?, always have the border and padding of a canvas be 0 if unless you want to go through all these steps. If the border and padding are zero you can just canvas.clientWidth and canvas.clientHeight for contentDisplayWidth and contentDisplayHeight in the example below and all the nonContextXXX values become 0.

function getRelativeMousePosition(event, target) {
  target = target || event.target;
  var rect = target.getBoundingClientRect();

  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  }
}

// assumes target or event.target is canvas
function getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {
  target = target || event.target;
  var pos = getRelativeMousePosition(event, target);

  pos.x = pos.x * target.width  / canvas.clientWidth;
  pos.y = pos.y * target.height / canvas.clientHeight;

  return pos;  
}

var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");

function clearCanvas() {
  ctx.fillStyle = "blue";
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
clearCanvas();

var posNode = document.createTextNode("");
document.querySelector("#position").appendChild(posNode);

function getRelativeMousePosition(event, target) {
  target = target || event.target;
  var rect = target.getBoundingClientRect();

  return {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  }
}

// assumes target or event.target is canvas
function getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {
  target = target || event.target;
  var pos = getRelativeMousePosition(event, target);
  
  pos.x = pos.x * target.width  / canvas.clientWidth;
  pos.y = pos.y * target.height / canvas.clientHeight;
  
  return pos;  
}

  
function handleMouseEvent(event) {
  var pos = getNoPaddingNoBorderCanvasRelativeMousePosition(event);
  posNode.nodeValue = JSON.stringify(pos, null, 2);
  ctx.fillStyle = "white";
  ctx.fillRect(pos.x | 0, pos.y | 0, 1, 1);
}

canvas.addEventListener('mousemove', handleMouseEvent);
canvas.addEventListener('click', clearCanvas);

* {
  box-sizing: border-box;
  cursor: crosshair;
}
html, body {
  width: 100%;
  height: 100%;
  color: white;
}
.outer {
  background-color: green;
  display: flex;
  display: -webkit-flex;
  
  -webkit-justify-content: center;
  -webkit-align-content: center;
  -webkit-align-items: center;

  justify-content: center;
  align-content: center;
  align-items: center;  
  
  width: 100%;
  height: 100%;
}
.inner {
  background-color: red;
  width: 90%;
  height: 80%;
  display: block;
}
#position {
  position: absolute;
  left: 1em;
  top: 1em;
  z-index: 2;
  pointer-events: none;
}

<div class="outer">
  <canvas class="inner"></canvas>
</div>
<pre id="position"></pre>

这篇关于使用原生 JavaScript 在画布中获取鼠标位置的最现代方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆