Javascript 如何获取鼠标单击画布元素时的坐标?

Javascript 如何获取鼠标单击画布元素时的坐标?,javascript,canvas,Javascript,Canvas,向画布元素添加click事件处理程序的最简单方法是什么,该元素将返回相对于画布元素的click的x和y坐标 不需要传统浏览器兼容性,Safari、Opera和Firefox就可以了。嘿,这在dojo中,只是因为我已经为一个项目准备了代码 如何将其转换回非dojo vanilla JavaScript应该是相当明显的 function onMouseClick(e) { var x = e.clientX; var y = e.clientY; } var ca

向画布元素添加click事件处理程序的最简单方法是什么,该元素将返回相对于画布元素的click的x和y坐标


不需要传统浏览器兼容性,Safari、Opera和Firefox就可以了。

嘿,这在dojo中,只是因为我已经为一个项目准备了代码

如何将其转换回非dojo vanilla JavaScript应该是相当明显的

  function onMouseClick(e) {
      var x = e.clientX;
      var y = e.clientY;
  }
  var canvas = dojo.byId(canvasId);
  dojo.connect(canvas,"click",onMouseClick);

希望有帮助

进行坐标转换时要小心;单击事件中返回了多个非跨浏览器值。如果浏览器窗口在Firefox 3.5和Chrome 3.0中进行了滚动验证,仅使用clientX和clientY是不够的

文章提供了一个更正确的函数,可以使用pageX或pageY,也可以使用clientX和document.body.scrollLeft以及clientY和document.body.scrollTop的组合来计算相对于文档原点的单击坐标

更新:此外,offsetLeft和offsetTop与元素的填充大小有关,而不是与内部大小有关。应用padding:style的画布不会将其内容区域的左上角报告为offsetLeft。这个问题有多种解决办法;最简单的方法可能是清除画布本身上的所有边框、填充等样式,而是将它们应用到包含画布的框中。

Edit 2018:这个答案非常古老,它使用不再需要的旧浏览器检查,因为clientX和clientY属性在所有当前浏览器中都起作用。您可能希望查看一个更简单、更新的解决方案

function myGetPxStyle(e,p)
{
    var r=window.getComputedStyle?window.getComputedStyle(e,null)[p]:"";
    return parseFloat(r);
}

function myGetClick=function(ev)
{
    // {x:ev.layerX,y:ev.layerY} doesn't work when zooming with mac chrome 27
    // {x:ev.clientX,y:ev.clientY} not supported by mac firefox 21
    // document.body.scrollLeft and document.body.scrollTop seem required when scrolling on iPad
    // html is not an offsetParent of body but can have non null offsetX or offsetY (case of wordpress 3.5.1 admin pages for instance)
    // html.offsetX and html.offsetY don't work with mac firefox 21

    var offsetX=0,offsetY=0,e=this,x,y;
    var htmls=document.getElementsByTagName("html"),html=(htmls?htmls[0]:0);

    do
    {
        offsetX+=e.offsetLeft-e.scrollLeft;
        offsetY+=e.offsetTop-e.scrollTop;
    } while (e=e.offsetParent);

    if (html)
    {
        offsetX+=myGetPxStyle(html,"marginLeft");
        offsetY+=myGetPxStyle(html,"marginTop");
    }

    x=ev.pageX-offsetX-document.body.scrollLeft;
    y=ev.pageY-offsetY-document.body.scrollTop;
    return {x:x,y:y};
}
const prevPos = {
  x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y:  Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
const currentPos = {
  x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
原始答复: 正如我在当时找到的一篇文章中所描述的,但现在已经不存在了:

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;
对我来说效果非常好。

根据fresh的说法,clientX和clientY方法在所有主要浏览器中都受支持。 好了,这是一段很好的工作代码,它在带有滚动条的页面上的滚动div中工作:

function getCursorPosition(canvas, event) {
var x, y;

canoffset = $(canvas).offset();
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - Math.floor(canoffset.left);
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - Math.floor(canoffset.top) + 1;

return [x,y];
}

这还需要$canvas.offset。

我做了一个完整的演示,可以在每个浏览器中使用此问题解决方案的完整源代码:。要尝试演示,请复制代码并将其粘贴到文本编辑器中。然后将其另存为example.html,最后用浏览器打开文件。

应改用Update 5/5/16:,因为它既简单又可靠

由于画布并不总是相对于整个页面进行样式设置,因此canvas.offsetLeft/Top并不总是返回您需要的内容。它将返回相对于offsetParent元素偏移的像素数,offsetParent元素可以类似于包含画布的div元素,并应用了position:relative样式。为了说明这一点,您需要循环通过offsetParents链,从canvas元素本身开始。这段代码非常适合我,在Firefox和Safari中进行了测试,但应该适合所有人

function relMouseCoords(event){
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do{
        totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;
        totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;
    }
    while(currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
最后一行便于获取相对于画布元素的鼠标坐标。获得有用坐标所需的只是

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;

在Prototype中,使用cumulativeOffset进行上面Ryan Artecona提到的递归求和


下面是对具有可变%宽度的画布进行的一个小修改:

 HTMLCanvasElement.prototype.relMouseCoords = function (event) {
    var totalOffsetX = 0;
    var totalOffsetY = 0;
    var canvasX = 0;
    var canvasY = 0;
    var currentElement = this;

    do {
        totalOffsetX += currentElement.offsetLeft;
        totalOffsetY += currentElement.offsetTop;
    }
    while (currentElement = currentElement.offsetParent)

    canvasX = event.pageX - totalOffsetX;
    canvasY = event.pageY - totalOffsetY;

    // Fix for variable canvas width
    canvasX = Math.round( canvasX * (this.width / this.offsetWidth) );
    canvasY = Math.round( canvasY * (this.height / this.offsetHeight) );

    return {x:canvasX, y:canvasY}
}

现代浏览器现在可以为您处理此问题。Chrome、IE9和Firefox都支持这样的offsetX/Y,从点击处理程序传入事件

function getRelativeCoords(event) {
    return { x: event.offsetX, y: event.offsetY };
}
大多数现代浏览器也支持layerX/Y,但是Chrome和IE使用layerX/Y表示页面点击的绝对偏移量,包括边距、填充等。在Firefox中,layerX/Y和offsetX/Y是等效的,但偏移量以前不存在。因此,为了与稍旧的浏览器兼容,您可以使用:

function getRelativeCoords(event) {
    return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}

下面是对上述Ryan Artecona解决方案的一些修改

function myGetPxStyle(e,p)
{
    var r=window.getComputedStyle?window.getComputedStyle(e,null)[p]:"";
    return parseFloat(r);
}

function myGetClick=function(ev)
{
    // {x:ev.layerX,y:ev.layerY} doesn't work when zooming with mac chrome 27
    // {x:ev.clientX,y:ev.clientY} not supported by mac firefox 21
    // document.body.scrollLeft and document.body.scrollTop seem required when scrolling on iPad
    // html is not an offsetParent of body but can have non null offsetX or offsetY (case of wordpress 3.5.1 admin pages for instance)
    // html.offsetX and html.offsetY don't work with mac firefox 21

    var offsetX=0,offsetY=0,e=this,x,y;
    var htmls=document.getElementsByTagName("html"),html=(htmls?htmls[0]:0);

    do
    {
        offsetX+=e.offsetLeft-e.scrollLeft;
        offsetY+=e.offsetTop-e.scrollTop;
    } while (e=e.offsetParent);

    if (html)
    {
        offsetX+=myGetPxStyle(html,"marginLeft");
        offsetY+=myGetPxStyle(html,"marginTop");
    }

    x=ev.pageX-offsetX-document.body.scrollLeft;
    y=ev.pageY-offsetY-document.body.scrollTop;
    return {x:x,y:y};
}

这是一个非常好的教程-

希望这有帮助

我推荐这个链接-


如果您喜欢简单,但仍然需要跨浏览器功能,我发现这个解决方案最适合我。这是@Aldekein解决方案的简化,但没有jQuery

你可以这样做:

var canvas = yourCanvasElement;
var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2;
var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;
这将为您提供鼠标指针的准确位置。

请参阅的演示


首先,正如其他人所说,您需要一个函数来获取。这里有一个比本页其他一些方法更优雅的方法。您可以将其传递给任何元素并获取其在文档中的位置:

function findPos(obj) {
    var curleft = 0, curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
    return undefined;
}
现在计算光标相对于该点的当前位置:

$('#canvas').mousemove(function(e) {
    var pos = findPos(this);
    var x = e.pageX - pos.x;
    var y = e.pageY - pos.y;
    var coordinateDisplay = "x=" + x + ", y=" + y;
    writeCoordinateDisplay(coordinateDisplay);
});
请注意,我已将通用findPos函数与事件处理代码分离。应该如此。我们应该努力使我们的职能只限于一项任务

offsetLeft和offsetTop的值是相对于offsetParent的,offsetParent可以是某个包装器div节点或其他任何对象。当没有元素包裹画布时,它们是相对于主体的,因此没有要减去的偏移量。这就是为什么我们需要先确定画布的位置 我们可以做任何其他事情

类似地,e.pageX和e.pageY给出了光标相对于文档的位置。这就是为什么我们从这些值中减去画布的偏移量,以得到真实位置

定位元素的另一种选择是直接使用e.layerX和e.layerY的值。由于两个原因,该方法不如上述方法可靠:

当事件未在定位元素内发生时,这些值也与整个文档相关 它们不是任何标准的一部分
我不确定所有这些答案的意义是什么,并且做了各种各样的事情

getBoundingClientRect方法设计用于处理任何元素的实际屏幕位置。这包括滚动,因此不需要像scrollTop这样的东西:

对视口区域或视图进行的滚动量 在计算 边框

正常图像 这封信已经贴在这里了。只要不涉及任意CSS规则,这是正确的

处理拉伸画布/图像 当图像像素宽度与其CSS宽度不匹配时,您需要对像素值应用一些比率:

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Recalculate mouse offsets to relative offsets
  x = event.clientX - left;
  y = event.clientY - top;
  //Also recalculate offsets of canvas is stretched
  var width = right - left;
  //I use this to reduce number of calculations for images that have normal size 
  if(this.width!=width) {
    var height = bottom - top;
    //changes coordinates by ratio
    x = x*(this.width/width);
    y = y*(this.height/height);
  } 
  //Return as an array
  return [x,y];
}
只要画布没有边框

处理CSS边框 如果画布有厚边框。实际上,您需要从边框中减去边框。这可以通过使用。这个

然后,函数会稍微长大:

/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/
HTMLCanvasElement.prototype.relativeCoords = function(event) {
  var x,y;
  //This is the current screen rectangle of canvas
  var rect = this.getBoundingClientRect();
  var top = rect.top;
  var bottom = rect.bottom;
  var left = rect.left;
  var right = rect.right;
  //Subtract border size
  // Get computed style
  var styling=getComputedStyle(this,null);
  // Turn the border widths in integers
  var topBorder=parseInt(styling.getPropertyValue('border-top-width'),10);
  var rightBorder=parseInt(styling.getPropertyValue('border-right-width'),10);
  var bottomBorder=parseInt(styling.getPropertyValue('border-bottom-width'),10);
  var leftBorder=parseInt(styling.getPropertyValue('border-left-width'),10);
  //Subtract border from rectangle
  left+=leftBorder;
  right-=rightBorder;
  top+=topBorder;
  bottom-=bottomBorder;
  //Proceed as usual
  ...
}
我想不出任何东西会混淆这个最终函数。看看你自己

笔记
如果您不喜欢修改本机原型,只需更改函数并使用canvas、event调用它,然后将其替换为canvas。

在2016年使用jQuery,要获得相对于画布的单击坐标,我会:

$(canvas).click(function(jqEvent) {
    var coords = {
        x: jqEvent.pageX - $(canvas).offset().left,
        y: jqEvent.pageY - $(canvas).offset().top
    };
});
这是因为无论滚动位置如何,画布偏移量和jqEvent.pageX/Y都是相对于文档的

请注意,如果画布已缩放,则这些坐标与画布逻辑坐标不同。要获得这些,您还需要执行以下操作:

ThreeJS r77

var x = event.offsetX == undefined ? event.layerX : event.offsetX;
var y = event.offsetY == undefined ? event.layerY : event.offsetY;

mouse2D.x = ( x / renderer.domElement.width ) * 2 - 1;
mouse2D.y = - ( y / renderer.domElement.height ) * 2 + 1;

在尝试了许多解决方案之后。这对我有用。可能会帮助其他人。从

这里有一个简化的解决方案,它不适用于边框/滚动:

function click(event) {
    const bound = event.target.getBoundingClientRect();

    const xMult = bound.width / can.width;
    const yMult = bound.height / can.height;

    return {
        x: Math.floor(event.offsetX / xMult),
        y: Math.floor(event.offsetY / yMult),
    };
}

所以这是一个简单但比表面上看起来更复杂的话题

首先,这里通常会有一些复杂的问题

如何获取元素相对鼠标坐标

如何获取2D画布API或WebGL的画布像素鼠标坐标

那么,答案是什么

如何获取元素相对鼠标坐标 对于所有元素,元素是否为画布获取元素相对鼠标坐标是相同的

对于如何获取画布相对鼠标坐标的问题,有两个简单的答案

简单答案1使用offsetX和offsetY 这个答案适用于Chrome、Firefox和Safari。与所有其他事件值不同,offsetX和offsetY将CSS转换考虑在内

offsetX和offsetY最大的问题是,从2019/05年起,它们在触摸屏上不存在,因此不能与iOS Safari一起使用。它们确实存在于Chrome和Firefox中的指针事件上,但Safari中不存在

另一个问题是事件必须在画布上。如果将它们放在其他元素或窗口上,则以后不能选择画布作为参考点

简单答案2使用clientX、clientY和canvas.getBoundingClientRect 如果您不关心CSS转换,下一个最简单的答案是调用canvas。getBoundingClientRect并从clientX中减去left,从clientY中减去top,如中所示

只要没有CSS转换,这就可以工作。它也适用于触摸事件,因此也适用于Safari iOS

canvas.addEventListener('touchmove', (e) => {
  const rect = canvas. getBoundingClientRect();
  const x = e.touches[0].clientX - rect.left;
  const y = e.touches[0].clientY - rect.top;
});
如何为2D canvas API获取画布像素鼠标坐标 为此,我们需要获取上面得到的值,并将画布显示的大小转换为画布本身的像素数

使用canvas.getBoundingClientRect和clientX和clientY

或者使用offsetX和offsetY

注意:在所有情况下,不要向画布添加填充或边框。这样做会使代码复杂化。您不希望在画布周围的其他元素中使用边框或填充,而是将填充和/或边框添加到外部元素中。 使用event.offsetX、event.offsetY的工作示例

[…document.querySelectorAll'canvas'].forEachcanvas=>{ const ctx=canvas.getContext'2d'; ctx.canvas.width=ctx.canvas.clientWidth; ctx.canvas.height=ctx.canvas.clientHeight; 让计数=0; 功能抽屉,半径=1{ 常数位置={ x:e.offsetX*canvas.width/canvas.clientWidth, y:e.offsetY*canvas.height/canvas.clientHeight, }; document.querySelector'debug'.textContent=count; ctx.beginPath; ctx.arcpos.x,pos.y,半径,0,数学π*2; ctx.fillStyle=hslcount++%100/100,1,0.5; ctx.fill; } 功能预防默认{ e、 防止违约; } 如果window.PointerEvent{ canvas.addEventListener'pointermove',e=>{ 抽屉,Math.maxMath.maxe.width,e.height/2,1; }; addEventListener'touchstart',preventDefault,{passive:false}; addEventListener'touchmove',preventDefault,{passive:false}; }否则{ canvas.addEventListener'mousemove',draw; addEventListener'mousedown',preventDefault; } }; 功能hslh、s、l{ 返回'hsl${h*360 | 0},${s*100 | 0}%,${l*100 | 0}%`; } .现场{ 宽度:200px; 高度:200px; 透视图:600px; } .立方体{ 宽度:100%; 身高:100%; 位置:相对位置; 变换样式:保留-3d; 动画持续时间:16s; 动画名称:旋转; 动画迭代次数:无限; 动画计时功能:线性; } @关键帧旋转{ 来自{transform:translateZ-100px rotateX 0deg rotateY 0deg;} 到{变换:translateZ-100px旋转360度旋转720度;} } .cube___面{ 位置:绝对位置; 宽度:200px; 高度:200px; 显示:块; } .cube_uu正面{背景:rgba255,0,0,0.2;变换:旋转0deg translateZ100px;} .cube_uu面右{背景:rgba0,255,0,0.2;变换:旋转90度translateZ100px;} .cube__面对面{背景:rgba0,0,255,0.2;变换:旋转180度translateZ100px;} .cube__面左{背景:rgba255,255,0,0.2;变换:rotateY-90deg translateZ100px;} .cube_uu面顶{背景:rgba0,255,255,0.2;变换:rotateX 90度translateZ100px;} .cube_uu面底{背景:rgba255,0,255,0.2;变换:rotateX-90deg translateZ100px;}
我正在创建一个应用程序,在pdf上有一个画布,这涉及到很多画布的大小调整,比如放大和缩小pdf,反过来,在每次放大/缩小pdf时,我必须调整画布大小以适应pdf的大小,我在stackOverflow中找到了很多答案,并且没有找到一个最终解决问题的完美解决方案

我使用的是rxjs和angular 6,没有找到任何针对最新版本的答案

下面是对任何利用rxjs在画布上绘制的人都很有帮助的完整代码片段

  private captureEvents(canvasEl: HTMLCanvasElement) {

    this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
      .pipe(
        switchMap((e: any) => {

          return fromEvent(canvasEl, 'mousemove')
            .pipe(
              takeUntil(fromEvent(canvasEl, 'mouseup').do((event: WheelEvent) => {
                const prevPos = {
                  x: null,
                  y: null
                };
              })),

              takeUntil(fromEvent(canvasEl, 'mouseleave')),
              pairwise()
            )
        })
      )
      .subscribe((res: [MouseEvent, MouseEvent]) => {
        const rect = this.cx.canvas.getBoundingClientRect();
        const prevPos = {
          x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
          y:  Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
        };
        const currentPos = {
          x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
          y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
        };

        this.coordinatesArray[this.file.current_slide - 1].push(prevPos);
        this.drawOnCanvas(prevPos, currentPos);
      });
  }
这是一个片段,它修复了鼠标相对于画布大小的坐标,而不管您如何放大/缩小画布

const prevPos = {
  x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y:  Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
const currentPos = {
  x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};

clientX/clientY在不同浏览器中的行为并不相似。此解决方案并不总是有效的-Ryan Artecona的答案适用于更一般的情况,即画布不一定相对于整个页面进行定位。如果性能重要,则不适合此解决方案,因为Dom访问是在每次单击/移动时完成的。getBoundingClientRect现在已经存在,并且更加优雅。不,它使用的是内置javascript原型对象my Chrome具有event.offsetX和event.offsetY属性,因此我通过添加if event.offsetX!==未定义&event.offsetY!==未定义的{return{x:event.offsetX,y:event.offsetY};}。Baczek对Chrome的event.offsetX和event.offsetY的看法是正确的,后者在IE9中也有效。对于通过v13测试的Firefox,您可以使用event.layerX和event.layerY。我还添加了以下内容:canvasX=event.pageX-totalOffsetX-document.body.scrollLeft;canvasY=event.pageY-totalOffsetY-document.body.scrollTop;这个答案的最终版本对我不起作用。在Firefox上,如果滚动整个屏幕,我会得到被替换的值作为输出。对我有效的是一个非常类似的解决方案,它不是event.pageX/Y,而是从event.clientX/Y中减去计算出的偏移量。有人能回顾一下并解释一下吗?相当于@N4ppeL answer。这应该与从普通dom元素获取鼠标事件没有什么不同。上面列出的代码只有在画布不深入其他容器时才有效。通常,您需要使用类似jquery offset函数[var testDiv=$'testDiv';var offset=testDiv.offset;]的功能,以跨浏览器的方式获取正确的偏移量。这在***中是一个真正的痛苦。如果包含画布的页面滚动,上面发布的带有更新的代码将无法工作。我删除了作为问题更新包含的旧答案。如前所述,它已经过时且不完整。因为这里有大约50个答案,我建议滚动到这个家伙的答案:patriques-一个简单的5行程序。Ryan Artecona的解决方案不适用于带有zoom的平板浏览器。然而,这一个是。不适用于CSS宽度/高度被覆盖的图像,但仍然是最好的解决方案之一。如果页面向下滚动,我想还应该考虑文档的滚动偏移量。@PeppeL-G bounding client rectangle为您计算。在发布评论之前,您可以在控制台中轻松测试它。@TomášZato,噢,getBoundingClientRect返回相对于视图的位置
港口城市那我猜错了。我从未测试过它,因为这对我来说从来都不是问题,我很想提醒其他读者我看到了一个潜在的问题,但谢谢你的澄清。如果画布被缩放,这是不起作用的。不确定这是否是浏览器错误。为像我这样的人添加用法:var canvas=document.getElementById'canvasID';canvas.addEventListenermousedown,函数e{getCursorPositioncanvas,e;};哇!“jqEvent”是如何定义的?还是“画布”?或者在第二个例子“coords”中?您需要在第二个示例之前运行第一个示例吗?既然如此,你为什么不写信去买呢,你也会这样做的?这一切都在onclick函数中吗?给点背景,伙计。考虑到最初的问题是在2008年提出的,我认为你需要结合2008年可用的技术来回答。使用v1.2时可用的有效jQuery版本优化您的答案;好吧,对不起我的放肆。我将编辑以删除该选项。我确实打算使用最新的框架提供答案。我相信程序员不需要解释什么是jqEvent、canvas和coords。看起来不错。谢谢你的意见!对不起,我让你很难过;有趣的是,layerX、layerY是如何在Chrome和Firefox上定义的,但在Chrome上它是不准确的,或者意味着其他东西。@JulianMann感谢您提供的信息。我已经根据当前更多的支持更新了这个答案。现在看来,几乎所有的人都可以不用补偿x/Y。x=新数字有什么意义?下面的代码重新分配了x,这意味着分配的号码会立即被丢弃。这对我来说很有效。在处理Y值时,offsetX/Y版本的代码有两个输入错误。固定行为:常量元素相对性=e.offsetY;const canvasRelativeY=elementRelativeY*canvas.height/canvas.clientHeight;谢谢固定的注意:您可以编辑答案。您的编辑将被审阅,请参见Mozilla的示例2D canvas API上的第一个示例对我来说非常有用:
canvas.addEventListner('mousemove', (e) => {
  const x = e.offsetX;
  const y = e.offsetY;
});
canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
});
canvas.addEventListener('touchmove', (e) => {
  const rect = canvas. getBoundingClientRect();
  const x = e.touches[0].clientX - rect.left;
  const y = e.touches[0].clientY - rect.top;
});
canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const elementRelativeX = e.clientX - rect.left;
  const elementRelativeY = e.clientY - rect.top;
  const canvasRelativeX = elementRelativeX * canvas.width / rect.width;
  const canvasRelativeY = elementRelativeY * canvas.height / rect.height;
});
canvas.addEventListener('mousemove', (e) => {
  const elementRelativeX = e.offsetX;
  const elementRelativeY = e.offsetY;
  const canvasRelativeX = elementRelativeX * canvas.width / canvas.clientWidth;
  const canvasRelativeY = elementRelativeY * canvas.height / canvas.clientHeight;
});
  private captureEvents(canvasEl: HTMLCanvasElement) {

    this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
      .pipe(
        switchMap((e: any) => {

          return fromEvent(canvasEl, 'mousemove')
            .pipe(
              takeUntil(fromEvent(canvasEl, 'mouseup').do((event: WheelEvent) => {
                const prevPos = {
                  x: null,
                  y: null
                };
              })),

              takeUntil(fromEvent(canvasEl, 'mouseleave')),
              pairwise()
            )
        })
      )
      .subscribe((res: [MouseEvent, MouseEvent]) => {
        const rect = this.cx.canvas.getBoundingClientRect();
        const prevPos = {
          x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
          y:  Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
        };
        const currentPos = {
          x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
          y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
        };

        this.coordinatesArray[this.file.current_slide - 1].push(prevPos);
        this.drawOnCanvas(prevPos, currentPos);
      });
  }
const prevPos = {
  x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y:  Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
const currentPos = {
  x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
  y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};