Saya percaya bahwa setiap orang pasti pernah mengalami kebutuhan seperti itu ketika mempelajari kanvas atau menggunakan kanvas dalam pengembangan proyek: untuk mengimplementasikan gadget sketsa yang dapat ditulis.
Baiklah, saya yakin bagi anak-anak yang lebih familiar dengan kanvas, hal ini bisa dilakukan hanya dengan beberapa lusin baris kode. Demo berikut adalah contoh sederhananya:
<!DOCTYPE html><html><head> <title>Demo sketsa</title> <style type=text/css> kanvas { batas: 1 piksel biru solid; } </style></head><body> <kanvas id=lebar kanvas=800 tinggi=500></kanvas> <tipe skrip=teks/javascript> biarkan isDown = false; biarkan BeginPoint = null; document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); // Tetapkan warna garis ctx.strokeStyle = 'red'; .lineCap = 'bulat'; canvas.addEventListener('mousedown', bawah, false); pindah, salah); kanvas.addEventListener('mouseup', atas, salah); kanvas.addEventListener('mouseout', atas, salah); fungsi bawah(evt) { isDown = true; pindahkan(evt) { jika (!isDown) kembali; const endPoint = getPos(evt); drawLine(beginPoint, endPoint = endPoint); up(evt) { jika (!isDown) kembali; const endPoint = getPos(evt); drawLine(beginPoint, endPoint = null; isDown = false; } fungsi getPos(evt) { kembali { x: evt.clientX, y: evt.clientY } } function drawLine(beginPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, startPoint.y); ctx.lineTo(endPoint.x, endPoint.y); ctx.closePath(); >
Logika implementasinya juga sangat sederhana:
mousedown
, mouseup
dan mousemove
, dan kami juga membuat variabel isDown
;mousedown
), setel isDown
ke true
, dan saat pengguna meletakkan mouse ( mouseup
), setel ke false
;mousemove
. Jika dan hanya jika isDown
true
(yaitu, dalam keadaan penulisan), titik saat ini akan dihubungkan dan digambar dengan titik sebelumnya melalui metode lineTo
pada metode tersebut. kanvas;Melalui langkah-langkah di atas, kita dapat mewujudkan fungsi dasar papan gambar. Namun, hal-hal tidak sesederhana itu. Sepatu anak-anak yang berhati-hati mungkin akan mengalami masalah yang sangat serius - garis yang digambar dengan cara ini bergerigi dan tidak cukup mulus, dan Anda Semakin cepat Anda. menggambar, semakin kuat kesan garis putus-putusnya. Performanya ditunjukkan di bawah ini:
Mengapa ini terjadi? Analisis masalahAlasan utama untuk fenomena ini adalah:
Kita menghubungkan titik-titik tersebut menggunakan metode lineTo
pada kanvas. Yang menghubungkan dua titik yang berdekatan adalah garis lurus, bukan kurva, jadi yang digambar dengan cara ini adalah polyline;
Dibatasi oleh frekuensi pengumpulan peristiwa mousemove
oleh browser, semua orang tahu bahwa selama mousemove
, browser mengumpulkan koordinat mouse saat ini setiap periode waktu yang singkat. Oleh karena itu, semakin cepat mouse bergerak, jarak antara dua titik yang berdekatan dikumpulkan adalah Semakin jauh semakin jauh, semakin jelas kesan garis lipat;
Sebenarnya ada cara untuk menggambar kurva halus. Jika lineTo
tidak dapat diandalkan, kita dapat menggunakan API gambar kanvas lainnya - quadraticCurveTo
, yang digunakan untuk menggambar kurva Bezier kuadrat.
kurva bezier kuadrat
quadraticCurveTo(cp1x, cp1y, x, y)
Memanggil metode quadraticCurveTo
memerlukan empat parameter cp1x
dan cp1y
yang menjelaskan titik kontrol, sedangkan x
dan y
adalah titik akhir kurva:
Informasi lebih detail dapat ditemukan di MDN
Karena kita ingin menggunakan kurva Bezier, jelas bahwa data kita tidak cukup. Untuk mendeskripsikan kurva Bezier kuadrat secara lengkap, kita memerlukan: titik awal, titik kontrol, dan titik akhir.
Ada algoritma yang sangat cerdas yang dapat membantu kita memperoleh informasi ini
Algoritma untuk mendapatkan poin kunci Bezier kuadratAlgoritma ini tidak sulit untuk dipahami. Mari saya beri contoh secara langsung:
Misalkan kita mengumpulkan total 6 koordinat mouse dalam sebuah lukisan, yaitu A, B, C, D, E, F
; ambil tiga titik sebelumnya A, B, C
, hitung titik tengah B1
dari B
dan C
, dan gunakan A
is titik awal, B
adalah titik kontrol, B1
adalah titik akhir. Gunakan quadraticCurveTo
untuk menggambar segmen kurva Bezier kuadrat;
Selanjutnya, hitung titik tengah C1
antara titik C
dan D
, dan lanjutkan menggambar kurva dengan B1
sebagai titik awal, C
sebagai titik kontrol, dan C1
sebagai titik akhir;
Gambaran dilanjutkan dengan analogi. Ketika titik terakhir F
tercapai, kurva Bezier diakhiri dengan D1
, titik tengah D
dan E
, sebagai titik awal, E
sebagai titik kontrol, dan F
sebagai titik akhir.
Oke, algoritmanya seperti ini, selanjutnya kita akan mengupgrade kode yang ada berdasarkan algoritma ini:
let isDown = false;let points = [];let BeginPoint = null;const canvas = document.querySelector('#canvas');const ctx = canvas.getContext('2d');//Atur warna garis ctx.strokeStyle = 'merah';ctx.lineWidth = 1;ctx.lineJoin = 'bulat';ctx.lineCap = 'bulat';canvas.addEventListener('mousedown', bawah, false);canvas.addEventListener('mousemove', pindah, false);canvas.addEventListener('mouseup', atas, false);canvas.addEventListener('mouseout' , atas, salah); fungsi bawah(evt) { isDown = benar; poin.push({x, y});beginPoint = {x, y};}fungsi bergerak(evt) { jika (!isDown) kembali; const { x, y} = getPos(evt); x, y}); if (titik.panjang > 3) { const lastTwoPoints = poin.slice(-2); const controlPoint = lastTwoPoints[0]; x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2, y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2, } drawLine(beginPoint, controlPoint, endPoint); BeginPoint = EndPoint; }}fungsi naik(evt) { jika (!isDown) kembali; const { x, y } = getPos(evt); points.push({x, y}); if (points.length > 3) { const lastTwoPoints = points.slice(-2); const controlPoint = lastTwoPoints[0]; const endPoints = lastTwoPoints[1]; , titik kendali, titik akhir); } titik awal = null; isDown = salah; poin = [];}fungsi getPos(evt) { kembali { x: evt.clientX, y: evt.clientY }}fungsi drawLine(beginPoint, controlPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, beginPoint.y); y, titik akhir.x, titik akhir.y); ctx.stroke(); ctx.closePath();}
Berdasarkan aslinya, kami membuat variabel points
untuk menyimpan titik yang dilewati mouse pada peristiwa mousemove
sebelumnya. Menurut algoritma ini, dibutuhkan setidaknya 3 titik untuk menggambar kurva Bezier kuadrat, jadi kami hanya memiliki poin dalam points
Pengundian dimulai hanya ketika jumlah poin lebih besar dari 3. Pemrosesan selanjutnya sama persis dengan algoritma ini, jadi saya tidak akan membahas detailnya di sini.
Setelah pembaruan kode, kurva kita menjadi lebih mulus, seperti yang ditunjukkan pada gambar di bawah ini:
Artikel ini berakhir di sini. Saya harap Anda semua bersenang-senang menggambar di kanvas~ Sampai jumpa lagi :)
Jika Anda tertarik dengan sepatu anak-anak, Anda dapat mengklik di sini untuk mengikuti blog saya. Setiap postingan blog baru dan menarik akan segera dibagikan di sini~
Di atas adalah keseluruhan isi artikel ini, saya harap dapat bermanfaat untuk pembelajaran semua orang. Saya juga berharap semua orang mendukung VeVb Wulin Network.