Seperti yang kita ketahui bersama, canvas merupakan sebuah bitmap, di dalamnya kita dapat menggambar berbagai macam hal, antara lain gambar, garis, dan lain-lain. Jadi apa yang harus kita lakukan jika kita ingin menambahkan event klik pada gambar tertentu di kanvas. Dan js hanya bisa memonitor event canvas saja. Yang jelas gambar ini tidak ada dan gambar yang ada di dom hanya digambar di canvas. Selanjutnya, saya hanya akan menerapkan event binding untuk setiap gambar di dalam kanvas.
Izinkan saya berbicara terlebih dahulu tentang prinsip penerapannya: prinsip ini sebenarnya mengikat peristiwa terkait ke kanvas. Dengan mencatat koordinat kanvas tempat gambar itu berada, dapat dinilai di gambar mana peristiwa itu terjadi. Dengan cara ini, rasanya agak mirip dengan agen acara. Namun penerapannya masih sedikit rumit.
ps: Saya menulis kode berikut di ts. Anda bisa membacanya sebagai es6.
Dokumentasi skrip ketikan (skrip ketikan sangat mudah digunakan, saya sarankan Anda mempelajarinya lebih lanjut).
1. Buatlah hubungan antara gambar dan kanvas (di sini saya menggunakan blok warna sebagai pengganti gambar)Di sini kita perlu membuat hubungan tertentu antara blok warna dan kanvas, bukan hanya rendering. Catat juga koordinat, lebar dan tinggi blok warna. Mari kita terapkan langkah demi langkah
Pertama tulis halaman html dasar untuk membuat kanvas:
<!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 -Konten yang kompatibel=ie=Edge> <title>acara kanvas</title> <style> html, body { tinggi: 100%; latar belakang: #eee; #fff; tampilan: blok; margin: 0 otomatis; } </style></head><body> <lebar kanvas=500 tinggi=500 id=kanvas></canvas></body>Selanjutnya, kita perlu mendefinisikan kelas Canvas. Fungsi apa yang harus dimiliki kelas ini?
Karena blok warna juga memiliki beberapa parameternya sendiri, untuk memfasilitasi perluasan, kami juga mendefinisikan kelas untuk blok warna. Fungsi yang diperlukan untuk tipe ini adalah:
Lebar, tinggi, warna, koordinat (x, y), dan instance Canvas; mari kita tentukan terlebih dahulu.
Oke, mulailah menulis
// Kelas kanvas kelas Kanvas { blockList: Block[] ctx: kanvas apa pun: any createBlock (opsi) { option.Canvas = this this.blockList.push(new Block(option)) this.painting() } rendering (blok) { // Render fungsi blok warna this.ctx.fillStyle = block.color this.ctx.fillRect(block.x, block.y, block.w, block.h) } lukisan () { // Render semua blok warna dalam container ke kanvas // Hapus kanvas (yang lama harus dibersihkan sebelum dirender) this.ctx.fillStyle = '#fff' this.ctx.fillRect(0, 0, this.canvas. width, this .canvas.height) this.blockList.forEach(ele => { this.rendering(ele) }) } konstruktor (ele) { // Fungsi inisialisasi (inputnya adalah kanvas) // Setel kanvas this.canvas = ele this.ctx = this.canvas.getContext('2d') // Wadah blok warna this.blockList = [] }}class Block { w: nomor h: nomor x: nomor y: warna nomor : string Kanvas: Hierarki kanvas: konstruktor angka ({ w, h, x, y, warna, Kanvas }) { // Inisialisasi dan atur properti terkait blok warna this.w = w this.h = h this.x = x ini.y = y ini.warna = warna ini.Kanvas = Kanvas }}Mari kita coba menjalankan gelombang di bawah
// Buat instance Canvas dan tambahkan blok warna biru dengan lebar dan tinggi 100px, posisi (100,100), (300,100) blok warna merah dan biru var canvas = new Canvas(document.getElementById('canvas')) canvas. createBlock({ // merah x: 100, y: 100, w: 100, h: 100, warna: '#f00' }) canvas.createBlock({ // biru x: 100, y: 100, w: 300, h: 100, warna: '#00f' })Hasil yang berjalan adalah sebagai berikut:
2. Tambahkan event klik ke blok warnaDi sini Anda tidak bisa langsung menambahkan event klik ke blok warna, jadi Anda perlu menggunakan koordinat untuk menentukan blok warna mana yang sedang diklik.
class Block { // ...Hilangkan sebagian kode checkBoundary (x, y) { // Tentukan metode batas return x > this.x && x < (this.x + this.w) && y > this.y && y < (this.y + this.h) } mousedownEvent () { // Klik event console.log(`Mengklik blok warna dengan warna ${this.color}`) }}class Canvas { // .. .dihilangkan konstruktor kode bagian (ele) { this.canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Pengikatan acara (ada satu hal yang perlu diperhatikan di sini. Saya menggunakan metode pengikatan di sini, yang mana adalah Untuk mengalihkan penunjuk ini dalam metode mousedownEvent ke Canvas) this.canvas.addEventListener('click', this.mousedownEvent.bind(this)) // Click event} mousedownEvent () { // Peristiwa klik const x = e.offsetX const y = e.offsetY // Di sini koordinat klik diteruskan ke semua blok warna, dan metode penilaian batas digunakan untuk menentukan apakah klik ada di dalam. Jika ya, jalankan metode acara blok warna. this.blockList.forEach(ele => { if (ele.checkBoundary(x, y)) ele.mousedownEvent(e) }) }}Sejauh ini, kami telah menerapkan pengikatan peristiwa klik terkait ke blok warna berbeda di kanvas berbeda. Namun peristiwa klik ini belum sempurna, karena sejauh ini kami belum memperkenalkan konsep hierarki, yang berarti jika dua blok warna yang tumpang tindih diklik, keduanya akan terpicu. Jadi kita juga perlu menambahkan atribut hierarki ke blok warna. Jika Anda mengklik blok warna untuk mengubah blok warna, level blok warna akan dinaikkan ke level tertinggi.
class Block { // ...Hilangkan sebagian konstruktor kode ({ w, h, x, y, warna, Canvas, hierarki }) { // Inisialisasi dan atur properti yang berhubungan dengan blok warna this.w = w this .h = h this.x = x this.y = y this.color = color this.Canvas = Canvas this.hierarchy = 0 }}class Canvas { // ...hilangkan bagian dari konstruktor kode (ele) { this .kanvas = atau ini.ctx = this.canvas.getContext('2d') this.blockList = [] // Pengikatan peristiwa (ada satu hal yang perlu diperhatikan di sini. Saya menggunakan metode pengikatan di sini untuk mengalihkan penunjuk ini dalam metode mousedownEvent ke Canvas) this .canvas .addEventListener('click', this.mousedownEvent.bind(this)) // Klik event this.nowBlock = null // Blok warna yang dipilih saat ini} createBlock (opsi) { // Buat fungsi blok warna (Blok di sini adalah kelas blok warna) option.Canvas = this // Level pembuatan blok warna terbaru harus yang tertinggi option.hierarchy = this.blockList.length this.blockList.push(Blok baru ( pilihan)) this.rendering() } mousedownEvent (e) { // Klik event const x = e.offsetX const y = e.offsetY // Dapatkan blok warna level tertinggi pada poin this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // Jika tidak ada blok warna yang diambil, langsung keluar jika (!this .nowBlock) return // Naikkan level blok warna yang diklik ke level tertinggi this.nowBlock.hierarchy = this.blockList.length // Susun ulang (dari kecil ke besar) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // Alokasi ulang hierarki dari 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // Urutkan ulang dalam urutan terbalik lalu render ulang. this.painting() this.nowBlock.mousedownEvent(e) // Hanya memicu event untuk blok warna yang dipilih}}// Di sini kita harus menambahkan blok warna ketiga yang tumpang tindih dengan blok warna merah canvas.createBlock({ x: 150 , y: 150, w: 100, h: 100, warna: '#0f0'})Kode dalam metode mousedownEvent di Canvas agak rumit, terutama karena agak berbelit-belit.
Efek setelah dijalankan adalah sebagai berikut:
3. Seret dan lepas blok warna yang berbedaDi atas kami telah menerapkan perolehan blok warna yang berbeda dan memodifikasi levelnya. Selanjutnya kita perlu menerapkan menyeret blok warna, terutama untuk mendapatkan perubahan koordinat posisi selama pergerakan mouse dan saat mouse pertama kali diklik. Prinsip ini sama dengan implementasi drag and drop DOM biasa.
Mendapatkan titik dimana blok warna diklik dan jarak (disX, disY) dari kiri dan atas blok warna.
Saat mouse bergerak, kurangi (disX, disY) dari jarak mouse saat ini dari kiri dan atas kanvas. Ini adalah koordinat x dan y dari blok warna.
class Block { // ...hilangkan sebagian kode mousedownEvent (e: MouseEvent) { /* Cara perhitungan disX dan disY disini: e.offsetX memperoleh jarak antara klik mouse dan sisi kiri kanvas, ini .x adalah jarak blok warna Jarak ke kiri kanvas. e.offsetX-this.x adalah jarak ke kiri blok warna. Ini harusnya mudah dipahami */ const disX = e.offsetX - this.x // Jarak dari sisi kiri blok warna saat diklik const disY = e.offsetY - this.y // Jarak dari atas blok warna saat diklik // Ikat event geser mouse; di sini mouseEvent.offsetX juga merupakan jarak antara mouse dan sisi kiri kanvas, mouseEvent.offsetX - disX adalah koordinat x dari blok warna. Dengan cara yang sama, y dihitung dengan cara yang sama. Terakhir, tinggal render ulang. document.onmousemove = (mouseEvent) => { this.x = mouseEvent.offsetX - disX this.y = mouseEvent.offsetY - disY this.Canvas.painting() } // Hapus semua event saat mouse dilepaskan document.onmouseup = ( ) => { dokumen.onmousemove = dokumen.onmousedown = null } // console.log(`Blok warna 22 dengan warna ${this.color} telah diklik`) }}Efeknya adalah sebagai berikut:
Kode lengkapnya ditempelkan di bawah (HTML dan metode pemanggilannya tidak disertakan). Contoh ini hanyalah implementasi sederhana dari peristiwa pengikatan ke konten di kanvas Selain menyeret, Anda dapat memperbesar, memutar, menghapus gambar, dll.
class Canvas { blockList: Block[] ctx: kanvas apa saja: any nowBlock: Blok createBlock (opsi) { option.hierarchy = this.blockList.length option.Canvas = this this.blockList.push(new Block(option)) this. lukisan() } rendering (blok) { this.ctx.fillStyle = block.color this.ctx.fillRect(block.x, block.y, block.w, block.h) } lukisan () { // Kosongkan kanvas 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) { // Klik acara const x = e.offsetX const y = e.offsetY // Dapatkan blok warna level tertinggi pada poin this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // Jika tidak ada blok warna yang diambil, langsung keluar jika (!this .nowBlock) return // Naikkan level blok warna yang diklik ke level tertinggi this.nowBlock.hierarchy = this.blockList.length // Susun ulang (dari kecil ke besar) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // Alokasi ulang hierarki dari 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // Urutkan ulang dalam urutan terbalik lalu render ulang. this.painting() this.nowBlock.mousedownEvent(e) // this.blockList.forEach(ele => { // if (ele.checkBoundary(x, y)) ele.clickEvent(e) // }) } konstruktor (ele) { this.canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Pengikatan acara this.canvas.addEventListener('mousedown', this.mousedownEvent.bind(this)) }}class Block { w: nomor h: nomor x: nomor y: nomor warna: string Kanvas: Hierarki kanvas: konstruktor nomor ( { w, h, x, y, warna, Kanvas, hierarki }) { ini.w = w ini.h = h ini.x = x ini.y = y ini.warna = warna ini.Kanvas = Kanvas this.hierarchy = hierarki } 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(`Blok warna 22 dengan warna ${ini.warna} telah diklik`) }}Di atas adalah keseluruhan isi artikel ini, saya harap dapat bermanfaat untuk pembelajaran semua orang. Saya juga berharap semua orang mendukung VeVb Wulin Network.