อย่างที่เราทราบกันดีว่า canvas คือบิตแมป ในบิตแมป เราสามารถวาดสิ่งต่าง ๆ ในนั้นได้ รวมถึงรูปภาพ เส้น ฯลฯ แล้วเราควรทำอย่างไรหากเราต้องการเพิ่มเหตุการณ์การคลิกให้กับรูปภาพบางรูปบนผืนผ้าใบ และ js สามารถตรวจสอบได้เฉพาะเหตุการณ์บนผ้าใบเท่านั้น แน่นอนว่าไม่มีรูปภาพนี้ และรูปภาพใน dom ก็ถูกวาดบนผืนผ้าใบเท่านั้น ต่อไป ฉันจะใช้การเชื่อมโยงเหตุการณ์กับแต่ละภาพภายในแคนวาส
ก่อนอื่นให้ฉันพูดถึงหลักการนำไปใช้งาน: จริง ๆ แล้วมันเป็นการเชื่อมโยงเหตุการณ์ที่เกี่ยวข้องกับผืนผ้าใบ โดยการบันทึกพิกัดของผืนผ้าใบที่รูปภาพนั้นตั้งอยู่ จะถูกตัดสินว่ารูปภาพใดที่เหตุการณ์นั้นกระทำ ด้วยวิธีนี้ จึงให้ความรู้สึกคล้ายกับตัวแทนเหตุการณ์เล็กน้อย อย่างไรก็ตาม การดำเนินการยังคงซับซ้อนเล็กน้อย
PS: ฉันเขียนโค้ดต่อไปนี้ใน ts คุณสามารถอ่านเป็น es6 ได้ คุณสามารถตรวจสอบได้ว่ามันแตกต่างออกไปเล็กน้อยหรือไม่
เอกสาร Typescript (typescript ใช้งานง่ายมาก ฉันขอแนะนำให้คุณเรียนรู้เพิ่มเติมเกี่ยวกับเรื่องนี้)
1. สร้างการเชื่อมโยงระหว่างรูปภาพกับแคนวาส (ในที่นี้ฉันใช้บล็อคสีแทนรูปภาพ)ที่นี่เราจำเป็นต้องสร้างการเชื่อมต่อบางอย่างระหว่างบล็อกสีและแคนวาส แทนที่จะแค่เรนเดอร์ บันทึกพิกัด ความกว้าง และความสูงของบล็อกสีด้วย มาปรับใช้ทีละขั้นตอนกัน
ขั้นแรกให้เขียนหน้า html พื้นฐานเพื่อสร้างแคนวาส:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <meta name=viewport content=width=device-width, Initial-scale=1.0> <meta http-equiv=X-UA - เนื้อหาที่เข้ากันได้=ie=edge> <title>เหตุการณ์ผ้าใบ</title> <style> html, ร่างกาย { ความสูง: 100%; พื้นหลัง: #eee } ผ้าใบ { พื้นหลัง: #fff; display: block; Margin: 0 auto; } </style></head><body> <canvas width=500 height=500 id=canvas></canvas></body>
ต่อไปเราจำเป็นต้องกำหนดคลาส Canvas คลาสนี้ควรมีฟังก์ชันอะไรบ้าง?
เนื่องจากบล็อคสียังมีพารามิเตอร์บางอย่างของตัวเอง เพื่ออำนวยความสะดวกในการขยาย เราจึงกำหนดคลาสสำหรับบล็อคสีด้วย ฟังก์ชันที่จำเป็นสำหรับประเภทนี้คือ:
ความกว้าง ความสูง สี พิกัด (x, y) และอินสแตนซ์ Canvas มาตัดสินใจกันตั้งแต่แรก
ตกลงเริ่มเขียน
// คลาส Canvas คลาส Canvas { blockList: บล็อก [] ctx: ผืนผ้าใบใด ๆ: createBlock ใด ๆ (ตัวเลือก) { option.Canvas = this this.blockList.push (บล็อกใหม่ (ตัวเลือก)) this.painting () } การแสดงผล (บล็อก) { // ฟังก์ชันบล็อกสีเรนเดอร์ this.ctx.fillStyle = block.color this.ctx.fillRect(block.x, block.y, block.w, block.h) } ภาพวาด () { // แสดงบล็อกสีทั้งหมดในคอนเทนเนอร์ไปยังแคนวาส // ล้างแคนวาส (อันเก่าควรล้างก่อนเรนเดอร์) this.ctx.fillStyle = '#fff' this.ctx.fillRect(0, 0, this.canvas. width, this .canvas.height) this.blockList.forEach(ele => { this.rendering(ele) }) } ตัวสร้าง (ele) { // ฟังก์ชันการเริ่มต้น (อินพุตเป็น canvas) // ตั้งค่า canvas this.canvas = ele this.ctx = this.canvas.getContext('2d') // คอนเทนเนอร์บล็อกสี this.blockList = [] }}คลาส Block { w: หมายเลข h: หมายเลข x: หมายเลข y: สีตัวเลข : string Canvas: ลำดับชั้นของ Canvas: ตัวสร้างตัวเลข ({ w, h, x, y, สี, Canvas }) { // เริ่มต้นและตั้งค่าคุณสมบัติที่เกี่ยวข้องกับบล็อกสี this.w = w this.h = h this.x = x this.y = y this.color = สี this.Canvas = แคนวาส }}
มาลองใช้คลื่นด้านล่างกัน
// สร้างอินสแตนซ์ Canvas และเพิ่มบล็อกสีน้ำเงินที่มีความกว้างและความสูง 100px ตำแหน่ง (100,100), (300,100) บล็อกสีแดงและสีน้ำเงิน var canvas = new Canvas(document.getElementById('canvas')) canvas createBlock ({ // สีแดง x: 100, y: 100, w: 100, h: 100, สี: '#f00' }) canvas.createBlock({ // สีน้ำเงิน x: 100, y: 100, w: 300, h: 100, สี: '#00f' })
ผลการวิ่งมีดังนี้:
2. เพิ่มเหตุการณ์การคลิกลงในบล็อคสีที่นี่คุณไม่สามารถเพิ่มเหตุการณ์การคลิกลงในบล็อกสีได้โดยตรง ดังนั้นคุณจึงจำเป็นต้องใช้พิกัดเพื่อกำหนดว่าบล็อกสีใดที่ถูกคลิกในปัจจุบัน
class Block { // ...ละเว้นส่วนหนึ่งของโค้ด checkBoundary (x, y) { // กำหนดวิธีการขอบเขต return x > this.x && x < (this.x + this.w) && y > this.y && y < (this.y + this.h) } mousedownEvent () { // คลิก event console.log(`คลิกบนบล็อกสีที่มีสี ${this.color}`) }}คลาส Canvas { // .. .ละเว้นตัวสร้างรหัสชิ้นส่วน (ele) { this.canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Event Binding (มีสิ่งหนึ่งที่ควรทราบในที่นี้ ผมใช้วิธี bind ที่นี่ ซึ่ง คือ เพื่อสลับตัวชี้นี้ในวิธี mousedownEvent เป็น Canvas) this.canvas.addEventListener('click', this.mousedownEvent.bind(this)) // Click event} mousedownEvent () { // เหตุการณ์คลิก const x = e.offsetX const y = e.offsetY // ที่นี่พิกัดของการคลิกจะถูกส่งผ่านไปยังบล็อคสีทั้งหมด และใช้วิธีตัดสินขอบเขตเพื่อพิจารณาว่าคลิกอยู่ภายในหรือไม่ หากใช่ ให้ดำเนินการตามวิธีเหตุการณ์ของบล็อคสี this.blockList.forEach(ele => { ถ้า (ele.checkBoundary(x, y)) ele.mousedownEvent(e) }) }}
จนถึงตอนนี้ เราได้นำการเชื่อมโยงเหตุการณ์การคลิกที่สอดคล้องกันไปใช้กับบล็อกสีต่างๆ ในผืนผ้าใบต่างๆ อย่างไรก็ตาม เหตุการณ์การคลิกนี้ไม่สมบูรณ์แบบ เนื่องจากจนถึงขณะนี้เรายังไม่ได้แนะนำแนวคิดเรื่องลำดับชั้น ซึ่งหมายความว่าหากมีการคลิกบล็อกสีสองบล็อกที่ทับซ้อนกัน ทั้งสองบล็อกจะถูกทริกเกอร์ ดังนั้นเราจึงจำเป็นต้องเพิ่มคุณลักษณะแบบลำดับชั้นให้กับบล็อคสีด้วย หากคุณคลิกที่บล็อคสีเพื่อเปลี่ยนบล็อคสี ระดับของบล็อคสีจะถูกยกระดับไปที่ระดับสูงสุด
class Block { // ...ละเว้นส่วนหนึ่งของตัวสร้างโค้ด ({ w, h, x, y, สี, Canvas, ลำดับชั้น }) { // เริ่มต้นและตั้งค่าคุณสมบัติที่เกี่ยวข้องกับบล็อกสี this.w = w this .h = h this. x = x this.y = y this.color = color this.Canvas = Canvas this.hierarchy = 0 }}คลาส Canvas { // ...ละเว้นส่วนหนึ่งของตัวสร้างโค้ด (ele) { this .canvas = เอเล this.ctx = this.canvas.getContext('2d') this.blockList = [] // Event Binding (มีสิ่งหนึ่งที่ควรทราบที่นี่ ฉันใช้วิธีการผูกที่นี่เพื่อสลับตัวชี้นี้ในวิธี mousedownEvent เป็น Canvas) .canvas นี้ .addEventListener('click', this.mousedownEvent.bind(this)) // คลิกเหตุการณ์ this.nowBlock = null // บล็อกสีที่เลือกในปัจจุบัน} createBlock (ตัวเลือก) { // สร้างฟังก์ชันบล็อกสี (บล็อกที่นี่คือคลาสของบล็อกสี) option.Canvas = this // ระดับการสร้างบล็อกสีล่าสุดควรเป็นตัวเลือกสูงสุด.hierarchy = this.blockList.length this.blockList.push(new Block ( option)) this.rendering() } mousedownEvent (e) { // คลิกเหตุการณ์ const x = e.offsetX const y = e.offsetY // รับบล็อกสีระดับสูงสุด ณ จุดนี้ this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // หากไม่มีบล็อกสีที่บันทึกไว้ ให้ออกโดยตรงหาก (!this .nowBlock) return // เพิ่มระดับบล็อกสีที่ถูกคลิกให้สูงสุด this.nowBlock.hierarchy = this.blockList.length // เรียงลำดับใหม่ (จากเล็กไปใหญ่) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // จัดสรรลำดับชั้นใหม่จาก 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // เรียงลำดับใหม่ในลำดับย้อนกลับแล้วเรนเดอร์อีกครั้ง this.painting() this.nowBlock.mousedownEvent(e) // ทริกเกอร์เฉพาะเหตุการณ์สำหรับบล็อกสีที่เลือก}}// ที่นี่เราต้องเพิ่มบล็อกสีที่สามที่ทับซ้อนบล็อกสีแดง canvas.createBlock({ x: 150 , y: 150, ก: 100, ส: 100, สี: '#0f0'})
โค้ดในเมธอด mousedownEvent ใน Canvas นั้นซับซ้อนเล็กน้อย ส่วนใหญ่เป็นเพราะมันซับซ้อนเล็กน้อย
ผลลัพธ์หลังการวิ่งจะเป็นดังนี้:
3. ลากและวางบล็อกสีต่างๆข้างต้นเราได้ดำเนินการรับบล็อคสีต่างๆ และปรับเปลี่ยนระดับของมัน ต่อไป เราจำเป็นต้องใช้การลากบล็อคสี โดยหลักๆ เพื่อรับการเปลี่ยนแปลงพิกัดตำแหน่งระหว่างการเคลื่อนไหวของเมาส์และเมื่อคลิกเมาส์ครั้งแรก หลักการนี้เหมือนกับหลักการลากและวาง DOM ทั่วไป
รับจุดที่คลิกบล็อกสีและระยะห่าง (disX, disY) จากด้านซ้ายและด้านบนของบล็อกสี
เมื่อเมาส์เคลื่อนที่ ให้ลบ (disX, disY) จากระยะห่างปัจจุบันของเมาส์จากด้านซ้ายและด้านบนของผืนผ้าใบ นี่คือพิกัด x และ y ของบล็อกสี
class Block { // ...ละเว้นส่วนหนึ่งของโค้ด mousedownEvent (e: MouseEvent) { /* วิธีการคำนวณของ disX และ disY ที่นี่: e.offsetX รับระยะห่างระหว่างการคลิกเมาส์และด้านซ้ายของผืนผ้าใบ นี่ .x คือระยะบล็อกสี ระยะห่างทางด้านซ้ายของผืนผ้าใบ e.offsetX-this.x คือระยะห่างทางด้านซ้ายของบล็อกสี ควรเข้าใจได้ง่าย */ const disX = e.offsetX - this.x // ระยะห่างจากด้านซ้ายของบล็อกสีเมื่อคลิก const disY = e.offsetY - this.y // ระยะห่างจากด้านบนของ บล็อกสีเมื่อคลิก // ผูกเหตุการณ์การเลื่อนเมาส์ ที่นี่ mouseEvent.offsetX คือระยะห่างระหว่างเมาส์กับด้านซ้ายของผืนผ้าใบ mouseEvent.offsetX - disX คือพิกัด x ของบล็อกสี ในทำนองเดียวกัน y ก็คำนวณในลักษณะเดียวกัน สุดท้ายก็แค่เรนเดอร์อีกครั้ง document.onmousemove = (mouseEvent) => { this.x = mouseEvent.offsetX - disX this.y = mouseEvent.offsetY - disY this.Canvas.painting() } // ล้างเหตุการณ์ทั้งหมดเมื่อปล่อยเมาส์ document.onmouseup = ( ) => { document.onmousemove = document.onmousedown = null } // console.log(`บล็อกสี 22 ที่มีสี ${this.color} ถูกคลิก`) }}
ผลกระทบมีดังนี้:
โค้ดที่สมบูรณ์จะถูกวางด้านล่าง (ไม่รวม HTML และวิธีการเรียก) ตัวอย่างนี้เป็นเพียงการใช้งานอย่างง่ายของการเชื่อมโยงเหตุการณ์กับเนื้อหาบนผืนผ้าใบ คุณสามารถปรับใช้โค้ดที่ซับซ้อนมากขึ้นได้ เช่น การแทนที่บล็อคสีด้วยรูปภาพ นอกจากการลากแล้ว คุณยังสามารถซูม หมุน ลบ ฯลฯ รูปภาพได้
class Canvas { blockList: Block[] ctx: canvas ใด ๆ: any nowBlock: Block createBlock (ตัวเลือก) { option.hierarchy = this.blockList.length option.Canvas = this this.blockList.push (บล็อกใหม่ (ตัวเลือก)) สิ่งนี้ ภาพวาด () } การเรนเดอร์ (บล็อก) { this.ctx.fillStyle = block.color this.ctx.fillRect (block.x, block.y, block.w, block.h) } จิตรกรรม () { // ล้างผ้าใบ this.ctx.fillStyle = '#fff' this.ctx.fillRect (0, 0, this.canvas.width, this.canvas.height) this.blockList.forEach (ele => { this.rendering(ele) }) } mousedownEvent (e: MouseEvent) { // คลิกเหตุการณ์ const x = e.offsetX const y = e.offsetY // รับบล็อกสีระดับสูงสุด ณ จุดนี้ this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // หากไม่มีบล็อกสีที่บันทึกไว้ ให้ออกโดยตรงหาก (!this .nowBlock) return // เพิ่มระดับบล็อกสีที่ถูกคลิกให้สูงสุด this.nowBlock.hierarchy = this.blockList.length // เรียงลำดับใหม่ (จากเล็กไปใหญ่) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // จัดสรรลำดับชั้นใหม่จาก 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // เรียงลำดับใหม่ในลำดับย้อนกลับแล้วเรนเดอร์อีกครั้ง this.painting() this.nowBlock.mousedownEvent(e) // this.blockList.forEach(ele => { // if (ele.checkBoundary(x, y)) ele.clickEvent(e) // }) } ตัวสร้าง (ele) { this.canvas = ele this.ctx = this.canvas.getContext ('2d') this.blockList = [] // การเชื่อมโยงเหตุการณ์ this.canvas.addEventListener('mousedown', this.mousedownEvent.bind(this)) }}คลาส Block { w: หมายเลข h: หมายเลข x: หมายเลข y: หมายเลขสี: สตริง ผ้าใบ: ลำดับชั้นของผ้าใบ: ตัวสร้างตัวเลข ( { w, h, x, y, สี, แคนวาส, ลำดับชั้น }) { this.w = w this.h = h this.x = x this.y = y this.color = color this.Canvas = Canvas this.hierarchy = ลำดับชั้น } checkBoundary (x, y) { return x > this.x && x < (this.x + this.w) && y > this.y && y < (this.y + this.h) } mousedownEvent (e: MouseEvent) { const disX = e.offsetX - this.x const disY = e.offsetY - this.y document.onmousemove = (mouseEvent) => { this.x = mouseEvent.offsetX - disX this.y = mouseEvent.offsetY - disY this.Canvas.painting() } document.onmouseup = () => { document.onmousemove = document.onmousedown = null } // console.log(`บล็อกสี 22 ที่มีสี ${this.color} ถูกคลิก`) }}
ข้างต้นคือเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการศึกษาของทุกคน ฉันหวังว่าทุกคนจะสนับสนุน VeVb Wulin Network