Wie erhalte ich die Koordinaten eines Mausklicks auf ein Canvas-Element?
-
09-06-2019 - |
Frage
Was ist die einfachste Möglichkeit, einem Canvas-Element einen Click-Event-Handler hinzuzufügen, der die X- und Y-Koordinaten des Klicks (relativ zum Canvas-Element) zurückgibt?
Keine Kompatibilität mit älteren Browsern erforderlich, Safari, Opera und Firefox reichen aus.
Lösung
Bearbeiten 2018: Diese Antwort ist ziemlich alt und es verwendet Kontrollen für alten Browser, das nicht mehr erforderlich ist, da die clientX
und clientY
Eigenschaften in allen gängigen Browsern. Sie könnten Patriques Antwort für eine einfachere, aktuellere Lösung zu sehen.
Original Antwort:
Wie in einem Artikel fand ich damals aber nicht mehr existiert:
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;
Arbeitete völlig in Ordnung für mich.
Andere Tipps
Aktualisieren (5/5/16): patriques' Antwort sollte stattdessen verwendet werden , wie es ist einfacher und zuverlässiger.
Da die Leinwand nicht immer bezogen auf die gesamte Seite gestylt ist, wird das canvas.offsetLeft/Top
nicht immer wieder zurückkehren, was Sie brauchen. Es wird die Anzahl der Pixel wieder in dem offset Elemente versetzt wird, das so etwas wie ein div
Element sein kann, enthält, angewandt, um die Leinwand mit einem position: relative
Stil. Um zu berücksichtigen, diese müssen Sie durch die Kette von offsetParent
s Schleife, mit dem Canvas-Element beginnt sich. Dieser Code funktioniert perfekt für mich, getestet in Firefox und Safari, aber sollte für alle arbeiten.
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;
Die letzte Zeile macht die Dinge bequem für das Erhalten der Maus auf ein Canvas-Element relativ koordiniert. Alles, was benötigt, um die nützlichen Koordinaten zu erhalten, ist
coords = canvas.relMouseCoords(event);
canvasX = coords.x;
canvasY = coords.y;
Wenn Sie Einfachheit mögen, aber immer noch wollen, Cross-Browser-Funktionalität fand ich diese Lösung am besten funktioniert für mich. Dies ist eine Vereinfachung von @ Aldekein's Lösung aber ohne 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);
}
Moderne Browser ist jetzt handhaben dies für Sie. Chrome, IE9 und Firefox die offsetX / Y wie dies unterstützen, im Fall von den Click-Handler übergeben.
function getRelativeCoords(event) {
return { x: event.offsetX, y: event.offsetY };
}
Die meisten modernen Browser auch layerX / Y, aber Chrome und IE verwenden layerX / Y für die absoluten Offset des Klick auf der Seite einschließlich Marge, Polsterung, usw. In Firefox, layerX / Y und offsetX / Y ist äquivalent unterstützen, aber versetzt vorher nicht existieren. Also, für die Kompatibilität mit etwas älteren Browsern können Sie verwenden:
function getRelativeCoords(event) {
return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}
Nach frischen Quirksmode die clientX
und clientY
Methoden in allen unterstützt werden gängige Browser.
Also, hier geht es - den guten, Arbeitscode, der auf einer Seite mit Bildlaufleisten in einem Scroll-div funktioniert:
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];
}
Dies erfordert auch jQuery $(canvas).offset()
.
habe ich eine volle demostration, die mit dem vollständigen Quellcode der Lösung dieses Problems in jedem Browser funktioniert: Koordinaten eines Mausklicks auf Leinwand in Javascript . Um zu versuchen, die Demo, kopieren Sie den Code und fügen Sie ihn in einen Texteditor. dann speichern Sie es als example.html und schließlich öffnen Sie die Datei mit einem Browser.
Hier ist eine kleine Änderung an Ryan Artecona Antwort für Leinwände mit einer Variablen (%) Breite:
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}
}
Seien Sie vorsichtig, während die Koordinatenumwandlung zu tun; gibt es mehrere nicht-Cross-Browser-Werte in einem Click-Ereignis zurückgegeben. Mit clientX und clientY allein ist nicht ausreichend, wenn die Browser-Fenster (überprüft in Firefox 3.5 und Chrome 3.0) gescrollt werden.
Diese Quirksmodus Artikel eine korrekte Funktion bereitstellt, die entweder pageX verwenden können, oder pageY oder eine Kombination aus clientX mit document.body.scrollLeft und clientY document.body.scrollTop mit der Klick-Koordinate relativ zu dem Ursprung Dokument zu berechnen.
UPDATE: Zusätzlich offsetleft und offsetTop auf die gepolsterte Größe des Elements relativ ist, nicht die innere Größe. Eine Leinwand mit der Polsterung: Stil angewendet wird die linke obere ihres Inhalts Region nicht offsetleft melden. Es gibt verschiedene Lösungen für dieses Problem; die einfachste können alle Grenze zu löschen, Polsterung usw. Stile auf der Leinwand selbst und wenden sie stattdessen zu einer Box die Leinwand enthält.
Ich bin nicht sicher, was ist der Sinn all dieser Antworten, die href="https://stackoverflow.com/a/5932203/607407"> Schleife durch übergeordnete Elemente und tun alle Arten von weird stuff .
Die HTMLElement.getBoundingClientRect
Verfahren wurde entwickelt, um auf tatsächliche Bildschirmposition eines Elements handhaben. Dazu gehören Scrollen, so Sachen wie scrollTop
ist nicht erforderlich:
(von MDN) die Menge des Scrollens, die im Darstellungsbereich gemacht wurde (oder andere rollbare Element ) berücksichtigt bei der Berechnung der Begrenzungsrechteck
Normale Bild
Die einfachsten Ansatz bereits hier gepostet wurde. Das ist richtig, solange keine wilden CSS Regeln beteiligt sind.
Handhabung Leinwand / Bild
Wenn die Bildpixelbreite von ihm nicht abgestimmt ist CSS Breite, müssen Sie einige Verhältnis auf Pixelwerte anwenden:
/* 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];
}
Solange die Leinwand keine Grenze hat, es funktioniert für gestreckte Bilder (jsFiddle) .
Handling CSS Grenzen
Wenn die Leinwand hat dicke Grenze, die Dinge etwas kompliziert bekommen. Sie werden buchstäblich müssen die Grenze von dem Begrenzungsrechteck subtrahieren. Dies kann href="https://developer.mozilla.org/en/docs/Web/API/window.getComputedStyle" rel="nofollow noreferrer"> .getComputedStyle mit Antwort beschreibt den Prozess .
Die Funktion dann wächst ein wenig:
/* 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
...
}
Ich kann an nichts denken, dass diese letzte Funktion verwirren würde. Sehen Sie sich unter JsFiddle .
Notizen
Wenn Sie nicht wie die nativen prototype
s ändern, nur die Funktion ändern und nennt es mit (canvas, event)
(und ersetzt jede this
mit canvas
).
Hier ist ein sehr schönes Tutorial -
http://www.html5canvastutorials.com/advanced/html5-canvas -Maus-Koordinaten /
<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);
hoffe, das hilft!
jQuery Mit 2016 Klick-Koordinaten in Bezug auf die Leinwand zu bringen, das tue ich:
$(canvas).click(function(jqEvent) {
var coords = {
x: jqEvent.pageX - $(canvas).offset().left,
y: jqEvent.pageY - $(canvas).offset().top
};
});
arbeitet Dies, da sowohl Leinwand Offset () und jqEvent.pageX / Y relativ zu dem Dokument ist unabhängig von Scroll-Position.
Beachten Sie, wenn Sie Ihre Leinwand skaliert wird dann diese Koordinaten sind nicht die gleichen wie Leinwand logische Koordinaten . Die zu bekommen, würden Sie auch zu tun:
var logicalCoords = {
x: coords.x * (canvas.width / $(canvas).width()),
y: coords.y * (canvas.height / $(canvas).height())
}
Ich empfehle dieses Link- http://miloq.blogspot.in/2011/05/coordinates -Maus-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 verwendet cumulativeOffset () die rekursive Aufsummierung zu tun, wie oben von Ryan Artecona erwähnt.
Sie können nur tun:
var canvas = yourCanvasElement;
var mouseX = (event.clientX - (canvas.offsetLeft - canvas.scrollLeft)) - 2;
var mouseY = (event.clientY - (canvas.offsetTop - canvas.scrollTop)) - 2;
Dies gibt Ihnen die genaue Position des Mauszeigers.
Siehe Demo unter http://jsbin.com/ApuJOSA/1/edit?html , Ausgabe .
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 };
}
Das ist also sowohl einfache, aber ein etwas kompliziertes Thema, als es scheint.
Als erstes gibt es in der Regel zu conflated Fragen hier
-
Wie Element relativ Mauskoordinaten
bekommen
-
Wie Leinwand Pixel Maus-Koordinaten für den 2D-Canvas-API oder WebGL
bekommen
so, Antworten
Wie Element relativ Mauskoordinaten
bekommenUnabhängig davon, ob das Element ein Leinwand immer Element relativ Mauskoordinaten ist das gleiche für alle Elemente.
Es gibt zwei einfache Antworten auf die Frage „Wie Leinwand relativ Mauskoordinaten erhalten“
Einfache Antwort # 1 Verwendung offsetX
und offsetY
canvas.addEventListner('mousemove', (e) => {
const x = e.offsetX;
const y = e.offsetY;
});
Diese Antwort funktioniert in Chrome, Firefox und Safari. Im Gegensatz zu allen anderen Ereigniswerten offsetX
und CSS offsetY
nehmen verwandelt zu berücksichtigen.
Das größte Problem mit offsetX
und offsetY
ist ab 2019/05 sie auf Berührungsereignisse nicht vorhanden sind und kann daher nicht mit iOS Safari verwendet werden. Es gibt sie auf Pointer Ereignisse, die in Chrome und Firefox existieren, aber nicht Safari obwohl anscheinend Safari daran zu arbeiten .
Ein weiteres Problem ist die Ereignisse auf der Leinwand selbst sein muss. Wenn Sie sie auf einem anderen Element oder das Fenster setzen können Sie später nicht mehr die Leinwand wählen Ihr Bezugspunkt sein.
Einfache Antwort # 2 Verwendung clientX
, clientY
und canvas.getBoundingClientRect
Wenn Sie nicht über CSS egal verwandelt sich die nächste einfachste Antwort ist canvas. getBoundingClientRect()
anrufen und die linke von clientX
und top
von clientY
wie in
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
});
Das wird funktionieren, solange es keine CSS-Transformationen sind. Es funktioniert auch mit Touch-Ereignisse und so funktioniert mit Safari iOS
canvas.addEventListener('touchmove', (e) => {
const rect = canvas. getBoundingClientRect();
const x = e.touches[0].clientX - rect.left;
const y = e.touches[0].clientY - rect.top;
});
Wie Leinwand Pixel Maus erhalten Koordinaten für den 2D-Canvas-API
Dazu brauchen wir die Werte nehmen wir oben bekam und konvertieren von der Größe der Leinwand auf die Anzahl der Pixel in der Leinwand angezeigt wird, selbst
mit canvas.getBoundingClientRect
und clientX
und clientY
canvas.addEventListener('mousemove', (e) => {
const rect = canvas.getBoundingClientRect();
const elementRelativeX = e.clientX - rect.left;
const elementRelativeY = e.clientY - rect.top;
const canvasRelativeX = elementRelativeX * canvas.width / rect.width;
const canvasRelativeY = elementRelativeY * canvas.height / rect.height;
});
oder mit offsetX
und offsetY
canvas.addEventListener('mousemove', (e) => {
const elementRelativeX = e.offsetX;
const elementRelativeX = e.offsetY;
const canvasRelativeX = elementRelativeX * canvas.width / canvas.clientWidth;
const canvasRelativeY = elementRelativeX * canvas.height / canvas.clientHeight;
});
Hinweis: In allen Fällen fügen keine Polsterung oder Grenzen auf die Leinwand. Dadurch wird massiv den Code erschweren. Statt Sie eine Grenze oder padding die Leinwand in einem anderen Elemente umgeben und die Polsterung und oder Grenze zu dem äußeren Elemente hinzuzufügen.
Arbeitsbeispiel mit event.offsetX
, event.offsetY
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
let count = 0;
function draw(e, radius = 1) {
const pos = {
x: e.offsetX * canvas.width / canvas.clientWidth,
y: e.offsetY * canvas.height / canvas.clientHeight,
};
document.querySelector('#debug').textContent = count;
ctx.beginPath();
ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
ctx.fill();
}
function preventDefault(e) {
e.preventDefault();
}
if (window.PointerEvent) {
canvas.addEventListener('pointermove', (e) => {
draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
});
canvas.addEventListener('touchstart', preventDefault, {passive: false});
canvas.addEventListener('touchmove', preventDefault, {passive: false});
} else {
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mousedown', preventDefault);
}
});
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
.scene {
width: 200px;
height: 200px;
perspective: 600px;
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation-duration: 16s;
animation-name: rotate;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
@keyframes rotate {
from { transform: translateZ(-100px) rotateX( 0deg) rotateY( 0deg); }
to { transform: translateZ(-100px) rotateX(360deg) rotateY(720deg); }
}
.cube__face {
position: absolute;
width: 200px;
height: 200px;
display: block;
}
.cube__face--front { background: rgba(255, 0, 0, 0.2); transform: rotateY( 0deg) translateZ(100px); }
.cube__face--right { background: rgba(0, 255, 0, 0.2); transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back { background: rgba(0, 0, 255, 0.2); transform: rotateY(180deg) translateZ(100px); }
.cube__face--left { background: rgba(255, 255, 0, 0.2); transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top { background: rgba(0, 255, 255, 0.2); transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { background: rgba(255, 0, 255, 0.2); transform: rotateX(-90deg) translateZ(100px); }
<div class="scene">
<div class="cube">
<canvas class="cube__face cube__face--front"></canvas>
<canvas class="cube__face cube__face--back"></canvas>
<canvas class="cube__face cube__face--right"></canvas>
<canvas class="cube__face cube__face--left"></canvas>
<canvas class="cube__face cube__face--top"></canvas>
<canvas class="cube__face cube__face--bottom"></canvas>
</div>
</div>
<pre id="debug"></pre>
Arbeitsbeispiel mit canvas.getBoundingClientRect
und event.clientX
und event.clientY
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
let count = 0;
function draw(e, radius = 1) {
const rect = canvas.getBoundingClientRect();
const pos = {
x: (e.clientX - rect.left) * canvas.width / canvas.clientWidth,
y: (e.clientY - rect.top) * canvas.height / canvas.clientHeight,
};
ctx.beginPath();
ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
ctx.fill();
}
function preventDefault(e) {
e.preventDefault();
}
if (window.PointerEvent) {
canvas.addEventListener('pointermove', (e) => {
draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
});
canvas.addEventListener('touchstart', preventDefault, {passive: false});
canvas.addEventListener('touchmove', preventDefault, {passive: false});
} else {
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mousedown', preventDefault);
}
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
canvas { background: #FED; }
<canvas width="400" height="100" style="width: 300px; height: 200px"></canvas>
<div>canvas deliberately has differnt CSS size vs drawingbuffer size</div>
Hey, das in Dojo ist, nur weil es ist, was ich in den Code bereits hatte für ein Projekt.
Es sollte ganz klar sein, wie es zu konvertieren zurück zu nicht Dojo Vanille JavaScript.
function onMouseClick(e) {
var x = e.clientX;
var y = e.clientY;
}
var canvas = dojo.byId(canvasId);
dojo.connect(canvas,"click",onMouseClick);
Ich hoffe, das hilft.
Hier sind einige Modifikationen der obigen Ryan Artecona Lösung.
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};
}
Zuerst wird, wie andere gesagt haben, müssen Sie eine Funktion der Position des Canvas-Element erhalten . Hier ist eine Methode, die auf dieser Seite (IMHO) ein wenig eleganter als einige der anderen ist. Sie können es passieren jeder -Element und erhalten ihre Position im Dokument:
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;
}
Jetzt die aktuelle Position des Cursors relativ berechnen:
$('#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);
});
Beachten Sie, dass ich die allgemeine findPos
Funktion aus dem Event-Handling-Code getrennt haben. ( Wie es sein sollte . Wir sollten versuchen, unsere Funktionen zu halten, um eine Aufgabe jeder.)
Die Werte von offsetLeft
und offsetTop
bezüglich offsetParent
, die einige Wrapper div
Knoten (oder irgendetwas anderes, was das betrifft) sein könnte. Wenn kein Element Einwickeln des canvas
sie die body
relativ ist, so gibt es keinen Versatz zu subtrahieren. Aus diesem Grunde wir die Position der Leinwand bestimmen müssen, bevor wir etwas anderes tun können.
Similary, e.pageX
und e.pageY
gibt die Position des Cursors relativ zu dem Dokument. Deshalb haben wir die Leinwand der aus diesen Werten Offset subtrahieren an der wahren Position zu gelangen.
Eine Alternative für positioniert Elemente direkt die Werte von e.layerX
und e.layerY
zu verwenden. Dies ist weniger zuverlässig als die oben beschriebene Methode aus zwei Gründen:
- Diese Werte sind auch in Bezug auf das gesamte Dokument, wenn das Ereignis nicht stattfindet innerhalb eines positionierten Elements
- Sie sind nicht Teil irgendeines Standards
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;
Nach vielen Lösungen versuchen. Das funktionierte für mich. Könnte helfen, jemand anderes damit veröffentlichen. Verstanden von hier
Hier ist eine vereinfachte Lösung (das funktioniert nicht mit Grenzen / Scrollen):
function click(event) {
const bound = event.target.getBoundingClientRect();
const xMult = bound.width / can.width;
const yMult = bound.height / can.height;
return {
x: Math.floor(event.offsetX / xMult),
y: Math.floor(event.offsetY / yMult),
};
}
Ich war die Schaffung eine Anwendung mit einer Leinwand über ein pdf, das eine Menge komprimiert die Größe der Leinwand beteiligt wie Zooming die pdf-in und aus, und wiederum bei jedem Zoom-in / aus PDF ich die Leinwand, um die Größe hatte die Größe des pdf anzupassen, ging ich durch viele Antworten in Stackoverflow, und nicht eine perfekte Lösung gefunden, die das Problem eventuell lösen werden.
Ich war mit rxjs und Winkel 6 und fand es noch keine Antwort spezifisch auf die neueste Version.
Hier ist den gesamten Code-Schnipsel, die hilfreich sein würden, zu jedem nutzen rxjs auf der Leinwand zu ziehen.
private captureEvents(canvasEl: HTMLCanvasElement) {
this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
.pipe(
switchMap((e: any) => {
return fromEvent(canvasEl, 'mousemove')
.pipe(
takeUntil(fromEvent(canvasEl, 'mouseup').do((event: WheelEvent) => {
const prevPos = {
x: null,
y: null
};
})),
takeUntil(fromEvent(canvasEl, 'mouseleave')),
pairwise()
)
})
)
.subscribe((res: [MouseEvent, MouseEvent]) => {
const rect = this.cx.canvas.getBoundingClientRect();
const prevPos = {
x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
y: Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
const currentPos = {
x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
this.coordinatesArray[this.file.current_slide - 1].push(prevPos);
this.drawOnCanvas(prevPos, currentPos);
});
}
Und hier ist das Snippet, das festlegt, koordiniert Maus Größe der Leinwand bezogen, unabhängig davon, wie Sie Zoom-In / out die Leinwand.
const prevPos = {
x: Math.floor( ( res[0].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
y: Math.floor( ( res[0].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};
const currentPos = {
x: Math.floor( ( res[1].clientX - rect.left ) / ( rect.right - rect.left ) * this.cx.canvas.width ),
y: Math.floor( ( res[1].clientY - rect.top ) / ( rect.bottom - rect.top ) * this.cx.canvas.height )
};