Як отримати координати клацання миші на елементі полотна?


276

Який найпростіший спосіб додати обробник подій клацання до елемента полотна, який поверне координати x та y клацання (відносно елемента полотна)?

Не потрібна сумісна версія браузера, Safari, Opera і Firefox.


Це не повинно відрізнятися від отримання подій миші від звичайних елементів дому. quirksmode має гарне посилання на це.
аеропорт

4
Код, який ви перераховуєте вище, працює лише тоді, коли полотно не знаходиться глибоко в інших контейнерах. Взагалі вам потрібно використовувати щось на зразок функції зсуву jquery [var testDiv = $ ('# testDiv'); var offset = testDiv.offset ();] для отримання правильного зміщення крос-браузерним способом. Це справжній біль у ***.
Аарон Уоттерс

Код, розміщений вище за допомогою оновлення, не спрацьовує, якщо сторінка, що містить полотно, прокручується.
Тимофі Кім,

Я видалив свою стару "відповідь", яка була включена як оновлення до питання. Як згадувалося, він був застарілим та неповним.
Том

3
Оскільки тут є 50 відповідей, я рекомендую прокрутити відповідь до цього хлопця: патрікі - хороший і простий 5 лайнерів.
Ігор Л.

Відповіді:


77

Редагувати 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;

Для мене працювали ідеально чудово.


30
Це рішення не завжди працює - відповідь Райана Артекона працює в більш загальному випадку, коли полотно не обов'язково розташоване відносно всієї сторінки.
Кріс Джонсон

3
Це рішення не підходить, якщо продуктивність має значення, оскільки доступ до дому здійснюється при кожному натисканні / переміщенні. І 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)
})

Якщо сторінка прокручується вниз, я думаю, слід також врахувати зміщення прокрутки документа.
Peppe LG

8
@ Обмежувальний прямокутник клієнта PeppeL-G обчислює це для вас. Ви можете легко протестувати його в консолі, перш ніж опублікувати коментар (саме це я і зробив).
Томаш Зато - Відновіть Моніку

1
@ TomášZato, о, getBoundingClientRectповертає позиції відносно порту перегляду? Тоді моя здогадка помилялась. Я ніколи не перевіряв це, оскільки це ніколи для мене не було проблемою, і я люб’язно хотів попередити інших читачів про потенційну проблему, яку я бачив, але дякую за ваше уточнення.
Peppe 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, починаючи з самого елемента полотна. Цей код ідеально працює для мене, перевірений у 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;

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}; }. схоже, це працює.
Baczek

3
Baczek правильно про Хрома event.offsetXі event.offsetYякий також працює в IE9. Для Firefox (тестований w / v13) ви можете використовувати event.layerXі event.layerY.
mafafu

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 для абсолютного зміщення натискання сторінки, включаючи поле, накладку і т.д. раніше не існувало. Отже, для сумісності з трохи старшими браузерами ви можете використовувати:

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

1
Цікаво, як layerX, layer Y визначено і в Chrome, і в Firefox, але в Chrome це неточно (або означає щось інше).
Джуліан Манн

@JulianMann Дякую за інформацію Цю відповідь я оновив на основі більш актуальної підтримки. Схоже, ви можете втекти з офсетX / Y майже повсюдно зараз.
mafafu

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().


Еквівалентна відповіді @ N4ppeL.
Paweł Szczur

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

7

Будьте обережні, роблячи перетворення координат; є декілька значень, які не перехрещуються у веб-переглядачі, повертаються у події кліку Використання лише clientX та clientY недостатньо, якщо прокручується вікно браузера (перевірено у Firefox 3.5 та Chrome 3.0).

Ця стаття про режим диваків забезпечує більш правильну функцію, яка може використовувати або pageX або pageY, або комбінацію clientX з document.body.scrollLeft та clientY з document.body.scrollTop для обчислення координати кліку відносно походження документа.

ОНОВЛЕННЯ: Додатково, offsetLeft і offsetTop відносно розміру елемента, що вкладається, а не внутрішнього розміру. Полотно з вкладкою padding: стиль, що не застосовується, не буде повідомляти верхній лівий край своєї області вмісту як offsetLeft. Існують різні рішення цієї проблеми; найпростішим може бути очищення всіх стилів кордону, прокладки тощо на самому полотні та замість цього застосувати їх до поля, що містить полотно.


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-coordinate/

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

сподіваюся, що це допомагає!


Рішення Райана Артекона не працювало для браузерів планшетів із збільшенням. Однак цей.
Енді Мейєрс

Не працює з зображеннями, які мають CSS width/ heightпереосмислені, але все-таки є одним з найкращих рішень.
Томаш Зато - Відновити Моніку

3

Використовуючи jQuery в 2016 році, щоб отримати координати кліків відносно полотна, я роблю:

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

Це працює, оскільки зміщення полотна () та 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). ;)
Айеліс

1
Гаразд, вибачте за мою самонадійність. Я відредагую, щоб видалити це. Я мав намір надати відповідь, використовуючи найсвіжіші рамки. І я вважаю, що програмісту не потрібно було б пояснювати, що таке jqEvent, полотно та координати.
Сарсапарілья

Виглядає добре. Дякуємо за ваш внесок! Вибачте, що я дав вам важкий час! ;)
Айеліс

3

Тож це і проста, але трохи складніша тема, ніж здається.

По-перше, тут зазвичай виникають суперечливі питання

  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 вони не існують на події дотику , і тому не можуть бути використані з прошивкою 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


2

Я рекомендую це посилання- http://miloq.blogspot.in/2011/05/coordinate-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що означає, що виділене число негайно
відміняється


1

Ви можете просто зробити:

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

Це дасть вам точне положення вказівника миші.


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

По-перше, як говорили інші, вам потрібна функція, щоб отримати положення елемента полотна . Ось метод, який трохи елегантніший, ніж деякі інші на цій сторінці (ІМХО). Ви можете передати йому будь-який елемент і отримати його положення в документі:

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. Вони не входять до жодного стандарту

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

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.