4

webkitConvertPointFromPageToNode(in Node node, in WebKitPoint p)方法很棒;给它一个 DOM 节点和页面坐标中的一个点(例如,鼠标光标位置),它会在该节点的本地坐标系中将坐标返回给您。不幸的是,它目前仅在 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    

我已经把我的整个数学大脑都投入到了这个问题上,但无论我有多接近,我的实现都会因多一层的构图或 3D 透视的应用而崩溃。

是时候使用convertPointFromPageToNode3D 中与 WebKit 实现一样有效的 polyfill 了。@4esn0k 试 了一下,但它只解决了 2D 的情况。

你能写一个让这个 JSFiddle 工作的吗?

webkitConvertPointFromPageToNode 在复杂转换的元素上踢屁股并取名

http://jsfiddle.net/steveluscher/rA27K/

4

3 回答 3

3

这似乎是一个令人惊奇的问题,但这里有一个几乎重复的问题:如何获取具有 CSS3 变换的元素的 MouseEvent 坐标?但没有人在那里看我的答案,这似乎更笼统,所以我会在这里再次发布,并进行一些修改以使其更清楚:

基本上,它的工作原理是:拆分您尝试为其查找相对坐标的元素,并将其拆分为 9 个较小的元素。使用 document.elementFromPoint 来查找坐标是否在那个小元素之上。如果是,则将该元素拆分为另外 9 个元素,并继续这样做,直到可以得到相当准确的坐标。然后使用 getBoundingClientRect 查找该迷你元素的屏幕坐标。繁荣!

jsfiddle:http: //jsfiddle.net/markasoftware/rA27K/8/

这是 JavaScript 函数:

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

重要的!!!您还必须包含此 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 一个 id 并在你的 css 中引用它#div1而不是div因为我的代码生成 div 来修改你的一些 css,并且你的 div 样式也适用于我的代码使用的那些并弄乱了它向上

最后一件事:我不知道 CoffeeScript,所以我调整了您的代码以使其成为纯 JavaScript。对于那个很抱歉。

于 2013-10-29T01:05:06.693 回答
2

我已经编写了一些 TypeScript 代码来进行一些转换: jsidea core library。它还不稳定(pre alpha)。你可以这样使用它:

创建您的转换实例:

var transformer = jsidea.geom.Transform.create(yourElement);

您要转换为的盒子模型(默认值:“border”):

var toBoxModel = "border";

您的输入坐标来自的盒子模型(默认值:“border”):

var fromBoxModel = "border";

将您的全局坐标(此处为 {x:50, y:100, z: 0})转换为本地空间。结果点有 4 个分量:x、y、z 和 w。

var local = transformer.globalToLocal(50, 100, 0, toBoxModel, fromBoxModel);

我已经实现了一些其他功能,例如 localToGlobal 和 localToLocal。如果您想尝试一下,只需下载发布版本并使用 jsidea.min.js。

于 2015-08-14T19:50:31.833 回答
0

我有这个问题并开始尝试计算矩阵。我围绕它建立了一个图书馆:https ://github.com/ombr/referentiel

$('.referentiel').each ->
  ref = new Referentiel(this)
  $(this).on 'click', (e)->
    input = [e.pageX, e.pageY]
    p = ref.global_to_local(input)
    $pointer = $('.pointer', this)
    $pointer.css('left', p[0]-1)
    $pointer.css('top', p[1]-1)

你怎么看 ?

于 2017-09-18T17:28:52.563 回答