Hai, nama saya Artyom, saya adalah kepala salah satu grup pengembangan antarmuka di Yandex. Seminggu yang lalu di Ya, Subbotnik saya memberi tahu bagaimana kami menggunakan SVG untuk membuat kalender internal. Ini adalah transkrip laporan saya, beberapa cerita dari penerapan widget kalender: penskalaan, pengisian pola, topeng, simbol, dan fitur format.

- Ada banyak orang yang bekerja di Yandex, semuanya di kota yang berbeda, di zona waktu yang berbeda, dan Anda perlu memahami kapan rekan kerja Anda sibuk, dan kapan Anda bisa bertemu dan berbicara dengan mereka. Kami memutuskan untuk merancang kalender yang akan membantu mengetahuinya.
Kami mulai, tentu saja, dengan tata letak. Dia terlihat seperti ini:

Ini menunjukkan even dan even aneh dengan isian berbeda. Acara yang tumpang tindih dengan acara lain, yaitu, berada di lapisan kedua - isian lainnya. Acara yang menghabiskan cat sepanjang hari sepanjang hari. Waktu saat ini ditampilkan di bawah. Itulah tujuannya.

Kami mulai memilih apa yang akan kami lakukan. Membuat beberapa prototipe berbeda. Kami mulai dengan kanvas, tetapi ada banyak kode, scaling secara manual untuk menulis. Kami memiliki gagasan bahwa kalender memakan ruang sebanyak yang diperlukan, dalam tata letak yang berbeda, bentuk dan ukurannya berbeda. Dan untuk kanvas itu rumit.
Ada prototipe keren ketika kami membuat seluruh gambar ini dengan gradien linier, tapi itu pindah ketika penskalaan dan ketika beralih ke retina. Karena itu, pada akhirnya, kami datang ke SVG. Mengapa Pertama, ada sistem koordinat yang sepenuhnya independen dari dokumen, sehingga Anda dapat sepenuhnya memposisikan semua yang ada di dalamnya, dan ini tidak akan merusak apa pun. Juga ada pekerjaan normal dengan penskalaan. Bahkan jika Anda memperbesar peramban, jika Anda membuka retina atau meregangkan kalender entah bagaimana, itu akan mengubah ukuran seperti gambar dan dalam hal apapun terlihat normal. Kami memiliki sel isi pada tata letak, dan sangat bagus bahwa SVG memiliki pola isian.

Untuk menggambar kalender, Anda memerlukan beberapa data. Untuk menggambar satu di tata letak, Anda perlu tahu tanggal mulai apa - biasanya tanggal saat ini - untuk mengetahui berapa hari harus horisontal, berapa jam harus ditampilkan secara vertikal dan berapa jam hari di kalender dimulai. Kita perlu entah bagaimana mendapatkan acara.
Karena kami memiliki banyak kantor di zona waktu yang berbeda, kami memutuskan bahwa acara akan selalu datang di UTC, dan kami sudah akan menampilkannya di klien untuk pengguna, karena ada kebutuhan untuk melihat kalender untuk zona waktu kami dan untuk zona waktu orang tersebut, kalender siapa yang Anda lihat - untuk memahami bahwa sekarang sudah malam, dan lebih baik tidak membuat janji. Apa yang disorot dengan warna merah akan digunakan nanti.

Mari kita mulai dengan dasar-dasarnya. SVG adalah bidang koordinat raksasa tempat grafik vektor dapat ditempatkan secara sewenang-wenang. Pada saat yang sama, bagian dari area yang kita lihat ditentukan oleh viewBox, dan apa yang ada di balik perbatasannya adalah luapan yang tersembunyi pada steroid. Apa pun itu, itu tidak akan terlihat. Kami memutuskan bahwa untuk kesederhanaan perhitungan, kami akan membuat satu piksel dalam kalender sama dengan satu menit. Karena itu, satu jam akan menempati tepat 60 piksel. Untuk membuatnya lebih sederhana, kami memutuskan bahwa hari dengan lebar juga akan menjadi 60 piksel - sehingga semuanya persegi, seperti di tentara. Dan mereka mulai mengeset.
Viewbox diatur oleh empat parameter. Dua yang pertama adalah titik kiri atas dalam sistem koordinat, dari mana viewBox dipertimbangkan, bagi kami itu adalah 0,0. Lebar 60 * untuk jumlah hari, dan tingginya 60 * untuk jumlah jam.
Adalah sah untuk memasukkan dokumen SVG lain ke dalam SVG, yang akan memiliki sistem koordinat sendiri di dalamnya. Dan agar acara dalam sehari hanya dapat diposisikan di sepanjang sumbu vertikal, kami memutuskan bahwa untuk setiap hari kami akan memiliki SVG terpisah, dan kami hanya menggesernya secara horizontal sebesar 60 * ke posisi hari di kalender. Maka semua acara dapat diatur secara vertikal di Y, itu akan sangat nyaman. Dan di dalam setiap SVG, yang merupakan hari, kami menempatkan kotak yang akan menampilkan isi hari itu.
Kotak ini, karena tidak ada warna isian yang ditentukan, akan mewarisi properti isian dari SVG. Dalam hal ini, hari ini bekerja, dan dua hari libur seminggu, sehingga mereka dibanjiri cahaya. Ini hanya ditentukan oleh kelas.

Ada yang kosong. Sekarang Anda perlu menambahkan kisi. Karena kami ingin mengubah ukuran kalender, dan garis grid harus selalu satu-pixel, kami menggunakan atribut vektor-efek = non-scaling-stroke. Ini mengarah pada fakta bahwa tidak peduli bagaimana kami mengubah ukuran atau memperbesar, akan selalu ada kotak piksel tunggal. Cukup dengan menambahkan jumlah garis horizontal dan vertikal yang tepat, dan akan ada kotak seperti itu.

Kami telah menemukan dasarnya, mari beralih ke acara sepanjang hari. Ini hal yang sulit. Anda perhatikan ada acara di kalender dan ada tanda centang "sepanjang hari". Peristiwa ini berbeda karena mereka berlangsung sepanjang hari, tidak peduli apa zona waktu yang Anda lihat. Oleh karena itu, jika suatu tempat di awal zona waktu di Alaska acara dimulai pagi-pagi, maka di suatu tempat dalam 48 jam di ujung dunia yang berbeda masih akan berlangsung. Kedengarannya rumit, tetapi paling mudah diterapkan: bandingkan saja tanggal dengan tanggal hari yang ditampilkan. Jika itu mengenai, itu berarti suatu peristiwa pada hari itu. Jika dua peristiwa sepanjang hari jatuh pada hari itu, maka yang akan dimulai ditampilkan. Jadi isi acara acara sepanjang hari.

Dengan acara lain, ini sedikit lebih sulit. Katakanlah ada pertemuan. Warnanya biru, semuanya sederhana. Namun, jika dua pertemuan diadakan berturut-turut, sesuai dengan tata letak kami, kami mengisinya dengan warna yang berbeda, mereka genap dan aneh.
Jika satu pertemuan bersinggungan dengan yang lain, terletak lebih tinggi, Anda perlu menampilkannya. Jika ada persimpangan dengan rapat, maka mereka dituangkan sepenuhnya secara terpisah, dalam sel. Dan untuk membuat kami lebih menyenangkan, kami tidak hanya memiliki pertemuan, tetapi juga absen, konferensi, dan banyak hal lainnya. Saya tidak ingin meng-hardcode semua ini dalam tata letak, jadi kami memutuskan untuk mencari tahu bagaimana ini lebih atau kurang lintas-browser dan nyaman untuk dikonfigurasikan dalam CSS.

Sekarang akan ada contoh yang paling sulit dari seluruh laporan, bersabar dan perhatikan, akan ada tiga langkah, maka itu akan menjadi lebih mudah.
Mari kita mulai. SVG memiliki tag <defs>, ini memungkinkan Anda untuk mendeklarasikan elemen di dalamnya yang tidak ditampilkan, tetapi Anda dapat menggunakannya dengan referensi, merujuk padanya. Hal pertama yang akan kita lakukan adalah mendeklarasikan <defs> dan membuat pola di dalamnya. <pola> adalah tag yang memungkinkan Anda mendeklarasikan pola yang dapat Anda gunakan untuk mengisi elemen tertentu dengan pola tertentu.
Kita perlu membuat sel dalam pola ini. Kami memiliki 60 x 60 piksel, sel harus 6 x 6, jadi kami mendeklarasikan pola 12 x 12 dan menggambar <path> di dalamnya, seperti pada diagram di sebelah kiri. Ini memiliki atribut d, yang menunjukkan dengan tepat bagaimana garis bergerak. Dimulai dari titik 0,0, dan kemudian koordinat menunjukkan panah bagaimana itu digambar. Jika kita mengisinya dengan putih, kita mendapatkan pola berikut: apa yang tidak dibanjiri dengan putih, dibanjiri dengan hitam.

Pergi ke langkah berikutnya, sekarang mendeklarasikan topeng. <mask> adalah elemen dalam SVG yang memungkinkan Anda untuk menambahkan saluran alfa ke elemen lain. Apa yang digambar dalam topeng hitam, dalam elemen yang digunakan topeng, tidak terlihat, transparan. Apa yang dicat putih adalah buram. Apa yang abu-abu itu tembus. Kami memiliki pola hitam dan putih, dan kami akan menambahkan persegi panjang di dalam topeng, dan mengisinya dengan pola ini. Sekarang kita punya topeng.
Langkah selanjutnya adalah <simbol>. Ini adalah tag di SVG, yang memungkinkan Anda untuk mendeklarasikan gambar yang dapat digunakan kembali. Paling sering, simbol digunakan, misalnya, untuk ikon. Dan di sini kita mendeklarasikan simbol, di dalamnya kita meletakkan dua persegi panjang. Satu tidak mengisi dengan apa pun sehingga mewarisi properti isian dari induk SVG, dan yang lainnya akan mengisi dengan currentColor dan menerapkan masker padanya. Sekarang kita akan memiliki dua persegi panjang: satu dengan lubang dan diisi dengan currentColor, dan yang lainnya tanpa lubang dan diisi dengan mengisi. Dan mereka berbaring di atas satu sama lain. Jika kita mengatur warna-warna ini sama, kita akan memiliki warna solid. Dan jika berbeda - sel. Ini semua berlalu. Sekarang Anda bisa menggunakan CSS dan melalui kelas mengatur dua warna sewenang-wenang untuk semua acara.

Sekarang Anda perlu menentukan dengan tepat acara apa yang harus dimasukkan dalam kalender pada hari tertentu. Kami memiliki zona waktu +3, di mana kita semua duduk, ia memiliki skala dari 9 hingga 20 jam. Ada juga orang yang duduk di Orenburg bersyarat, ia memiliki zona waktu +5, skalanya diimbangi oleh dua jam relatif terhadap kami. Kami akan membuat proyeksi pada UTC, dan melihat bahwa pada UTC interval ini dari atas ke bawah perlu ditampilkan di bagian bawah sehingga pengguna dapat, beralih di antara zona waktu, melihat kedua peristiwa yang termasuk dalam kalendernya dan kalender orang yang dia lihat. .
Ingat angka-angka ini, yang diimbangi, karena paling mudah untuk menempatkan peristiwa yang tiba di UTC dalam UTC yang sama. Untuk melakukan ini, kami mengambil tag <g>, yang menunjukkan grup dalam SVG, dan kami menempatkan semua peristiwa di sana secara absolut oleh UTC, dan kami akan menggeser <g> dengan jumlah piksel yang kami perlukan untuk menampilkan satu atau satu zona waktu lainnya.

Kesimpulan dari penelitian ini, kami mendapatkan bahwa kami memiliki simbol yang kami rujuk, ada jenis acara, level, paritas, ada -120 menit dari awal hari di UTC dan durasi 30 menit. Dengan menambahkan semua acara, kami mendapatkan gambar seperti itu.

Waktu saat ini juga dilakukan secara sederhana, itu akan menjadi garis dengan efek non-scaling-stroke yang sama, sehingga selalu tunggal-pixel. Beginilah caranya ditampilkan.
Waktu tidak berhenti, dan panah harus bergerak. Cara paling keren yang kami buat adalah animasi. Kami memutuskan bahwa kami akan membuat animasi yang akan menggeser panah dengan jumlah menit dalam sehari, dan melakukannya dalam sehari. Dan agar itu tidak terus-menerus bergerak lambat, yaitu, berdetak satu menit sekali, kami menggunakan langkah-langkah (). Dan segera setelah kami menambahkannya, waktu mulai bergerak. Pada saat yang sama, pada kenyataannya, karena animasi tidak menjamin bahwa ia akan terus bergerak, ia tertinggal, atau sesuatu yang lain. Tetapi kami memiliki acara di kalender yang diperbarui dari waktu ke waktu, dan di suatu tempat setiap dua hingga tiga menit atau ketika pengguna meninggalkan tab dan kembali, seluruh kalender digambar ulang dan waktu diperbarui. Oleh karena itu, animasi hanya terlihat ketika Anda duduk dan menonton dengan penuh perhatian apakah itu berdetak atau tidak.

Ada satu masalah. Di sini saya membuat kalender lebih luas sehingga lebih mirip dengan yang di produksi. Menjadi jelas bahwa sel-sel tidak lagi persegi. Ini karena proporsi tidak dipertahankan, dan jika kita meregangkan atau mengubah aspek rasio secara fisik, maka itu berubah seperti pada gambar. Untuk menghindari ini, Anda perlu menulis sedikit JS. Ada viewBox rasio aspek, yang ada di SVG asli kami, dan rasio aspek aktual, yang digunakan dalam tata letak kami. Jika Anda menemukan rasio rasio-rasio ini dan kemudian memasukkannya ke dalam transformasi pola, maka sel-sel akan menjadi persegi. Dan juga koefisien ini, yang kami dapatkan di sini, dapat digunakan jika kita ingin memahami di mana pengguna mengklik. Karena kita memiliki satu menit dalam SVG asli sama dengan satu piksel, dengan koordinat klik dikalikan dengan koefisien ini, kita dapat memahami pada jam berapa pengguna mendapat.

Tetap menambahkan HTML sehingga ada huruf dan angka di atasnya. Dapatkan kalender.


Jadi hal ini terlihat dalam produksi melalui mata pengguna yang duduk di zona waktu +5. Di bawah ini adalah sakelar sakelar yang ditekan rekan saya, dan kalender bergerak dalam zona waktu. Kemudian dia mengklik acara tersebut dan melihat bahwa pada hari Sabtu di zona waktu +5, yaitu, saat ini, laporan saya aktif.

Beberapa contoh lagi. Ini adalah kalender pengembang, ia memiliki stand-up, beberapa pertemuan rutin dan hanya itu. Ini adalah kalender manajer. Dan inilah desainernya.
Gunakan CSS, gunakan SVG. Terima kasih