상세 컨텐츠

본문 제목

[JavaScript] 자바스크립트 마우스 위치, 포지션 관련

WEB/html5

by AlrepondTech 2017. 11. 14. 20:25

본문

반응형
728x170

 

 

 

=================================

=================================

=================================

 

 

 

 

This should not be any different from getting mouse events from normal dom elements. quirksmode has a good reference on that. – airportyh Sep 11 '08 at 2:50
4  
The code you list above only works when the canvas isn't deep inside other containers. In general you need to use something like the jquery offset function [var testDiv = $('#testDiv'); var offset = testDiv.offset();] to get the correct offset in a cross browser way. This is a real pain in the ***. – Aaron Watters Jun 14 '10 at 20:34
    
The code posted above with Update fails to work if the page containing the canvas scrolls. – Timothy Kim Feb 8 '11 at 3:52
    
I removed my old "answer" that was included as an update to the question. As mentioned, it was out of date and incomplete. – Tom Mar 28 '11 at 8:50
2  
Since there is like 50 answers here, I recommend scrolling to this guys answer: patriques - a good and simple 5 liner. – Igor L. Apr 21 '14 at 11:04

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

As described here:

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;

Worked perfectly fine for me.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

Since the canvas isn't always styled relative to the entire page, the canvas.offsetLeft/Top doesn't always return what you need. It will return the number of pixels it is offset relative to its offsetParent element, which can be something like a div element containing the canvas with a position: relative style applied. To account for this you need to loop through the chain of offsetParents, beginning with the canvas element itself. This code works perfectly for me, tested in Firefox and Safari but should work for all.

function relMouseCoords(event){     var totalOffsetX = 0;     var totalOffsetY = 0;     var canvasX = 0;     var canvasY = 0;     var currentElement = this;      do{         totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft;         totalOffsetY += currentElement.offsetTop - currentElement.scrollTop;     }     while(currentElement = currentElement.offsetParent)      canvasX = event.pageX - totalOffsetX;     canvasY = event.pageY - totalOffsetY;      return {x:canvasX, y:canvasY} } HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;

The last line makes things convenient for getting the mouse coordinates relative to a canvas element. All that's needed to get the useful coordinates is

coords = canvas.relMouseCoords(event); canvasX = coords.x; canvasY = coords.y;

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

No, it is using the builtin javascript prototype object --- developer.mozilla.org/en/… – garg Mar 17 '12 at 23:02
12  
my Chrome has event.offsetX and event.offsetY attributes, so I modified your solution by adding if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. looks like it works. – Baczek May 28 '12 at 20:36 
3  
Baczek is correct about Chrome's event.offsetX and event.offsetY which also works in IE9. For Firefox (tested w/ v13) you can use event.layerX and event.layerY. – mafafu Aug 24 '12 at 17:33
3  
I additionally added this: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop; – amirpc Sep 29 '12 at 19:49
4  
This final version on answer didn't work for me. On Firefox, if whole screen is scrolled, I got the displaced value as output. What worked for me was a very similar solution, given on stackoverflow.com/a/10816667/578749 that instead of event.pageX/Y, it subtracted calculated offset from event.clientX/Y. Could someone review this and explain? – lvella Jul 4 '13 at 19:41

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

If you like simplicity but still want cross-browser functionality I found this solution worked best for me. This is a simplification of @Aldekein´s solution but without jQuery.

function getCursorPosition(canvas, event) {     var rect = canvas.getBoundingClientRect();     var x = event.clientX - rect.left;     var y = event.clientY - rect.top;     console.log("x: " + x + " y: " + y); }

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

Modern browser's now handle this for you. Chrome, IE9, and Firefox support the offsetX/Y like this, passing in the event from the click handler.
function getRelativeCoords(event) { return { x: event.offsetX, y: event.offsetY }; }
Most modern browsers also support layerX/Y, however Chrome and IE use layerX/Y for the absolute offset of the click on the page including margin, padding, etc. In Firefox, layerX/Y and offsetX/Y are equivalent, but offset didn't previously exist. So, for compatibility with slightly older browsers, you can use:
function getRelativeCoords(event) { return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY }; }

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

interesting how layerX, layerY is defined on both Chrome and Firefox, but on Chrome it is inaccurate (or means something else). – Julian Mann Jul 5 '16 at 17:51
    
@JulianMann Thanks for the info. I've updated this answer based on more current support. Looks like you can get away with offsetX/Y almost universally now. – mafafu Jul 6 '16 at 18:47
1  
This works and it is short and sweet. +1. Thanks! 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

According to fresh Quirksmode the clientX and clientY methods are supported in all major browsers. So, here it goes - the good, working code that works in a scrolling div on a page with scrollbars:

function getCursorPosition(canvas, event) { var x, y;  canoffset = $(canvas).offset(); x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - Math.floor(canoffset.left); y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - Math.floor(canoffset.top) + 1;  return [x,y]; }

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I made a full demostration that works in every browser with the full source code of the solution of this problem: Coordinates of a mouse click on Canvas in Javascript. To try the demo, copy the code and paste it into a text editor. Then save it as example.html and, finally, open the file with a browser.

 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

Here is a small modification to Ryan Artecona's answer for canvases with a variable (%) width:

 HTMLCanvasElement.prototype.relMouseCoords = function (event) {     var totalOffsetX = 0;     var totalOffsetY = 0;     var canvasX = 0;     var canvasY = 0;     var currentElement = this;      do {         totalOffsetX += currentElement.offsetLeft;         totalOffsetY += currentElement.offsetTop;     }     while (currentElement = currentElement.offsetParent)      canvasX = event.pageX - totalOffsetX;     canvasY = event.pageY - totalOffsetY;      // Fix for variable canvas width     canvasX = Math.round( canvasX * (this.width / this.offsetWidth) );     canvasY = Math.round( canvasY * (this.height / this.offsetHeight) );      return {x:canvasX, y:canvasY} }
 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 
Be wary while doing the coordinate conversion; there are multiple non-cross-browser values returned in a click event. Using clientX and clientY alone are not sufficient if the browser window is scrolled (verified in Firefox 3.5 and Chrome 3.0).
This quirks mode article provides a more correct function that can use either pageX or pageY or a combination of clientX with document.body.scrollLeft and clientY with document.body.scrollTop to calculate the click coordinate relative to the document origin.
UPDATE: Additionally, offsetLeft and offsetTop are relative to the padded size of the element, not the interior size. A canvas with the padding: style applied will not report the top-left of its content region as offsetLeft. There are various solutions to this problem; the simplest one may be to clear all border, padding, etc. styles on the canvas itself and instead apply them to a box containing the canvas.
 

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Here is a very nice tutorial-

http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/

 <canvas id="myCanvas" width="578" height="200"></canvas> <script>   function writeMessage(canvas, message) {     var context = canvas.getContext('2d');     context.clearRect(0, 0, canvas.width, canvas.height);     context.font = '18pt Calibri';     context.fillStyle = 'black';     context.fillText(message, 10, 25);   }   function getMousePos(canvas, evt) {     var rect = canvas.getBoundingClientRect();     return {       x: evt.clientX - rect.left,       y: evt.clientY - rect.top     };   }   var canvas = document.getElementById('myCanvas');   var context = canvas.getContext('2d');    canvas.addEventListener('mousemove', function(evt) {     var mousePos = getMousePos(canvas, evt);     var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;     writeMessage(canvas, message);   }, false);

hope this helps!

shareimprove this answer
 

 

 
반응형

 

 

 
728x90
 

 

 
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
 
I'm not sure what's the point of all these answers that loop through parent elements and do all kinds of weird stuff.
The HTMLElement.getBoundingClientRect method is designed to to handle actual screen position of any element. This includes scrolling, so stuff like scrollTop is not needed:
(from MDN) The amount of scrolling that has been done of the viewport area (or any other scrollable element) is taken into account when computing the bounding rectangle

Normal image

The very simplest approach was already posted here. This is correct as long as no wild CSS rules are involved.

Handling stretched canvas/image

When image pixel width isn't matched by it's CSS width, you'll need to apply some ratio on pixel values:
/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/ HTMLCanvasElement.prototype.relativeCoords = function(event) { var x,y; //This is the current screen rectangle of canvas var rect = this.getBoundingClientRect(); var top = rect.top; var bottom = rect.bottom; var left = rect.left; var right = rect.right; //Recalculate mouse offsets to relative offsets x = event.clientX - left; y = event.clientY - top; //Also recalculate offsets of canvas is stretched var width = right - left; //I use this to reduce number of calculations for images that have normal size if(this.width!=width) { var height = bottom - top; //changes coordinates by ratio x = x*(this.width/width); y = y*(this.height/height); } //Return as an array return [x,y]; }
As long as the canvas has no border, it works for stretched images (jsFiddle).

Handling CSS borders

If the canvas has thick border, the things get little complicated. You'll literally need to subtract the border from the bounding rectangle. This can be done using .getComputedStyle. This answer describes the process.
The function then grows up a little:
/* Returns pixel coordinates according to the pixel that's under the mouse cursor**/ HTMLCanvasElement.prototype.relativeCoords = function(event) { var x,y; //This is the current screen rectangle of canvas var rect = this.getBoundingClientRect(); var top = rect.top; var bottom = rect.bottom; var left = rect.left; var right = rect.right; //Subtract border size // Get computed style var styling=getComputedStyle(this,null); // Turn the border widths in integers var topBorder=parseInt(styling.getPropertyValue('border-top-width'),10); var rightBorder=parseInt(styling.getPropertyValue('border-right-width'),10); var bottomBorder=parseInt(styling.getPropertyValue('border-bottom-width'),10); var leftBorder=parseInt(styling.getPropertyValue('border-left-width'),10); //Subtract border from rectangle left+=leftBorder; right-=rightBorder; top+=topBorder; bottom-=bottomBorder; //Proceed as usual ... }
I can't think of anything that would confuse this final function. See yourself at JsFiddle.

Notes

If you don't like modifying the native prototypes, just change the function and call it with (canvas, event) (and replace any this with canvas).
 
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Using jQuery in 2016, to get click coordinates relative to the canvas, I do:

$(canvas).click(function(jqEvent) {     var coords = {         x: jqEvent.pageX - $(canvas).offset().left,         y: jqEvent.pageY - $(canvas).offset().top     }; });

This works since both canvas offset() and jqEvent.pageX/Y are relative to the document regardless of scroll position.

Note that if your canvas is scaled then these coordinates are not the same as canvas logical coordinates. To get those, you would also do:

var logicalCoords = {     x: coords.x * (canvas.width / $(canvas).width()),     y: coords.y * (canvas.height / $(canvas).height()) }

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

I recommend this link- http://miloq.blogspot.in/2011/05/coordinates-mouse-click-canvas.html

 

<style type="text/css">    #canvas{background-color: #000;}  </style>  <script type="text/javascript">    document.addEventListener("DOMContentLoaded", init, false);    function init()   {     var canvas = document.getElementById("canvas");     canvas.addEventListener("mousedown", getPosition, false);   }    function getPosition(event)   {     var x = new Number();     var y = new Number();     var canvas = document.getElementById("canvas");      if (event.x != undefined && event.y != undefined)     {       x = event.x;       y = event.y;     }     else // Firefox method to get the position     {       x = event.clientX + document.body.scrollLeft +           document.documentElement.scrollLeft;       y = event.clientY + document.body.scrollTop +           document.documentElement.scrollTop;     }      x -= canvas.offsetLeft;     y -= canvas.offsetTop;      alert("x: " + x + "  y: " + y);   }  </script>
 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

In Prototype, use cumulativeOffset() to do the recursive summation as mentioned by Ryan Artecona above.

http://www.prototypejs.org/api/element/cumulativeoffset

shareimprove this answer

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

You could just do:

var canvas = yourCanvasElement; var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2; var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;

This will give you the exact position of the mouse pointer.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

See demo at http://jsbin.com/ApuJOSA/1/edit?html,output .

  function mousePositionOnCanvas(e) {       var el=e.target, c=el;       var scaleX = c.width/c.offsetWidth || 1;       var scaleY = c.height/c.offsetHeight || 1;        if (!isNaN(e.offsetX))            return { x:e.offsetX*scaleX, y:e.offsetY*scaleY };        var x=e.pageX, y=e.pageY;       do {         x -= el.offsetLeft;         y -= el.offsetTop;         el = el.offsetParent;       } while (el);       return { x: x*scaleX, y: y*scaleY };   }

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Hey, this is in dojo, just cause it's what I had the code in already for a project.

It should be fairly Obvious how to convert it back to non dojo vanilla JavaScript.

  function onMouseClick(e) {       var x = e.clientX;       var y = e.clientY;   }   var canvas = dojo.byId(canvasId);   dojo.connect(canvas,"click",onMouseClick);

Hope that helps.

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Here is some modifications of the above Ryan Artecona's solution.

function myGetPxStyle(e,p) {     var r=window.getComputedStyle?window.getComputedStyle(e,null)[p]:"";     return parseFloat(r); }  function myGetClick=function(ev) {     // {x:ev.layerX,y:ev.layerY} doesn't work when zooming with mac chrome 27     // {x:ev.clientX,y:ev.clientY} not supported by mac firefox 21     // document.body.scrollLeft and document.body.scrollTop seem required when scrolling on iPad     // html is not an offsetParent of body but can have non null offsetX or offsetY (case of wordpress 3.5.1 admin pages for instance)     // html.offsetX and html.offsetY don't work with mac firefox 21      var offsetX=0,offsetY=0,e=this,x,y;     var htmls=document.getElementsByTagName("html"),html=(htmls?htmls[0]:0);      do     {         offsetX+=e.offsetLeft-e.scrollLeft;         offsetY+=e.offsetTop-e.scrollTop;     } while (e=e.offsetParent);      if (html)     {         offsetX+=myGetPxStyle(html,"marginLeft");         offsetY+=myGetPxStyle(html,"marginTop");     }      x=ev.pageX-offsetX-document.body.scrollLeft;     y=ev.pageY-offsetY-document.body.scrollTop;     return {x:x,y:y}; }
shareimprove this answer

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

First, as others have said, you need a function to get the position of the canvas element. Here's a method that's a little more elegant than some of the others on this page (IMHO). You can pass it any element and get its position in the document:

function findPos(obj) {     var curleft = 0, curtop = 0;     if (obj.offsetParent) {         do {             curleft += obj.offsetLeft;             curtop += obj.offsetTop;         } while (obj = obj.offsetParent);         return { x: curleft, y: curtop };     }     return undefined; }

Now calculate the current position of the cursor relative to that:

$('#canvas').mousemove(function(e) {     var pos = findPos(this);     var x = e.pageX - pos.x;     var y = e.pageY - pos.y;     var coordinateDisplay = "x=" + x + ", y=" + y;     writeCoordinateDisplay(coordinateDisplay); });

Notice that I've separated the generic findPos function from the event handling code. (As it should be. We should try to keep our functions to one task each.)

The values of offsetLeft and offsetTop are relative to offsetParent, which could be some wrapper div node (or anything else, for that matter). When there is no element wrapping the canvas they're relative to the body, so there is no offset to subtract. This is why we need to determine the position of the canvas before we can do anything else.

Similary, e.pageX and e.pageY give the position of the cursor relative to the document. That's why we subtract the canvas's offset from those values to arrive at the true position.

An alternative for positioned elements is to directly use the values of e.layerX and e.layerY. This is less reliable than the method above for two reasons:

  1. These values are also relative to the entire document when the event does not take place inside a positioned element
  2. They are not part of any standard

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

ThreeJS r77

var x = event.offsetX == undefined ? event.layerX : event.offsetX; var y = event.offsetY == undefined ? event.layerY : event.offsetY;  mouse2D.x = ( x / renderer.domElement.width ) * 2 - 1; mouse2D.y = - ( y / renderer.domElement.height ) * 2 + 1;

After trying many solutions. This worked for me. Might help someone else hence posting. Got it from here

 

 

=================================

=================================

=================================

 

 

반응형
그리드형


관련글 더보기

댓글 영역