Hai Saya belajar di front-end, dan secara paralel, dalam proyek pelatihan, saya mengembangkan SPA di Vue.js untuk back-end, yang mengumpulkan data dari bot pencarian. Bot menghasilkan dari 0 hingga 500 entri, dan saya harus: mengunggah, mengurutkan berdasarkan kriteria yang ditentukan, tampil di tabel.
Baik back-end maupun bot tidak dapat mengurutkan data, jadi saya harus mengunduh semua data dan memprosesnya di sisi browser. Penyortiran sangat cepat, tetapi kecepatan unduhan tergantung pada koneksi, dan 500 catatan yang ditunjukkan dapat dimuat dari 10 hingga 40 detik.
Pada awalnya, saat memuat, saya menunjukkan spiner, kekurangannya adalah bahwa pengguna tidak tahu kapan unduhan akan berakhir. Dalam kasus saya, jumlah catatan yang ditemukan bot diketahui sebelumnya, sehingga Anda dapat menunjukkan berapa banyak catatan yang dimuat.
Untuk mencerahkan menunggu pengguna, saya memutuskan untuk menunjukkan kepadanya proses pemuatan:
- digit - berapa% catatan yang sudah dimuat
- jadwal - memuat waktu setiap catatan
- mengisi -% beban. Karena grafik mengisi blok persegi panjang saat memuat, jelas bagian mana dari blok yang masih harus diisi
Inilah animasi hasil yang saya inginkan dan dapatkan:

... menurut saya, ternyata lucu.
Dalam artikel ini saya akan menunjukkan kepada Anda bagaimana bergerak menuju hasil langkah demi langkah. Saya tidak menggambar grafik fungsi di browser sebelum desa, jadi pengembangan indikator membawakan saya pengetahuan yang sederhana namun baru tentang penggunaan SVG dan Vue.
Memilih Metode Canvas atau SVG Rendering
Saya menggunakan Canvas dalam permainan ular sederhana di JS, dan SVG, dalam satu proyek, saya hanya memasukkannya ke dalam halaman dengan tag objek dan memperhatikan bahwa ketika penskalaan, gambar SVG selalu menjaga ketajaman (itu sebabnya itu adalah vektor) dan Canvas mengamati gambar buram. Berdasarkan pengamatan ini, saya memutuskan untuk menggambar grafik menggunakan SVG, karena Anda harus mulai kapan-kapan.
Rencana kerja
Berdasarkan kerangka Vue yang dipilih, dan metode pembentukan gambar yang dipilih menggunakan SVG, saya membuat sendiri rencana kerja berikut:
- Cari dan pelajari informasi tentang topik menggunakan SVG dengan Vue
- Eksperimen dengan pembentukan dan perubahan SVG dalam konteks Vue
- Indikator memuat prototipe
- Alokasi indikator pemuatan ke dalam komponen Vue yang terpisah
- Penerapan komponen dalam SPA
Memulai
Membuat proyek kosongSaya telah vue cli diinstal . Untuk membuat proyek baru, pada prompt perintah saya memasukkan vue create loadprogresser , pilih pengaturan proyek secara default , proyek vue baru dibuat dengan nama loadprogresser, lalu saya menghapus yang tidak perlu dari itu:
Cari dan pelajari informasi tentang topik menggunakan SVG bersama dengan Vue
Situs hebat dengan info berguna tentang HTML, CSS, dan SVG css.yoksel.ru Contoh yang bagus dengan SVG tersedia di dokumentasi Vue sendiri. Contoh SVG-grafik dan tautan semacam itu. Berdasarkan bahan-bahan ini, templat komponen minimal dengan SVG lahir dari mana saya mulai:
<template> <div class="wrapper"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"> //svg // svg- </svg> </div> </template>
Eksperimen dengan pembentukan dan perubahan SVG dalam konteks Vue
SVG rectangle rect
rect - a rectangle, sosok paling sederhana. Saya membuat svg dengan dimensi 100x100px, dan menggambar persegi panjang dengan koordinat awal 25:25 dan ukuran 50x50 px, warna isi standar adalah hitam (tanpa gaya)
Styling SVG dan arahkan kursor pseudo-class:
Saya akan mencoba untuk gaya rectangle rect di svg. Untuk melakukan ini, saya menambahkan kelas "sample" ke svg, di bagian style dari file-vue saya menambahkan style .sample rect (saya mewarnai rectangular rectangle dengan yellow) dan .sample rect: hover yang membuat style elemen rect ketika Anda mengarahkan mouse:
Kode sumber <template> <div id="app"> <svg class="sample" version="1.1" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"> <rect x=25 y=25 width="50px" height="50px"/> </svg> </div> </template> <script> export default { name: 'app' } </script> <style> .sample rect { fill: yellow; stroke: green; stroke-width: 4; transition: all 350ms; } .sample rect:hover { fill: gray; } </style>
Implementasi JSfiddle
Kesimpulan: svg sangat cocok dengan file template vue dan ditata dengan gaya yang ditentukan. Sebuah awal telah dibuat!
Jalur SVG sebagai dasar indikator
Pada bagian ini, saya akan mengganti rect dengan path, <path :d="D" class="path"/>
pada atribut d dari tag path, saya akan meneruskan string D dengan koordinat path dari vue. Koneksi dilakukan melalui v-bind:d="D"
, yang disingkat :d="D"
Baris D = āM 0 0 0 50 50 50 50 0 Zā menarik tiga garis dengan koordinat 0: 0-> 0: 50-> 50: 50-> 0:50 dan menutup kontur dengan perintah Z, membentuk kotak 50x50px mulai dari koordinasikan 0: 0. Menggunakan gaya jalur, bentuknya diberi warna isian kuning dan batas abu-abu 1px.
Sumber PATH kuning <template> <div id="app"> <svg class="sample" version="1.1" xmlns="http://www.w3.org/2000/svg" width="100px" height="100px"> <path :d="D" class="path"/> </svg> </div> </template> <script> export default { name: 'app', data(){ return { D:"M 0 0 0 50 50 50 50 0 Z" } } } </script> <style> .path { fill:yellow; stroke:gray; } </style>
Indikator memuat prototipe
Dalam versi minimal, saya membuat diagram sederhana. Wadah svg dengan ketinggian 100px, lebar 400px dimasukkan dalam templat, tag path ditempatkan di dalam, ke atribut d yang saya tambahkan string path yang dihasilkan d dari data vue, yang pada gilirannya dibentuk dari array timePoints di mana satu dari 400 ditambahkan (setiap lebar wadah) angka acak dalam rentang dari 0 hingga 100. Semuanya sederhana, dalam kait siklus hidup yang dibuat, metode pembaruan disebut di mana titik (acak) baru ditambahkan ke diagram melalui metode addTime, kemudian metode getSVGTimePoints mengembalikan string untuk dikirim ke PATH, melalui setTimeout memulai kembali metode pembaruan
Lebih lanjut tentang pembentukan string untuk PATH
String untuk PATH dibentuk dalam metode getSVGTimePoints, dari array timePoints yang saya proses dengan pengurangan. Sebagai nilai awal dari pengurangan, saya menggunakan "M 0 0" (mulai dari koordinat 0: 0). Lebih lanjut dalam mengurangi, pasangan baru koordinat relatif dX dan dY akan ditambahkan ke baris. Huruf besar "l" (besar "L" menunjukkan koordinat absolut) bertanggung jawab untuk koordinat yang relatif, setelah d ditempatkan dX dan kemudian dY, dipisahkan oleh spasi. Dalam prototipe ini, dY = 1 (kenaikan demi 1px), di masa depan, di sepanjang sumbu X saya akan bergerak dengan kenaikan dX yang dihitung dari lebar wadah dan jumlah titik yang perlu ditempatkan di dalamnya. Di baris terakhir dari generasi PATH
path +=`L ${this.timePoints.length} 0`
Saya memaksakan, dari titik terakhir, saya selesai membangun garis ke sumbu X. Jika Anda perlu menutup kontur, Anda dapat menambahkan "Z" ke ujung garis, pada awalnya saya berpikir bahwa tanpa kontur tertutup, angka yang dihasilkan tidak akan diisi (isi), tetapi ternyata tidak di mana itu tidak ditutup, stroke - stroke tidak akan ditarik.
getSVGTimePoints:function(){ let predY = 0 let path = this.timePoints.reduce((str, item)=>{ let dY = item - predY predY = item return str + `l 1 ${dY} ` },'M 0 0 ') path +=`L ${this.timePoints.length} 0`
Saya akan terus melakukan perubahan. Indikator saya harus diskalakan dengan lebar dan tinggi sehingga semua titik yang ditransmisikan masuk ke dalam wadah yang diberikan. Untuk melakukan ini, buka DOM dan cari tahu dimensi wadah
ref - mendapatkan informasi tentang elemen DOM
Ke wadah div (di mana svg dimasukkan) saya menambahkan kelas pembungkus untuk melewati lebar dan tinggi melalui gaya. Dan agar svg memakan seluruh ruang kontainer, atur tinggi dan lebarnya menjadi 100%. RECT, pada gilirannya, juga akan menempati seluruh ruang kontainer dan akan menjadi latar belakang untuk PATH
<div id="app" class="wrapper" ref="loadprogresser"> <svg id="sample" version="1.1" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"> <rect x=0 y=0 width="100%" height="100%"/> <path :d="d" fill="transparent" stroke="black"/> </svg> </div>
Untuk menemukan wadah DIV saya di DOM Vue virtual, saya menambahkan atribut ref dan memberinya nama yang dengannya saya akan mencari ref="loadprogresser"
. Dalam kait siklus hidup yang mounted
, saya akan memanggil metode getScales (), di mana, dengan string const {width, height} = this.$refs.loadprogresser.getBoundingClientRect()
saya menemukan lebar dan tinggi elemen DIV setelah muncul di DOM.
Selanjutnya, perhitungan sederhana kenaikan di sepanjang sumbu X, tergantung pada lebar wadah dan jumlah titik yang ingin kita masukkan ke dalamnya. Skala di sepanjang sumbu Y dihitung ulang setiap kali maksimum ditemukan dalam nilai yang ditransmisikan.
transform - ubah sistem koordinat
Pada titik ini, saya perhatikan bahwa kita perlu mengubah sistem koordinat sehingga koordinat 0: 0 dimulai dari sudut kiri bawah, dan sumbu Y tumbuh ke atas, bukan ke bawah. Anda tentu saja dapat membuat perhitungan untuk setiap titik, tetapi SVG memiliki atribut transformasi yang memungkinkan Anda untuk mengubah koordinat.
Dalam kasus saya, saya perlu menerapkan skala -1 ke koordinat Y (sehingga nilai-nilai Y diletakkan kembali), dan menggeser asal ke ketinggian wadah minus . Karena ketinggian wadah dapat berupa (diatur melalui gaya), kami harus membentuk garis transformasi koordinat dalam kait yang mounted
dengan kode berikut: this.transform = `scale( 1, -1) translate(0,${-this.wrapHeight})`
Tetapi transformasi yang diterapkan pada PATH saja tidak akan berfungsi, untuk ini Anda perlu membungkus PATH dalam grup (g tag) yang menerapkan transformasi koordinat:
<g :transform="transform"> <path :d="d" fill="transparent" stroke="black"/> </g>
Hasilnya, koordinat terbalik dengan benar, indikator unduhan menjadi lebih dekat dengan desain
Teks SVG dan pemusatan teks
Teks diperlukan untuk menampilkan% memuat. Penempatan teks di tengah secara vertikal dan horizontal di SVG cukup sederhana untuk diatur (dibandingkan dengan HTML / CSS), atribut datang ke penyelamatan (saya segera menulis nilai-nilai) dominan-baseline = "pusat" dan teks-jangkar = "tengah"
Teks dalam SVG ditampilkan dengan tag yang sesuai:
<text x="50%" y="50%" dominant-baseline="central" text-anchor="middle">{{TextPrc}}</text>
di mana TextPrc adalah pengikatan ke variabel terkait, dihitung dengan rasio sederhana dari jumlah poin yang diharapkan dengan jumlah yang ditransfer this.TextPrc = `${((this.Samples * 100)/this.maxSamples) | 0} %`
this.TextPrc = `${((this.Samples * 100)/this.maxSamples) | 0} %`
.
Koordinat awal x = "50%" y = "50%" sesuai dengan pusat wadah, dan atribut dasar-jangkar dan teks-jangkar bertanggung jawab untuk teks yang disejajarkan secara vertikal dan horizontal.
Hal-hal dasar pada topik telah dikerjakan, sekarang kita perlu memilih prototipe indikator dalam komponen terpisah.
Alokasi indikator pemuatan ke dalam komponen Vue yang terpisah
Untuk memulainya, saya akan menentukan data yang akan saya transfer ke komponen, ini akan menjadi: maxSamples - jumlah sampel dengan lebar 100%, dan Point - unit data (titik) yang akan dimasukkan ke dalam array titik (berdasarkan yang, setelah pemrosesan, akan dibentuk jadwal). Data yang dikirimkan ke komponen dari induk, saya letakkan di bagian alat peraga
props:{ maxSamples: {
Masalah reaktivitas
Properti getPath yang dikomputasi bertanggung jawab atas fakta bahwa titik baru yang diteruskan ke komponen diproses, yang bergantung pada Point (dan jika ya, itu dihitung ulang ketika Point berubah)
Pada awalnya saya membuat Point of type Number, yang logis, tetapi kemudian tidak semua titik diproses, tetapi hanya berbeda dari yang sebelumnya. Misalnya, jika hanya nomor 10 yang ditransfer dari induk ke suatu titik, maka hanya satu titik yang akan ditarik pada bagan, semua yang berikutnya akan diabaikan karena mereka tidak berbeda dari yang sebelumnya.
Mengganti tipe Point dari Number dengan objek {value: 0} mengarah ke hasil yang diinginkan - getPath properti yang dikomputasi () sekarang memproses setiap titik yang ditransmisikan, melalui Point.value Saya meneruskan nilai poin tersebut
Sumber komponen Progresser.vue <template> <div class="wrapper" ref="loadprogresser"> <svg class="wrapper__content" version="1.1" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" > <g :transform="transform"> <path :d="getPath"/> </g> <text x="50%" y="50%" dominant-baseline="central" text-anchor="middle"> {{TextPrc}} </text> </svg> </div> </template> <script> export default { props:{ maxSamples: {
Memanggil dari komponen induk dan melewati parameter
Untuk bekerja dengan komponen, Anda perlu mengimpornya ke komponen induk
import Progresser from "./components/Progresser"
dan menyatakan dalam bagian
components: {Progresser }
Dalam templat komponen induk, komponen indikator progres dimasukkan dengan konstruksi berikut:
<progresser class="progresser" :maxSamples = "SamplesInProgresser" :Point = "Point" ></progresser>
Melalui kelas "progreser", pertama-tama, ukuran blok indikator ditetapkan. MaxSamples (jumlah maksimum poin dalam grafik) dari variabel induk SamplesInProgresser ditransfer ke props komponen, dan titik berikutnya (dalam bentuk objek) dari objek orangtua. Variabel Point objek ditransfer ke props Point. Titik induk dihitung dalam fungsi pembaruan, dan menunjukkan peningkatan angka acak. Saya mendapatkan gambar ini:

Sumber induk App.vue <template> <div> <progresser class="progresser" :maxSamples = "SamplesInProgresser" :Point = "Point" ></progresser> </div> </template> <script> import Progresser from "./components/Progresser" export default { name: 'app', data(){ return { SamplesInProgresser:400,// - Point:{value:0},//"" index:0, // - TimeM:100 // } }, created: function () { this.update() }, methods:{ update(){ if (this.index < this.SamplesInProgresser) { this.index++; this.Point = {value:(this.TimeM*Math.random() | 0)} this.TimeM *= 1.01 setTimeout(this.update, 0) } } }, components: { Progresser } } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; margin-top: 60px; } /* */ .progresser { width: 300px; height: 80px; } </style>
Penerapan komponen dalam SPA
Mencapai titik di mana semuanya berjalan. Jadi, saya memiliki operasi asinkron untuk memuat catatan tentang identitas tertentu dari database. Waktu pelaksanaan operasi asinkron tidak diketahui sebelumnya. Saya akan mengukur waktu eksekusi dengan cara sepele, menggunakan Date () baru. GetTime () sebelum dan setelah operasi, dan saya akan mentransfer perbedaan waktu yang dihasilkan ke komponen. Secara alami, indikator akan dibangun ke dalam blok yang akan muncul pada tahap pemuatan, dan mengaburkan tabel yang memuat data.
async getCandidatesData(){ ... this.LoadRecords = true
Dalam data komponen induk saya meresepkan sehubungan dengan indikasi beban:
data (){ return { ...
Dan di templat:
<div class="wait_loading" v-show="LoadRecords"> <progresser class="progresser" :maxSamples = "SamplesInProgresser" :Point = "Point" ></progresser> </div>
Kesimpulan
Seperti yang diperkirakan, tidak ada yang rumit. Hingga titik tertentu, Anda dapat memperlakukan SVG sebagai tag HTML biasa, dengan spesifiknya sendiri. SVG adalah alat yang ampuh yang sekarang akan saya gunakan lebih sering dalam pekerjaan saya untuk visualisasi data
Referensi
Unduh Kode Sumber IndikatorArtikel jalur lgg