Pengembangan diagram pohon dinamis menggunakan SVG dan Vue.js

Bahan, terjemahan yang kami terbitkan hari ini, dikhususkan untuk proses pengembangan sistem visualisasi untuk diagram pohon yang dinamis. Untuk menggambar kurva Bezier kubik, teknologi SVG (Scalable Vector Graphics, scalable vector graphics) digunakan di sini. Pekerjaan reaktif dengan data diatur oleh Vue.js.

Ini adalah versi demo dari sistem yang dapat digunakan untuk percobaan.


Bagan Pohon Interaktif

Kombinasi fitur kuat dari SVG dan kerangka kerja Vue.js memungkinkan kami untuk membuat sistem untuk membangun diagram yang berbasis data, interaktif, dan dapat disesuaikan.

Diagram adalah kumpulan kurva Bezier kubik mulai dari satu titik. Kurva berakhir pada titik yang berbeda berjarak sama satu sama lain. Posisi akhir mereka tergantung pada data yang dimasukkan oleh pengguna. Akibatnya, bagan ini dapat bereaksi secara reaktif terhadap perubahan data.

Pertama, kita akan berbicara tentang bagaimana kurva kubik Bezier terbentuk, kemudian kita akan mencari cara untuk merepresentasikannya dalam sistem koordinat elemen <svg> , dan berbicara tentang membuat topeng untuk gambar.

Penulis materi mengatakan bahwa dia menyiapkan banyak ilustrasi untuknya, berusaha membuatnya dimengerti dan menarik. Tujuan dari materi ini adalah untuk membantu semua orang mendapatkan pengetahuan dan keterampilan yang diperlukan untuk mengembangkan sistem diagram mereka sendiri.

Svg


โ– Bagaimana kurva Bezier kubik terbentuk?


Kurva yang digunakan dalam proyek ini disebut Cubic Bezier Curve. Gambar berikut menunjukkan elemen kunci dari kurva ini.


Elemen Kunci dari Kurva Kubik Bezier

Kurva digambarkan oleh empat pasang koordinat. Pasangan pertama (x0, y0) adalah titik awal jangkar kurva. Pasangan koordinat terakhir (x3, y3) adalah titik referensi akhir.

Di antara titik-titik ini, Anda dapat melihat apa yang disebut titik kontrol. Ini intinya (x1, y1) dan intinya (x2, y2) .

Lokasi titik kontrol sehubungan dengan titik kontrol menentukan bentuk kurva. Jika kurva ditetapkan hanya oleh titik awal dan akhir, koordinat (x0, y0) dan (x3, y3) , maka kurva ini akan terlihat seperti segmen lurus yang terletak di diagonal.

Sekarang kita akan menggunakan koordinat dari empat titik yang dijelaskan di atas untuk memplot kurva menggunakan elemen <path> SVG. Berikut adalah sintaks yang digunakan dalam elemen <path> untuk membangun kurva Bezier kubik:

 <path D="M x0,y0 C x1,y1 x2,y2 x3,y3" /> 

Huruf , yang dapat dilihat dalam kode, adalah singkatan dari Cubic Bezier Curve. Huruf kecil ( c ) berarti penggunaan nilai relatif, huruf besar ( C ) berarti penggunaan nilai absolut. Saya menggunakan nilai absolut untuk membangun diagram, ini ditunjukkan dengan huruf kapital yang digunakan dalam contoh.

โ–Membuat diagram simetris


Simetri adalah aspek kunci dari proyek ini. Untuk membangun diagram simetris, saya hanya menggunakan satu variabel, menerima atas dasar nilai-nilai seperti tinggi, lebar atau koordinat pusat dari objek tertentu.

Beri nama size variabel ini. Karena bagan diorientasikan secara horizontal - variabel size dapat dianggap sebagai seluruh ruang horisontal yang tersedia untuk bagan.

Tetapkan nilai yang realistis untuk variabel ini. Kami akan menggunakan nilai ini untuk menghitung koordinat elemen bagan.

 size = 1000 

Menemukan koordinat elemen bagan


Sebelum kita dapat menemukan koordinat yang diperlukan untuk membangun diagram, kita perlu berurusan dengan sistem koordinat SVG.

โ–Sistem koordinasi dan kotak tampilan


Atribut <svg> viewBox sangat penting dalam proyek kami. Faktanya adalah ini menggambarkan sistem koordinat pengguna dari gambar SVG. Sederhananya, viewBox menentukan posisi dan ukuran ruang di mana gambar SVG terlihat di layar akan dibuat.

Atribut viewBox terdiri dari empat angka yang menentukan parameter sistem koordinat dan berikut ini dalam urutan ini: min-x , min-y , width , height . Parameter min-x dan min-y mengatur asal sistem koordinat pengguna, parameter width dan height mengatur lebar dan tinggi gambar yang ditampilkan. Di sini akan terlihat seperti apa atribut viewBox :

 <svg viewBox="min-x min-y width height">...</svg> 

Variabel size yang kami jelaskan di atas akan digunakan untuk mengontrol parameter width dan height sistem koordinat ini.

Kemudian, di bagian Vue.js, kita akan mengikat viewBox ke properti yang dihitung untuk menentukan nilai width dan height . Selain itu, dalam proyek kami, properti min-x dan min-y akan selalu disetel ke 0.

Perhatikan bahwa kita tidak menggunakan atribut height dan width dari elemen <svg> itu sendiri. Kami akan mengaturnya menjadi width: 100% dan height: 100% menggunakan CSS. Ini akan memungkinkan kami untuk membuat gambar SVG yang secara fleksibel menyesuaikan dengan ukuran halaman.

Sekarang setelah sistem koordinat pengguna siap untuk menggambar bagan, mari kita bicara tentang menggunakan variabel size untuk menghitung koordinat elemen-elemen bagan.

Coordinates Koordinat tidak berubah dan dinamis



Konsep bagan

Lingkaran di mana gambar ditampilkan adalah bagian dari diagram. Itulah mengapa penting untuk memasukkannya dalam perhitungan sejak awal. Mari kita, berdasarkan ilustrasi di atas, mencari koordinat untuk lingkaran dan satu kurva eksperimental.

Ketinggian grafik dibagi menjadi dua bagian. Ini adalah topHeight ( size 20%) dan bottomHeight (ukuran 80% sisanya). Lebar total diagram dibagi menjadi 2 bagian - panjang masing-masing adalah 50% dari size .

Ini membuat kesimpulan dari parameter lingkaran tidak memerlukan penjelasan khusus (di sini indikator topHeight dan topHeight digunakan). Parameter radius diatur ke setengah nilai topHeight . Berkat ini, lingkarannya sangat cocok dengan ruang yang tersedia.

Sekarang mari kita lihat koordinat kurva.

  • Koordinat (x0, y0) menentukan titik referensi awal dari kurva. Koordinat ini tetap konstan sepanjang waktu. Koordinat x0 adalah pusat bagan (setengah size ), dan y0 adalah koordinat di mana bagian bawah lingkaran berakhir. Oleh karena itu, dalam rumus untuk menghitung koordinat ini, jari-jari lingkaran digunakan. Hasilnya, koordinat titik ini dapat ditemukan dengan rumus berikut : (50% size, 20% size + radius) .
  • Koordinat (x1, y1) adalah titik kontrol pertama dari kurva. Itu juga tetap tidak berubah untuk semua kurva. Jika kita tidak lupa bahwa kurva harus simetris, ternyata nilai x1 dan y1 selalu sama dengan setengah dari nilai size . Maka rumus untuk perhitungan mereka: (50% size, 50% size) .
  • Koordinat (x2, y2) mewakili titik kontrol kedua dari kurva Bezier. Di sini x2 menunjukkan bentuk kurva yang seharusnya. Indikator ini dihitung secara dinamis untuk setiap kurva. Dan indikator y2 , seperti sebelumnya, akan menjadi setengah size . Maka rumus berikut untuk menghitung koordinat ini: (x2, 50% size) .
  • Koordinat (x3, y3) adalah titik referensi ujung kurva. Koordinat ini menunjukkan di mana Anda ingin selesai menggambar garis. Di sini, nilai x3 , seperti x2 , dihitung secara dinamis. Dan y3 mengambil nilai yang sama dengan size 80%. Hasilnya, kami memperoleh rumus berikut: (x3, 80% size) .

Kami menulis ulang, secara umum, kode untuk elemen <path> , dengan mempertimbangkan formula yang baru saja kami peroleh. Persentase yang digunakan di atas disajikan di sini dengan membaginya dengan 100.

 <path d="M size*0.5, (size*0.2) + radius          C size*0.5, size*0.5           x2,    size*0.5           x3,    size*0.8" > 

Harap perhatikan bahwa pada pandangan pertama, penggunaan persentase dalam formula kami mungkin tampak opsional, hanya berdasarkan pendapat saya sendiri. Namun, nilai-nilai ini tidak diterapkan pada kemauan, tetapi karena penggunaannya membantu mencapai simetri dan proporsi diagram yang benar. Setelah Anda merasakan peran mereka dalam pembuatan bagan, Anda dapat mencoba nilai persentase Anda sendiri dan memeriksa hasil yang diperoleh dengan menerapkannya.

Sekarang mari kita bicara tentang bagaimana kita akan mencari koordinat x2 dan x3 . Mereka memungkinkan Anda untuk secara dinamis membuat banyak kurva berdasarkan index elemen dalam array yang sesuai.

Membagi ruang horisontal yang tersedia dari bagan menjadi bagian yang sama didasarkan pada jumlah elemen dalam array. Akibatnya, setiap bagian menerima ruang yang sama di sepanjang sumbu x.

Rumus yang kami peroleh selanjutnya harus bekerja dengan sejumlah elemen. Tapi di sini kita akan bereksperimen dengan array yang mengandung 5 elemen: [0,1,2,3,4] . Visualisasi array seperti itu berarti perlu menggambar 5 kurva.

โ–Menemukan koordinat dinamis (x2 dan x3)


Pertama, saya membagi size dengan jumlah elemen, yaitu dengan panjang array. Saya menyebut distance variabel ini. Ini mewakili jarak antara dua elemen.

 distance = size/arrayLength // distance = 1000/5 = 200 

Lalu saya berjalan di sekitar array dan mengalikan indeks masing-masing elemen ( index ) dengan distance . Untuk kesederhanaan, saya cukup memanggil x baik parameter x2 dan parameter x3 .

 //  x2  x3 x = index * distance 

Jika Anda menerapkan nilai yang diperoleh saat membuat diagram, yaitu, menggunakan nilai x dihitung di atas untuk x2 dan x3 , itu akan terlihat sedikit aneh.


Diagram asimetris

Seperti yang Anda lihat, elemen-elemen tersebut berada di area di mana seharusnya mereka berada, tetapi diagram tersebut ternyata asimetris. Tampaknya di bagian kirinya ada lebih banyak elemen daripada di kanan.

Sekarang saya perlu membuat nilai x3 terletak di tengah segmen yang sesuai, yang panjangnya diatur menggunakan variabel distance .

Untuk membawa diagram ke bentuk yang saya butuhkan, saya hanya menambahkan x setengah nilai distance .

 x = index * distance + (distance * 0.5) 

Akibatnya, saya menemukan pusat segmen distance dan menempatkan koordinat x3 di dalamnya. Selain itu, saya membawa ke formulir yang kita butuhkan koordinat x2 untuk kurva No. 2.


Bagan simetris

Menambahkan setengah nilai distance ke koordinat x2 dan x3 membuat rumus perhitungan untuk koordinat ini cocok untuk memvisualisasikan array yang berisi elemen genap dan ganjil.

โ– Penyembunyian gambar


Kita perlu gambar tertentu untuk ditampilkan di bagian atas diagram, di dalam lingkaran. Untuk mengatasi masalah ini, saya membuat topeng kliping yang berisi lingkaran.

 <defs>  <mask id="svg-mask">     <circle :r="radius"             :cx="halfSize"             :cy="topHeight"             fill="white"/>  </mask> </defs> 

Kemudian, dengan menggunakan tag <image> dari elemen <image> <svg> <image> untuk menampilkan gambar, saya menautkan gambar ke elemen <mask> yang dibuat di atas menggunakan atribut mask dari elemen <image> .

 <image mask="url(#svg-mask)"      :x="(halfSize-radius)"      :y="(topHeight-radius)" ... > </image> 

Karena kami mencoba menyesuaikan gambar persegi menjadi "jendela" bundar, saya menyesuaikan posisi elemen dengan mengurangi parameter radius dari parameter yang sesuai. Hasilnya, gambar terlihat melalui topeng yang dibuat dalam bentuk lingkaran.

Mari kita kumpulkan semua yang kita bicarakan dalam satu gambar. Ini akan membantu kita melihat gambaran keseluruhan dari kemajuan pekerjaan.


Data yang digunakan dalam menghitung parameter grafik

Membuat gambar SVG dinamis menggunakan Vue.js


Pada titik ini, kami menemukan kurva Bezier kubik dan melakukan perhitungan yang diperlukan untuk membentuk diagram. Akibatnya, kita sekarang dapat membuat diagram SVG statis. Jika kita menggabungkan kemampuan SVG dan Vue.js, kita dapat membuat diagram yang didorong oleh data. Grafik statis akan menjadi dinamis.

Pada bagian ini, kami merevisi diagram SVG, menyajikannya sebagai satu set komponen Vue. Kami juga akan melampirkan atribut SVG ke properti yang dihitung dan membuat bagan menanggapi perubahan data.

Selain itu, pada akhir proyek, kami akan membuat komponen yang merupakan panel konfigurasi. Komponen ini akan digunakan untuk memasukkan data yang akan dikirim ke bagan.

โ–Mengikat data dengan melihat parameter Box


Mari kita mulai dengan menyesuaikan sistem koordinat. Tanpa melakukan ini, kita tidak akan bisa menggambar gambar SVG. Properti viewbox dikomputasi akan mengembalikan apa yang kita butuhkan menggunakan variabel size . Akan ada empat nilai yang dipisahkan oleh spasi. Semua ini akan menjadi nilai atribut viewBox dari elemen <svg> .

 viewbox() {   return "0 0 " + this.size + " " + this.size; } 

Di SVG, nama atribut viewBox sudah ditulis menggunakan gaya unta.

 <svg viewBox="0 0 1000 1000"> </svg> 

Oleh karena itu, untuk mengikat atribut ini dengan benar ke properti yang dihitung, saya menuliskan nama atribut dalam gaya kebab dan menempatkan pengubah .camel setelahnya. Dengan pendekatan ini, dimungkinkan untuk "menipu" HTML dan menerapkan ikatan atribut dengan benar.

 <svg :view-box.camel="viewbox">   ... </svg> 

Sekarang ketika mengubah size bagan dikonfigurasi ulang secara independen. Kami tidak perlu mengubah tata letak secara manual.

โ– Penghitungan parameter kurva


Karena sebagian besar nilai yang diperlukan untuk membangun kurva dihitung berdasarkan variabel tunggal ( size ), saya biasa mencari semua koordinat tetap dengan properti yang dihitung. Apa yang kita sebut "koordinat tetap" di sini dihitung berdasarkan size , dan setelah itu tidak berubah dan tidak tergantung pada berapa banyak kurva yang akan dimasukkan oleh diagram.

Jika Anda mengubah size - "koordinat tetap" akan dihitung ulang. Setelah itu, mereka tidak akan berubah sampai size berikutnya berubah. Diberikan di atas, berikut adalah lima nilai yang perlu kita gambar kurva Bezier:

  • topHeight โ€” size * 0.2
  • bottomHeight โ€” size * 0.8
  • width โ€” size
  • halfSize โ€” size * 0.5
  • distance โ€” size/arrayLength

Sekarang kita hanya memiliki dua nilai yang tidak diketahui yang tersisa - x2 dan x3 . Rumus untuk menghitungnya telah kami peroleh:

 x = index * distance + (distance * 0.5) 

Untuk menemukan nilai tertentu, kita perlu mengganti indeks elemen array dalam rumus ini.

Sekarang mari kita bertanya pada diri sendiri apakah properti yang dihitung tepat untuk kita temukan x . Jawab dengan singkat pertanyaan ini, lalu - tidak, itu tidak akan berhasil.

Properti yang dihitung tidak dapat melewati parameter. Faktanya adalah bahwa ini adalah properti, bukan fungsi. Selain itu, kebutuhan untuk menggunakan parameter untuk menghitung sesuatu berarti bahwa tidak ada keuntungan nyata dari menggunakan properti yang dihitung dalam hal caching.

Harap dicatat bahwa ada pengecualian terkait prinsip di atas. Ini tentang Vuex. Jika Anda menggunakan Vuex getter yang mengembalikan fungsi, Anda bisa meneruskan parameter kepada mereka.

Dalam hal ini, kami tidak menggunakan Vuex. Tetapi bahkan dalam situasi ini, kami memiliki beberapa cara untuk menyelesaikan masalah ini.

โ– Opsi nomor 1


Anda dapat mendeklarasikan fungsi ke mana index dilewatkan sebagai argumen, dan yang mengembalikan hasil yang kita butuhkan. Pendekatan ini terlihat lebih bersih jika kita akan menggunakan nilai yang dikembalikan oleh fungsi serupa di beberapa tempat di templat.

 <g v-for="(item, i) in itemArray">  <path :d="'M' + halfSize + ','     + (topHeight+r) +' '+            'C' + halfSize + ','     + halfSize +' '+                     calculateXPos(i) + ',' + halfSize +' '+                  calculateXPos(i) + ',' + bottomHeight"  /> </g> 

Metode calculateXPos() akan melakukan perhitungan setiap kali dipanggil. Metode ini sebagai argumen indeks elemen - i .

 <script>  methods: {    calculateXPos (i)    {      return distance * i + (distance * 0.5)    }  } </script> 

Berikut adalah contoh pada CodePen yang menggunakan solusi ini.


Layar untuk varian aplikasi pertama

โ– Opsi nomor 2


Opsi ini lebih baik daripada yang pertama. Kita dapat mengekstrak markup SVG kecil yang diperlukan untuk membangun kurva menjadi komponen anak kecil yang terpisah dan meneruskan index kepadanya sebagai salah satu properti.

Dengan pendekatan ini, Anda bahkan dapat menggunakan properti yang dihitung untuk menemukan x2 dan x3 .

 <g v-for="(item, i) in items">    <cubic-bezier :index="i"                   :half-size="halfSize"                   :top-height="topHeight"                   :bottom-height="bottomHeight"                   :r="radius"                   :d="distance"     >     </cubic-bezier> </g> 

Opsi ini memberi kita kesempatan untuk mengatur kode dengan lebih baik. Misalnya, kita bisa membuat komponen anak lain untuk topeng:

 <clip-mask :title="title"           :half-size="halfSize"           :top-height="topHeight"                               :r="radius"> </clip-mask> 

โ– Panel konfigurasi



Panel konfigurasi

Anda mungkin sudah melihat panel konfigurasi, dipanggil oleh tombol yang terletak di sudut kiri atas layar contoh di atas. Panel ini memudahkan untuk menambahkan elemen ke array dan menghapusnya dari itu. Mengikuti ide-ide yang dibahas di bagian "Opsi # 2", saya membuat komponen turunan untuk panel konfigurasi. Berkat ini, komponen tingkat atas bersih dan mudah dibaca. Hasilnya, komponen Vue kami yang kecil dan bagus terlihat seperti di bawah ini.


Pohon Komponen Proyek

Ingin melihat kode yang mengimplementasikan versi proyek ini? Jika demikian, lihat di sini .


Layar untuk varian aplikasi kedua

Repositori proyek


Ini adalah repositori GitHub proyek ("Opsi # 2" diimplementasikan di sini). Saya percaya ini akan berguna bagi Anda untuk melihatnya sebelum Anda melanjutkan ke bagian selanjutnya.

PR


Cobalah untuk membuat diagram yang sama dengan yang kami jelaskan di sini, tetapi buatlah itu berorientasi vertikal. Manfaatkan ide-ide yang diuraikan dalam artikel ini.

Jika Anda berpikir bahwa ini adalah tugas yang mudah, bahwa untuk membangun diagram seperti itu cukup untuk menukar koordinat x dan y , maka Anda benar. Mempertimbangkan bahwa proyek yang dipertimbangkan di sini tidak dibuat sebagai universal, setelah mengubah koordinat di mana Anda membutuhkannya, Anda juga perlu mengedit kode dengan mengganti nama beberapa variabel dan metode.

Berkat Vue.js, bagan sederhana kami dapat dilengkapi dengan fitur tambahan. Misalnya, berikut ini:

  • Anda dapat membuat mekanisme yang memungkinkan Anda untuk beralih antara mode grafik horizontal dan vertikal.
  • Kurva dapat mencoba menghidupkan. Misalnya, menggunakan GSAP.
  • Anda dapat menyesuaikan properti kurva (katakan - warna dan lebar garis) dari panel konfigurasi.
  • Anda dapat menggunakan perpustakaan eksternal untuk mengatur penyimpanan diagram dalam format grafik apa pun atau sebagai file PDF. Bahan-bahan ini dapat diunduh untuk mereka yang bekerja dengan bagan.

Coba pekerjaan rumah ini. Dan jika Anda memiliki masalah - di bawah ini akan diberikan tautan ke solusinya.

Ringkasan


Elemen <path> adalah salah satu fitur kuat dari SVG. Elemen ini memungkinkan Anda membuat berbagai gambar dengan akurasi tinggi. Di sini kami menemukan bagaimana kurva Bezier terstruktur, dan bagaimana mempraktikkannya untuk membuat diagram Anda sendiri.

, , JavaScript-. Vue.js . , , , , DOM. , โ€” .

, , , , , Vue.js SVG. โ€” , Vue.js. โ€” .

, - , , , โ€” .

Pembaca yang budiman! ?

Source: https://habr.com/ru/post/id463329/


All Articles