Как получить координаты щелчка мыши по элементу холста?

StackOverflow https://stackoverflow.com/questions/55677

  •  09-06-2019
  •  | 
  •  

Вопрос

Каков самый простой способ добавить обработчик событий щелчка к элементу холста, который будет возвращать координаты x и y щелчка (относительно элемента холста)?

Совместимость с устаревшими браузерами не требуется, подойдут Safari, Opera и Firefox.

Это было полезно?

Решение

Редактировать 2018: Этот ответ довольно старый и использует проверки для старых браузеров, которые больше не нужны, так как clientX и clientY свойства работают во всех современных браузерах.Возможно, вы захотите проверить Патрик Ответ для более простого и свежего решения.

Оригинальный ответ:
Как описано в статье, которую я нашел тогда, но больше не существует:

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;

У меня сработало отлично.

Другие советы

Обновлять (5/5/16): ответ Патрика вместо этого следует использовать, поскольку это проще и надежнее.


Поскольку холст не всегда стилизован относительно всей страницы, canvas.offsetLeft/Top не всегда возвращает то, что вам нужно.Он вернет количество пикселей, на которое он смещен относительно своего элемента 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;

Если вам нравится простота, но вам по-прежнему нужна кроссбраузерная функциональность, я считаю, что это решение подойдет мне лучше всего.Это упрощение решения @Aldekein, но без jQuery.

function getCursorPosition(canvas, event) {
    var rect = canvas.getBoundingClientRect();
    var x = event.clientX - rect.left;
    var y = event.clientY - rect.top;
    console.log("x: " + x + " y: " + y);
}

Современные браузеры теперь справятся с этой задачей за вас.Chrome, IE9 и Firefox поддерживают смещение X/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 };
}

По свежим данным Причудливый режим тот clientX и clientY методы поддерживаются во всех основных браузерах.Итак, вот хороший, работающий код, который работает в прокручиваемом элементе управления на странице с полосами прокрутки:

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

Это также требует jQuery для $(canvas).offset().

Я сделал полную демонстрацию, работающую в каждом браузере, с полным исходным кодом решения этой проблемы: Координаты щелчка мыши на Canvas в Javascript.Чтобы попробовать демо-версию, скопируйте код и вставьте его в текстовый редактор.Затем сохраните его как example.html и, наконец, откройте файл в браузере.

Вот небольшая модификация Ответ Райана Артеконы для полотен с переменной (%) шириной:

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

Будьте осторожны при преобразовании координат;в событии щелчка возвращается несколько некросс-браузерных значений.Использование только clientX и clientY недостаточно, если окно браузера прокручивается (проверено в Firefox 3.5 и Chrome 3.0).

Этот режим причуд В статье представлена ​​более правильная функция, которая может использовать либо pageX, либо pageY, либо комбинацию clientX с document.body.scrollLeft и clientY с document.body.scrollTop для расчета координаты щелчка относительно источника документа.

ОБНОВЛЯТЬ:Кроме того, offsetLeft и offsetTop относятся к дополненному размеру элемента, а не к внутреннему размеру.Холст с отступом:Примененный стиль не будет сообщать верхний левый угол своей области содержимого как offsetLeft.Существуют различные решения этой проблемы;самым простым может быть очистка всех границ, отступов и т. д.стили на самом холсте и вместо этого примените их к блоку, содержащему холст.

Я не уверен, какой смысл во всех этих ответах, которые перебирать родительские элементы и делать все виды странные вещи.

А HTMLElement.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];
}

Пока холст не имеет границ, это работает для растянутых изображений (jsFiddle).

Обработка границ CSS

Если холст имеет толстую кайму, все становится немного сложнее.Вам буквально нужно будет вычесть границу из ограничивающего прямоугольника.Это можно сделать с помощью .getComputedStyle.Этот ответ описывает процесс.

Затем функция немного вырастает:

/* 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
  ...
}

Я не могу придумать ничего, что могло бы сбить с толку эту последнюю функцию.Увидеть себя в JsFiddle.

Примечания

Если вам не нравится изменять родной prototypes, просто измените функцию и вызовите ее с помощью (canvas, event) (и заменить любой this с canvas).

Вот очень хороший урок-

http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

 <canvas id="myCanvas" width="578" height="200"></canvas>
<script>
  function writeMessage(canvas, message) {
    var context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.font = '18pt Calibri';
    context.fillStyle = 'black';
    context.fillText(message, 10, 25);
  }
  function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
  }
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');

  canvas.addEventListener('mousemove', function(evt) {
    var mousePos = getMousePos(canvas, evt);
    var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
    writeMessage(canvas, message);
  }, false);

надеюсь это поможет!

Используя jQuery в 2016 году, чтобы получить координаты щелчка относительно холста, я делаю:

$(canvas).click(function(jqEvent) {
    var coords = {
        x: jqEvent.pageX - $(canvas).offset().left,
        y: jqEvent.pageY - $(canvas).offset().top
    };
});

Это работает, поскольку и Canvas Offset(), и jqEvent.pageX/Y относятся к документу независимо от положения прокрутки.

Обратите внимание: если ваш холст масштабирован, эти координаты не совпадают с координатами холста. логические координаты.Чтобы получить их, вам нужно также делать:

var logicalCoords = {
    x: coords.x * (canvas.width / $(canvas).width()),
    y: coords.y * (canvas.height / $(canvas).height())
}

Рекомендую эту ссылку-http://miloq.blogspot.in/2011/05/coordinates-mouse-click-canvas.html

<style type="text/css">

  #canvas{background-color: #000;}

</style>

<script type="text/javascript">

  document.addEventListener("DOMContentLoaded", init, false);

  function init()
  {
    var canvas = document.getElementById("canvas");
    canvas.addEventListener("mousedown", getPosition, false);
  }

  function getPosition(event)
  {
    var x = new Number();
    var y = new Number();
    var canvas = document.getElementById("canvas");

    if (event.x != undefined && event.y != undefined)
    {
      x = event.x;
      y = event.y;
    }
    else // Firefox method to get the position
    {
      x = event.clientX + document.body.scrollLeft +
          document.documentElement.scrollLeft;
      y = event.clientY + document.body.scrollTop +
          document.documentElement.scrollTop;
    }

    x -= canvas.offsetLeft;
    y -= canvas.offsetTop;

    alert("x: " + x + "  y: " + y);
  }

</script>

В Prototype используйте cumulativeOffset() для выполнения рекурсивного суммирования, как упоминалось выше Райаном Артеконой.

http://www.prototypejs.org/api/element/cumulativeoffset

Вы можете просто сделать:

var canvas = yourCanvasElement;
var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2;
var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;

Это даст вам точное положение указателя мыши.

Посмотрите демо на http://jsbin.com/ApuJOSA/1/edit?html,вывод .

  function mousePositionOnCanvas(e) {
      var el=e.target, c=el;
      var scaleX = c.width/c.offsetWidth || 1;
      var scaleY = c.height/c.offsetHeight || 1;

      if (!isNaN(e.offsetX)) 
          return { x:e.offsetX*scaleX, y:e.offsetY*scaleY };

      var x=e.pageX, y=e.pageY;
      do {
        x -= el.offsetLeft;
        y -= el.offsetTop;
        el = el.offsetParent;
      } while (el);
      return { x: x*scaleX, y: y*scaleY };
  }

Итак, это одновременно простая и немного более сложная тема, чем кажется.

Во-первых, здесь обычно возникают смешанные вопросы.

  1. Как получить координаты элемента относительно мыши

  2. Как получить пиксельные координаты мыши холста для 2D Canvas API или WebGL

итак, ответы

Как получить координаты элемента относительно мыши

Независимо от того, является ли элемент холстом, координаты элемента относительно мыши одинаковы для всех элементов.

Есть 2 простых ответа на вопрос «Как получить координаты мыши относительно холста»

Простой ответ №1: используйте offsetX и offsetY

canvas.addEventListner('mousemove', (e) => {
  const x = e.offsetX;
  const y = e.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 и top от clientY как в

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.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;
});

Как получить координаты мыши в пикселях холста для API 2D Canvas

Для этого нам нужно взять значения, которые мы получили выше, и преобразовать размер отображаемого холста в количество пикселей в самом холсте.

с canvas.getBoundingClientRect и clientX и clientY

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

или с offsetX и offsetY

canvas.addEventListener('mousemove', (e) => {
  const elementRelativeX = e.offsetX;
  const elementRelativeX = e.offsetY;
  const canvasRelativeX = elementRelativeX * canvas.width / canvas.clientWidth;
  const canvasRelativeY = elementRelativeX * canvas.height / canvas.clientHeight;
});

Примечание: Ни в коем случае не добавляйте к холсту отступы или границы.Это значительно усложнит код.Вместо этого вы хотите, чтобы граница или отступ окружала холст в каком-либо другом элементе, и добавляйте отступ и/или границу к внешнему элементу.

Рабочий пример с использованием event.offsetX, event.offsetY

[...document.querySelectorAll('canvas')].forEach((canvas) => {
  const ctx = canvas.getContext('2d');
  ctx.canvas.width  = ctx.canvas.clientWidth;
  ctx.canvas.height = ctx.canvas.clientHeight;
  let count = 0;

  function draw(e, radius = 1) {
    const pos = {
      x: e.offsetX * canvas.width  / canvas.clientWidth,
      y: e.offsetY * canvas.height / canvas.clientHeight,
    };
    document.querySelector('#debug').textContent = count;
    ctx.beginPath();
    ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
    ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
    ctx.fill();
  }

  function preventDefault(e) {
    e.preventDefault();
  }

  if (window.PointerEvent) {
    canvas.addEventListener('pointermove', (e) => {
      draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
    });
    canvas.addEventListener('touchstart', preventDefault, {passive: false});
    canvas.addEventListener('touchmove', preventDefault, {passive: false});
  } else {
    canvas.addEventListener('mousemove', draw);
    canvas.addEventListener('mousedown', preventDefault);
  }
});

function hsl(h, s, l) {
  return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
.scene {
  width: 200px;
  height: 200px;
  perspective: 600px;
}

.cube {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  animation-duration: 16s;
  animation-name: rotate;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}

@keyframes rotate {
  from { transform: translateZ(-100px) rotateX(  0deg) rotateY(  0deg); }
  to   { transform: translateZ(-100px) rotateX(360deg) rotateY(720deg); }
}

.cube__face {
  position: absolute;
  width: 200px;
  height: 200px;
  display: block;
}

.cube__face--front  { background: rgba(255, 0, 0, 0.2); transform: rotateY(  0deg) translateZ(100px); }
.cube__face--right  { background: rgba(0, 255, 0, 0.2); transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back   { background: rgba(0, 0, 255, 0.2); transform: rotateY(180deg) translateZ(100px); }
.cube__face--left   { background: rgba(255, 255, 0, 0.2); transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top    { background: rgba(0, 255, 255, 0.2); transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { background: rgba(255, 0, 255, 0.2); transform: rotateX(-90deg) translateZ(100px); }
<div class="scene">
  <div class="cube">
    <canvas class="cube__face cube__face--front"></canvas>
    <canvas class="cube__face cube__face--back"></canvas>
    <canvas class="cube__face cube__face--right"></canvas>
    <canvas class="cube__face cube__face--left"></canvas>
    <canvas class="cube__face cube__face--top"></canvas>
    <canvas class="cube__face cube__face--bottom"></canvas>
  </div>
</div>
<pre id="debug"></pre>

Рабочий пример с использованием canvas.getBoundingClientRect и event.clientX и event.clientY

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.canvas.width  = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
let count = 0;

function draw(e, radius = 1) {
  const rect = canvas.getBoundingClientRect();
  const pos = {
    x: (e.clientX - rect.left) * canvas.width  / canvas.clientWidth,
    y: (e.clientY - rect.top) * canvas.height / canvas.clientHeight,
  };
  ctx.beginPath();
  ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
  ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
  ctx.fill();
}

function preventDefault(e) {
  e.preventDefault();
}

if (window.PointerEvent) {
  canvas.addEventListener('pointermove', (e) => {
    draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
  });
  canvas.addEventListener('touchstart', preventDefault, {passive: false});
  canvas.addEventListener('touchmove', preventDefault, {passive: false});
} else {
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mousedown', preventDefault);
}

function hsl(h, s, l) {
  return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
canvas { background: #FED; }
<canvas width="400" height="100" style="width: 300px; height: 200px"></canvas>
<div>canvas deliberately has differnt CSS size vs drawingbuffer size</div>

Эй, это в додзё, просто потому, что у меня уже был код для проекта.

Должно быть совершенно очевидно, как преобразовать его обратно в не-додзё-ванильный JavaScript.

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

Надеюсь, это поможет.

Вот некоторые модификации вышеупомянутого решения Райана Артеконы.

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

Во-первых, как говорили другие, вам нужна функция, чтобы получить положение элемента холста.Вот метод, который немного более элегантен, чем некоторые другие на этой странице (ИМХО).Ты можешь пройти это любой элемент и получить его позицию в документе:

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, который может быть оберткой div node (или что-нибудь еще, если уж на то пошло).Когда нет элемента, обертывающего canvas они относительно body, поэтому нет смещения для вычитания.Вот почему нам нужно определить положение холста, прежде чем мы сможем сделать что-нибудь еще.

Аналогично, e.pageX и e.pageY укажите положение курсора относительно документа.Вот почему мы вычитаем смещение холста из этих значений, чтобы получить истинное положение.

Альтернатива для расположен элементов заключается в непосредственном использовании значений e.layerX и e.layerY.Этот метод менее надежен, чем описанный выше метод, по двум причинам:

  1. Эти значения также относятся ко всему документу, если событие не происходит внутри позиционированного элемента.
  2. Они не являются частью какого-либо стандарта.

ТриJS 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),
    };
}

Я создавал приложение, имеющее холст над 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 )
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top