Elemen internal kanvas tidak dapat menambahkan event pendengar interaktif senyaman elemen DOM, karena tidak ada konsep elemen di kanvas, hanya grafik yang digambar dengan kanvas. Ini adalah hambatan yang diperlukan untuk pengembangan interaktif. Ide untuk memantau peristiwa klik pada suatu grafik sangat sederhana. Cukup dengarkan peristiwa klik dari elemen kanvas itu sendiri, lalu tentukan grafik mana yang koordinat kliknya terletak di dalamnya, dan maka peristiwa klik grafis dapat diwujudkan secara terselubung. Artikel ini akan memperkenalkan tiga metode untuk menentukan apakah titik koordinat terletak di dalam grafik kanvas.
PerjanjianTiga metode yang diperkenalkan dalam artikel ini cocok untuk mengidentifikasi peristiwa klik grafis dengan bentuk tidak beraturan dan posisi tidak beraturan di kanvas. Untuk adegan dengan bentuk beraturan atau posisi beraturan, harus ada implementasi yang lebih sederhana, yang tidak akan dibahas di sini.
metode pikselIde metode deteksi piksel adalah menggambar beberapa grafik di kanvas (jika ada beberapa) di luar layar secara terpisah, dan menggunakan metode getImageData() untuk mendapatkan data piksel dan menyimpannya. Saat elemen kanvas mendengarkan peristiwa klik, koordinat klik dapat digunakan untuk langsung menghitung piksel pada kanvas tempat klik terjadi, lalu menelusuri data grafik yang disimpan sebelumnya untuk melihat apakah nilai alfa piksel ini adalah 0. Jika bernilai 0, artinya titik pendaratan tidak berada dalam angka saat ini, jika tidak maka titik tersebut telah mencapai angka tersebut.
Cara mendapatkan nomor piksel yang diklik berdasarkan koordinat klik:
Nomor piksel = (ordinat-1) * lebar kanvas + absis
Misalnya kita klik koordinat (3,3) pada kanvas yang lebarnya 5, maka jumlah piksel yang diperoleh berdasarkan rumus di atas adalah (3-1) * 5 + 3 = 18, seperti terlihat pada gambar:
Karena data grafik yang diekspor oleh kanvas menyimpan setiap piksel dalam array 4 angka dalam urutan rgba, jadi jika Anda ingin mengakses nilai alpha dari piksel tertentu, Anda hanya perlu membaca nilai pIndex * 4 + 3 dari array ini. , jika nilainya bukan 0 berarti pikselnya terlihat, yaitu grafiknya diklik.
Cara ini menurut saya memiliki ide paling langsung, hasil paling akurat, dan tidak memiliki persyaratan apa pun pada bentuk grafik. Namun, metode ini memiliki keterbatasan yang fatal. Ketika grafik perlu dipindahkan ke kanvas, cache data harus sering dibuat untuk memastikan deteksi. Dipengaruhi oleh ukuran kanvas dan jumlah grafik, kinerja metode getImageData() akan menjadi hambatan serius. Jadi jika grafik kanvasnya statis maka cara ini sangat cocok, sebaliknya tidak cocok menggunakan cara ini.
Metode sudutPrinsip metode penilaian sudut mudah dipahami. Jika suatu titik berada di dalam poligon, sudut antara titik dan semua simpul poligon harus berjumlah tepat 360°.
Proses perhitungan dapat diubah menjadi tiga langkah berikut:
1. Diketahui simpul poligon dan koordinat yang diketahui, gabungkan koordinat dan simpul secara berpasangan untuk membentuk antrian tiga titik.
2. Untuk mencari sudut antara tiga titik yang diketahui, Anda dapat menggunakan teorema Yu Xuan
3. Tentukan apakah jumlah sudut-sudut yang disertakan adalah 360°
Setiap langkah sederhana dan diterapkan sebagai berikut:
//Hitung jarak antara dua titik const getDistence = function (p1, p2) { return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2. y) * (p1.y - p2.y))};//Metode sudut menentukan bahwa titik berada di dalam poligon const checkPointInPolyline = (titik, polylinePoints) => { let totalA = 0; const A = titik; untuk (misalkan i = 0; i < polylinePoints.length; i++) { misalkan B, C; jika (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] }; } //Hitung sudut konstan sudutA = 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 } //Nilai jumlah dari sudut kembali totalA === 2 * Math.PI}Salah satu keterbatasan metode ini adalah bentuknya harus berupa poligon cembung. Jika poligon tersebut bukan poligon cembung, maka perlu dipotong menjadi poligon cembung sebelum perhitungannya, yang lebih rumit.
Ide serupa adalah metode luas. Jika suatu titik berada di dalam poligon, maka jumlah luas segitiga yang dibentuk oleh titik tersebut dan semua titik sudut poligon harus sama dengan luas poligon tersebut sangat merepotkan untuk menghitung luas poligon terlebih dahulu, jadi cara ini bisa Anda lewati secara langsung.
metode sinarMetode sinar merupakan metode yang tidak dapat saya jelaskan dengan jelas namun sangat mudah digunakan, selama jumlah titik potong antara suatu titik dan salah satu sisi poligon adalah bilangan ganjil, maka titik tersebut berada di dalam poligon. Perhatikan bahwa Anda hanya perlu menghitung jumlah titik fokus di sisi mana pun, misalnya sisi kiri. Metode ini tidak membatasi jenis poligon, poligon cembung, poligon cekung, atau bahkan cincin dapat diterima.
Penerapannya juga sangat mudah:
const checkPointInPolyline = (titik, polylinePoints) => { //Metode sinar biarkan Sisi Kiri = 0; const A = titik; untuk (misalkan i = 0; i < polylinePoints.length; i++) { biarkan 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] }; } //Juri persimpangan kiri let sortByY = [By, Cy].sort((a,b) => ab) if (sortByY[0] < Ay && sortByY[1] > Ay){ if(Bx<Ax || Cx < Ax){ leftSide++ } } } kembalikan LeftSide % 2 === 1}Terdapat kasus khusus pada metode sinar, yang memerlukan perlakuan khusus bila titik berada pada tepi multi-deformasi. Tapi secara teknis menurut saya tidak perlu diolah, karena jika kebetulan user mengklik batas grafik tersebut, maka program mengira belum mengklik dan bisa lewat.
MeringkaskanKetiga metode di atas semuanya dapat mewujudkan deteksi klik pada grafik tidak beraturan di kanvas. Diantaranya, keuntungan dari metode piksel adalah tidak memilih bentuk dan memiliki keunggulan kinerja tertentu dalam pemandangan statis; metode sudut harus dikatakan hanya memiliki nilai teoritis dan kepraktisan yang buruk. Yang paling praktis dalam bidang teknik adalah metode sinar , yang memiliki sedikit keterbatasan dan mudah diterapkan. Sederhana, seringkali Anda hanya perlu mengetahui metode ray.