显示webkitConvertPointFromPageToNode的Javascript实现 [英] Show me a Javascript implementation of webkitConvertPointFromPageToNode
问题描述
webkitConvertPointFromPageToNode(在Node节点,在WebKitPoint p)
方法是真棒;给它一个DOM节点和一个点的页面坐标(比如说,鼠标光标位置),它会给一个坐标回到你在那个节点的局部坐标系。很抱歉,目前的
这看起来是一个惊人的问题,但是在这里有一个ALMOST重复:如何获取具有CSS3变换的元素的MouseEvent坐标?,但没有人在看我的答案,这里似乎是更一般的,所以我会再次在这里发布,与几个修改,使它更清楚:
基本上,它的工作原理是:拆分您要为其查找相对坐标的元素,并将其拆分为9个较小的元素。使用document.elementFromPoint来查找坐标是否超过该小元素。如果是,将该元素拆分为9个元素,并继续这样做,直到一个相当精确的坐标是可能的。然后使用getBoundingClientRect来查找该小元素的屏幕坐标。 BOOM!
jsfiddle: http:// jsfiddle .net / markasoftware / rA27K / 8 /
以下是JavaScript函数:
function convertPointFromPageToNode(elt,coords){
///元素的原始innerHTML
var origHTML = elt.innerHTML;
//现在清除它
elt.innerHTML ='';
//现在保存并清除不良样式
var origPadding = elt.style.padding =='0px'?'':elt.style.padding;
var origMargin = elt.style.margin =='0px'?'':elt.style.margin;
elt.style.padding = 0;
elt.style.margin = 0;
//确保事件在给定的元素中
if(document.elementFromPoint(coords.x,coords.y)!== elt){
//重置元素
elt.innerHTML = origHTML;
//和styles
elt.style.padding = origPadding;
elt.style.margin = origMargin;
//我们没有什么显示,所以返回null
return null;
}
//矩形的所有位置的数组
var rectPlaces = ['topleft','topcenter','topright','centerleft','centercenter','centerright' bottomleft','bottomcenter','bottomright'];
//向元素添加9个矩形的函数
function addChildren(elt){
//循环遍历所有位置
rectPlaces.forEach(function(curRect){
//为此rect创建元素
var curElt = document.createElement('div');
//添加类和id
curElt.setAttribute('class','offsetrect ');
curElt.setAttribute('id',curRect +'offset');
//将其添加到元素
elt.appendChild(curElt);
}
//获取元素表单点及其样式
var eltFromPoint = document.elementFromPoint(coords.x,coords.y);
var eltFromPointStyle = getComputedStyle(eltFromPoint);
//返回事件所在的小于1像素的元素,或递归直到找到它,并返回递归的结果
return Math.max(parseFloat(eltFromPointStyle.getPropertyValue( 'height')),parseFloat(eltFromPointStyle.getPropertyValue('width')))<= 1?eltFromPoint:addChildren(eltFromPoint);
}
//这是最内层的元素
var correctElt = addChildren(elt);
//通过遍历它的所有父对象并将值相加,找到元素的顶部和左边的值,因为顶部和左边是相对于父元素的,但我们想要相对的墙
for(var curElt = correctElt,correctTop = 0,correctLeft = 0; curElt!== elt; curElt = curElt.parentNode){
//获取当前元素的样式
var curEltStyle = getComputedStyle(curElt)
//将当前元素的顶部和左边添加到总计
correctTop + = parseFloat(curEltStyle.getPropertyValue('top'));
correctLeft + = parseFloat(curEltStyle.getPropertyValue('left'));
}
//重置元素
elt.innerHTML = origHTML;
//恢复元素样式
elt.style.padding = origPadding;
elt.style.margin = origMargin;
//返回的对象
var returnObj = {
x:correctLeft,
y:correctTop
}
return returnObj;
}
重要!您还必须包含此CSS才能正常工作:
.offsetrect {
position:absolute;
opacity:0;
height:33.333%;
width:33.333%;
}
#topleftoffset {
top:0;
left:0;
}
#topcenteroffset {
top:0;
left:33.333%;
}
#toprightoffset {
top:0;
left:66.666%;
}
#centerleftoffset {
top:33.333%;
left:0;
}
#centercenteroffset {
top:33.333%;
left:33.333%;
}
#centerrightoffset {
top:33.333%;
left:66.666%;
}
#bottomleftoffset {
top:66.666%;
left:0;
}
#bottomcenteroffset {
top:66.666%;
left:33.333%;
}
#bottomrightoffset {
top:66.666%;
left:66.666%;
}
另外:我通过给祖父div使用#div1
而不是 div
,因为我的代码生成div和您的div样式也适用于我的代码使用的和弄乱了
一个最后:我不知道CoffeeScript,所以我调整你的代码,使它纯JavaScript。对不起,
The webkitConvertPointFromPageToNode(in Node node, in WebKitPoint p)
method is awesome; give it a DOM node and a point in page-coordinates (say, the mouse cursor position) and it will give a coordinate back to you in that node's local coordinate system. Unfortunately, it's currently only available in webkit.
# Choose a node into which we'll map the mouse coordinates
node = $('#subjectElement').get(0)
handleMouseMove = (e) ->
# Convert the mouse position to a Point
mousePoint = new WebKitPoint(e.pageX, e.pageY)
# Convert the mouse point into node coordinates using WebKit
nodeCoords = webkitConvertPointFromPageToNode(node, mousePoint)
# Attach a handler to track the mouse position
$(document).on 'mousemove', handleMouseMove
I've thrown my entire math-brain at the problem, but no matter how close I get, my implementation falls apart with one extra level of composition, or the application of 3D perspective.
It's time for a convertPointFromPageToNode
polyfill that works as well as the WebKit implementation, in 3D. @4esn0k gave one a shot, but it only solves the 2D case.
Can you write one that makes this JSFiddle work?
http://jsfiddle.net/steveluscher/rA27K/
This seems like an amazing question, but there is an ALMOST duplicate right here: How to get the MouseEvent coordinates for an element that has CSS3 Transform? but nobody is looking at my answer there and this seems to be much more general so I'll post it again here, with a few modifications to make it more clear:
Basically, it works by doing this: split the element you are trying to find relative coordinates for, and split it into 9 smaller elements. Use document.elementFromPoint to find if the coordinate is over that mini-element. If it is, split that element into 9 more elements, and keep doing this until a pretty accurate coordinate is possible. Then use getBoundingClientRect to find the on-screen coordinates of that mini-element. BOOM!
jsfiddle: http://jsfiddle.net/markasoftware/rA27K/8/
Here is the JavaScript function:
function convertPointFromPageToNode(elt,coords){
///the original innerHTML of the element
var origHTML=elt.innerHTML;
//now clear it
elt.innerHTML='';
//now save and clear bad styles
var origPadding=elt.style.padding=='0px'?'':elt.style.padding;
var origMargin=elt.style.margin=='0px'?'':elt.style.margin;
elt.style.padding=0;
elt.style.margin=0;
//make sure the event is in the element given
if(document.elementFromPoint(coords.x,coords.y)!==elt){
//reset the element
elt.innerHTML=origHTML;
//and styles
elt.style.padding=origPadding;
elt.style.margin=origMargin;
//we've got nothing to show, so return null
return null;
}
//array of all places for rects
var rectPlaces=['topleft','topcenter','topright','centerleft','centercenter','centerright','bottomleft','bottomcenter','bottomright'];
//function that adds 9 rects to element
function addChildren(elt){
//loop through all places for rects
rectPlaces.forEach(function(curRect){
//create the element for this rect
var curElt=document.createElement('div');
//add class and id
curElt.setAttribute('class','offsetrect');
curElt.setAttribute('id',curRect+'offset');
//add it to element
elt.appendChild(curElt);
});
//get the element form point and its styling
var eltFromPoint=document.elementFromPoint(coords.x,coords.y);
var eltFromPointStyle=getComputedStyle(eltFromPoint);
//Either return the element smaller than 1 pixel that the event was in, or recurse until we do find it, and return the result of the recursement
return Math.max(parseFloat(eltFromPointStyle.getPropertyValue('height')),parseFloat(eltFromPointStyle.getPropertyValue('width')))<=1?eltFromPoint:addChildren(eltFromPoint);
}
//this is the innermost element
var correctElt=addChildren(elt);
//find the element's top and left value by going through all of its parents and adding up the values, as top and left are relative to the parent but we want relative to teh wall
for(var curElt=correctElt,correctTop=0,correctLeft=0;curElt!==elt;curElt=curElt.parentNode){
//get the style for the current element
var curEltStyle=getComputedStyle(curElt);
//add the top and left for the current element to the total
correctTop+=parseFloat(curEltStyle.getPropertyValue('top'));
correctLeft+=parseFloat(curEltStyle.getPropertyValue('left'));
}
//reset the element
elt.innerHTML=origHTML;
//restore element styles
elt.style.padding=origPadding;
elt.style.margin=origMargin;
//the returned object
var returnObj={
x: correctLeft,
y: correctTop
}
return returnObj;
}
IMPORTANT!!! You must also include this CSS for it to work:
.offsetrect{
position: absolute;
opacity: 0;
height: 33.333%;
width: 33.333%;
}
#topleftoffset{
top: 0;
left: 0;
}
#topcenteroffset{
top: 0;
left: 33.333%;
}
#toprightoffset{
top: 0;
left: 66.666%;
}
#centerleftoffset{
top: 33.333%;
left: 0;
}
#centercenteroffset{
top: 33.333%;
left: 33.333%;
}
#centerrightoffset{
top: 33.333%;
left: 66.666%;
}
#bottomleftoffset{
top: 66.666%;
left: 0;
}
#bottomcenteroffset{
top: 66.666%;
left: 33.333%;
}
#bottomrightoffset{
top: 66.666%;
left: 66.666%;
}
ALSO: I modified a little of your css by giving the "grandfather" div an id and referencing to it in your css using #div1
instead of div
because my code generates divs, and your div styles were also applying to the ones my code uses and messed it up
ONE LAST THING: I don't know CoffeeScript so I adjusted your code to make it pure JavaScript. Sorry about that.
这篇关于显示webkitConvertPointFromPageToNode的Javascript实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!