Làm cách nào để có được tọa độ của một lần nhấp chuột trên phần tử canvas?


276

Cách đơn giản nhất để thêm một trình xử lý sự kiện nhấp chuột vào một phần tử canvas sẽ trả về tọa độ x và y của nhấp chuột (liên quan đến phần tử canvas)?

Không yêu cầu tương thích trình duyệt cũ, Safari, Opera và Firefox sẽ làm.


Điều này không nên khác với việc nhận các sự kiện chuột từ các yếu tố dom bình thường. quirksmode có một tài liệu tham khảo tốt về điều đó.
sân bay

4
Mã bạn liệt kê ở trên chỉ hoạt động khi khung vẽ không nằm sâu bên trong các thùng chứa khác. Nói chung, bạn cần sử dụng một cái gì đó như hàm bù jquery [var testDiv = $ ('# testDiv'); var offset = testDiv.offset ();] để lấy phần bù chính xác theo cách trình duyệt chéo. Đây là một nỗi đau thực sự trong ***.
Aaron Watters

Mã được đăng ở trên với Cập nhật không hoạt động nếu trang chứa các cuộn vải.
Timothy Kim

Tôi đã xóa "câu trả lời" cũ được đưa vào dưới dạng cập nhật cho câu hỏi. Như đã đề cập, nó đã lỗi thời và không đầy đủ.
Tom

3
Vì có khoảng 50 câu trả lời ở đây, tôi khuyên bạn nên cuộn đến câu trả lời của những người này: những người yêu nước - một lớp lót 5 tốt và đơn giản.
Igor L.

Câu trả lời:


77

Chỉnh sửa 2018: Câu trả lời này khá cũ và nó sử dụng kiểm tra các trình duyệt cũ không còn cần thiết nữa, vì các thuộc tính clientXclientYhoạt động trong tất cả các trình duyệt hiện tại. Bạn có thể muốn kiểm tra Câu trả lời của Patriques để có giải pháp đơn giản hơn, gần đây hơn.

Câu trả lời gốc:
Như được mô tả trong một bài viết tôi đã tìm thấy sau đó nhưng không còn tồn tại:

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;

Làm việc hoàn toàn tốt cho tôi.


30
Giải pháp này không phải lúc nào cũng hoạt động - câu trả lời của Ryan Artecona hoạt động trong trường hợp tổng quát hơn khi khung vẽ không nhất thiết phải được định vị so với toàn bộ trang.
Chris Johnson

3
Giải pháp này không được trang bị nếu hiệu suất hoạt động, vì truy cập Dom được thực hiện trên mỗi lần nhấp / di chuyển. Và getBoundingClientRect tồn tại và thanh lịch hơn.
GameAlchemist

192

Nếu bạn thích sự đơn giản nhưng vẫn muốn chức năng trình duyệt chéo, tôi thấy giải pháp này phù hợp nhất với tôi. Đây là một sự đơn giản hóa của giải pháp @ Aldekein nhưng không có jQuery .

function getCursorPosition(canvas, event) {
    const rect = canvas.getBoundingClientRect()
    const x = event.clientX - rect.left
    const y = event.clientY - rect.top
    console.log("x: " + x + " y: " + y)
}

const canvas = document.querySelector('canvas')
canvas.addEventListener('mousedown', function(e) {
    getCursorPosition(canvas, e)
})

Nếu trang được cuộn xuống, tôi đoán người ta cũng nên cân nhắc cuộn cuộn của tài liệu.
Peppe LG

8
@ PeppeL-G giới hạn hình chữ nhật máy khách tính toán điều đó cho bạn. Bạn có thể dễ dàng kiểm tra nó trong bảng điều khiển trước khi đăng bình luận (đó là những gì tôi đã làm).
Tomáš Zato - Phục hồi Monica

1
@ TomášZato, oh, getBoundingClientRecttrả về các vị trí liên quan đến cổng xem? Sau đó, dự đoán của tôi là sai. Tôi chưa bao giờ kiểm tra nó vì đây không bao giờ là vấn đề đối với tôi và tôi muốn cảnh báo những độc giả khác về một vấn đề tiềm ẩn mà tôi đã thấy, nhưng cảm ơn bạn đã làm rõ.
Peppe LG

1
Điều này không hoạt động nếu khung vẽ được thu nhỏ. Không chắc chắn nếu đó là một lỗi trình duyệt.
Jeroen

2
Thêm cách sử dụng cho một người như tôi:var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
SnowOnion

179

Cập nhật (5/5/16): nên sử dụng câu trả lời của những người yêu nước , vì nó vừa đơn giản vừa đáng tin cậy hơn.


Vì khung vẽ không phải lúc nào cũng được tạo kiểu so với toàn bộ trang, nên canvas.offsetLeft/Topkhông phải lúc nào cũng trả về những gì bạn cần. Nó sẽ trả về số pixel mà nó được bù tương đối so với phần tử offsetParent của nó, có thể giống như một divphần tử chứa canvas với position: relativekiểu được áp dụng. Để giải thích cho điều này, bạn cần lặp qua chuỗi offsetParents, bắt đầu bằng chính phần tử canvas. Mã này hoạt động hoàn hảo đối với tôi, được thử nghiệm trong Firefox và Safari nhưng sẽ hoạt động cho tất cả.

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;

Dòng cuối cùng làm cho mọi thứ thuận tiện cho việc lấy tọa độ chuột so với phần tử canvas. Tất cả những gì cần thiết để có được tọa độ hữu ích là

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

8
Không, nó đang sử dụng đối tượng nguyên mẫu javascript dựng sẵn --- developer.mozilla.org/en/
mẹo

14
Chrome của tôi có event.offsetXevent.offsetYthuộc tính, vì vậy tôi đã sửa đổi giải pháp của bạn bằng cách thêm if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }. có vẻ như nó hoạt động
Baczek

3
Baczek là chính xác về Chrome event.offsetXevent.offsetYcũng hoạt động trong IE9. Đối với Firefox (đã thử nghiệm w / v13), bạn có thể sử dụng event.layerXevent.layerY.
mafafu

3
Tôi cũng đã thêm điều này: canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
amirpc

4
Phiên bản cuối cùng về câu trả lời này không phù hợp với tôi. Trên Firefox, nếu toàn bộ màn hình được cuộn, tôi nhận được giá trị thay thế làm đầu ra. Điều làm việc cho tôi là một giải pháp rất giống nhau, được đưa ra trên stackoverflow.com/a/10816667/578749 thay vì event.pageX / Y, nó đã trừ đi phần bù được tính từ event.clientX / Y. Ai đó có thể xem lại và giải thích?
lvella

33

Trình duyệt hiện đại bây giờ xử lý việc này cho bạn. Chrome, IE9 và Firefox hỗ trợ offsetX / Y như thế này, chuyển qua sự kiện từ trình xử lý nhấp chuột.

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

Hầu hết các trình duyệt hiện đại cũng hỗ trợ layerX / Y, tuy nhiên Chrome và IE sử dụng layerX / Y để bù đắp tuyệt đối cho nhấp chuột trên trang bao gồm lề, phần đệm, v.v. Trong Firefox, layerX / Y và offsetX / Y là tương đương, nhưng offset Trước đây tồn tại. Vì vậy, để tương thích với các trình duyệt cũ hơn một chút, bạn có thể sử dụng:

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

1
Thật thú vị khi layerX, layerY được định nghĩa trên cả Chrome và Firefox, nhưng trên Chrome thì nó không chính xác (hoặc có nghĩa là cái gì khác).
Julian Mann

@JulianMann Cảm ơn thông tin. Tôi đã cập nhật câu trả lời này dựa trên sự hỗ trợ hiện tại. Có vẻ như bây giờ bạn có thể thoát khỏi offsetX / Y gần như phổ biến.
mafafu

18

Theo tươi Quirksmode sự clientXclientYphương pháp được hỗ trợ trong tất cả các trình duyệt chính. Vì vậy, ở đây nó đi - mã hoạt động tốt, hoạt động trong một div cuộn trên một trang với thanh cuộn:

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

Điều này cũng yêu cầu jQuery cho $(canvas).offset().


Tương đương với câu trả lời @ N4ppeL.
Paweł Szczur


11

Đây là một sửa đổi nhỏ cho câu trả lời của Ryan Artecona cho các bức tranh có chiều rộng thay đổi (%):

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

7

Hãy cảnh giác trong khi thực hiện chuyển đổi phối hợp; có nhiều giá trị không phải trình duyệt chéo được trả về trong một sự kiện nhấp chuột. Chỉ sử dụng clientX và clientY là không đủ nếu cửa sổ trình duyệt được cuộn (được xác minh trong Firefox 3.5 và Chrome 3.0).

Bài viết chế độ quirks này cung cấp một hàm chính xác hơn có thể sử dụng pageX hoặc pageY hoặc kết hợp clientX với document.body.scrollLeft và clientY với document.body.scrollTop để tính tọa độ nhấp chuột liên quan đến nguồn gốc tài liệu.

CẬP NHẬT: Ngoài ra, offsetLeft và offsetTop liên quan đến kích thước đệm của phần tử, không phải kích thước bên trong. Một khung vẽ có phần đệm: kiểu được áp dụng sẽ không báo cáo phía trên bên trái của vùng nội dung của nó là offsetLeft. Có nhiều giải pháp cho vấn đề này; cách đơn giản nhất có thể là xóa tất cả các kiểu viền, đệm, v.v. trên chính khung vẽ và thay vào đó áp dụng chúng vào hộp chứa khung vẽ.


7

Tôi không chắc ý nghĩa của tất cả những câu trả lời này lặp qua các phần tử cha mẹ và làm tất cả các loại công cụ kỳ lạ .

Các HTMLElement.getBoundingClientRectphương pháp được thiết kế để xử lý các vị trí màn hình thực tế của bất kỳ yếu tố. Điều này bao gồm cuộn, vì vậy những thứ như scrollTopkhông cần thiết:

(từ MDN) Số lượng cuộn đã được thực hiện của khu vực chế độ xem (hoặc bất kỳ yếu tố có thể cuộn nào khác ) được tính đến khi tính toán hình chữ nhật giới hạn

Hình ảnh bình thường

Các cách tiếp cận rất đơn giản đã được đăng ở đây. Điều này đúng miễn là không có quy tắc CSS hoang dã nào được tham gia.

Xử lý vải / hình ảnh kéo dài

Khi chiều rộng pixel hình ảnh không khớp với chiều rộng CSS, bạn sẽ cần áp dụng một số tỷ lệ trên các giá trị 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];
}

Miễn là khung vẽ không có viền, nó hoạt động đối với các hình ảnh bị kéo dài (jsFiddle) .

Xử lý viền CSS

Nếu vải có viền dày, mọi thứ sẽ hơi phức tạp . Bạn thực sự cần phải trừ đường viền khỏi hình chữ nhật giới hạn. Điều này có thể được thực hiện bằng cách sử dụng .getComputingStyle . Câu trả lời này mô tả quá trình .

Các chức năng sau đó lớn lên một chút:

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

Tôi không thể nghĩ bất cứ điều gì có thể nhầm lẫn chức năng cuối cùng này. Xem bản thân tại JsFiddle .

Ghi chú

Nếu bạn không muốn sửa đổi bản gốc prototype, chỉ cần thay đổi chức năng và gọi nó bằng (canvas, event)(và thay thế bất kỳ thisbằng canvas).


6

Đây là một hướng dẫn rất hay

http://www.html5canvastutorials.com/advified/html5-canvas-mouse-coordins/

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

hi vọng điêu nay co ich!


Giải pháp của Ryan Artecona không hoạt động đối với các trình duyệt máy tính bảng có zoom. Tuy nhiên điều này đã làm.
Andy Meyers

Không hoạt động với hình ảnh có CSS width/ heightoverriden nhưng vẫn là một trong những giải pháp tốt nhất.
Tomáš Zato - Phục hồi Monica

3

Sử dụng jQuery vào năm 2016, để có được tọa độ nhấp liên quan đến khung vẽ, tôi thực hiện:

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

Điều này hoạt động vì cả canvas offset () và jqEvent.pageX / Y đều liên quan đến tài liệu bất kể vị trí cuộn.

Lưu ý rằng nếu canvas của bạn được chia tỷ lệ thì các tọa độ này không giống với tọa độ logic của canvas . Để có được những thứ đó, bạn cũng sẽ làm:

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

Ồ Làm thế nào để 'jqEvent' được xác định? Hay 'vải'? Hay trong ví dụ thứ hai 'coords'? Bạn có cần chạy ví dụ đầu tiên trước lần thứ hai không? Trong trường hợp đó, tại sao bạn không viết "để có được những thứ đó, bạn cũng sẽ làm"? Tất cả điều này đi trong một chức năng onclick hay gì? Cho một bối cảnh nhỏ, bạn đời. Và xem xét câu hỏi ban đầu đã được hỏi vào năm 2008, tôi nghĩ bạn cần trả lời trong bối cảnh công nghệ đã có sẵn trong năm 2008. Hãy tinh chỉnh câu trả lời của bạn bằng cách sử dụng jQuery hợp lệ từ phiên bản có sẵn tại thời điểm đó (v1.2). ;)
Ayelis

1
OK, xin lỗi vì sự tự phụ của tôi. Tôi sẽ chỉnh sửa để loại bỏ điều đó. Tôi đã có ý định cung cấp câu trả lời bằng cách sử dụng các khung gần đây nhất. Và tôi tin rằng một lập trình viên sẽ không cần phải giải thích jqEvent, canvas và coords là gì.
Sarsaparilla

Có vẻ tốt. Cảm ơn vì đầu vào của bạn! Xin lỗi tôi đã cho bạn một thời gian khó khăn! ;)
Ayelis

3

Vì vậy, đây là cả hai đơn giản nhưng một chủ đề phức tạp hơn một chút so với nó có vẻ.

Trước hết thường có những câu hỏi xáo trộn ở đây

  1. Cách lấy tọa độ chuột tương đối

  2. Cách nhận tọa độ chuột pixel canvas cho API Canvas 2D hoặc WebGL

vì vậy, câu trả lời

Cách lấy tọa độ chuột tương đối

Việc phần tử có phải là một khung vẽ hay không, phần tử tương đối tọa độ chuột là như nhau cho tất cả các phần tử.

Có 2 câu trả lời đơn giản cho câu hỏi "Làm thế nào để có được tọa độ chuột tương đối"

Câu trả lời đơn giản số 1 sử dụng offsetXoffsetY

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

Câu trả lời này hoạt động trong Chrome, Firefox và Safari. Không giống như tất cả các giá trị sự kiện khác offsetXoffsetYđưa các biến đổi CSS vào tài khoản.

Vấn đề lớn nhất với offsetXoffsetYlà vào năm 2019/05 chúng không tồn tại trên các sự kiện cảm ứng và vì vậy không thể sử dụng với iOS Safari. Chúng tồn tại trên các Sự kiện Con trỏ tồn tại trong Chrome và Firefox chứ không phải Safari mặc dù rõ ràng Safari đang hoạt động trên nó .

Một vấn đề khác là các sự kiện phải nằm trên khung vẽ. Nếu bạn đặt chúng trên một số yếu tố khác hoặc cửa sổ, sau đó bạn không thể chọn khung vẽ làm điểm tham chiếu của mình.

Câu trả lời đơn giản số 2 sử dụng clientX, clientYcanvas.getBoundingClientRect

Nếu bạn không quan tâm đến chuyển đổi CSS, câu trả lời đơn giản tiếp theo là gọi canvas. getBoundingClientRect()và trừ bên trái từ clientXtoptrong clientYnhư trong

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

Điều này sẽ hoạt động miễn là không có biến đổi CSS. Nó cũng hoạt động với các sự kiện cảm ứng và do đó sẽ hoạt động với 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;
});

Cách nhận tọa độ chuột pixel canvas cho API Canvas 2D

Để làm điều này, chúng ta cần lấy các giá trị chúng ta có ở trên và chuyển đổi từ kích thước của khung vẽ được hiển thị thành số pixel trong chính khung vẽ

với canvas.getBoundingClientRectclientXclientY

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

hoặc với offsetXoffsetY

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

Lưu ý: Trong mọi trường hợp, không thêm phần đệm hoặc viền vào khung vẽ. Làm như vậy sẽ làm phức tạp mã. Thay vì bạn muốn có một đường viền hoặc phần đệm bao quanh khung vẽ trong một số phần tử khác và thêm phần đệm và hoặc đường viền cho phần tử bên ngoài.

Ví dụ làm việc bằng cách sử dụng event.offsetX,event.offsetY

Ví dụ làm việc sử dụng canvas.getBoundingClientRectevent.clientXevent.clientY


2

Tôi khuyên bạn nên liên kết này- http://miloq.blogspot.in/2011/05/coordins-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>

quan điểm của là x = new Number()gì? Mã bên dưới gán lại xcó nghĩa là Số được phân bổ sẽ bị loại bỏ ngay lập tức
gman


1

Bạn chỉ có thể làm:

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

Điều này sẽ cung cấp cho bạn vị trí chính xác của con trỏ chuột.


1

Xem bản demo tại http://jsbin.com/ApuJOSA/1/edit?html,output .

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

0

Dưới đây là một số sửa đổi của giải pháp Ryan Artecona ở trên.

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

0

Đầu tiên, như những người khác đã nói, bạn cần một hàm để có được vị trí của phần tử canvas . Đây là một phương pháp thanh lịch hơn một chút so với một số phương pháp khác trên trang này (IMHO). Bạn có thể vượt qua nó bất kỳ yếu tố nào và có được vị trí của nó trong tài liệu:

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

Bây giờ hãy tính vị trí hiện tại của con trỏ so với đó:

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

Lưu ý rằng tôi đã tách findPoschức năng chung khỏi mã xử lý sự kiện. ( Vì nó nên . Chúng ta nên cố gắng giữ các chức năng của mình cho mỗi nhiệm vụ.)

Các giá trị của offsetLeftoffsetTopcó liên quan đến offsetParent, có thể là một số divnút bao bọc (hoặc bất cứ thứ gì khác, cho vấn đề đó). Khi không có phần tử bao bọc thì canvaschúng có liên quan đến phần tử body, vì vậy không có phần bù nào để trừ. Đây là lý do tại sao chúng ta cần xác định vị trí của khung vẽ trước khi chúng ta có thể làm bất cứ điều gì khác.

Similary, e.pageXe.pageY đưa ra vị trí của con trỏ so với tài liệu. Đó là lý do tại sao chúng tôi trừ phần bù của khung vẽ khỏi các giá trị đó để đến vị trí thực.

Một thay thế cho các yếu tố định vị là sử dụng trực tiếp các giá trị của e.layerXe.layerY. Điều này ít đáng tin cậy hơn phương pháp trên vì hai lý do:

  1. Các giá trị này cũng liên quan đến toàn bộ tài liệu khi sự kiện không diễn ra bên trong một yếu tố định vị
  2. Chúng không phải là một phần của bất kỳ tiêu chuẩn nào

0

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;

Sau khi thử nhiều giải pháp. Điều này làm việc cho tôi. Có thể giúp đỡ người khác do đó đăng bài. Có nó từ đây


0

Đây là một giải pháp đơn giản hóa (cách này không hoạt động với viền / cuộn):

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

0

Tôi đang tạo một ứng dụng có canvas trên pdf, liên quan đến việc thay đổi kích thước canvas như Phóng to và thu nhỏ pdf, và lần lượt trên mỗi phóng to / thu nhỏ PDF tôi phải thay đổi kích thước canvas để điều chỉnh kích thước của pdf, tôi đã trải qua rất nhiều câu trả lời trong stackOverflow và không tìm thấy một giải pháp hoàn hảo nào cuối cùng sẽ giải quyết được vấn đề.

tôi đang sử dụng rxjs và angular 6, và không tìm thấy câu trả lời cụ thể nào cho phiên bản mới nhất.

Đây là toàn bộ đoạn mã sẽ hữu ích, cho bất kỳ ai tận dụng rxjs để vẽ lên trên khung vẽ.

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

Và đây là đoạn mã sửa lỗi, tọa độ chuột tương ứng với kích thước của khung vẽ, bất kể bạn phóng to / thu nhỏ khung vẽ như thế nào.

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

-1

Này, đây là trong võ đường, chỉ vì đó là những gì tôi đã có mã cho một dự án.

Rõ ràng là làm thế nào để chuyển đổi nó trở lại JavaScript không dojo vanilla.

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

Mong rằng sẽ giúp.


6
clientX / clientY không hoạt động tương tự trên các trình duyệt.
tfwright
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.