This is a complete mess which this page hopes to clarify.
Background
Unfortunately, javascript security prevents the code from determining the color of pixels in an image. If this was not the case, then it would be possible for code to disable the image captchas used to verify that you are a person and not a program. There are a couple of ways around that, but
Test region
|
|
Browser | client X Y | layer X Y | X Y | canvas.offset Left Top | evt.client X Y |
---|---|---|---|---|---|
Chrome 49 Windows XP | 155 223 | 100 100 | 155 223 | 5 23 | 100 100.4 |
367 241 | 100 100 | 367 241 | 5 41 | 100 100.4 | |
Chrome 55 Windows 10 | 154 446 | 17 -721 | 154 446 | 5 22 | 99.2 98.8 |
366 464 | -301 -747 | 366 464 | 5 40 | 99 99.2 | |
Firefox 24 Windows XP | 155 250 | 155 706 | undefined | 5 32 | 100 98.699.. |
367 383 | 367 725 | 5 50 | 100 98.699.. | ||
Firefox 47 Windows 10 | 155 354 | 155 678 | undefined | 5 22 | 100 99.699.. |
366 372 | 366 696 | 5 40 | 99 100.299.. | ||
MS Edge 25 & MSIE 11 Windows 10 | 155 364 | 155 364 | 155 364 | 5 22 | 100 100.92 |
367 380 | 367 380 | 367 380 | 5 39 | 100 99.72 |
For the browsers that support it, clientXY and XY are the same. However, Firefox does not support XY.
I don't understand how subtracting one integer from another produces a non-integer result.
Getting data from Images
The canvas has been tainted by cross-origin data. |
As mentioned above, this is a reasonable security measure. Without it, malicious code would be able to read images and do bad stuff. I found a work around, but it requires a server modification and is "browser dependent". Since
To be clear - when the javascript file and image are both stored in the same directory on a local machine, Chrome produces the security error. As a result, for me, this is a show stopper.
Also, neither of these references even mentions this "problem".
Suggested code (that fails)
By comparing the examples below and the tables above, it should be obvious that both sources are clueless. The numbers are from a debug session using Chrome 49 on Windows XP.
// How to make your own custom color picker suggests the following var X = e.clientX - ctx.canvas.offsetLeft; // 95 - 8 = 87 var Y = e.clientY - ctx.canvas.offsetTop; // 577 - 1480 = -903 // mozilla.org suggests the following var X = e.layerX ; // 87 these are correct values for var Y = e.layerY ; // 97 Chrome 49 on Windows XP - ONLY |
The (very poorly documented) problem with the first suggestion is that canvas.offsetLeft and canvas.offsetTop refer to the canvas position relative to the object that contains it unless it is placed directly in the page body. In that case, they are referenced to the viewport and there is no problem. However, when the canvas is placed in a table (which I usually do), then the offsets are with respect to the top left corner of the table! On the other hand, e.clientX and e.clientY are always referenced to the viewport . Using the images above, when you scroll the page the e.clientY value for the target changes. The solution (shown in the next section) is to use getBoundingClientRect() to get the canvas location relative to the viewport ... and not the table or some other UI component. (Note - the viewport is the visible part of the window.)
w3schools.com documents these mouse event properties (only the X-versions are shown)
canvas.onmousedown = function (event) { var x = event.layerX || event.offsetX; var y = event.layerY || event.offsetY; alert(x + " " + y); } |
At any rate, in Chrome 55 on Windows 10, layerX is OK, but layerY provides the wrong value (-1841). In fact, offsetX and offsetY appear to contain the "correct" values. (Since they aren't in the spec, I did not bother to test them.)
This browser incompatibility problem is simply a nightmare!
The solution is to use getBoundingClientRect() to get the canvas location relative to the viewport ... the visible part of the window.
This is the code I used with GHCN_Temperature_Plotter.html
// get mouse coordinates in canvas function mouseXY( e ) { var rect = document.getElementById("mapCanvas").getBoundingClientRect(); return { clientX:(e.clientX-rect.left), clientY:(e.clientY-rect.top) } } // add event listeners to handle screen drag canvas.addEventListener("mousedown", function(event){ var evt = mouseXY(event); mouseDown = true; startDrag.x = evt.clientX; startDrag.y = evt.clientY; }); |