19 ответов:
Как рассказали здесь:
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;последняя строка делает вещи удобными для получения координат мыши относительно элемента canvas. Все, что нужно для получения полезных координат-это
coords = canvas.relMouseCoords(event); canvasX = coords.x; canvasY = coords.y;
Если вы любите простоту, но все еще хотите кросс-браузер функциональность я нашел это решение работает лучше всего для меня. Это упрощение решения @Aldekeins, но без 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 поддерживают 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 }; }
по данным свежей Quirksmode the
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]; }этой jQuery на
$(canvas).offset().
Я сделал полную демострацию, которая работает в каждом браузере с полным исходным кодом решения этой проблемы:координаты щелчка мыши по холсту в Javascript. Чтобы попробовать демо, скопируйте код и вставьте его в текстовый редактор. Затем сохраните его в качестве примера.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} }
будьте осторожны при выполнении преобразования координат; в событии click возвращается несколько значений, отличных от кросс-браузера. Использование только clientX и clientY недостаточно, если прокручивается окно браузера (проверено в Firefox 3.5 и Chrome 3.0).
этот режим совместимости статья предоставляет более правильную функцию, которая может использовать либо pageX или pageY, либо комбинацию clientX с документом.тело.прокрутка и клиенты с документом.тело.scrollTop для расчета щелкните координата относительно источника документа.
UPDATE: кроме того, offsetLeft и offsetTop относятся к размеру элемента, а не к внутреннему размеру. Холст с примененным стилем padding: style не будет сообщать о верхнем левом углу своей области содержимого как offsetLeft. Существуют различные решения этой проблемы; самым простым из них может быть очистка всех границ, заполнение и т. д. стили на самом холсте и вместо этого применить их к коробке, содержащей холст.
вот очень хороший учебник -
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);надеюсь, что это помогает!
Я не уверен, в чем смысл всех этих ответов, что цикл через родительские элементы и делать все виды странные вещи.
The
HTMLElement.getBoundingClientRectметод предназначен для обработки фактического положения экрана любого элемента. Это включает в себя прокрутку, так что вещи, какscrollTopне нужен:(от MDN) количество прокрутки, выполненной в области видового экрана (или любой другой прокручиваемый элемент) учитывается при вычислении ограничивающий прямоугольник
нормальное изображение
The очень простой подход уже было опубликовано здесь. Это правильно пока нет дикого 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).
используя 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 относятся к документу независимо от положения прокрутки.
обратите внимание, что если ваш холст масштабируется, то эти координаты не совпадают с холста логические координаты. Чтобы получить их, вы бы и do:
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>
в прототипе используйте 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 }; }
Эй, это в додзе, просто потому, что это то, что у меня был код уже для проекта.
должно быть довольно очевидно, как преобразовать его обратно в не dojo vanilla 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}; }
во-первых, как уже сказали, вам нужна функция, чтобы получить положение элемента холста. Вот метод, который немного более элегантен, чем некоторые другие на этой странице (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. Это менее надежно, чем метод выше по двум причинам:
- эти значения также относятся ко всему документу, когда событие не происходит внутри позиционированного элемента
- они не являются частью какого-либо стандарта
r77 ThreeJS
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;после попытки многих решений. Это сработало для меня. Может помочь кому-то еще, следовательно, размещение. Получил его от!--4-->здесь
Comments