لقد استخدمت مكتبة الرسوم البيانية منذ بضعة أيام، ويبدو أن ECharts من Baidu هي الأفضل، حيث تستخدم مخططات Canvas بشكل افتراضي أفضل من SVG في معالجة البيانات الضخمة. ثم سأستخدم اللوحة القماشية أيضًا لتنفيذ مكتبة الرسوم البيانية، ولن يبدو الأمر صعبًا للغاية، فلنقم بتنفيذ مخطط شريطي بسيط أولاً.
التأثير هو كما يلي: تشمل نقاط الوظيفة الرئيسية ما يلي:أولاً، دعونا نلقي نظرة على كيفية استخدامه، ونشير إلى بعض طرق استخدام ECharts أولاً، نقوم بتمرير علامة html لعرض المخطط، ثم استدعاء init، وتمرير البيانات أثناء التهيئة.
var con=document.getElementById('container'); var Chart=new Bar(con); Chart.init({ title:'الرسم البياني لهطول الأمطار على مدار العام'، xAxis:{// بيانات المحور السيني: ["يناير"، "فبراير"، "مارس"، "أبريل"، "مايو"، "يونيو"، "يوليو"، "أغسطس"، "سبتمبر"، "أكتوبر"، "نوفمبر"، 'ديسمبر'] }، المحور ص:{// اسم المحور الصادي: 'حجم المياه'، المنسق:'{القيمة} مل' }، السلسلة:[//بيانات المجموعة{ الاسم:'الهطول في الشرق'، البيانات:[62,20,17,45,100,56,19,38,50,120,56,130] }, { الاسم:'الهطول في الغرب'، البيانات:[52,10,17 ,25 ,60,39,19,48,70,30,56,8] }, { الاسم:'هطول الأمطار الجنوبي', البيانات:[12,10,17,25,27,39,50,38,100,30,56,90] }, { اللون:'hsla(270,80%,60%,1)'، الاسم:'هطول الأمطار الشمالي الكمية'، البيانات:[12,30,17,25,7,39,49,38,60,30,56,10] } ] });بالنسبة للفئة الأساسية للمخططات، سنكتب أيضًا مخططات دائرية ومخططات خطية لاحقًا، لذلك سنقوم باستخراج الأجزاء المشتركة. لاحظ أن Canvas.style.width وcanvas.width مختلفان، فالأول سوف يقوم بتمديد الرسومات، في حين أن الأخير هو ما نستخدمه بشكل طبيعي ولن يقوم بتمديد الرسومات. الغرض من كتابة التوسيع الأول ثم التخفيض هنا هو حل مشكلة عدم وضوح النص عند رسم النص على القماش.
class Chart{ buildor(container){ this.container=container; this.canvas=document.createElement('canvas'); this.ctx=this.canvas.getContext('2d'); this.H=600*2; this.padding=120; this.paddingTop=50; this.series=[]; // حل مشكلة طمس الخط عن طريق مضاعفة الحجم this.canvas.width=this.W; this.canvas.height=this.H; 2 + 'px'; this.canvas.style.height = this.H/2 + 'px'; } }لتهيئة الرسم البياني، قم باستدعاء Object.assi(this,opt) في es6. وهذا يعادل الطريقة الممتدة في JQ، والتي تنسخ الخصائص إلى المثيل الحالي. وفي الوقت نفسه، يتم أيضًا إنشاء سمة تلميح، وهي علامة html وتستخدم لعرض معلومات البيانات لاحقًا. ثم ارسم الرسومات واربط أحداث الماوس.
this.yAxis=[]; this.animateArr=[] } init(opt){ Object.sign(this,opt) ; if(!this.container)return; this.container.style.position='relative'; this.tip.style.cssText='display: none; : 99;'; this.container.appendChild(this.canvas); this.draw(); this.bindEvent(); } draw(){//Drawing} showInfo(){//عرض المعلومات} animate(){//تنفيذ الرسوم المتحركة} showData(){//عرض البيانات}ارسم المحور XY
قم أولاً برسم العنوان، ثم المحور XY، ثم اجتياز سلسلة البيانات المجمعة، التي تحتوي على حسابات معقدة، ثم ارسم مقياس المحور XY، وارسم تسميات المجموعة، وأخيرًا ارسم البيانات. سلسلة عناصر البيانات عبارة عن بيانات مجمعة تتوافق مع xAxis.data للمحور السيني واحد لواحد. يمكن أن يكون لكل عنصر اسم ولون مخصصان، إذا لم يتم تحديده، فسيتم إعطاء الاسم بدون اسم ويتم إنشاء اللون تلقائيًا. تُستخدم سمة وسيلة الإيضاح هنا أيضًا لتسجيل معلومات قائمة العلامات، لأنها مفيدة لنقرات الماوس اللاحقة لتحديد ما إذا كانت النقرة صحيحة.
نقاط المعرفة الرئيسية للقماش:
draw(){ var that=this, ctx=this.ctx, Canvas=this.canvas, W=this.W, H=this.H, الحشو=this.padding, paddingTop=this.paddingTop, xl=0,xs=0,xdis=W-padding*2,// عدد وحدات المحور x، طول كل وحدة، إجمالي طول المحور x yl=0,ys=0,ydis=H-padding* 2-paddingTop; // عدد وحدات المحور الصادي، طول كل وحدة، الطول الإجمالي للمحور الصادي ctx.fillStyle='hsla(0,0%,20%,1)'; ctx.strokeStyle='hsla(0,0%,10%,1)'; ctx.lineWidth=1; ctx.textAlign='center'; ctx.clearRect(0,0,W,H); ctx.textAlign='left'; ctx.font='bold 40px arial'; ctx.fillText(this.title,padding-50,70); } if(this.yAxis&&this.yAxis.name) { ctx.fillText(this.yAxis.name,padding,padding+paddingTop-30 }); // المحور السيني ctx.save(); ctx.beginPath(); ctx.translate(padding,H-padding ctx.moveTo(0,0); ctx .stroke(); // مقياس المحور السيني 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. lineTo(x,10); ctx.fillText(obj,x-xs/2,40 }); ctx.restore(); // المحور الصادي ctx.save(); ctx.beginPath(); .moveTo(0,0); ctx.lineTo(0,2*padding+paddingTop-H); ctx.stroke(); ctx.restore(); if(this.series.length){ var curr,txt,dim,info,item,tw=0; for(var i=0;i<this.series.length ;i++){ item=this.series[i]; if(!item.data||!item.data.length){ this.series.splice(i--,1);continue } // قم بتعيين العناصر بدون لون 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'; // رسم تسميات التجميع ctx.save(); ctx.translate(padding+W/4,paddingTop+40); that.legend.push({ إخفاء:item.hide||خطأ, الاسم:item.name, اللون:item.color, x:padding+that.W /4+i*90+tw, y:paddingTop+40, w:60, h:30, r:5 }); ctx.textAlign='left'; ctx.fillStyle=item.color; ctx.strokeStyle=item.color; roundRect(ctx,i*90+tw,0,60,30,5); (); ctx.fillText(item.name,i*90+tw+70,26); tw+=ctx.measureText(item.name).width;// احسب طول الحرف ctx.restore(); if(item.hide)continue; // احسب البيانات على مقياس المحور Y if(!info){ info=calculateY( item.data.slice(0,xl)); } curr=calculateY(item.data.slice(0,xl)); info=curr } } if(!info) return; yl=info.num; ) '; ctx.translate(padding,H-padding); for(var i=0;i<=yl;i++){ ctx.beginPath(); ctx.strokeStyle='hsl(220,100%,50%)'; ctx.moveTo(-10,-Math.floor(ys*i)); ctx.stroke(); ctx.beginPath(); ctx.strokeStyle='hsla(0,0%,80%,1)'; ctx.moveTo(0,-Math.floor(ys*i)); ctx.lineTo(xdis,-Math.floor(ys*i)); ctx.textAlign='right'; Math.min(Math.floor(info.step*i),info.max); txt=this.yAxis.formatter?this.yAxis.formatter.replace('{value}',dim):dim; ctx.fillText(txt,-20,-ys*i+10); // ارسم البيانات this.showData(xl,xs,info.max }}); بيانات المؤامرةنظرًا لأن عنصر البيانات يجب أن يتم تحريكه لاحقًا وعرضه عند تمرير الماوس فوقه، يتم وضعه في قائمة انتظار الرسوم المتحركة animateArr. نحتاج هنا إلى توسيع البيانات المجمعة، وتحويل المصفوفتين المتداخلتين السابقتين إلى طبقة واحدة، وحساب سمات كل عنصر بيانات، مثل الاسم، والإحداثي x، والإحداثي y، والعرض، والسرعة، واللون. بعد تنظيم البيانات، يتم تنفيذ الرسوم المتحركة.
showData(xl,xs,max){ // ارسم البيانات var that=this, ctx=this.ctx, ydis=this.H-this.padding*2-this.paddingTop, sl=this.series.filter(s=) >!s.hide).length, sp=Math.max(Math.pow(10-sl,2)/3-4,5), w=(xs-sp*(sl+1))/sl, h,x,index=0; that.animateArr.length=0; // قم بتوسيع عناصر البيانات وملء قائمة انتظار الرسوم المتحركة for(var i=0 ,item ,len=this.series.length;i<len;i++){ item=this.series[i]; item.data.slice(0,xl).forEach((d,j)=>{ h=d/max*ydis; x=xs*j+w*index+sp*(index+1); that.animateArr .push({ Index:i, name:item.name, num: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, color:item.color }); تنفيذ الرسوم المتحركةليس هناك الكثير مما يمكن قوله عن تنفيذ الرسوم المتحركة، فهي مجرد وظيفة إغلاق ذاتية التنفيذ. مبدأ الرسوم المتحركة هو تجميع قيمة السرعة بشكل تسلسلي على المحور ص. لكن تذكر أنه عندما تنتهي قائمة الانتظار من تنفيذ الرسوم المتحركة، يجب إيقافها، لذلك هناك علامة isStop، والتي يتم الحكم عليها في كل مرة تنتهي فيها قائمة الانتظار من التنفيذ.
animate(){ var that=this, ctx=this.ctx, isStop=true; (function run(){ isStop=true; for(var i=0,item;i<that.animateArr.length;i++){ item =that.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(that.padding+item.x,that.H-that.padding); .fillRect(that.padding+item.x,that.H-that.padding-item.y,item.w,item.y); this.isStop=false } } if(isStop)return; حدث ملزمالحدث 1: عند تحريك الماوس، تحقق مما إذا كان موضع الماوس على تسمية المجموعة أو عنصر البيانات. بعد رسم المسار، اتصل بـ isPointInPath(x,y) إذا كان صحيحًا، Canvas.style.cursor='pointer'; عنصر بيانات، وتحتاج أيضًا إلى إعادة رسم العمود وتعيين الشفافية وتمييزه. يجب أيضًا عرض المحتوى. فيما يلي div الذي تم وضعه بشكل مطلق بالنسبة لحاوية الحاوية الأصلية. تم إنشاء سمة التلميح أثناء التهيئة. نقوم بتغليف جزء العرض في طريقة showInfo.
الحدث 2: عند حدوث هبوط بالماوس، حدد تسمية المجموعة التي ينقر عليها الماوس، ثم قم بتعيين سمة الإخفاء في سلسلة بيانات المجموعة المقابلة. إذا كان هذا صحيحًا، فهذا يعني أنه لن يتم عرض العنصر، ثم قم باستدعاء طريقة الرسم وتجاوز العرض والرسم، وقم بتنفيذ الرسوم المتحركة.
bindEvent(){ var that=this, Canvas=this.canvas, ctx=this.ctx; this.canvas.addEventListener('mousemove',function(e){ var isLegend=false; // pos=WindowToCanvas(canvas,e) .clientX,e.clientY); var box=canvas.getBoundingClientRect(); var pos = { x:e.clientX-box.left, y:e.clientY-box.top }; // تسمية التجميع for(var i=0,item,len=that.legend.length;i<len;i++){ item =that.legend[i]; ctx.save(); roundRect(ctx,item.x,item.y,item.w,item.h,item.r); نظرًا لأنه مضاعف، تكون الإحداثيات *2 if(ctx.isPointInPath(pos.x*2,pos.y*2)){ Canvas.style.cursor='ctx.restore(); isLegend=true ; Break; } Canvas.style.cursor='default'; ctx.restore(); } if(isLegend) return; i=0,item,len=that.animateArr.length;i<len;i++){ item=that.animateArr[i]; ctx.fillStyle=item.color; ctx.rect(that.padding+item.x,that.H-that.padding-item.h,item.w,item.h); if(ctx.isPointInPath(pos.x*2,pos.y*2)){ // امسح الرسومات ثم أعد رسمها بشفافية 0.5 ctx.clearRect(that.padding+item.x,that.H-that padding-item.h,item.w,item.h); ctx.globalAlpha=0.5; that.showInfo(pos,item); ctx.restore(); } Canvas.style.cursor='default'; ctx.restore(); } },false); e.preventDefault(); var box=canvas.getBoundingClientRect(); var pos = { x:e.clientX-box.left, y:e.clientY-box.top }; =that.legend.length;i<len;i++){ item=that.legend[i]; roundRect(ctx,item.x,item.y,item.w,item.h,item.r); // لأنه مضاعف، تكون الإحداثيات *2 if(ctx.isPointInPath(pos.x*2, pos .y*2)){ that.series[i].hide=!that.series[i].hide; that.animateArr.length=0; },false); } // عرض البيانات showInfo(pos,obj){ var txt=this.yAxis.formatter?this.yAxis.formatter.replace('{value}',obj.num):obj.num; box=this.canvas.getBoundingClientRect(); var con=this.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='block' } تلخيصما تم إكماله هنا هو مجرد تأثير أساسي، في الواقع، هناك العديد من المجالات التي تحتاج إلى مزيد من التحسين، مثل الدعم سريع الاستجابة، ودعم الهاتف المحمول، وتأثيرات الرسوم المتحركة، ودعم المحاور المتعددة، وتأثيرات محتوى العرض، ودعم الوظائف المتعددة الخطوط. .
ما ورد أعلاه هو المحتوى الكامل لهذه المقالة وآمل أن يكون مفيدًا لدراسة الجميع وآمل أيضًا أن يدعم الجميع شبكة VeVb Wulin.