在本机JavaScript中在画布中获取鼠标位置的最现代方法

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

方法1:

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

方法2:

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

方法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 };
};

方法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;

等等.

我很好奇的是哪种方法在浏览器支持方面最为现代,并且在画布中获得鼠标位置方便.或者是那些具有边际影响的东西,上述任何一种都是不错的选择? (是的,我意识到上面的代码并不完全相同)

解决方法:

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

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;  
}

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

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

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>

那么,最好的建议?,除非你想要完成所有这些步骤,否则总是将画布的边框和填充为0.如果边框和填充为零,则可以在下面的示例中对contentDisplayWidth和contentDisplayHeight使用canvas.clientWidth和canvas.clientHeight,并且所有nonContextXXX值都将变为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>
上一篇:linux – 来自4种不同鼠标的输入


下一篇:Oracle VM VirtualBox安装Centos8后配置静态ip,使用xshell6的ssh连接方便操作,下载docker