Получение положения мыши относительно области содержимого элемента
Когда мышь перемещается по элементу, я хочу получить координаты мыши курсора относительно левого верхнего края области содержимого элемента (это область, исключая заполнение, границу и контур). Звучит просто, не так ли? До сих пор я пользуюсь очень популярной функцией:
function element_position(e) {
var x = 0, y = 0;
do {
x += e.offsetLeft;
y += e.offsetTop;
} while (e = e.offsetParent);
return { x: x, y: y };
}
И я бы получил положение мыши относительно элемента element
с помощью:
p = element_position(element);
x = mouseEvent.pageX - p.x;
y = mouseEvent.pageY - p.y;
Это не совсем правильно. Поскольку offsetLeft
и offsetTop
- это различия между "внешним" верхним левым элементом и "внутренним" верхним левым от его родителя смещения, позиция суммы будет пропускать границы all и paddings в иерархии.
Здесь сравнение, которое должно (надеюсь) прояснить, что я имею в виду.
- Если я получу сумму расстояний в позиции между "внешним" верхним левым элементом и "внутренним" верхним левым от их смещенных родителей ( outers минус внутри, что я делаю прямо сейчас), я получаю позицию области содержимого элемента, минус все границы и paddings в иерархии смещения.
- Если я получаю сумму расстояний в позиции между "внешним" верхним левым элементом и "внешним" верхним левым от их смещенных родителей (outers минус outers), я получаю положение области содержимого элемента, минус граница и добавление нужного элемента (близко, но не совсем).
- Если я получу сумму расстояний в позиции между "внутренним" верхним левым элементом и "внутренним" верхним левым от их смещенных родителей (внутри минус внутри), я получаю положение области содержимого элемента. Это то, что я хочу.
Ответы
Ответ 1
Здесь показан живой пример, который использует функцию element_position()
, которая знает о заполнении и границах. Я добавил некоторые дополнительные дополнения и поля в ваш оригинальный пример.
http://jsfiddle.net/Skz8g/4/
Чтобы использовать его, переместите курсор над коричневой областью. Полученная белая область является фактическим содержимым холста. Коричневый цвет является дополнением, красный - границей и т.д. Как в этом примере, так и в следующем, показания canvas x
и canvas y
указывают положение курсора относительно содержимого холста.
Здесь код для element_position()
:
function getNumericStyleProperty(style, prop){
return parseInt(style.getPropertyValue(prop),10) ;
}
function element_position(e) {
var x = 0, y = 0;
var inner = true ;
do {
x += e.offsetLeft;
y += e.offsetTop;
var style = getComputedStyle(e,null) ;
var borderTop = getNumericStyleProperty(style,"border-top-width") ;
var borderLeft = getNumericStyleProperty(style,"border-left-width") ;
y += borderTop ;
x += borderLeft ;
if (inner){
var paddingTop = getNumericStyleProperty(style,"padding-top") ;
var paddingLeft = getNumericStyleProperty(style,"padding-left") ;
y += paddingTop ;
x += paddingLeft ;
}
inner = false ;
} while (e = e.offsetParent);
return { x: x, y: y };
}
Код должен корректно работать в IE9, FF и Chrome, хотя я заметил, что в Opera это не совсем правильно.
Моя первоначальная наклонность заключалась в том, чтобы использовать что-то вроде свойств e.offsetX/Y
, потому что они были ближе к тому, что вы хотите, и не связаны с циклом над вложенными элементами. Однако их поведение сильно варьируется в браузерах, поэтому требуется немного перекрестного браузера. Живой пример:
http://jsfiddle.net/xUZAa/6/
Он должен работать во всех современных браузерах - Opera, FF, Chrome, IE9. Я лично предпочитаю это, но думал, что, хотя ваш первоначальный вопрос касался "получения позиции мыши относительно области содержимого элемента", вы действительно спрашивали о том, как сделать функцию element_position()
работать правильно.
Ответ 2
с помощью jQuery:
function posRelativeToElement(elem, ev){
var $elem = $(elem),
ePos = $elem.offset(),
mousePos = {x: ev.pageX, y: ev.pageY};
mousePos.x -= ePos.left + parseInt($elem.css('paddingLeft')) + parseInt($elem.css('borderLeftWidth'));
mousePos.y -= ePos.top + parseInt($elem.css('paddingTop')) + parseInt($elem.css('borderTopWidth'));
return mousePos;
};
живой пример: http://jsfiddle.net/vGKM3/
Корень этого прост: вычислите позицию элемента относительно документа. Затем я отбрасываю верхнюю и левую прокладку и границу (маржа включена в базовые расчеты позиционирования). Внутренний код jQuery для этого основан на getComputedStyle
и element.currentStyle
. К сожалению, я не думаю, что есть другой способ...
Ядро функции jQuery .offset()
, которая получает позицию элемента относительно документа:
if ( "getBoundingClientRect" in document.documentElement ) {
...
try {
box = elem.getBoundingClientRect();
} catch(e) {}
var body = doc.body,
win = getWindow(doc),
clientTop = docElem.clientTop || body.clientTop || 0,
clientLeft = docElem.clientLeft || body.clientLeft || 0,
scrollTop = (win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop ),
scrollLeft = (win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft),
top = box.top + scrollTop - clientTop,
left = box.left + scrollLeft - clientLeft;
return { top: top, left: left };
}else{
// calculate recursively based on .parentNode and computed styles
}
Теоретически, другим способом сделать это будет, используя приведенный выше код позиционирования:
- убедитесь, что ваш элемент имеет
position: relative
(или абсолютный) набор
- добавить новый элемент
position: absolute; top:0px; left:0px;
- получить позицию нового элемента относительно документа. Это будет то же самое, что и позиция содержимого родительского
- удалить новый элемент
Ответ 3
В вашей функции element_position(e)
, итерации по иерархии с помощью parentNode
, получите отступы, смещения и границы с помощью getComputedStyle(e, null).getPropertyValue(each_css)
и суммируйте их со значениями ваших значений x
и y
перед возвратом.
Там есть сообщение, предлагающее кросс-браузерное чтение стилей здесь:
http://bytes.com/topic/javascript/answers/796275-get-div-padding
Ответ 4
Я не уверен, что это лучший способ, или наиболее эффективный ресурс...
Но я бы предложил получить X/Y для тега canvas, ширины рамки и дополнения и использовать их вместе в качестве смещения.
Edit:
Используйте offsetLeft и offsetTop
Ссылка: Как использовать элементы Canvas и Draw в HTML5
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;