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.

War es hilfreich?

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 offsetParents 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 prototypes ä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.

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

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

  1. Wie Element relativ Mauskoordinaten

  2. bekommen
  3. Wie Leinwand Pixel Maus-Koordinaten für den 2D-Canvas-API oder WebGL

  4. bekommen

so, Antworten

Wie Element relativ Mauskoordinaten

bekommen

Unabhä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

subtrahieren
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:

  1. Diese Werte sind auch in Bezug auf das gesamte Dokument, wenn das Ereignis nicht stattfindet innerhalb eines positionierten Elements
  2. 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 )
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top