2010-07-13 5 views
117

Я хочу сделать небольшое приложение для рисования, используя холст. Поэтому мне нужно найти положение мыши на холсте.Найти положение мыши относительно элемента

+2

Полное решение: http://acko.net/blog/mouse-handling-and-absolute-positions-in-javascript/ –

+0

Мне нравится, как коротка, но объясняет все, что это за сообщение. – dwjohnston

+0

Это действительно старый, но я только что начал проект GitHub, который, помимо всего прочего, делает именно то, что вам нужно: http://brainlessdeveloper.com/mouse-move-interaction-spot-js/ –

ответ

128

Для людей, использующих JQuery:

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

Вы берете положение мыши, а затем вычитаете его из положения смещения родительского элемента.

var x = evt.pageX - $('#element').offset().left; 
var y = evt.pageY - $('#element').offset().top; 

Если вы пытаетесь получить позицию мыши на странице внутри прокруткой панели:

var x = (evt.pageX - $('#element').offset().left) + self.frame.scrollLeft(); 
var y = (evt.pageY - $('#element').offset().top) + self.frame.scrollTop(); 

или положение относительно страницы:

var x = (evt.pageX - $('#element').offset().left) + $(window).scrollLeft(); 
var y = (evt.pageY - $('#element').offset().top) + $(window).scrollTop(); 

Обратите внимание на следующее оптимизация производительности:

var offset = $('#element').offset(); 
// Then refer to 
var x = evt.pageX - offset.left; 

Таким образом, JQuery не нужно искать #element для каждой строки.

+7

Это сработало для вас @ben, я бы оценил «Правильный ответ» или комментарий о том, что еще не работает для вас. Может быть, я могу помочь дальше. – Spider

+6

Следует избегать использования $ ('selector') в обработчике событий, если вы не хотите очень вялого кода. Предварительно выберите свой элемент и используйте предварительно выбранную ссылку в вашем обработчике. То же самое для $ (window) делает это один раз и кэширует его. –

+1

Это необязательное упоминание: если вы скопируете приведенный выше код, не забудьте исправить 'var y = (evt.pageY - $ ('# element'). Offset(). Left) + $ (window). scrollTop(); 'to' var y = (evt.pageY - $ ('# element'). offset(). top) + $ (window) .scrollTop(); ' –

0

вы можете получить его

var element = document.getElementById(canvasId); 
element.onmousemove = function(e) { 
    var xCoor = e.clientX; 
    var yCoor = e.clientY; 
} 
+0

Будет ли это работать IE, или IE все еще использует window.event вместо передачи события первому аргументу слушателя? edit - Я думаю, что IE не имеет элемент canvas в любом случае до версии 9, но это все равно должно поддерживать IE из-за таких вещей, как excanvas .... –

+11

Это даст координаты относительно окна браузера, все равно нужно выяснить, в элементе using element.getBoundingClientRect() –

+0

благодарю вас за то, что вы сообщили мне о getBoundingClientRect !!!! Я никогда не понимал, что есть такая вещь! –

17

Хороший подправить от сложности этой проблемы можно найти здесь: http://www.quirksmode.org/js/events_properties.html#position

Используя методику, описанную здесь вы можете найти позицию Мышки в документ. Затем вы просто проверяете, находится ли он в ограничивающей рамке вашего элемента, который вы можете найти, вызвав element.getBoundingClientRect(), который вернет объект со следующими свойствами: {снизу, высота, левая, правая, верхняя, ширина }. Оттуда тривиально выяснить, произошло ли даже внутри вашего элемента или нет.

+1

К сожалению, это не удается, если происходит какой-либо поворот – Eric

42

Ниже вычисляет положение мыши относительно элемента холста:

var example = document.getElementById('example'); 
example.onmousemove = function(e) { 
    var x = e.pageX - this.offsetLeft; 
    var y = e.pageY - this.offsetTop; 
} 

В этом примере, this относится к example элементу, и e является onmousemove событием.

+3

Что? IE9 поддерживает Canvas, что вы делаете неправильно? – Andrea

+76

Может быть, это я, но две строки кодов, которые используют контекст «этот» недостаток? – Deratrius

+9

Определенно недостающий контекст. «e» - это событие, а «this» - это элемент, связанный с событием 'var example = document.getElementById ('example'); example.onmousemove = function (e) { var X = e.pageX - this.offsetLeft; var Y = e.pageY - this.offsetTop; } ' –

6

I +1 'Ответ Марка ван Вайка, поскольку он меня в правильном направлении, но не совсем решил его для меня. У меня все еще было смещение при рисовании в элементах, содержащихся в другом элементе.

СЛЕДУЮЩИЙ решил это для меня:

 x = e.pageX - this.offsetLeft - $(elem).offset().left; 
     y = e.pageY - this.offsetTop - $(elem).offset().top; 

Других слов - я просто укладываюсь все смещения от всех элементов, вложенных

+0

+1 для вас! Это тот ответ, который я искал. У меня было два холста, наложенных друг на друга, и все координаты были неправильными из-за других div. Я знал, что это проблема, но не знает логики/уравнения, чтобы компенсировать это. Вы тоже исправили мою проблему! = D спасибо! – Partack

+0

Это работает для меня. Благодаря! – user359519

10

Я нашел этот вопрос, заданный в 2010 году, но никто не кажется, удовлетворенный его : в чистом javascript нет ответа, который возвращает относительные координаты, когда ссылочный элемент вложен внутри других, который может быть с абсолютным позиционированием.Вот мое решение:

var container = myReferenceElement; 

function getRelativeCoordinates (e) { 

    var pos = {}, offset = {}, ref; 

    ref = container.offsetParent; 

    pos.x = !! e.touches ? e.touches[ 0 ].pageX : e.pageX; 
    pos.y = !! e.touches ? e.touches[ 0 ].pageY : e.pageY; 

    offset.left = container.offsetLeft; 
    offset.top = container.offsetTop; 

    while (ref) { 

     offset.left += ref.offsetLeft; 
     offset.top += ref.offsetTop; 

     ref = ref.offsetParent; 
    } 

    return { 
     x : pos.x - offset.left, 
     y : pos.y - offset.top, 
     }; 

} 
+1

Я не думаю, что он учитывает смещение элемента 'html' – apieceofbart

4

Ни один из вышеперечисленных ответов не являются удовлетворительной IMO, так вот что я использую:

// Cross-browser AddEventListener 
function ael(e, n, h){ 
    if(e.addEventListener){ 
     e.addEventListener(n, h, true); 
    }else{ 
     e.attachEvent('on'+n, h); 
    } 
} 

var touch = 'ontouchstart' in document.documentElement; // true if touch device 
var mx, my; // always has current mouse position IN WINDOW 

if(touch){ 
    ael(document, 'touchmove', function(e){var ori=e;mx=ori.changedTouches[0].pageX;my=ori.changedTouches[0].pageY}); 
}else{ 
    ael(document, 'mousemove', function(e){mx=e.clientX;my=e.clientY}); 
} 

// local mouse X,Y position in element 
function showLocalPos(e){ 
    document.title = (mx - e.getBoundingClientRect().left) 
     + 'x' 
     + Math.round(my - e.getBoundingClientRect().top); 
} 

И если вы когда-нибудь нужно знать о текущем Y прокрутки положения страницы:

var yscroll = window.pageYOffset 
     || (document.documentElement && document.documentElement.scrollTop) 
     || document.body.scrollTop; // scroll Y position in page 
16

Как я не нашел JQuery-свободный ответ, который я мог копировать/вставить, вот решение, которое я использовал:

function clickEvent(e) { 
    // e = Mouse click event. 
    var rect = e.target.getBoundingClientRect(); 
    var x = e.clientX - rect.left; //x position within the element. 
    var y = e.clientY - rect.top; //y position within the element. 
} 

JSFiddle of full example

+0

Вам нужно [округлить ограничивающий прямоугольник] (https://stackoverflow.com/questions/40879171/in-javascript-why-does-getboundingclientrect-sometimes- return-floating-point) для обеспечения целочисленных значений с помощью этого метода. –

+3

Координата 'y' выключена, когда прокрутка https://jsfiddle.net/mnpenner/p3w227tg/ – mpen

+0

Новое редактирование должно исправить проблемы прокрутки (с использованием clientX/Y) –

2

Взятые из this tutorial, с исправлениями сделал благодаря началу комментарий:

function getMousePos(canvas, evt) { 
    var rect = canvas.getBoundingClientRect(); 
    return { 
     x: Math.floor((evt.clientX - rect.left)/(rect.right - rect.left) * canvas.width), 
     y: Math.floor((evt.clientY - rect.top)/(rect.bottom - rect.top) * canvas.height) 
    }; 
} 

Использование на холсте следующим образом:

var canvas = document.getElementById('myCanvas'); 
canvas.addEventListener('mousemove', function(evt) { 
    var mousePos = getMousePos(canvas, evt); 
}); 
0

Вы должны знать структуру ваша страница, потому что если ваш холст является дочерним элементом div, который, в свою очередь, является дочерним элементом другого div ... тогда история становится более сложной. Вот мой код для холста, который находится внутри 2 уровней div s:

canvas.addEventListener("click", function(event) { 
var x = event.pageX - (this.offsetLeft + this.parentElement.offsetLeft); 
var y = event.pageY - (this.offsetTop + this.parentElement.offsetTop); 
console.log("relative x=" + x, "relative y" + y); 

});

2

Я понимаю, что я немного опоздал, но это работает с Javascript PURE, и даже дает вам координаты указателя внутри элемента, если элемент больше, чем область просмотра, и пользователь прокручивал.

var element_offset_x ; // The distance from the left side of the element to the left of the content area 


....// some code here (function declaration or element lookup) 



element_offset_x = element.getBoundingClientRect().left - document.getElementsByTagName("html")[0].getBoundingClientRect().left ; 

....// code here 




function mouseMoveEvent(event) 
{ 
    var pointer_location = (event.clientX + window.pageXOffset) - element_offset_x ; 
} 

Как это работает.

Первое, что мы делаем, это получить местоположение элемента HTML (область содержимого) относительно текущего видового экрана. Если на странице есть полосы прокрутки и прокручивается, то число, возвращаемое getBoundingClientRect().left для тега html, будет отрицательным. Затем мы используем это число для вычисления расстояния между элементом и левой частью области содержимого. С element_offset_x = element.getBoundingClientRect().left......;

Зная расстояние от элемента из области содержимого. event.clientX дает нам расстояние от указателя в окне просмотра. Важно понимать, что область просмотра и область содержимого являются двумя разными объектами, просмотр может перемещаться, если страница прокручивается. Следовательно, clientX вернет ТОЛЬКО номер, даже если прокручивается страница.

Чтобы компенсировать это, нам нужно добавить позицию x указателя (относительно окна просмотра) в положение x окна просмотра (относительно области содержимого). Х-положение окна просмотра находится с window.pageXOffset.

+0

Благодарим вас за то, что вы единственный, кто думает о прокрутке. Попробуйте изменить свой ответ, чтобы добавить ось y. – frabjous

0

Оригинальный ответ сказал, чтобы положить его в iframe. Лучшее решение - использовать события offsetX и offsetY на холсте, который имеет дополнение к 0px.

<html> 
<body> 
<script> 

var main=document.createElement('canvas'); 
main.width="200"; 
main.height="300"; 
main.style="padding:0px;margin:30px;border:thick dashed red"; 
document.body.appendChild(main); 

// adding event listener 

main.addEventListener('mousemove',function(e){ 
    var ctx=e.target.getContext('2d'); 
    var c=Math.floor(Math.random()*0xFFFFFF); 
    c=c.toString(16); for(;c.length<6;) c='0'+c; 
    ctx.strokeStyle='#'+c; 
    ctx.beginPath(); 
    ctx.arc(e.offsetX,e.offsetY,3,0,2*Math.PI); 
    ctx.stroke(); 
    e.target.title=e.offsetX+' '+e.offsetY; 
    }); 

// it worked! move mouse over window 

</script> 
</body> 
</html> 
1

Координаты мыши внутри холста могут быть получены благодаря event.offsetX и event.offsetY.Вот небольшой фрагмент кода, чтобы доказать свою точку зрения:

c=document.getElementById("c"); 
 
ctx=c.getContext("2d"); 
 
ctx.fillStyle="black"; 
 
ctx.fillRect(0,0,100,100); 
 
c.addEventListener("mousemove",function(mouseEvt){ 
 
    // the mouse's coordinates on the canvas are just below 
 
    x=mouseEvt.offsetX; 
 
    y=mouseEvt.offsetY; 
 
    // the following lines draw a red square around the mouse to prove it 
 
    ctx.fillStyle="black"; 
 
    ctx.fillRect(0,0,100,100); 
 
    ctx.fillStyle="red"; 
 
    ctx.fillRect(x-5,y-5,10,10); 
 
});

 
body { 
 
    background-color: blue; 
 
} 
 

 
canvas { 
 
    position: absolute; 
 
    top: 50px; 
 
    left: 100px; 
 
}
<canvas id="c" width="100" height="100"></canvas> 
 

1
canvas.onmousedown = function(e) { 
    pos_left = e.pageX - e.currentTarget.offsetLeft; 
    pos_top = e.pageY - e.currentTarget.offsetTop; 
    console.log(pos_left, pos_top) 
} 

HTMLElement.offsetLeft

HTMLElement.offsetLeft свойство только для чтения возвращает количество пикселей, в верхнем левом углу текущего элемента смещается влево в пределах узла HTMLElement.offsetParent.

Для элементов уровня блока, offsetTop, offsetLeft, offsetWidth и offsetHeight описывают границы блока элемента по отношению к offsetParent.

Однако для элементов инлайн-уровня (например, span), который можно обернуть с одной линии на другую, offsetTop и offsetLeft описывают позиции первого пограничного ящика (используйте Element.getClientRects(), чтобы получить его ширину и высоту), в то время как offsetWidth и offsetHeight описывают размеры ограничивающего прямоугольника (используйте Element.getBoundingClientRect(), чтобы получить его положение). Поэтому поле с левым, верхним, шириным и высотой offsetLeft, offsetTop, offsetWidth и offsetHeight не будет ограничивающей рамкой для пролета с обернутым текстом.

HTMLElement.offsetTop

HTMLElement.offsetTop свойство только для чтения возвращает расстояние текущего элемента по отношению к верхней части offsetParent узла.

MouseEvent.pageX

pageX свойство только для чтения возвращает X (по горизонтали), координаты в пикселях событий относительно всего документа. Это свойство учитывает любую горизонтальную прокрутку страницы.

MouseEvent.pageY

MouseEvent.pageY свойство только для чтения возвращает Y (по вертикали) координат в пикселях событий относительно всего документа. Это свойство учитывает любую вертикальную прокрутку страницы.

Для более подробного объяснения, обратитесь к сети разработчиков Mozilla:

https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageY https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetLeft https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop

+0

Хотя этот фрагмент кода может решить вопрос, [включая объяснение] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин вашего предложения кода. –

+0

Я действительно надеюсь, что читатели в будущем имеют JS API, который вычисляет это для них. ;-) Это, наверное, самый простой, полный, автономный ответ. Комментирование самоочевидного кода просто отвлекает отходы. – lama12345

+0

I второй запрос PatrickHund для объяснения. Я не эксперт по CSS/JS, и знать больше о взаимоотношениях между, например, 'page' и' offset' было бы очень полезно для меня. Спасибо, что рассмотрели этот запрос! – cxw

2

на основе @ решения Паука, моя не версия JQuery это:

// Get the container element's bounding box 
var sides = document.getElementById("container").getBoundingClientRect(); 

// Apply the mouse event listener 
document.getElementById("canvas").onmousemove = (e) => { 
    // Here 'self' is simply the current window's context 
    var x = (e.clientX - sides.left) + self.pageXOffset; 
    var y = (e.clientY - sides.top) + self.pageYOffset; 
} 

Это работает как с прокруткой и масштабированием (в этом случае иногда он возвращает flo ATS).

+0

Я бы поднял, но не должны ли это быть минус-знаками для смещения страницы? Либо это, либо круглые скобки вокруг второй части? –

Смежные вопросы