كيف يمكنني الحصول على إحداثيات الماوس انقر على قماش عنصر ؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

ما هو أبسط طريقة لإضافة انقر فوق معالج الحدث إلى عنصر قماش أنه سيعود x و y إحداثيات انقر فوق (نسبة إلى عنصر قماش)?

لا إرث متصفح التوافق المطلوب, سفاري, اوبرا و فايرفوكس سوف تفعل.

هل كانت مفيدة؟

المحلول

تحرير 2018: هذه الإجابة هي قديمة جدا ويستخدم يتحقق المتصفحات القديمة التي ليس من الضروري بعد الآن ، clientX و clientY خصائص العمل في جميع المتصفحات الحالية.قد ترغب في التحقق Patriques الإجابة أبسط من الحل.

الجواب الأصلية:
كما هو موضح في مقال وجدت آنذاك ولكن لم يعد موجودا:

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;

عملت على ما يرام تماما بالنسبة لي.

نصائح أخرى

التحديث (5/5/16): patriques' الجواب ينبغي أن تستخدم بدلا من ذلك, كما انها على حد سواء أبسط وأكثر موثوقية.


منذ قماش ليس دائما نصب نسبة إلى صفحة كاملة ، canvas.offsetLeft/Top لا تعود دائما ما تحتاجه.فإنه سيعود عدد البكسل هو تعويض نسبة إلى offsetParent العنصر الذي يمكن أن يكون شيئا مثل div العنصر الذي يحتوي على قماش مع position: relative تطبيق نمط.لحساب هذه تحتاج إلى حلقة من خلال سلسلة من offsetParents, بداية مع عنصر قماش نفسها.هذا الكود يعمل تماما بالنسبة لي ، اختبار في فايرفوكس وسفاري ولكن يجب أن تعمل من أجل الجميع.

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;

السطر الأخير يجعل الأمور مريحة للحصول على إحداثيات الماوس نسبة إلى عنصر قماش.كل ما هو مطلوب للحصول على فائدة الإحداثيات

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

إذا كنت تحب البساطة ولكن لا تزال تريد عبر متصفح وظائف وجدت هذا الحل يعمل بشكل أفضل بالنسبة لي.هذا هو تبسيط @Aldekeins الحل ولكن دون مسج.

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

الحديث المتصفح الآن التعامل مع هذا لك.كروم, IE9, و فايرفوكس دعم offsetX/Y مثل هذا يمر في حالة من فوق معالج.

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

معظم المتصفحات الحديثة تدعم أيضا layerX/Y, ومع ذلك كروم وإنترنت إكسبلورر استخدام layerX/Y المطلق إزاحة انقر على الصفحة بما في ذلك الهامش, الحشو, الخ.في فايرفوكس ، layerX/Y و offsetX/Y هي ما يعادلها ، ولكن تعويض لم تكن موجودة سابقا.لذلك ، من أجل التوافق مع قليلا المتصفحات القديمة ، يمكنك استخدام:

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

وفقا الطازجة Quirksmode على clientX و clientY طرق معتمدة في جميع المتصفحات الرئيسية.حتى هنا يذهب - جيدة ، العامل التعليمات البرمجية التي تعمل في التمرير div على صفحة مع التمرير:

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

وهذا يتطلب أيضا مسج بالنسبة $(canvas).offset().

أنا جعلت كامل demostration أن يعمل في كل متصفح مع رمز مصدر الكامل على حل هذه المشكلة: إحداثيات الماوس انقر على قماش في جافا سكريبت.محاولة التجريبي ، نسخ الكود ولصقه في محرر نص.ثم احفظ example.html وأخيرا فتح الملف مع المتصفح.

هنا هو تعديل صغير على ريان Artecona الجواب على اللوحات مع متغير (%) العرض:

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

أن نكون حذرين أثناء القيام تنسيق التحويل ؛ هناك عدة غير عبر متصفح القيم التي يتم إرجاعها في الحدث انقر فوق.باستخدام clientX و clientY وحدها لا تكفي إذا كانت نافذة المتصفح تمريره (التحقق منها في فيرفكس 3.5 وما Chrome 3.0).

هذا وضع المراوغات المادة توفر وظيفة الصحيحة التي يمكن أن تستخدم إما pageX أو pageY أو مزيج من clientX مع الوثيقة.الجسم.scrollLeft و clientY مع الوثيقة.الجسم.scrollTop لحساب انقر فوق تنسيق بالنسبة إلى الوثيقة الأصلية.

تحديث:بالإضافة إلى ذلك ، offsetLeft و offsetTop بالنسبة إلى مبطن حجم العنصر ، وليس الداخلية الحجم.قماش مع الحشو:تطبيق نمط لا تقرير الجزء العلوي الأيسر من محتواه المنطقة offsetLeft.هناك العديد من الحلول لهذه المشكلة ؛ أبسط واحد قد يكون واضح كل الحدود, الحشو, الخ.أنماط على القماش نفسه بدلا تطبيقها على صندوق يحتوي على قماش.

لست متأكدا ما هو الهدف من كل هذه الإجابات التي حلقة من خلال الوالدين العناصر والقيام بكل أنواع أشياء غريبة.

على HTMLElement.getBoundingClientRect طريقة يهدف إلى التعامل مع الشاشة الفعلي موقف من أي عنصر.ويشمل هذا التمرير, حتى الاشياء مثل scrollTop ليست هناك حاجة:

(من MDN) كمية التمرير الذي تم إنجازه من العرض المنطقة (أو أي تمرير عنصر) يؤخذ في الاعتبار عند حساب مستطيل إحاطة

الصورة العادية

على جدا أبسط النهج تم بالفعل نشر هنا.هذا هو الصحيح طالما لا البري المغلق قواعد المشاركة.

التعامل مع قماش/صورة

عندما صورة بكسل العرض لم يقابل من قبل انها CSS العرض, سوف تحتاج إلى تطبيق بعض نسبة على القيم بكسل:

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

طالما قماش لا الحدود ، يعمل على تمدد الصور (jsFiddle).

التعامل مع CSS الحدود

إذا كان قماش سميكة الحدود ، فإن الأمور معقدة بعض الشيء.سوف حرفيا بحاجة إلى طرح الحدود من مستطيل إحاطة.ويمكن أن يتم ذلك باستخدام .getComputedStyle.هذا الجواب يصف عملية.

وظيفة ثم يكبر قليلا:

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

لا أستطيع التفكير في أي شيء من شأنه أن تخلط بين هذا الأخير وظيفة.ترى نفسك في JsFiddle.

ملاحظات

إذا كنت لا ترغب في تعديل الأصلي prototypes, مجرد تغيير وظيفة و الاتصال مع (canvas, event) (و استبدال أي this مع canvas).

هنا هو البرنامج التعليمي لطيفة جدا-

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

ويساعد هذا الأمل!

باستخدام مسج في عام 2016 ، انقر للحصول على الإحداثيات النسبية إلى قماش ، أنا:

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

يعمل هذا لأن كلا من قماش تعويض() و jqEvent.pageX/Y بالنسبة إلى الوثيقة بغض النظر عن موضع التمرير.

ملاحظة أنه إذا كان لديك قماش نظيفة ثم هذه الإحداثيات ليست نفس قماش المنطقي الإحداثيات.للحصول على هذه, كنت أيضا هل:

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

أوصي هذا الرابط- 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>

في النموذج ، استخدام cumulativeOffset() للقيام متكررة الجمع كما ذكر ريان Artecona أعلاه.

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

يمكنك فقط القيام به:

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

هذا وسوف تعطيك الموضع الدقيق من مؤشر الماوس.

انظر التجريبي في http://jsbin.com/ApuJOSA/1/edit?html الإخراج .

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

لذلك هذا هو على حد سواء بسيطة ولكن قليلا أكثر تعقيدا الموضوع مما يبدو عليه.

أولا هناك عادة إلى الخلط الأسئلة هنا

  1. كيفية الحصول على عنصر النسبية إحداثيات الماوس

  2. كيفية الحصول على قماش بكسل الماوس الإحداثيات 2D قماش API أو WebGL

لذا إجابات

كيفية الحصول على عنصر النسبية إحداثيات الماوس

ما إذا كان العنصر هو قماش الحصول على عنصر النسبية إحداثيات الماوس هو نفسه بالنسبة لجميع العناصر.

هناك 2 إجابات بسيطة على السؤال "كيف تحصل على قماش النسبية إحداثيات الماوس"

الإجابة بسيطة #1 استخدام offsetX و offsetY

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

هذا الجواب يعمل في الكروم, فايرفوكس, رحلات السفاري.على عكس كل حدث آخر القيم offsetX و offsetY تأخذ التحويلات CSS في الاعتبار.

أكبر مشكلة مع offsetX و offsetY هو من 2019/05 أنها لا توجد في الأحداث التي تعمل باللمس بحيث يمكن استخدامها مع دائرة الرقابة الداخلية سفاري.إلا أنها موجودة على مؤشر الأحداث التي توجد في كروم و فايرفوكس لكن ليس سفاري على الرغم من على ما يبدو سفاري هو العمل على ذلك.

وثمة مسألة أخرى هي الأحداث يجب أن تكون على القماش نفسه.إذا كنت وضعت لهم على بعض العناصر الأخرى أو نافذة لا يمكنك بعدها اختيار قماش أن يكون نقطة مرجعية.

الإجابة بسيطة #2 استخدام clientX, clientY و canvas.getBoundingClientRect

إذا كنت لا تهتم حول التحويلات CSS التالي أبسط الجواب هو الاتصال canvas. getBoundingClientRect() وطرح اليسار من clientX و top من clientY كما في

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

هذا العمل طالما لا توجد التحويلات CSS.كما أنها تعمل مع أحداث اللمس و كذلك العمل مع سفاري دائرة الرقابة الداخلية

canvas.addEventListener('touchmove', (e) => {
  const rect = canvas. getBoundingClientRect();
  const x = e.touches[0].clientX - rect.left;
  const y = e.touches[0].clientY - rect.top;
});

كيفية الحصول على قماش بكسل الماوس الإحداثيات 2D قماش API

لهذا نحن بحاجة إلى أن تأخذ القيم لدينا أعلاه التحويل من حجم قماش عرض عدد البكسل في قماش نفسها

مع canvas.getBoundingClientRect و clientX و 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;
});

أو مع offsetX و 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;
});

ملاحظة: في جميع الحالات لا تضيف الحشو أو الحدود إلى قماش.القيام بذلك على نطاق واسع تعقيد رمز.بدلا من تريد الحدود أو الحشو تحيط قماش في بعض العناصر الأخرى ويضاف الحشو أو الحدود الخارجية عنصر.

على سبيل المثال العمل باستخدام 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>

على سبيل المثال العمل باستخدام canvas.getBoundingClientRect و event.clientX و 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>

مرحبا, هذا هو في دوجو, فقط لأن هذا ما لدي مدونة في المشروع.

فإنه ينبغي أن يكون واضحا إلى حد ما كيفية تحويل مرة أخرى إلى عدم دوجو الفانيليا جافا سكريبت.

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

على أمل أن يساعد.

هنا بعض التعديلات المذكورة أعلاه ريان Artecona الحل.

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

أولا كما قال آخرون ، كنت في حاجة الى وظيفة للحصول على موقف عنصر قماش.وهنا طريقة أكثر أناقة من بعض من الآخرين في هذه الصفحة (IMHO).يمكنك تمرير ذلك أي العنصر والحصول على موقفه في الوثيقة:

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

الآن حساب الموقف الحالي المؤشر نسبة إلى:

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

لاحظ أنني قمت بفصل العامة findPos وظيفة من التعامل مع الحدث التعليمات البرمجية.(كما ينبغي أن يكون.علينا أن نحاول أن نحافظ على وظائف مهمة واحدة لكل منهما.)

قيم offsetLeft و offsetTop بالنسبة إلى offsetParent, والتي يمكن أن تكون بعض المجمع div عقدة (أو أي شيء آخر لهذه المسألة).عندما لا يكون هناك عنصر التفاف canvas إنهم بالنسبة إلى body, لذا لا يوجد تعويض إلى طرح.هذا هو السبب في أننا بحاجة إلى تحديد الموقف من قماش قبل أن نتمكن من فعل أي شيء آخر.

المثل ، e.pageX و e.pageY إعطاء موقف المؤشر نسبة إلى المستند.هذا هو السبب في أننا طرح قماش هو تعويض عن تلك القيم للوصول إلى حقيقة الموقف.

بديلا وضع عناصر مباشرة استخدام قيم e.layerX و e.layerY.هذا هو أقل موثوقية من الأسلوب أعلاه لسببين:

  1. هذه القيم هي أيضا نسبة إلى المستند بأكمله عند هذا الحدث لا يأخذ مكان داخل وضع عنصر
  2. فهي ليست جزءا من أي معيار

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;

بعد محاولة العديد من الحلول.هذا عملت بالنسبة لي.قد تساعد شخص آخر ومن ثم النشر.حصلت عليه من هنا

هنا هو الحل المبسط (هذا لا يعمل مع الحدود/التمرير):

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

لقد كان إنشاء تطبيق من وجود قماش على pdf, التي تنطوي على الكثير من تغيير حجم قماش مثل التكبير pdf- ، و في المقابل على كل التكبير في/خارج PDF اضطررت إلى تغيير قماش على التكيف مع حجم pdf, ذهبت من خلال الكثير من الإجابات في ستاكوفيرفلوو و لم أجد الحل الأمثل أن في نهاية المطاف سوف يحل المشكلة.

كنت تستخدم rxjs و الزاوي 6 و لم أجد أي إجابة محددة إلى الإصدار الأحدث.

هنا هو رمز كامل مقتطف من شأنها أن تكون مفيدة لأي شخص الاستفادة rxjs رسم على رأس قماش.

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

وهنا مقتطف من أن الإصلاحات إحداثيات الماوس نسبة إلى حجم قماش ، بغض النظر عن كيفية التكبير في/خارج قماش.

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 )
};
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top