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

276

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

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

Том
источник
Это не должно отличаться от получения событий мыши из обычных элементов dom. Quirksmode имеет хорошую ссылку на это.
аэропорту
4
Код, который вы перечислили выше, работает только тогда, когда холст не находится глубоко внутри других контейнеров. В общем случае вам нужно использовать что-то вроде функции смещения jquery [var testDiv = $ ('# testDiv'); var offset = testDiv.offset ();], чтобы получить правильное смещение кросс-браузерным способом. Это настоящая боль в ***.
Аарон Уоттерс
Приведенный выше код с обновлением не работает, если страница, содержащая холст, прокручивается.
Тимоти Ким
Я удалил свой старый «ответ», который был включен в качестве обновления на вопрос. Как уже упоминалось, это было устаревшим и неполным.
Том
3
Поскольку здесь около 50 ответов, я рекомендую прокрутить до ответа этого парня: patriques - хороший и простой 5 лайнер.
Игорь Л.

Ответы:

77

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

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

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;

Работал отлично для меня.

N4ppeL
источник
30
Это решение не всегда работает - ответ Райана Артеконы работает в более общем случае, когда холст не обязательно располагается относительно всей страницы.
Крис Джонсон
3
Это решение не подходит, если производительность имеет значение, так как доступ к Dom осуществляется при каждом нажатии / перемещении. И getBoundingClientRect существует в настоящее время и является более элегантным.
GameAlchemist
192

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

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

const canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function(e) {
    getCursorPosition(canvas, e)
})
patriques
источник
Если страница прокручивается вниз, я думаю, следует также учитывать смещение прокрутки документа.
Пеппе LG
8
@ PeppeL-G ограничивающий клиентский прямоугольник рассчитывает это для вас. Вы можете легко проверить это в консоли, прежде чем оставлять комментарий (это то, что я сделал).
Томаш Зато - Восстановить Монику
1
@ TomášZato, о, getBoundingClientRectвозвращает позиции относительно порта просмотра? Тогда мое предположение было неверным. Я никогда не проверял это, так как это никогда не было проблемой для меня, и я любезно хотел бы предупредить других читателей о потенциальной проблеме, которую я видел, но спасибо за ваше разъяснение.
Пеппе LG
1
Это не работает, если холст масштабируется. Не уверен, что это ошибка браузера.
Йероен
2
Добавить использование для кого-то, как я:var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
SnowOnion
179

Обновление (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;

Последняя строка упрощает получение координат мыши относительно элемента canvas. Все, что нужно для получения полезных координат, это

coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
Райан Артекона
источник
8
Нет, он использует встроенный объект-прототип javascript --- developer.mozilla.org/en/…
garg
14
мой Chrome имеет event.offsetXи event.offsetYатрибуты, поэтому я изменил свое решение, добавив if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. Похоже, это работает.
Бачек
3
Бачек прав насчет Chrome event.offsetXи event.offsetYтакже работает в IE9. Для Firefox (протестировано с v / v13) вы можете использовать event.layerXи event.layerY.
Мафафу
3
Я дополнительно добавил это: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
amirpc
4
Эта окончательная версия ответа не сработала для меня. В Firefox, если прокрутить весь экран, я получил смещенное значение в качестве вывода. Для меня сработало очень похожее решение, приведенное на stackoverflow.com/a/10816667/578749, которое вместо event.pageX / Y вычитало вычисленное смещение из event.clientX / Y. Может ли кто-то рассмотреть это и объяснить?
lvella
33

Современный браузер теперь справится с этим для вас. 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 };
}
mafafu
источник
1
Интересно, как layerX, layerY определяется как в Chrome, так и в Firefox, но в Chrome это неточно (или означает что-то еще).
Джулиан Манн
@JulianMann Спасибо за информацию. Я обновил этот ответ на основе более актуальной поддержки. Похоже, что теперь вы можете сойти с offsetX / Y почти повсеместно.
Мафафу
18

Согласно свежему QuirksmodeclientX и 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().

Aldekein
источник
Эквивалент @ N4ppeL ответа.
Павел Щур
13

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

Мануэль Игнасио Лопес Кинтеро
источник
11

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

 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}
}
Cryptovirus
источник
7

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

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

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

fixermark
источник
7

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

HTMLElement.getBoundingClientRectМетод предназначен для для обработки фактического положения экрана любого элемента. Это включает прокрутку, поэтому такие вещи scrollTopне нужны:

(из MDN) Количество прокрутки, которая была сделана из области области просмотра (или любого другого прокручиваемого элемента ), учитывается при вычислении ограничивающего прямоугольника

Нормальное изображение

Самый простой подход уже был опубликован здесь. Это правильно до тех пор, пока нет дикого 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).

Томаш Зато - Восстановить Монику
источник
6

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

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

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

Frazer
источник
Решение Райана Артеконы не работает для планшетных браузеров с зумом. Однако этот сделал.
Энди Мейерс
Не работает с изображениями, которые имеют CSS width/ heightпереопределение, но все еще является одним из лучших решений.
Томаш Зато - Восстановить Монику
3

Используя 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())
}
сарсапарель
источник
Вот это да. Как 'jqEvent' становится определенным? Или «холст»? Или во втором примере 'координаты'? Вам нужно запустить первый пример перед вторым? В таком случае, почему бы вам не написать «чтобы получить их, вы бы тоже сделали»? Все это входит в функцию onclick или как? Дай немного контекста, приятель. И, учитывая, что первоначальный вопрос был задан в 2008 году, я думаю, что вам нужно ответить в контексте технологии, которая была доступна в 2008 году. Уточните свой ответ, используя действительный jQuery из версии, которая была доступна в то время (v1.2). ;)
Ayelis
1
Хорошо, извините за мою самонадеянность. Я буду редактировать, чтобы удалить это. Я намеревался дать ответ, используя самые последние рамки. И я считаю, что программисту не нужно объяснять, что такое jqEvent, canvas и ords.
Sarsaparilla
Выглядит хорошо. Спасибо за ваш вклад! Извините, я доставил вам неприятности! ;)
Ayelis
3

Так что это простая, но немного более сложная тема, чем кажется.

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

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

  2. Как получить координаты пиксельной мыши Canvas для 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. Они существуют в Pointer Events, которые существуют в Chrome и Firefox, но не в Safari, хотя, очевидно, 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;
});

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

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

с 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

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

GMan
источник
2

Я рекомендую эту ссылку - 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>

источник
какой смысл x = new Number()? Приведенный ниже код переназначает, xчто означает, что выделенное число сразу же отбрасывается
gman
1

Вы могли бы просто сделать:

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

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

user2310569
источник
1

Смотрите демонстрацию на http://jsbin.com/ApuJOSA/1/edit?html,output .

  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 };
  }
Даниэль Патру
источник
0

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

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};
}
Саймон Привет
источник
0

Во-первых, как уже говорили другие, вам нужна функция, чтобы получить положение элемента canvas . Вот метод, который немного более элегантен, чем некоторые другие на этой странице (IMHO). Вы можете передать ему любой элемент и получить его положение в документе:

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

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

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

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

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;

Попробовав много решений. Это сработало для меня. Может помочь кому-то еще, следовательно, размещения. Получил это отсюда

Аникет Беткикар
источник
0

Вот упрощенное решение (это не работает с границами / прокруткой):

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),
    };
}
haykam
источник
0

Я создавал приложение, имеющее холст поверх 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 )
};
Дивьяншу Рават
источник
-1

Привет, это в додзё, просто потому, что у меня уже есть код для проекта.

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

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

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

Брайан Джанфоркаро
источник
6
clientX / clientY не ведут себя одинаково во всех браузерах.
tfwright