องค์ประกอบภายในของ Canvas ไม่สามารถเพิ่ม Listener เหตุการณ์เชิงโต้ตอบได้สะดวกพอๆ กับองค์ประกอบ DOM เนื่องจากไม่มีแนวคิดเกี่ยวกับองค์ประกอบต่างๆ ใน Canvas แต่เป็นเพียงกราฟิกที่วาดด้วย Canvas นี่เป็นอุปสรรคที่จำเป็นสำหรับการพัฒนาเชิงโต้ตอบ แนวคิดในการตรวจสอบเหตุการณ์การคลิกของกราฟิกนั้นง่ายมาก เพียงฟังเหตุการณ์การคลิกขององค์ประกอบ Canvas จากนั้นกำหนดว่ากราฟิกใดที่พิกัดการคลิกอยู่ข้างในและ จากนั้นเหตุการณ์การคลิกกราฟิกสามารถเกิดขึ้นได้โดยไม่เปิดเผย บทความนี้จะแนะนำสามวิธีในการพิจารณาว่าจุดพิกัดอยู่ภายในกราฟิกแคนวาสหรือไม่
ข้อตกลงวิธีการทั้งสามที่แนะนำในบทความนี้เหมาะสำหรับการระบุเหตุการณ์การคลิกกราฟิกที่มีรูปร่างไม่ปกติและตำแหน่งที่ไม่ปกติบนผืนผ้าใบ สำหรับฉากที่มีรูปร่างปกติหรือตำแหน่งปกติ จะต้องมีการใช้งานที่ง่ายกว่า ซึ่งจะไม่กล่าวถึงในที่นี้
วิธีพิกเซลแนวคิดของวิธีการตรวจจับพิกเซลคือการวาดภาพกราฟิกหลายภาพบนผืนผ้าใบ (หากมีหลายภาพ) นอกหน้าจอแยกจากกัน และใช้วิธี getImageData() เพื่อรับข้อมูลพิกเซลและบันทึกไว้ เมื่อองค์ประกอบแคนวาสฟังเหตุการณ์การคลิก พิกัดการคลิกสามารถใช้เพื่อคำนวณพิกเซลบนผืนผ้าใบโดยตรงที่เกิดการคลิก จากนั้นจึงสำรวจข้อมูลกราฟิกที่บันทึกไว้ก่อนหน้านี้เพื่อดูว่าค่าอัลฟ่าของพิกเซลนี้เป็น 0 หรือไม่ หาก มันคือ 0 หมายความว่า จุดลงจอดไม่อยู่ในตัวเลขปัจจุบัน มิฉะนั้น หมายความว่าจุดนั้นถึงตัวเลขนี้แล้ว
วิธีรับหมายเลขพิกเซลที่ถูกคลิกตามพิกัดการคลิก:
หมายเลขพิกเซล = (พิกัด-1) * ความกว้างของผืนผ้าใบ + abscissa
ตัวอย่างเช่น หากคุณคลิกพิกัด (3,3) บนผืนผ้าใบที่มีความกว้าง 5 จำนวนพิกเซลที่ได้รับตามสูตรด้านบนคือ (3-1) * 5 + 3 = 18 ดังแสดงในรูป:
เนื่องจากข้อมูลกราฟิกที่ส่งออกโดย Canvas จะจัดเก็บแต่ละพิกเซลในอาร์เรย์ 4 หมายเลขตามลำดับ rgba ดังนั้นหากคุณต้องการเข้าถึงค่าอัลฟ่าของพิกเซลที่ระบุ คุณจะต้องอ่านค่า pIndex * 4 + 3 ของอาร์เรย์นี้เท่านั้น หากค่านี้ไม่ใช่ 0 แสดงว่าพิกเซลนั้นมองเห็นได้ นั่นคือกราฟิกถูกคลิก
วิธีนี้เป็นวิธีที่ฉันคิดว่ามีแนวคิดที่ตรงที่สุดและผลลัพธ์ที่แม่นยำที่สุด และไม่มีข้อกำหนดใดๆ เกี่ยวกับรูปร่างของกราฟิก อย่างไรก็ตาม วิธีการนี้มีข้อจำกัดร้ายแรง เมื่อจำเป็นต้องย้ายกราฟิกบนผืนผ้าใบ ต้องสร้างแคชข้อมูลบ่อยครั้งเพื่อให้แน่ใจว่าผลลัพธ์มีความแม่นยำ เนื่องจากขนาดแคนวาสและจำนวนกราฟิก ประสิทธิภาพของเมธอด getImageData() จะกลายเป็นปัญหาคอขวดร้ายแรง ดังนั้นหากกราฟิกแคนวาสเป็นแบบคงที่ วิธีนี้เหมาะมาก ไม่เช่นนั้นก็ไม่เหมาะที่จะใช้วิธีนี้
วิธีมุมหลักการของวิธีการตัดสินมุมนั้นง่ายต่อการเข้าใจ หากจุดหนึ่งอยู่ภายในรูปหลายเหลี่ยม มุมระหว่างจุดนั้นกับจุดยอดทั้งหมดของรูปหลายเหลี่ยมควรรวมกันได้ 360° พอดี
กระบวนการคำนวณสามารถแปลงเป็นสามขั้นตอนต่อไปนี้:
1. เมื่อกำหนดจุดยอดรูปหลายเหลี่ยมและพิกัดที่ทราบแล้ว ให้รวมพิกัดและจุดยอดเป็นคู่กันเพื่อสร้างคิวสามจุด
2. หากต้องการหามุมระหว่างจุดสามจุดที่ทราบ คุณสามารถใช้ทฤษฎีบทของ Yu Xuan
3. พิจารณาว่าผลรวมของมุมที่รวมเป็น 360° หรือไม่
แต่ละขั้นตอนนั้นเรียบง่ายและดำเนินการดังนี้:
//คำนวณระยะห่างระหว่างจุดสองจุด const getDistence = function (p1, p2) { return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.x) y) * (p1.y - p2.y))};//วิธีมุมกำหนดว่าจุดอยู่ภายในรูปหลายเหลี่ยม const checkPointInPolyline = (point, polylinePoints) => { ให้ TotalA = 0; const A = point; for (let i = 0; i < polylinePoints.length; i++) { ให้ B, C; if (i === polylinePoints.length - 1) { B = { x: polylinePoints[i] [0] ], y: polylinePoints[i][1] }; C = { x: polylinePoints[0][0], y: polylinePoints[0][1] }; { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] }; } //คำนวณมุม const angleA = Math.acos((Math.pow(getDistence(A, C), 2) + Math.pow(getDistence(A, B), 2) - Math.pow(getDistence(B, C), 2)) / (2 * getDistence(A, C) * getDistence(A, B))) TotalA += angleA } //ตัดสินผลรวมของ มุมส่งคืนผลรวม A === 2 * Math.PI}ข้อจำกัดประการหนึ่งของวิธีนี้คือ รูปร่างจะต้องเป็นรูปหลายเหลี่ยมนูน หากรูปหลายเหลี่ยมไม่ใช่รูปหลายเหลี่ยมนูน จะต้องตัดให้เป็นรูปหลายเหลี่ยมนูนก่อนคำนวณ ซึ่งจะซับซ้อนกว่า
แนวคิดที่คล้ายกันคือวิธีการหาพื้นที่ ถ้าจุดหนึ่งอยู่ในรูปหลายเหลี่ยม ผลรวมของพื้นที่ของรูปสามเหลี่ยมที่เกิดจากจุดและจุดยอดทั้งหมดของรูปหลายเหลี่ยมควรจะเท่ากับพื้นที่ของรูปหลายเหลี่ยม ยุ่งยากมากในการคำนวณพื้นที่ของรูปหลายเหลี่ยมก่อน ดังนั้น วิธีนี้ คุณก็สามารถผ่านมันไปได้โดยตรง
วิธีเรย์วิธีเรย์เป็นวิธีการที่อธิบายไม่ชัดเจนแต่ใช้ง่ายมาก ตราบใดที่จำนวนจุดตัดระหว่างจุดกับด้านหนึ่งของรูปหลายเหลี่ยมเป็นเลขคี่ จุดนั้นก็จะอยู่ภายในรูปหลายเหลี่ยม โปรดทราบว่าคุณจะต้องนับจำนวนจุดโฟกัสที่ด้านใดก็ได้ เช่น ด้านซ้าย วิธีการนี้ไม่จำกัดประเภทของรูปหลายเหลี่ยม รูปหลายเหลี่ยมนูน รูปหลายเหลี่ยมเว้า หรือแม้แต่วงแหวนที่ยอมรับได้
การดำเนินการยังง่ายมาก:
const checkPointInPolyline = (point, polylinePoints) => { //วิธี Ray ให้ leftSide = 0; for (let i = 0; i < polylinePoints.length; i++) { ให้ B, C; == polylinePoints.length - 1) { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; polylinePoints[0][0], y: polylinePoints[0][1] }; else { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; : polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] }; // ผู้พิพากษาออกจากทางแยก ให้ sortByY = [โดย, Cy].sort((a,b) => ab) if (sortByY[0] < Ay && sortByY[1] > Ay){ if(Bx<Ax || Cx < Ax){ leftSide++ } } } ส่งคืน leftSide % 2 === 1}มีกรณีพิเศษของวิธีการฉายรังสี ซึ่งต้องได้รับการดูแลเป็นพิเศษเมื่อจุดที่อยู่บนขอบที่มีการเสียรูปหลายครั้ง แต่ในทางวิศวกรรมผมคิดว่ามันไม่จำเป็นต้องประมวลผล เพราะถ้า user บังเอิญคลิกตรงขอบเขตของกราฟิก โปรแกรมจะคิดว่าไม่ได้คลิกแล้วผ่านได้
สรุปวิธีการทั้งสามข้างต้นสามารถตรวจจับการคลิกของกราฟิกที่ผิดปกติบนผืนผ้าใบได้ ข้อดีของวิธีพิกเซลคือไม่เลือกรูปร่างและมีข้อได้เปรียบด้านประสิทธิภาพบางอย่างในฉากคงที่ ควรกล่าวว่าวิธีมุมมีเพียงค่าทางทฤษฎีและการปฏิบัติจริงที่ไม่ดีคือวิธีทางวิศวกรรม ซึ่งมีข้อจำกัดเล็กน้อยและนำไปปฏิบัติได้ง่าย โดยส่วนใหญ่แล้วคุณเพียงแค่ต้องทราบวิธี ray เท่านั้น