Comment puis-je obtenir les coordonnées d'un clic de souris sur un élément canvas?

StackOverflow https://stackoverflow.com/questions/55677

  •  09-06-2019
  •  | 
  •  

Question

Quelle est la façon la plus simple pour ajouter un gestionnaire d'événements click pour une toile élément qui sera de retour les coordonnées x et y de la souris (par rapport à l'élément canvas)?

Sans l'héritage de compatibilité avec les navigateurs requis, Safari, Opera et Firefox va faire.

Était-ce utile?

La solution

Edit 2018: Cette réponse est assez vieux et il utilise des contrôles pour les vieux navigateurs qui ne sont pas plus nécessaires, comme l' clientX et clientY propriétés fonctionnent dans tous les navigateurs actuels.Vous voudrez peut-être consulter Patriques Répondre pour une approche plus simple, plus récente de la solution.

Réponse Originale À Cette Question:
Comme décrit dans un article que j'ai trouvé à l'époque, mais n ' existe plus:

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;

A parfaitement fonctionné très bien pour moi.

Autres conseils

Mise à jour (5/5/16): patriques réponse doit être utilisé au lieu, comme il est à la fois plus simple et plus fiable.


Puisque la toile n'est pas toujours de style par rapport à l'ensemble de la page, la canvas.offsetLeft/Top n'est pas toujours le retour de ce que vous avez besoin.Il sera de retour le nombre de pixels qu'elle est en décalage par rapport à ses offsetParent élément, qui peut être quelque chose comme une div élément contenant la toile avec un position: relative style appliqué.Pour tenir compte de cela, vous avez besoin pour faire une boucle dans la chaîne de offsetParents, en commençant par l'élément canvas.Ce code fonctionne parfaitement pour moi, testé dans Firefox et Safari, mais devrait fonctionner pour tous.

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;

La dernière ligne rend les choses pratique pour obtenir les coordonnées de la souris par rapport à un élément canvas.Tout ce qui est nécessaire pour obtenir les coordonnées utiles est

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

Si vous aimez la simplicité, mais encore envie de la croix-des fonctionnalités du navigateur, j'ai trouvé cette solution qui a le mieux fonctionné pour moi.C'est une simplification de @Aldekeins solution mais sans 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);
}

Navigateur moderne est maintenant en occupera pour vous.Chrome, IE9, Firefox et soutenir la offsetX/Y comme ça, en passant, dans le cas du gestionnaire de clic.

function getRelativeCoords(event) {
    return { x: event.offsetX, y: event.offsetY };
}

La plupart des navigateurs modernes soutiennent également layerX/Y, toutefois Chrome et IE utiliser layerX/O pour le décalage absolu du clic sur la page y compris les margin, padding, etc.Dans Firefox, layerX/Y et offsetX/Y sont équivalents, mais le décalage n'existait pas encore.Donc, pour assurer la compatibilité avec un peu de navigateurs plus anciens, vous pouvez utiliser:

function getRelativeCoords(event) {
    return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}

Selon fraîche Quirksmode l' clientX et clientY les méthodes sont pris en charge dans tous les principaux navigateurs.Alors, voilà le bon code qui fonctionne dans une div défilement sur une page avec des barres de défilement:

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];
}

Cela nécessite aussi jQuery pour $(canvas).offset().

J'ai fait un plein de démonstration qui fonctionne dans tous les navigateurs avec le code source complet de la solution de ce problème: Coordonnées d'un clic de souris sur Toile en Javascript.D'essayer la démo, copiez le code et le coller dans un éditeur de texte.Ensuite de l'enregistrer comme example.html et, enfin, ouvrir le fichier avec un navigateur.

Voici une petite modification à la Ryan Artecona réponse pour les toiles avec une variable (%) largeur:

 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}
}

Méfiez-vous tout en faisant de la conversion de coordonnées;il y a plusieurs non-cross-browser valeurs renvoyées dans un événement de clic.À l'aide de clientX et clientY seuls ne sont pas suffisants si le navigateur de la fenêtre de défilement (vérifié dans Firefox 3.5 et Chrome 3.0).

Ce mode quirks l'article fournit plus exact de la fonction peut utiliser soit pageX ou pageY ou une combinaison de clientX avec le document.corps.scrollLeft et clientY avec le document.corps.scrollTop pour calculer le clic de coordonnées par rapport à l'origine du document.

Mise à JOUR:En outre, offsetLeft et offsetTop sont relatifs au collier de la taille de l'élément, de ne pas l'intérieur de la taille.Une toile avec les padding:style appliqué ne sera pas un rapport de la haut-gauche de sa zone de contenu comme offsetLeft.Il existe plusieurs solutions à ce problème;le plus simple peut-être pour effacer toutes les frontières, rembourrage, etc.styles sur la toile et au lieu de les appliquer à une boîte contenant de la toile.

Je ne suis pas sûr de ce qui est le point de toutes ces réponses boucle à travers les éléments de parent et faire toutes sortes de des choses bizarres.

L' HTMLElement.getBoundingClientRect la méthode est conçue pour gérer réel la position de l'écran de n'importe quel élément.Cela inclut le défilement des trucs comme scrollTop n'est pas nécessaire:

(à partir de MDN) Le montant de défilement qui a été fait de la zone de fenêtre d'affichage (ou tout autre élément déroulant est pris en compte lors du calcul de l' rectangle de délimitation

Image normale

L' très approche la plus simple a déjà été posté ici.C'est correct aussi longtemps que pas de joker CSS les règles sont impliqués.

La manipulation toile tendue/image

Lorsque la taille d'image en pixels largeur n'est pas compensée par il du CSS largeur, vous aurez besoin d'appliquer un ratio sur les valeurs de pixel:

/* 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];
}

Tant que la toile n'a pas de frontière, il travaille pour étirée images (jsFiddle).

La manipulation CSS frontières

Si la toile est épaisse frontière, les choses deviennent peu compliqué.Vous allez littéralement devez soustraire la frontière du rectangle de délimitation.Cela peut être fait en utilisant .getComputedStyle.Cette réponse décrit le processus.

La fonction se développe alors un peu:

/* 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
  ...
}

Je ne peux pas penser à tout ce qui nuirait à cette dernière fonction.Reportez-vous à JsFiddle.

Notes

Si vous n'aimez pas la modification de la maternelle prototypes, il suffit de modifier la fonction et de l'appeler avec (canvas, event) (et remplacer tout this avec canvas).

Voici un très bon tutoriel-

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);

espérons que cette aide!

À l'aide de jQuery en 2016, pour obtenir cliquez sur les coordonnées sont relatives à la toile, je fais:

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

Cela fonctionne puisque les deux toile offset() et jqEvent.pageX/Y sont relatifs au document indépendamment de la position de défilement.

Notez que si votre toile est mise à l'échelle, puis ces coordonnées ne sont pas les mêmes que toile coordonnées logiques.Pour obtenir celles-ci, vous aussi faire:

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

Je vous recommande ce lien 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>

À l'état de Prototype, l'utilisation cumulativeOffset() pour faire la somme récursive, comme mentionné par Ryan Artecona ci-dessus.

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

Vous pourriez faire:

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

Cela va vous donner la position exacte du pointeur de la souris.

Voir démo à http://jsbin.com/ApuJOSA/1/edit?html,sortie .

  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 };
  }

C'est donc à la fois simple mais un peu plus sujet compliqué qu'il n'y paraît.

Tout d'abord, il ya généralement à un amalgame des questions ici

  1. Comment obtenir de l'élément parent les coordonnées de la souris

  2. Comment obtenir une toile de pixel de coordonnées de la souris pour le Canvas 2D ou API WebGL

donc, les réponses

Comment obtenir de l'élément parent les coordonnées de la souris

Si oui ou non l'élément est une toile d'obtenir de l'élément parent les coordonnées de la souris est le même pour tous les éléments.

Il y a 2 réponses simples à la question "Comment obtenir une toile par rapport coordonnées de la souris"

Simple réponse #1 utilisation offsetX et offsetY

canvas.addEventListner('mousemove', (e) => {
  const x = e.offsetX;
  const y = e.offsetY;
});

Cette réponse fonctionne dans Chrome, Firefox et Safari.Contrairement à toutes les autres valeurs de l'événement offsetX et offsetY prendre CSS se transforme en compte.

Le plus gros problème avec offsetX et offsetY est comme de 2019/05 ils n'existent pas sur les événements tactiles et ne peut donc pas être utilisé avec iOS Safari.Elles existent sur les Événements de Pointeur qui existent dans Chrome et Firefox mais pas Safari bien que apparemment Safari est de travailler sur elle.

Un autre problème est que les événements doivent être sur la toile.Si vous les mettez sur un autre élément de la fenêtre, vous ne pouvez pas choisir plus tard la toile à votre point de référence.

Simple réponse #2 utilisation clientX, clientY et canvas.getBoundingClientRect

Si vous n'avez pas de soins sur CSS transforme la prochaine réponse la plus simple est d'appeler canvas. getBoundingClientRect() et soustraire la gauche à partir de clientX et top à partir de clientY comme dans

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
});

Cela permettra de travailler aussi longtemps qu'il n'y a pas de CSS transforme.Il fonctionne également avec les événements tactiles et donc fonctionne avec 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;
});

Comment obtenir une toile de pixel de coordonnées de la souris pour le 2D Toile API

Pour cela, nous devons prendre les valeurs que nous avons obtenu ci-dessus et de convertir de la taille de la toile est affiché le nombre de pixels dans la toile

avec canvas.getBoundingClientRect et clientX et 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;
});

ou avec offsetX et 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;
});

Note: Dans tous les cas, n'ajoutez pas de rembourrage ou des frontières de la toile.Ainsi donc massivement à compliquer le code.Au lieu de vous voulez une bordure ou d'un rembourrage surround de la toile en quelques autre élément et ajouter le rembourrage et le ou la bordure de l'élément extérieur.

Exemple de travail à l'aide de 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>

Exemple de travail à l'aide de canvas.getBoundingClientRect et event.clientX et 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, c'est dans le dojo, parce que c'est ce que j'ai eu le code en déjà pour un projet.

Il devrait être assez Évident, comment faire pour le convertir non dojo de vanille JavaScript.

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

Espérons que cela aide.

Voici quelques modifications de la ci-dessus Ryan Artecona de la 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};
}

Tout d'abord, comme d'autres l'ont dit, vous avez besoin d'une fonction pour obtenir les position de l'élément canvas.Voici une méthode qui est un peu plus élégant que certains des autres sur cette page (à mon humble avis).Vous pouvez la passer tout élément et obtenir sa position dans le 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;
}

Maintenant calculer la position actuelle du curseur par rapport à ce que:

$('#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);
});

Notez que j'ai séparé le générique findPos la fonction du code de gestion des événements.(Comme il se doit.Nous devrions essayer de garder nos fonctions à une tâche de chacun.)

Les valeurs de offsetLeft et offsetTop sont par rapport à offsetParent, qui pourrait être une wrapper div nœud (ou quoi que ce soit d'autre, d'ailleurs).Quand il n'y a aucun élément d'habillage de la canvas ils sont par rapport à la body, il n'est donc pas de décalage à soustraire.C'est pourquoi nous avons besoin de déterminer la position de la toile avant que nous puissions faire autre chose.

De même, e.pageX et e.pageY donner la position du curseur par rapport au document.C'est pourquoi nous soustraire la toile du décalage à partir de ces valeurs pour arriver à la véritable position.

Une alternative pour positionné éléments est d'utiliser directement les valeurs de e.layerX et e.layerY.C'est moins fiable que la méthode ci-dessus pour deux raisons:

  1. Ces valeurs sont aussi par rapport à l'ensemble du document lorsque l'événement n'a pas lieu à l'intérieur d'un élément positionné
  2. Ils ne font partie d'aucun 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;

Après avoir essayé de nombreuses solutions.Cela a fonctionné pour moi.Peut aider quelqu'un d'autre donc l'affichage.Obtenu à partir de ici

Voici une solution simplifiée (cela ne fonctionne pas avec les frontières/défilement):

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),
    };
}

J'ai été la création d'une application ayant un toile plus d'un fichier pdf, qui a nécessité beaucoup de redimensionne de la toile comme le Zoom sur le pdf dans et hors, et tour à tour sur chaque zoom-in/out de PDF, j'ai dû redimensionner la zone de travail pour adapter la taille du fichier pdf, je suis passé par beaucoup de réponses dans stackOverflow, et n'a pas trouvé une solution parfaite qui finira par résoudre le problème.

J'ai été en utilisant rxjs et angulaire 6, et n'ai pas trouvé de réponse spécifiques à la version la plus récente.

Voici l'intégralité de l'extrait de code qui pourrait être utile, pour toute personne exploitant rxjs dessiner sur la toile.

  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);
      });
  }

Et voici le bout de code qui résout, les coordonnées de la souris par rapport à la taille de la toile, indépendamment de la façon dont vous faites un zoom avant/arrière sur la toile.

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 )
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top