วิธีที่ง่ายที่สุดในการเพิ่มตัวจัดการเหตุการณ์การคลิกไปยังองค์ประกอบ Canvas ที่จะส่งคืนพิกัด x และ y ของการคลิก (สัมพันธ์กับองค์ประกอบ Canvas) คืออะไร
ไม่จำเป็นต้องใช้เบราว์เซอร์รุ่นเก่า Safari, Opera และ Firefox จะทำเช่นนั้น
วิธีที่ง่ายที่สุดในการเพิ่มตัวจัดการเหตุการณ์การคลิกไปยังองค์ประกอบ Canvas ที่จะส่งคืนพิกัด x และ y ของการคลิก (สัมพันธ์กับองค์ประกอบ Canvas) คืออะไร
ไม่จำเป็นต้องใช้เบราว์เซอร์รุ่นเก่า Safari, Opera และ Firefox จะทำเช่นนั้น
คำตอบ:
แก้ไข 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;
ทำงานได้ดีอย่างสมบูรณ์แบบสำหรับฉัน
หากคุณชอบความเรียบง่าย แต่ยังต้องการฟังก์ชั่นข้ามเบราว์เซอร์ฉันพบว่าโซลูชันนี้ทำงานได้ดีที่สุดสำหรับฉัน นี่คือความเรียบง่ายของการแก้ปัญหา @ Aldekein's แต่โดยไม่ต้อง 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)
})
getBoundingClientRect
ส่งคืนตำแหน่งที่สัมพันธ์กับพอร์ตมุมมองหรือไม่ จากนั้นฉันเดาว่าผิด ฉันไม่เคยทดสอบมันมาก่อนเพราะนี่ไม่ใช่ปัญหาสำหรับฉันและฉันอยากเตือนผู้อ่านคนอื่นถึงปัญหาที่อาจเกิดขึ้นที่ฉันเห็น แต่ขอบคุณสำหรับคำชี้แจงของคุณ
var canvas = document.getElementById('canvasID'); canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
อัปเดต (5/5/16): ควรใช้คำตอบของผู้รักชาติแทนเพราะทั้งง่ายและเชื่อถือได้มากกว่า
เนื่องจากผืนผ้าใบไม่ได้มีรูปแบบที่สัมพันธ์กับทั้งหน้าตลอดเวลาcanvas.offsetLeft/Top
จึงไม่ส่งคืนสิ่งที่คุณต้องการเสมอไป มันจะส่งคืนจำนวนพิกเซลที่จะชดเชยเมื่อเทียบกับองค์ประกอบ offsetParent ของมันซึ่งอาจเป็นสิ่งที่เหมือนdiv
องค์ประกอบที่มีผ้าใบที่มีposition: relative
สไตล์ที่ใช้ ในการพิจารณาเรื่องนี้คุณต้องวนผ่านสายโซ่ของoffsetParent
s โดยเริ่มจากองค์ประกอบผ้าใบ รหัสนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับฉันทดสอบใน Firefox และ Safari แต่ควรใช้ได้กับทุกคน
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;
event.offsetX
และแอตทริบิวต์ดังนั้นผมจึงมีการปรับเปลี่ยนวิธีการแก้ปัญหาของคุณโดยการเพิ่มevent.offsetY
if (event.offsetX !== undefined && event.offsetY !== undefined) { return {x:event.offsetX, y:event.offsetY}; }
ดูเหมือนว่ามันใช้งานได้
event.offsetX
และevent.offsetY
ยังใช้งานได้ใน IE9 สำหรับ Firefox (ทดสอบ w / v13) คุณสามารถใช้และevent.layerX
event.layerY
canvasX = event.pageX - totalOffsetX - document.body.scrollLeft; canvasY = event.pageY - totalOffsetY - document.body.scrollTop;
เบราว์เซอร์สมัยใหม่ที่จัดการกับสิ่งนี้เพื่อคุณ Chrome, IE9 และ Firefox รองรับ offsetX / Y เช่นนี้ส่งผ่านเหตุการณ์จากตัวจัดการคลิก
function getRelativeCoords(event) {
return { x: event.offsetX, y: event.offsetY };
}
เบราว์เซอร์ที่ทันสมัยส่วนใหญ่รองรับเลเยอร์ X / Y อย่างไรก็ตาม Chrome และ IE ใช้เลเยอร์ X / Y สำหรับออฟเซ็ตที่แน่นอนของการคลิกบนหน้าเว็บรวมถึงระยะขอบ, การเว้นระยะห่าง ฯลฯ ใน Firefox, layerX / Y และ offsetX / Y นั้นเทียบเท่ากัน ไม่มีอยู่ก่อนหน้านี้ ดังนั้นเพื่อความเข้ากันได้กับเบราว์เซอร์รุ่นเก่าคุณสามารถใช้:
function getRelativeCoords(event) {
return { x: event.offsetX || event.layerX, y: event.offsetY || event.layerY };
}
ตามที่สดquirksmodeclientX
และ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];
}
นอกจากนี้ยังต้องjQuery$(canvas).offset()
สำหรับ
ฉันทำสาธิตเต็มรูปแบบที่ใช้งานได้ในทุกเบราว์เซอร์ที่มีรหัสที่มาเต็มของการแก้ปัญหาของปัญหานี้: พิกัดของการคลิกเมาส์บนผ้าใบใน Javascript หากต้องการลองสาธิตให้คัดลอกรหัสและวางลงในโปรแกรมแก้ไขข้อความ จากนั้นให้บันทึกเป็น example.html และสุดท้ายให้เปิดไฟล์ด้วยเบราว์เซอร์
นี่คือการดัดแปลงเล็กน้อยสำหรับคำตอบของ Ryan 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 เพียงอย่างเดียวไม่เพียงพอหากหน้าต่างเบราว์เซอร์ถูกเลื่อน (ตรวจสอบใน Firefox 3.5 และ Chrome 3.0)
โหมดนิสัยใจคอนี้บทความนี้ให้ฟังก์ชันที่ถูกต้องมากขึ้นที่สามารถใช้ pageX หรือ pageY หรือการรวมกันของ clientX กับ document.body.scrollLeft และ clientY ด้วย document.body.scrollTop เพื่อคำนวณพิกัดคลิกที่สัมพันธ์กับที่มาของเอกสาร
UPDATE: นอกจากนี้ offsetLeft และ offsetTop สัมพันธ์กับขนาดเบาะขององค์ประกอบไม่ใช่ขนาดภายใน แคนวาสที่มีการเติมเต็ม: ใช้สไตล์จะไม่รายงานด้านบนซ้ายของพื้นที่เนื้อหาเป็น offsetLeft มีวิธีแก้ไขปัญหาต่าง ๆ นี้ สิ่งที่ง่ายที่สุดอาจจะเป็นการลบเส้นขอบการเติมและอื่น ๆ ทั้งหมดของรูปแบบบนผืนผ้าใบเองและนำไปใช้กับกล่องที่บรรจุผ้าใบแทน
ผมไม่แน่ใจว่าสิ่งที่จุดของทุกคำตอบเหล่านี้ที่ห่วงผ่านองค์ประกอบที่ผู้ปกครองและทำทุกชนิดของสิ่งที่แปลก
HTMLElement.getBoundingClientRect
วิธีถูกออกแบบมาเพื่อที่จะจัดการกับตำแหน่งหน้าจอที่แท้จริงขององค์ประกอบใด ๆ รวมถึงการเลื่อนดังนั้นscrollTop
ไม่จำเป็นต้องมีสิ่งต่อไปนี้:
(จาก MDN)จำนวนของการเลื่อนที่ทำในพื้นที่วิวพอร์ต (หรือ องค์ประกอบเลื่อนอื่น ๆ ) ถูกนำมาพิจารณาเมื่อคำนวณขอบเขตสี่เหลี่ยมผืนผ้า
วิธีที่ง่ายมากที่ถูกโพสต์อยู่ที่นี่แล้ว สิ่งนี้ถูกต้องตราบใดที่ไม่มีกฎCSS เสริมอยู่
เมื่อความกว้างของพิกเซลภาพไม่ตรงกับความกว้างของ 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)
หากผ้าใบมีชายแดนหนาสิ่งที่ได้รับความซับซ้อนน้อย คุณจะต้องลบเส้นขอบออกจากสี่เหลี่ยมผืนผ้าที่มีขอบเขต ซึ่งสามารถทำได้โดยใช้. 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
หากคุณไม่ชอบการแก้ไขเนทีprototype
ฟเพียงแค่เปลี่ยนฟังก์ชั่นแล้วโทรด้วย(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);
หวังว่านี่จะช่วยได้!
width
/ height
overriden แต่ยังคงเป็นหนึ่งในโซลูชันที่ดีที่สุด
ใช้ jQuery ในปี 2559 เพื่อรับพิกัดการคลิกเมื่อเทียบกับผืนผ้าใบฉัน:
$(canvas).click(function(jqEvent) {
var coords = {
x: jqEvent.pageX - $(canvas).offset().left,
y: jqEvent.pageY - $(canvas).offset().top
};
});
สามารถใช้งานได้เนื่องจากทั้งอ็อฟเซ็ต Canvas () และ jqEvent.pageX / Y นั้นสัมพันธ์กับเอกสารโดยไม่คำนึงถึงตำแหน่งการเลื่อน
โปรดทราบว่าถ้าผ้าใบของคุณจะถูกปรับขนาดแล้วพิกัดเหล่านี้จะไม่เหมือนกันเป็นผ้าใบพิกัดทางตรรกะ ที่จะได้รับเหล่านั้นคุณจะยังทำ:
var logicalCoords = {
x: coords.x * (canvas.width / $(canvas).width()),
y: coords.y * (canvas.height / $(canvas).height())
}
ดังนั้นนี่คือทั้งง่าย ๆ แต่เป็นหัวข้อที่ซับซ้อนกว่าเล็กน้อย
ก่อนอื่นมักจะมีคำถามที่ conflated ที่นี่
วิธีรับองค์ประกอบเมาส์สัมพันธ์
วิธีรับพิกัด Canvas pixel Mouse สำหรับ 2D Canvas API หรือ WebGL
ดังนั้นคำตอบ
ไม่ว่าองค์ประกอบนั้นจะเป็น Canvas หรือไม่รับองค์ประกอบของเมาส์ที่สัมพันธ์กันกับองค์ประกอบทั้งหมด
มีคำตอบง่ายๆ 2 ข้อสำหรับคำถาม "วิธีรับพิกัดของเมาส์เทียบกับผืนผ้าใบ"
offsetX
และoffsetY
canvas.addEventListner('mousemove', (e) => {
const x = e.offsetX;
const y = e.offsetY;
});
คำตอบนี้ใช้ได้ใน Chrome, Firefox และ Safari ไม่เหมือนกับค่าเหตุการณ์อื่น ๆ ทั้งหมดoffsetX
และoffsetY
นำการแปลง CSS มาพิจารณา
ปัญหาที่ใหญ่ที่สุดของoffsetX
และoffsetY
เป็นของ 2019/05 พวกเขาไม่ได้อยู่ในเหตุการณ์ที่สัมผัสและดังนั้นจึงไม่สามารถใช้กับ iOS Safari มีอยู่ในกิจกรรมตัวชี้ซึ่งมีอยู่ใน Chrome และ Firefox แต่ไม่ใช่ Safari แม้ว่าSafari จะทำงานอยู่จะทำงานกับมัน
อีกประเด็นคือเหตุการณ์ต้องอยู่บนผืนผ้าใบเอง หากคุณวางองค์ประกอบเหล่านี้ลงในองค์ประกอบอื่นหรือหน้าต่างคุณจะไม่สามารถเลือกผืนผ้าใบภายหลังเพื่อเป็นจุดอ้างอิงของคุณ
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 มันยังใช้งานได้กับกิจกรรมสัมผัสและจะทำงานกับ 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;
});
สำหรับสิ่งนี้เราต้องนำค่าที่เราได้รับไปใช้และแปลงจากขนาดที่ผืนผ้าใบแสดงเป็นจำนวนพิกเซลในผืนผ้าใบ
ด้วย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
ตัวอย่างการใช้งานcanvas.getBoundingClientRect
และevent.clientX
และevent.clientY
ฉันแนะนำลิงค์นี้ - 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>
x = new Number()
คืออะไร รหัสด้านล่างที่กำหนดใหม่x
ซึ่งหมายความว่าจำนวนที่จัดสรรจะถูกยกเลิกในทันที
ใน Prototype ให้ใช้ accumOffset () เพื่อทำผลรวมซ้ำแบบเรียกซ้ำโดย Ryan Artecona ด้านบน
คุณสามารถทำได้:
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,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 };
}
นี่คือการแก้ไขบางส่วนของวิธีการแก้ปัญหาของ Ryan 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
โหนดwrapper (หรือสิ่งอื่นใดสำหรับเรื่องนั้น) เมื่อไม่มีองค์ประกอบที่ห่อcanvas
พวกเขาจะสัมพันธ์กับbody
ดังนั้นจึงไม่มีการชดเชยการลบ นี่คือเหตุผลที่เราต้องกำหนดตำแหน่งของผืนผ้าใบก่อนที่เราจะทำสิ่งอื่นได้
Similary e.pageX
และe.pageY
ให้ตำแหน่งของเคอร์เซอร์สัมพันธ์กับเอกสาร นั่นเป็นเหตุผลที่เราลบผ้าใบตรงข้ามออกจากค่าเหล่านั้นเพื่อมาถึงตำแหน่งที่แท้จริง
ทางเลือกสำหรับตำแหน่งองค์ประกอบคือการใช้โดยตรงค่าของและe.layerX
e.layerY
วิธีนี้เชื่อถือได้น้อยกว่าวิธีการข้างต้นด้วยเหตุผลสองประการ:
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 ฉันได้คำตอบมากมายใน stackOverflow และไม่พบโซลูชันที่สมบูรณ์แบบที่จะแก้ปัญหาได้ในที่สุด
ฉันใช้rxjsและ angular 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 )
};
เฮ้นี่คือโดโจเพียงเพราะมันเป็นสิ่งที่ฉันมีรหัสในโครงการแล้ว
มันควรจะค่อนข้างชัดเจนว่าจะแปลงกลับไปเป็น non dojo vanilla JavaScript
function onMouseClick(e) {
var x = e.clientX;
var y = e.clientY;
}
var canvas = dojo.byId(canvasId);
dojo.connect(canvas,"click",onMouseClick);
หวังว่าจะช่วย