Show me the Javascript implementation for webkitConvertPointFromPageToNode

The webkitConvertPointFromPageToNode(in Node node, in WebKitPoint p) is awesome; give it a DOM node and a point in the page coordinates (say, the position of the mouse cursor), and it will return you the coordinates in this local node coordinate system. Unfortunately, it is 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 threw my whole mathematical brain at a problem, but no matter how much I get, my implementation falls apart into one additional level of composition or application of a three-dimensional perspective.

This is the time for convertPointFromPageToNode polyfill, which works the same as the WebKit implementation in 3D. @ 4esn0k gave one snapshot , but it only allows a 2D file.

Can you write what makes this JSFiddle work?

webkitConvertPointFromPageToNode kicking ass and taking names on a complicatedly transformed element

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

+4
source share
3 answers

This seems like an amazing question, but there is ALMOST duplicate here: How to get MouseEvent coordinates for an element with CSS3 Transform? but no one is looking at my answer there, and that seems a lot more general, so I will post it again here, with a few changes, to make it more clear:

Basically, it works by doing this: divide the element by which you are trying to find the relative coordinates, and divide it into 9 smaller elements. Use document.elementFromPoint to find out if the coordinate is above this mini element. If so, divide this element into another 9 elements and continue to do so until the coordinates are sufficiently accurate. Then use getBoundingClientRect to find the screen coordinates of this widget. 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 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 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 changed your css a bit by providing a β€œgrandfather” div id and referencing it in your css using #div1 instead of div because my code generates a div and your div styles also applied to the ones my code uses, and ruined it.

ONE LAST THING: I don't know CoffeeScript, so I adjusted your code to make it pure JavaScript. Excuse me.

+3
source

I wrote TypeScript code that does some conversion: the jsidea core library . Its unstable (pre alpha). You can use it like this:

Create an instance of the transformation:

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

The box model you want to convert (default: "border"):

 var toBoxModel = "border"; 

The window model where your input coordinates come from (default: "border"):

 var fromBoxModel = "border"; 

Convert your global coordinates (here {x: 50, y: 100, z: 0}) to local space. The resulting point has 4 components: x, y, z and w.

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

I implemented some other functions like localToGlobal and localToLocal. If you want to try, just download the release build and use jsidea.min.js.

+2
source

I have this problem and I started trying to calculate the matrix. I created a library around it: 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) 

What do you think?

0
source

Source: https://habr.com/ru/post/1494207/


All Articles