Membuat Ulang Tombol Tekan Arduino Menggunakan SVG Dan <lit-element>

Diterbitkan: 2022-03-10
Ringkasan cepat HTML hadir dengan sekumpulan kontrol input, dan ada banyak sekali pustaka komponen yang menyertakan banyak kontrol standar seperti kotak centang, dan tombol radio. Tetapi apa yang terjadi ketika Anda membutuhkan sesuatu yang tidak biasa?

Dalam artikel ini, Anda akan mempelajari cara membuat komponen HTML khusus yang meniru objek fisik, seperti Tombol Tekan Arduino. Kami akan menggambar komponen di Inkscape dari awal, mengoptimalkan kode SVG yang dihasilkan untuk Web, dan membungkusnya sebagai komponen web mandiri menggunakan pustaka lit-element ringan yang ringan, memberikan perhatian ekstra pada pertimbangan aksesibilitas dan kegunaan seluler.

Hari ini, saya akan membawa Anda melalui perjalanan membuat komponen HTML yang meniru komponen tombol tekan sesaat yang biasa digunakan dengan Arduino dan dalam proyek elektronik. Kami akan menggunakan teknologi seperti SVG, Web Components dan lit-element , dan mempelajari cara membuat tombol dapat diakses melalui beberapa tipu daya JavaScript-CSS.

Ayo mulai!

Dari Arduino Ke HTML: Kebutuhan Komponen Tombol Tekan

Sebelum memulai perjalanan, mari kita jelajahi apa yang akan kita buat, dan yang lebih penting, mengapa. Saya membuat simulator Arduino open-source dalam JavaScript yang disebut avr8js. Simulator ini mampu mengeksekusi kode Arduino dan saya akan menggunakannya dalam serangkaian tutorial dan kursus yang mengajarkan pembuat cara memprogram untuk Arduino.

Simulator itu sendiri hanya menangani eksekusi program — simulator menjalankan instruksi kode demi instruksi dan memperbarui status internal dan buffer memori sesuai dengan logika program. Untuk berinteraksi dengan program Arduino, Anda perlu membuat beberapa komponen elektronik virtual yang dapat mengirim input ke simulator atau bereaksi terhadap outputnya.

Menjalankan simulator sendiri sangat mirip dengan menjalankan JavaScript secara terpisah. Anda tidak dapat benar-benar berinteraksi dengan pengguna kecuali Anda juga membuat beberapa elemen HTML, dan mengaitkannya ke kode JavaScript melalui DOM.

Jadi, selain simulator prosesor, saya juga mengerjakan perpustakaan komponen HTML yang meniru perangkat keras fisik, dimulai dengan dua komponen pertama yang akan Anda temukan di hampir semua proyek elektronik: LED dan tombol tekan.

Elemen LED dan tombol tekan beraksi
Elemen LED dan tombol tekan beraksi

LED relatif sederhana, karena hanya memiliki dua status keluaran: hidup dan mati. Di balik layar, ia menggunakan filter SVG untuk menciptakan efek pencahayaan.

Tombol lebih menarik. Ini juga memiliki dua status, tetapi harus bereaksi terhadap input pengguna dan memperbarui statusnya sesuai dengan itu, dan dari sinilah tantangannya berasal, seperti yang akan segera kita lihat. Tapi pertama-tama, mari kita tentukan persyaratan dari komponen yang akan kita buat.

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Mendefinisikan Persyaratan Untuk Tombol Tekan

Komponen kami akan menyerupai tombol tekan 12mm. Tombol-tombol ini sangat umum di starter kit elektronik, dan dilengkapi dengan tutup dalam berbagai warna, seperti yang Anda lihat pada foto di bawah ini:

Simon Game dengan tombol tekan Kuning, Merah, Biru dan Hijau
Simon Game dengan tombol tekan Kuning, Merah, Biru dan Hijau (Pratinjau besar)

Dalam hal perilaku, tombol harus memiliki dua status: ditekan dan dilepaskan. Ini mirip dengan peristiwa HTML mousedown/mouseup, tetapi kita harus memastikan bahwa tombol juga dapat digunakan dari perangkat seluler, dan dapat diakses oleh pengguna tanpa mouse.

Karena kita akan menggunakan status tombol tekan sebagai input untuk Arduino, tidak perlu mendukung acara "klik" atau "klik dua kali". Terserah program Arduino yang berjalan dalam simulasi untuk memutuskan bagaimana bertindak atas keadaan tombol, dan tombol fisik tidak menghasilkan peristiwa klik.

Jika Anda ingin mempelajari lebih lanjut, lihat ceramah saya dengan Benjamin Gruenbaum di SmashingConf Freiburg pada tahun 2019: “Anatomy of a Click”.

Untuk meringkas persyaratan kami, tombol tekan kami perlu:

  1. terlihat mirip dengan tombol fisik 12mm;
  2. memiliki dua status berbeda: ditekan, dan dilepaskan, dan keduanya harus terlihat secara visual;
  3. mendukung interaksi mouse, perangkat seluler, dan dapat diakses oleh pengguna keyboard;
  4. mendukung warna topi yang berbeda (setidaknya merah, hijau, biru, kuning, putih dan hitam).

Sekarang kita telah mendefinisikan persyaratan, kita dapat mulai mengerjakan implementasinya.

SVG Untuk Kemenangan

Sebagian besar komponen web diimplementasikan menggunakan kombinasi CSS dan HTML. Ketika kita membutuhkan grafik yang lebih kompleks, kita biasanya menggunakan gambar raster, baik dalam format JPG atau PNG (atau GIF jika Anda merasa nostalgia).

Namun, dalam kasus kami, kami akan menggunakan pendekatan lain: grafik SVG. SVG cocok untuk grafik yang kompleks jauh lebih mudah daripada CSS (ya, saya tahu, Anda dapat membuat hal-hal menarik dengan CSS, tetapi itu tidak berarti harus). Tapi jangan khawatir, kami tidak menyerah sepenuhnya pada CSS. Ini akan membantu kita menata tombol tekan, dan akhirnya bahkan membuatnya dapat diakses.

SVG memiliki keuntungan besar lainnya, dibandingkan dengan gambar grafik raster: sangat mudah untuk dimanipulasi dari JavaScript dan dapat ditata melalui CSS. Ini berarti bahwa kami dapat menyediakan satu gambar untuk tombol dan menggunakan JavaScript untuk menyesuaikan batas warna, dan gaya CSS untuk menunjukkan status tombol. Rapi, bukan?

Terakhir, SVG hanyalah sebuah dokumen XML, yang dapat diedit dengan editor teks, dan disematkan langsung ke HTML, menjadikannya solusi sempurna untuk membuat komponen HTML yang dapat digunakan kembali. Apakah Anda siap untuk menggambar tombol kami?

Menggambar Tombol Tekan Dengan Inkscape

Inkscape adalah alat favorit saya untuk membuat grafik vektor SVG. Ini gratis dan dikemas dengan fitur-fitur canggih, seperti koleksi besar preset filter bawaan, pelacakan bitmap, dan operasi biner jalur. Saya mulai menggunakan Inkscape untuk membuat seni PCB, tetapi dalam dua tahun terakhir, saya mulai menggunakannya untuk sebagian besar tugas pengeditan grafis saya.

Menggambar tombol tekan di Inkscape cukup mudah. Kita akan menggambar ilustrasi tampilan atas dari tombol dan keempat ujung logamnya yang menghubungkannya ke bagian lain, sebagai berikut:

  1. Persegi panjang abu-abu gelap 12x12mm untuk wadah plastik, dengan sudut sedikit membulat untuk membuatnya lebih lembut.
  2. Lebih kecil, 10,5 × 10,5 persegi panjang abu-abu muda untuk penutup logam.
  3. Empat lingkaran yang lebih gelap, satu di setiap sudut untuk pin yang menahan tombol bersama-sama.
  4. Lingkaran besar di tengah, itulah kontur tutup kancing.
  5. Lingkaran yang lebih kecil di tengah untuk bagian atas tutup kancing.
  6. Empat persegi panjang abu-abu muda dalam bentuk "T" untuk ujung logam tombol.

Dan hasilnya, sedikit diperbesar:

Sketsa Tombol Tekan kami yang digambar tangan
Sketsa Tombol Tekan kami yang digambar tangan (Pratinjau besar)

Sebagai sentuhan terakhir, kami akan menambahkan beberapa keajaiban gradien SVG ke kontur tombol, untuk memberikan nuansa 3D:

Menambahkan isian gradien untuk membuat nuansa 3D
Menambahkan isian gradien untuk membuat nuansa 3D (Pratinjau besar)

Ini dia! Kami memiliki visualnya, sekarang kami perlu membawanya ke web.

Dari Inkscape ke Web SVG

Seperti yang saya sebutkan di atas, SVG cukup mudah untuk disematkan ke HTML — Anda cukup menempelkan konten file SVG ke dalam dokumen HTML Anda, membukanya di browser, dan itu akan ditampilkan di layar Anda. Anda dapat melihatnya beraksi dalam contoh CodePen berikut:

Lihat Tombol Tekan Pena SVG dalam HTML oleh @Uri Shaked

Lihat Tombol Tekan Pena SVG dalam HTML oleh @Uri Shaked

Namun, file SVG yang disimpan dari Inkscape mengandung banyak bagasi yang tidak perlu seperti versi Inkscape dan posisi jendela saat Anda terakhir menyimpan file tersebut. Dalam banyak kasus, ada juga elemen kosong, gradien dan filter yang tidak digunakan, dan semuanya membuat ukuran file membengkak, dan membuatnya lebih sulit untuk bekerja dengannya di dalam HTML.

Untungnya, Inkscape dapat membersihkan sebagian besar kekacauan untuk kita. Inilah cara Anda melakukannya:

  1. Buka menu File dan klik Clean up document . (Ini akan menghapus definisi yang tidak digunakan dari dokumen Anda.)
  2. Buka lagi ke File dan klik Simpan sebagai… . Saat menyimpan, pilih Optimized SVG ( *.svg ) di dropdown Save as type .
  3. Anda akan melihat dialog "Output SVG yang Dioptimalkan" dengan tiga tab. Centang semua opsi, kecuali "Simpan data editor", "Simpan definisi yang tidak direferensikan" dan "Simpan ID yang dibuat secara manual ...".
(Pratinjau besar)

Menghapus semua hal ini akan membuat file SVG lebih kecil yang lebih mudah digunakan. Dalam kasus saya, file berubah dari 4593 byte menjadi hanya 2080 byte, kurang dari setengah ukuran. Untuk file SVG yang lebih kompleks, ini bisa sangat menghemat bandwidth dan dapat membuat perbedaan mencolok dalam waktu pemuatan halaman web Anda.

SVG yang dioptimalkan juga lebih mudah dibaca dan dipahami. Dalam kutipan berikut, Anda seharusnya dapat dengan mudah melihat dua persegi panjang yang membentuk badan tombol tekan:

 <rect width="12" height="12" rx=".44" ry=".44" fill="#464646" stroke-width="1.0003"/> <rect x=".75" y=".75" width="10.5" height="10.5" rx=".211" ry=".211" fill="#eaeaea"/> <g fill="#1b1b1b"> <circle cx="1.767" cy="1.7916" r=".37"/> <circle cx="10.161" cy="1.7916" r=".37"/> <circle cx="10.161" cy="10.197" r=".37"/> <circle cx="1.767" cy="10.197" r=".37"/> </g> <circle cx="6" cy="6" r="3.822" fill="url(#a)"/> <circle cx="6" cy="6" r="2.9" fill="#ff2a2a" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08"/>

Anda bahkan dapat mempersingkat kode lebih jauh, misalnya, dengan mengubah lebar goresan persegi panjang pertama dari 1.0003 menjadi hanya 1 . Itu tidak membuat perbedaan yang signifikan dalam ukuran file, tetapi membuat kode lebih mudah dibaca.

Secara umum, pass manual atas file SVG yang dihasilkan selalu berguna. Dalam banyak kasus, Anda dapat menghapus grup kosong atau menerapkan transformasi matriks, serta menyederhanakan koordinat gradien dengan memetakannya dari "ruang pengguna yang digunakan" (koordinat global) ke "kotak pembatas objek" (relatif terhadap objek). Pengoptimalan ini bersifat opsional, tetapi Anda mendapatkan kode yang lebih mudah dipahami dan dipelihara.

Mulai saat ini, kita akan menyingkirkan Inkscape dan bekerja dengan representasi teks dari gambar SVG.

Membuat Komponen Web yang Dapat Digunakan Kembali

Sejauh ini, kami mendapatkan grafik untuk tombol tekan kami, siap untuk dimasukkan ke dalam simulator kami. Kita dapat dengan mudah menyesuaikan warna tombol dengan mengubah atribut fill dari lingkaran yang lebih kecil, dan warna awal dari gradien lingkaran yang lebih besar.

Tujuan kami selanjutnya adalah mengubah tombol tekan kami menjadi Komponen Web yang dapat digunakan kembali yang dapat dikustomisasi dengan melewatkan atribut color dan bereaksi terhadap interaksi pengguna (peristiwa tekan/rilis). Kami akan menggunakan lit-element , perpustakaan kecil yang menyederhanakan pembuatan Komponen Web.

lit-element unggul dalam membuat pustaka komponen kecil yang berdiri sendiri. Itu dibangun di atas standar Komponen Web, yang memungkinkan komponen ini dikonsumsi oleh aplikasi web apa pun, terlepas dari kerangka kerja yang digunakan: Angular, React, Vue atau Vanilla JS semuanya dapat menggunakan komponen kami.

Membuat komponen dalam lit-element dilakukan menggunakan sintaks berbasis kelas, dengan metode render() yang mengembalikan kode HTML untuk elemen tersebut. Sedikit mirip dengan React, jika Anda sudah familiar dengannya. Namun, tidak seperti react, lit-element menggunakan literal templat bertanda Javascript standar untuk mendefinisikan konten komponen.

Inilah cara Anda membuat komponen hello-world sederhana:

 import { customElement, html, LitElement } from 'lit-element'; @customElement('hello-world') export class HelloWorldElement extends LitElement { render() { return html` <h1> Hello, World! </h1> `; } }

Komponen ini kemudian dapat digunakan di mana saja dalam kode HTML Anda hanya dengan menulis <hello-world></hello-world> .

Catatan : Sebenarnya, tombol tekan kita hanya memerlukan sedikit kode lagi: kita perlu mendeklarasikan properti input untuk warna, menggunakan dekorator @property() (dan dengan nilai default merah), dan menempelkan kode SVG ke dalam render() , mengganti warna tutup tombol dengan nilai properti warna (lihat contoh). Bit penting berada di baris 5, di mana kita mendefinisikan properti warna: @property() color = 'red'; Juga, pada baris 35 (di mana kita menggunakan properti ini untuk menentukan warna isian untuk lingkaran yang membuat tutup tombol), menggunakan sintaks literal template JavaScript, ditulis sebagai ${color} :

 <circle cx="6" cy="6" r="2.9" fill="${color}" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08" />

Menjadikannya Interaktif

Bagian terakhir dari teka-teki adalah membuat tombol menjadi interaktif. Ada dua aspek yang perlu kita pertimbangkan: respons visual terhadap interaksi serta respons terprogram terhadap interaksi.

Untuk bagian visual, kita dapat dengan mudah membalikkan isian gradien dari kontur tombol, yang akan menciptakan ilusi tombol telah ditekan:

Membalikkan gradien kontur tombol
Membalikkan gradien kontur tombol (Pratinjau besar)

Gradien untuk kontur tombol ditentukan oleh kode SVG berikut, di mana ${color} diganti dengan warna tombol oleh lit-element , seperti dijelaskan di atas:

 <linearGradient x1="0" x2="1" y1="0" y2="1"> <stop stop-color="#ffffff" offset="0" /> <stop stop-color="${color}" offset="0.3" /> <stop stop-color="${color}" offset="0.5" /> <stop offset="1" /> </linearGradient>

Salah satu pendekatan untuk tampilan tombol yang ditekan adalah dengan menentukan gradien kedua, membalikkan urutan warna, dan menggunakannya sebagai isi lingkaran setiap kali tombol ditekan. Namun, ada trik bagus yang memungkinkan kita untuk menggunakan kembali gradien yang sama: kita dapat memutar elemen svg sebesar 180 derajat menggunakan transformasi SVG:

 <circle cx="6" cy="6" r="3.822" fill="url(#a)" transform="rotate(180 6 6)" />

Atribut transform memberi tahu SVG bahwa kita ingin memutar lingkaran sebesar 180 derajat, dan bahwa rotasi harus terjadi di sekitar titik (6, 6) yang merupakan pusat lingkaran (didefinisikan oleh cx dan cy ). Transformasi SVG juga memengaruhi isian bentuk, sehingga gradien kita juga akan diputar.

Kami hanya ingin membalikkan gradien saat tombol ditekan, jadi alih-alih menambahkan atribut transform langsung pada elemen <circle> , seperti yang kami lakukan di atas, kami sebenarnya akan menetapkan kelas CSS untuk elemen ini, dan kemudian memanfaatkannya fakta bahwa atribut SVG dapat diatur melalui CSS, meskipun menggunakan sintaks yang sedikit berbeda:

 transform: rotate(180deg); transform-origin: 6px 6px;

Kedua aturan CSS ini melakukan hal yang sama persis seperti transform yang kita lakukan di atas — putar lingkaran 180 derajat di sekitar pusatnya di (6, 6). Kami ingin aturan ini diterapkan hanya saat tombol ditekan, jadi kami akan menambahkan nama kelas CSS ke lingkaran kami:

 <circle class="button-contour" cx="6" cy="6" r="3.822" fill="url(#a)" />

Dan sekarang kita dapat menggunakan pseudo-class :active CSS untuk menerapkan transformasi ke button-contour setiap kali elemen SVG diklik:

 svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; }

lit-element memungkinkan kita untuk melampirkan stylesheet ke komponen kita dengan mendeklarasikannya dalam pengambil statis di dalam kelas komponen kita, menggunakan literal template yang diberi tag:

 static get styles() { return css` svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; } `; }

Sama seperti template HTML, sintaks ini memungkinkan kita untuk memasukkan nilai kustom ke kode CSS kita, meskipun kita tidak membutuhkannya di sini. lit-element juga menangani pembuatan Shadow DOM untuk komponen kita, sehingga CSS hanya memengaruhi elemen di dalam komponen kita dan tidak mengalir ke bagian lain dari aplikasi.

Sekarang, bagaimana dengan perilaku terprogram tombol saat ditekan? Kami ingin menjalankan suatu peristiwa sehingga pengguna komponen kami dapat mengetahui kapan pun status tombol berubah. Salah satu cara untuk melakukannya adalah dengan mendengarkan event mousedown dan mouseup pada elemen SVG, dan menjalankan event “button-press”/“button-release” secara bersamaan. Beginilah tampilannya dengan sintaks lit-element :

 render() { const { color } = this; return html` <svg @mousedown=${() => this.dispatchEvent(new Event('button-press'))} @mouseup=${() => this.dispatchEvent(new Event('button-release'))} ... </svg> `; }

Namun, ini bukan solusi terbaik, seperti yang akan segera kita lihat. Tapi pertama-tama, lihat sekilas kode yang kami dapatkan sejauh ini:

 import { customElement, css, html, LitElement, property } from 'lit-element'; @customElement('wokwi-pushbutton') export class PushbuttonElement extends LitElement { @property() color = 'red'; static get styles() { return css` svg:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; } `; } render() { const { color } = this; return html` <svg @mousedown=${() => this.dispatchEvent(new Event('button-press'))} @mouseup=${() => this.dispatchEvent(new Event('button-release'))} width="18mm" height="12mm" version="1.1" viewBox="-3 0 18 12" xmlns="https://www.w3.org/2000/svg" > <defs> <linearGradient x1="0" x2="1" y1="0" y2="1"> <stop stop-color="#ffffff" offset="0" /> <stop stop-color="${color}" offset="0.3" /> <stop stop-color="${color}" offset="0.5" /> <stop offset="1" /> </linearGradient> </defs> <rect x="0" y="0" width="12" height="12" rx=".44" ry=".44" fill="#464646" /> <rect x=".75" y=".75" width="10.5" height="10.5" rx=".211" ry=".211" fill="#eaeaea" /> <g fill="#1b1b1"> <circle cx="1.767" cy="1.7916" r=".37" /> <circle cx="10.161" cy="1.7916" r=".37" /> <circle cx="10.161" cy="10.197" r=".37" /> <circle cx="1.767" cy="10.197" r=".37" /> </g> <g fill="#eaeaea"> <path d="m-0.3538 1.4672c-0.058299 0-0.10523 0.0469-0.10523 0.10522v0.38698h-2.1504c-0.1166 0-0.21045 0.0938-0.21045 0.21045v0.50721c0 0.1166 0.093855 0.21045 0.21045 0.21045h2.1504v0.40101c0 0.0583 0.046928 0.10528 0.10523 0.10528h0.35723v-1.9266z" /> <path d="m-0.35376 8.6067c-0.058299 0-0.10523 0.0469-0.10523 0.10523v0.38697h-2.1504c-0.1166 0-0.21045 0.0939-0.21045 0.21045v0.50721c0 0.1166 0.093855 0.21046 0.21045 0.21046h2.1504v0.401c0 0.0583 0.046928 0.10528 0.10523 0.10528h0.35723v-1.9266z" /> <path d="m12.354 1.4672c0.0583 0 0.10522 0.0469 0.10523 0.10522v0.38698h2.1504c0.1166 0 0.21045 0.0938 0.21045 0.21045v0.50721c0 0.1166-0.09385 0.21045-0.21045 0.21045h-2.1504v0.40101c0 0.0583-0.04693 0.10528-0.10523 0.10528h-0.35723v-1.9266z" /> <path d="m12.354 8.6067c0.0583 0 0.10523 0.0469 0.10523 0.10522v0.38698h2.1504c0.1166 0 0.21045 0.0938 0.21045 0.21045v0.50721c0 0.1166-0.09386 0.21045-0.21045 0.21045h-2.1504v0.40101c0 0.0583-0.04693 0.10528-0.10523 0.10528h-0.35723v-1.9266z" /> </g> <g> <circle class="button-contour" cx="6" cy="6" r="3.822" fill="url(#a)" /> <circle cx="6" cy="6" r="2.9" fill="${color}" stroke="#2f2f2f" stroke-opacity=".47" stroke-width=".08" /> </g> </svg> `; } }
  • Lihat demo →

Anda dapat mengklik setiap tombol dan melihat bagaimana mereka bereaksi. Yang merah bahkan memiliki beberapa pendengar acara (didefinisikan dalam index.html ), jadi ketika Anda mengkliknya, Anda akan melihat beberapa pesan yang ditulis ke konsol. Tapi tunggu dulu, bagaimana jika Anda ingin menggunakan keyboard saja?

Membuat Komponen Dapat Diakses Dan Ramah Seluler

Hore! Kami membuat komponen tombol tekan yang dapat digunakan kembali dengan SVG dan lit-element !

Sebelum kita menandatangani pekerjaan kita, ada beberapa masalah yang harus kita perhatikan. Pertama, tombol tidak dapat diakses oleh orang yang menggunakan keyboard. Selain itu, perilaku di ponsel tidak konsisten — tombol-tombol itu tampak ditekan saat Anda menahan jari Anda di atasnya, tetapi peristiwa JavaScript tidak diaktifkan jika Anda menahan jari Anda selama lebih dari satu detik.

Mari kita mulai dengan mengatasi masalah keyboard. Kita dapat membuat tombol dapat diakses dengan keyboard dengan menambahkan atribut tabindex ke elemen svg, membuatnya dapat difokuskan. Alternatif yang lebih baik, menurut saya, adalah dengan membungkus tombol dengan elemen <button> standar. Dengan menggunakan elemen standar, kami juga membuatnya bermain dengan baik dengan pembaca layar dan teknologi bantu lainnya.

Pendekatan ini memiliki satu kelemahan, seperti yang Anda lihat di bawah:

Komponen cantik kami terbungkus di dalam elemen tombol
Komponen cantik kami terbungkus di dalam elemen <button> . (Pratinjau besar)

Elemen <button> hadir dengan beberapa gaya bawaan. Ini dapat dengan mudah diperbaiki dengan menerapkan beberapa CSS untuk menghapus gaya ini:

 button { border: none; background: none; padding: 0; margin: 0; text-decoration: none; -webkit-appearance: none; -moz-appearance: none; } button:active .button-contour { transform: rotate(180deg); transform-origin: 6px 6px; }

Perhatikan bahwa kami juga mengganti selektor yang membalikkan kisi kontur tombol, menggunakan button:active menggantikan svg:active . Ini memastikan bahwa gaya penekanan tombol berlaku setiap kali elemen <button> sebenarnya ditekan, terlepas dari perangkat input yang digunakan.

Kami bahkan dapat membuat komponen kami lebih ramah pembaca layar dengan menambahkan atribut aria-label yang menyertakan warna tombol:

 <button aria-label="${color} pushbutton">

Masih ada satu hal lagi yang harus ditangani: acara "tekan tombol" dan "pelepasan tombol". Idealnya, kita ingin mengaktifkannya berdasarkan CSS :active pseudo-class dari tombol, seperti yang kita lakukan pada CSS di atas. Dengan kata lain, kita ingin mengaktifkan event "button-press" setiap kali tombol menjadi :active , dan event "button-release" akan diaktifkan kapan pun :not(:active) .

Tetapi bagaimana Anda mendengarkan kelas semu CSS dari Javascript?

Ternyata, tidak sesederhana itu. Saya mengajukan pertanyaan ini kepada komunitas JavaScript Israel, dan akhirnya menggali satu ide yang berhasil dari utas tanpa akhir: gunakan pemilih :active untuk memicu animasi CSS super-pendek, dan kemudian saya dapat mendengarkannya dari JavaScript menggunakan animationstart peristiwa.

Eksperimen CodePen cepat membuktikan bahwa ini benar-benar bekerja dengan andal. Meskipun saya menyukai kecanggihan ide ini, saya memutuskan untuk menggunakan solusi berbeda yang lebih sederhana. Acara animationstart tidak tersedia di Edge dan iOS Safari, dan memicu animasi CSS hanya untuk mendeteksi perubahan status tombol tidak terdengar seperti cara yang tepat untuk melakukan sesuatu.

Sebagai gantinya, kita akan menambahkan tiga pasang event listener ke elemen <button> : mousedown/mouseup untuk mouse, touchstart/touchend untuk perangkat seluler, dan keyup/keydown untuk keyboard. Bukan solusi yang paling elegan, menurut saya, tetapi ini berhasil dan berfungsi di semua browser.

 <button aria-label="${color} pushbutton" @mousedown=${this.down} @mouseup=${this.up} @touchstart=${this.down} @touchend=${this.up} @keydown=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.down()} @keyup=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.up()} >

Di mana SPACE_KEY adalah konstanta yang sama dengan 32, dan up / down adalah dua metode kelas yang mengirimkan peristiwa penekanan button-press dan button-release :

 @property() pressed = false; private down() { if (!this.pressed) { this.pressed = true; this.dispatchEvent(new Event('button-press')); } } private up() { if (this.pressed) { this.pressed = false; this.dispatchEvent(new Event('button-release')); } }
  • Anda dapat menemukan kode sumber lengkap di sini.

Kita berhasil!

Itu adalah perjalanan yang cukup panjang yang dimulai dengan menguraikan persyaratan dan menggambar ilustrasi untuk tombol di Inkscape, melalui konversi file SVG kami menjadi komponen web yang dapat digunakan kembali menggunakan lit-element , dan setelah memastikan itu dapat diakses dan mobile-friendly, kami berakhir dengan hampir 100 baris kode komponen tombol tekan virtual yang menyenangkan.

Tombol ini hanyalah satu komponen dalam pustaka sumber terbuka dari komponen elektronik virtual yang saya buat. Anda diundang untuk mengintip kode sumber, atau memeriksa Buku Cerita online di mana Anda dapat melihat dan berinteraksi dengan semua komponen yang tersedia.

Dan akhirnya, jika Anda tertarik dengan Arduino, lihat kursus pemrograman Simon for Arduino yang sedang saya buat, di mana Anda juga dapat melihat tombol yang sedang bekerja.

Sampai waktu berikutnya, kalau begitu!