Saya menggunakan perpustakaan bagan beberapa hari yang lalu, di antaranya ECharts Baidu tampaknya yang terbaik. Ia menggunakan kanvas secara default. Bagan kanvas lebih baik daripada SVG dalam memproses data besar. Lalu saya juga akan menggunakan kanvas untuk mengimplementasikan pustaka diagram. Rasanya tidak terlalu sulit. Mari kita implementasikan diagram batang sederhana terlebih dahulu.
Efeknya adalah sebagai berikut: Poin fungsi utama meliputi:Pertama, mari kita lihat cara menggunakannya. Kita mengacu pada beberapa metode penggunaan ECharts. Pertama, kita meneruskan tag html untuk menampilkan grafik, lalu memanggil init, dan meneruskan data selama inisialisasi.
var con=document.getElementById('container'); var chart=new Bar(con); chart.init({ title:'histogram curah hujan sepanjang tahun', xAxis:{// data sumbu x: ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober','November', 'Desember'] }, sumbu y:{//nama sumbu y:'volume air', formatter:'{value} ml' }, seri:[//Data grup{ name:'Curah hujan di Timur', data:[62,20,17,45,100,56,19,38,50,120,56,130] }, { name:'Curah hujan di Barat', data:[52,10,17 ,25 ,60,39,19,48,70,30,56,8] }, { nama:'Curah hujan selatan', data:[12,10,17,25,27,39,50,38,100,30,56,90] }, { color:'hsla(270,80%,60%,1)', name:'Curah hujan utara Kuantitas', data:[12,30,17,25,7,39,49,38,60,30,56,10] } ] });
Untuk kelas dasar bagan, nanti kita juga akan menulis diagram lingkaran dan diagram garis, jadi kita akan mengekstrak bagian umumnya. Perhatikan bahwa canvas.style.width dan canvas.width berbeda. Yang pertama akan meregangkan grafik, sedangkan yang kedua adalah yang biasa kita gunakan dan tidak akan meregangkan grafik. Tujuan penulisan terlebih dahulu perluasan dan kemudian pengurangan di sini adalah untuk mengatasi masalah keburaman saat menggambar teks di atas kanvas.
kelas Bagan{ konstruktor(wadah){ this.container=container; this.canvas=document.createElement('canvas'); this.ctx=this.canvas.getContext('2d'); ini.H=600*2; ini.padding=120; ini.paddingTop=50; ini.judul=''; this.series=[]; //Selesaikan masalah keburaman font dengan menggandakan ukuran this.canvas.width=this.W; this.canvas.height=this.H; 2 + 'px'; ini.kanvas.gaya.tinggi = ini.H/2 + 'px';
Untuk menginisialisasi histogram, panggil Object.assign(this,opt) di es6. Ini setara dengan metode perluasan di JQ, yang menyalin properti ke instance saat ini. Pada saat yang sama juga dibuat atribut tip yang merupakan tag html dan digunakan untuk menampilkan informasi data nantinya. Kemudian gambar grafiknya dan ikat event mouse.
kelas Bar memperluas Bagan{ konstruktor(wadah){ super(wadah); this.xAxis={}; this.yAxis=[]; this.animateArr=[]; ; if(!this.container)return; this.container.style.position='relative'; this.tip=document.createElement('div'); this.tip.style.cssText='tampilan: tidak ada; posisi: absolut; opacity: 0,5; ukuran font: 8px; : 99;'; this.container.appendChild(ini.kanvas); this.container.appendChild(ini.tip); this.draw(); this.bindEvent(); } draw(){//Gambar} showInfo(){//Tampilkan informasi} animate(){//Lakukan animasi} showData(){//Tampilkan data}
Gambarlah sumbu XY
Pertama gambar judulnya, lalu sumbu XY, lalu telusuri rangkaian data yang dikelompokkan, yang berisi perhitungan rumit, lalu gambar skala sumbu XY, gambar label grup, dan terakhir gambar datanya. Seri item data adalah data yang dikelompokkan, yang sesuai dengan xAxis.data sumbu X satu-ke-satu. Setiap item dapat memiliki nama dan warna yang disesuaikan. Jika tidak ditentukan, nama diberikan kepada nunamed dan warna dihasilkan secara otomatis. Atribut legenda juga digunakan di sini untuk mencatat informasi daftar tag, karena berguna untuk klik mouse selanjutnya untuk menentukan apakah klik tersebut benar.
Poin pengetahuan utama kanvas:
draw(){ var itu=ini, ctx=ini.ctx, kanvas=ini.kanvas, W=ini.W, H=ini.H, padding=ini.padding, paddingTop=ini.paddingTop, xl=0,xs=0,xdis=W-padding*2,//Jumlah satuan sumbu x, panjang tiap satuan, total panjang sumbu x yl=0,ys=0,ydis=H-padding* 2-paddingTop; //Jumlah satuan sumbu y, panjang tiap satuan, total panjang sumbu y ctx.fillStyle='hsla(0,0%,20%,1)'; ctx.strokeStyle='hsla(0,0%,10%,1)'; ctx.lineWidth=1; ctx.textAlign='pusat'; ctx.textBaseLine='tengah'; ctx.clearRect(0,0,W,H); if(ini.judul){ ctx.save(); ctx.textAlign='kiri'; ctx.font='huruf tebal 40px'; ctx.fillText(ini.judul,padding-50,70); { ctx.fillText(ini.yAxis.nama,padding,padding+paddingTop-30); // sumbu x ctx.save(); ctx.beginPath(); ctx.translate(padding,H-padding); ctx .stroke(); // skala sumbu x if(this.xAxis&&(xl=this.xAxis.data.length)){ xs=(W-2*padding)/xl; this.xAxis.data.forEach((obj,i)=>{ var x=xs*(i+1); ctx.moveTo(x,0); ctx. barisKe(x,10); ctx.stroke(); ctx.fillText(obj,x-xs/2,40); ctx.restore(); // sumbu y ctx.save(); ctx.beginPath(); ctx.strokeStyle='hsl(220,100%,50%)'; .moveTo(0,0);ctx.lineTo(0,2*padding+paddingTop-H); ctx.stroke(); ctx.restore(); if(ini.seri.panjang){ var saat ini,txt,dim,info,item,tw=0; ;i++){ item=ini.series[i]; if(!item.data||!item.data.length){ this.series.splice(i--,1);lanjutkan; Tetapkan item tanpa warna if(!item.color){ var hsl=i%2?180+20*i/2:20*(i-1); item.color='hsla('+hsl+',70% , 60%,1)'; } item.name=item.name||'unnamed'; // Menggambar label pengelompokan ctx.save(); ctx.translate(padding+W/4,paddingTop+40); that.legend.push({ hide:item.hide||false, nama:item.name, color:item.color, x:padding+that.W /4+i*90+tw, y:paddingTop+40, w:60, h:30, r:5 }); ctx.fillStyle=item.warna; ctx.strokeStyle=item.color; roundRect(ctx,i*90+tw,0,60,30,5); (); ctx.fillText(nama item,i*90+tw+70,26); tw+=ctx.measureText(item.name).width;//Hitung panjang karakter ctx.restore(); if(item.hide)continue; //Hitung data pada skala sumbu Y if(!info){ info=hitungY( item.data.slice(0,xl)); } curr=hitungY(item.data.slice(0,xl)); if(curr.max>info.max){ info=curr; } } if(!info) return; yl=info.num; ys=ydis/yl; //Gambar skala sumbu Y ctx.save(); ) '; ctx.strokeStyle='hsl(220,100%,50%)'; ctx.moveTo(-10,-Math.floor(ys*i)); ctx.lineTo(0,-Math.floor(ys*i)); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0,-Math.floor(ys*i)); ctx.lineTo(xdis,-Math.floor(ys*i)); ctx.textAlign='kanan'; Math.min(Matematika.lantai(info.langkah*i),info.max); txt=ini.yAxis.formatter?ini.yAxis.formatter.replace('{value}',dim):redup;ctx.fillText(txt,-20,-ys*i+10); ; //Gambarkan data ini.showData(xl,xs,info.max }}data petak
Karena item data selanjutnya perlu dianimasikan dan ditampilkan ketika mouse menggesernya, item tersebut dimasukkan ke dalam antrian animasi animateArr. Di sini kita perlu memperluas data yang dikelompokkan, mengubah dua array bersarang sebelumnya menjadi satu lapisan, dan menghitung atribut setiap item data, seperti nama, koordinat x, koordinat y, lebar, kecepatan, dan warna. Setelah data diorganisasikan, animasi dijalankan.
showData(xl,xs,max){ //Gambar data var itu=ini, ctx=ini.ctx, ydis=ini.H-ini.padding*2-ini.paddingTop, sl=ini.series.filter(s= >!s.hide).length, sp=Matematika.max(Matematika.pow(10-sl,2)/3-4,5), w=(xs-sp*(sl+1))/sl, h,x,index=0; that.animateArr.length=0; // Perluas item data dan isi antrian animasi untuk(var i=0 ,item ,len=seri.ini.panjang;i<len;i++){ item=seri.ini[i]; if(item.hide)lanjutkan; item.data.slice(0,xl).forEach((d,j)=>{ h=d/max*ydis; x=xs*j+w*index+sp*(index+1); that.animateArr .push({ indeks:i, nama:nama item, angka:d, x:Math.round(x), y:1, w:Math.round(w), h:Math.floor(h+ 2) , vy:Math.max(300,Math.floor(h*2))/100, warna:item.warna }); indeks++;Jalankan animasi
Tidak banyak yang bisa dikatakan tentang mengeksekusi animasi, ini hanya fungsi penutupan yang dijalankan sendiri. Prinsip animasinya adalah mengakumulasikan nilai kecepatan vy secara berurutan pada sumbu y. Namun perlu diingat bahwa ketika antrian selesai mengeksekusi animasi, maka perlu dihentikan, sehingga ada flag isStop, yang dinilai setiap kali antrian selesai dieksekusi.
animate(){ var that=ini, ctx=ini.ctx, isStop=true; (fungsi dijalankan(){ isStop=true; for(var i=0,item;i<that.animateArr.length;i++){ item =itu.animateArr[i]; if(item.y-item.h>=0.1){ item.y=item.h; } else { item.y+=item.vy; } if(item.y<item.h){ ctx.save(); // ctx.translate(itu.padding+item.x,itu.H-itu.padding); .fillRect(itu.padding+item.x,itu.H-itu.padding-item.y,item.w,item.y); isStop=salah;Acara yang mengikat
Peristiwa 1: Saat menggerakkan mouse, periksa apakah posisi mouse berada pada label grup atau item data. Setelah menggambar jalur, panggil isPointInPath(x,y). Jika benar, canvas.style.cursor='pointer'; item data, Anda juga perlu menggambar ulang kolom, mengatur transparansi, dan membedakannya. Konten juga perlu ditampilkan. Berikut adalah div yang diposisikan secara absolut relatif terhadap wadah induk. Atribut tip telah ditetapkan selama inisialisasi. Kami merangkum bagian tampilan ke dalam metode showInfo.
Peristiwa 2: Saat mousedown terjadi, tentukan label grup mana yang diklik mouse, lalu atur atribut sembunyikan di seri data grup yang sesuai , menimpa rendering dan menggambar, dan melakukan animasi.
bindEvent(){ var itu=ini, kanvas=ini.kanvas, ctx=ini.ctx; ini.kanvas.addEventListener('mousemove',fungsi(e){ var isLegend=false; // pos=WindowToCanvas(kanvas,e .clientX,e.clientY); var kotak=kanvas.getBoundingClientRect(); x:e.clientX-box.left, y:e.clientY-box.top }; // Pengelompokan label untuk(var i=0,item,len=that.legend.length;i<len;i++){ item =itu.legenda[i]; ctx.save(); roundRect(ctx,item.x,item.y,item.w,item.h,item.r); Karena digandakan, koordinatnya adalah *2 if(ctx.isPointInPath(pos.x*2,pos.y*2)){ canvas.style.cursor='pointer'; ctx.restore(); break; } canvas.style.cursor='default'; ctx.restore(); } if(isLegend) return; //Pilih item data untuk(var i=0,item,len=itu.animateArr.length;i<len;i++){ item=itu.animateArr[i]; ctx.fillStyle=item.color; ctx.rect(itu.padding+item.x,itu.H-itu.padding-item.h,item.w,item.h); if(ctx.isPointInPath(pos.x*2,pos.y*2)){ //Hapus lalu gambar ulang grafik dengan transparansi 0,5 ctx.clearRect(that.padding+item.x,that.H-that .padding-item.h,item.w,item.h); ctx.globalAlpha=0,5; itu.showInfo(pos,item); ctx.restore(); istirahat; } kanvas.style.cursor='default'; itu.tip.style.display='tidak ada'; ); ctx.restore(); } },false); this.kanvas.addEventListener('mousedown',function(e){ e.preventDefault(); var box=kanvas.getBoundingClientRect(); var pos = { x:e.clientX-box.left, y:e.clientY-box.top }; =itu.legend.panjang;i<len;i++){ item=itu.legend[i]; roundRect(ctx,item.x,item.y,item.w,item.h,item.r); // Karena digandakan, koordinatnya adalah *2 if(ctx.isPointInPath(pos.x*2, pos) .y*2)){ that.series[i].hide=!that.series[i].hide; that.animateArr.length=0; that.draw(); },false); } //Menampilkan data showInfo(pos,obj){ var txt=this.yAxis.formatter?this.yAxis.formatter.replace('{value}',obj.num):obj.num; kotak=ini.kanvas.getBoundingClientRect(); var con=ini.container.getBoundingClientRect(); this.tip.innerHTML = '<p>'+obj.name+':'+txt+'</p>'; this.tip.style.left=(pos.x+(box.left-con.left)+10 )+'px'; this.tip.style.top=(pos.y+(box.top-con.top)+10)+'px'; this.tip.style.display='blok';Meringkaskan
Yang diselesaikan di sini hanya efek dasar saja, sebenarnya masih banyak area yang perlu dioptimalkan lebih lanjut, seperti dukungan responsif, dukungan seluler, efek animasi, dukungan multi-sumbu, efek konten tampilan, dan dukungan fungsi polyline. .
Di atas adalah keseluruhan isi artikel ini, saya harap dapat bermanfaat untuk pembelajaran semua orang. Saya juga berharap semua orang mendukung VeVb Wulin Network.