Pertanyaan Mendeteksi goyangan mouse dari titik-titik tertentu dalam sebuah kanvas HTML?


Saya telah membangun mesin visualisasi data analitis untuk Canvas dan telah diminta untuk menambahkan tooltip-like hover di atas elemen data untuk menampilkan metrik rinci untuk titik data di bawah kursor.

Untuk bagan sederhana & grafik Gaant, grafik pohon dan peta nodus dengan area persegi sederhana atau tempat menarik tertentu, saya dapat menerapkan ini dengan melapisi DIV dengan posisi absolut dengan: atribut mengambang, tetapi ada beberapa visualisasi yang lebih rumit seperti diagram lingkaran dan perenderan arus lalu lintas yang memiliki ratusan area terpisah yang ditentukan oleh kurva bezeir.

Apakah mungkin entah bagaimana melampirkan overlay, atau memicu peristiwa ketika pengguna mouse di atas jalur tertutup tertentu?

Setiap area yang harus ditentukan hover ditentukan sebagai berikut:

context.beginPath();
context.moveTo(segmentRight, prevTop);
context.bezierCurveTo(segmentRight, prevTop, segmentLeft, thisTop, segmentLeft, thisTop);
context.lineTo(segmentLeft, thisBottom);
context.bezierCurveTo(segmentLeft, thisBottom, segmentRight, prevBottom, segmentRight, prevBottom);
/*
 * ...define additional segments...
 */
// <dream> Ideally I would like to attach to events on each path:
context.setMouseover(function(){/*Show hover content*/});
// </dream>
context.closePath();

Mengikat ke objek seperti ini hampir sepele untuk diterapkan di Flash atau Silverlight, karena tetapi penerapan Canvas saat ini memiliki keuntungan langsung menggunakan API Javascript kami yang ada dan berintegrasi dengan elemen Ajax lainnya, kami berharap untuk tidak memasukkan Flash ke dalam campuran.

Ada ide?


32
2017-08-03 09:11


asal


Jawaban:


Anda dapat menangani acara mousemove dan mendapatkan koordinat x, y dari acara tersebut. Maka Anda mungkin harus melakukan iterasi atas semua jalur Anda untuk menguji apakah titik itu melewati jalur. Saya punya masalah serupa yang mungkin memiliki beberapa kode yang dapat Anda gunakan.

Mengulang-ulang hal-hal dengan cara ini bisa lambat, terutama pada IE. Salah satu cara Anda berpotensi mempercepatnya - dan ini adalah peretasan, tetapi akan cukup efektif - akan mengubah warna setiap jalur digambar sehingga tidak terlihat oleh manusia tetapi sehingga setiap jalur digambar dalam warna yang berbeda. Miliki tabel untuk mencari warna ke jalur dan hanya mencari warna piksel di bawah mouse.


21
2017-08-03 09:59



Kanvas Bayangan

Metode terbaik yang pernah saya lihat di tempat lain untuk mendeteksi gerakan mouse adalah mengulang bagian gambar Anda yang ingin Anda deteksi ke kanvas yang disembunyikan dan bersih. Kemudian simpan objek ImageData. Anda kemudian dapat memeriksa array ImageData untuk pixel yang diinginkan dan mengembalikan true jika nilai alpha lebih besar dari 0.

// slow part
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(100,100,canvas.width-100,canvas.height-100);
var pixels = ctx.getImageData(0,0,canvas.width,canvas.height).data;

// fast part
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (pixels[idx]) { // alpha > 0
  ...
}

Keuntungan

  • Anda dapat mendeteksi apa pun yang Anda inginkan karena Anda hanya mengulangi metode konteks. Ini bekerja dengan alpha PNG, bentuk gabungan gila, teks, dll.
  • Jika gambar Anda cukup statis, maka Anda hanya perlu melakukan ini satu kali per area yang diinginkan.
  • The "topeng" lambat, tetapi mencari pixel adalah kotoran murah. Jadi "bagian cepat" sangat bagus untuk deteksi gerakan mouse.

Kekurangan

  • Ini adalah memori babi. Setiap topeng adalah nilai W * H * 4. Jika Anda memiliki area kanvas kecil atau beberapa area untuk disamarkan, itu tidak seburuk itu. Gunakan task manager chrome untuk memonitor penggunaan memori.
  • Saat ini ada masalah yang diketahui dengan getImageData di Chrome dan Firefox. Hasilnya bukan sampah yang dikumpulkan segera jika Anda membatalkan variabel, jadi jika Anda melakukan ini terlalu sering, Anda akan melihat memori meningkat dengan cepat. Itu akhirnya mendapatkan sampah dikumpulkan dan seharusnya tidak crash browser, tetapi dapat dikenakan pajak pada mesin dengan jumlah kecil RAM.

Sebuah Hack untuk Menyimpan Memori

Daripada menyimpan seluruh susunan ImageData, kita dapat mengingat piksel mana yang memiliki nilai alfa. Ini menghemat banyak memori, tetapi menambahkan satu lingkaran ke proses masker.

var mask = {};
var len = pixels.length;
for (var i=3;i<len;i+=4) if ( pixels[i] ) mask[i] = 1;

// this works the same way as the other method
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (mask[idx]) {
  ...
}

13
2017-07-07 01:17



Ini bisa dilakukan dengan menggunakan metode ctx.isPointInPath, tetapi tidak diimplementasikan dalam ExCanvas untuk IE. Tetapi solusi lain adalah menggunakan peta HTML, seperti yang saya lakukan untuk perpustakaan kecil ini: http://phenxdesign.net/projects/phenx-web/graphics/example.htm Anda bisa mendapatkan inspirasi dari itu, tetapi masih sedikit buggy.


7
2017-08-03 16:47



Saya akan menyarankan overlaying peta gambar dengan koordinat yang tepat yang ditetapkan di daerah-daerah untuk mencocokkan item yang ditarik kanvas. Dengan cara ini, Anda mendapatkan tooltip dan banyak fungsi DOM / Browser lainnya secara gratis.


1
2017-09-08 14:53



Ada sebuah buku karya Eric Rowell bernama "HTML5 CANVAS COOKBOOK". Dalam buku itu ada bab bernama "Berinteraksi dengan Kanvas: Melampirkan Pendengar Acara untuk Bentuk dan Wilayah". aktivitas mouse, mouse, mouse, mouseout, mousemove, touchstart, touchout dan touchmove dapat diimplementasikan. Saya sangat menyarankan Anda membaca itu.


1
2018-03-13 08:52



Ini tidak dapat dilakukan (baik, setidaknya tidak semudah itu), karena objek yang Anda gambar di kanvas (jalur) tidak direpresentasikan sebagai objek yang sama di kanvas. Yang saya maksud adalah bahwa ini hanya konteks 2D sederhana dan setelah Anda menggambar sesuatu di atasnya, itu benar-benar lupa bagaimana itu digambar. Itu hanya satu set piksel untuk itu.

Untuk menonton gerakan mouse dan sejenisnya, Anda perlu beberapa jenis kanvas grafis vektor, yaitu SVG atau implementasikan sendiri di atas yang sudah ada (yang disarankan oleh Sam Hasler)


0
2017-08-03 10:03



Saya perlu mendeteksi klik mouse untuk kotak kuadrat (seperti sel dari spreadsheet excel). Untuk mempercepatnya, saya membagi grid ke dalam wilayah secara rekursif dengan separuh hingga sejumlah kecil sel tetap, misalnya untuk grid 100x100, 4 wilayah pertama bisa menjadi grid 50x50 yang terdiri dari empat kuadran. Kemudian ini dapat dibagi menjadi 4 lainnya masing-masing (sehingga memberikan 16 wilayah masing-masing 25x25). Ini membutuhkan sejumlah kecil perbandingan dan akhirnya grid 25x25 dapat diuji untuk setiap sel (625 perbandingan dalam contoh ini).


0
2017-12-20 18:32