Heim Web-Frontend H5-Tutorial Das H5-Canvas-Diagramm implementiert ein Balkendiagramm

Das H5-Canvas-Diagramm implementiert ein Balkendiagramm

Mar 27, 2018 pm 02:27 PM
canvas html5

Dieses Mal zeige ich Ihnen ein H5-Canvas-Diagramm zur Implementierung eines Histogramms. Was sind die Vorsichtsmaßnahmen für die Implementierung eines Histogramms in einem Canvas-Diagramm?

Ich habe vor ein paar Tagen eine Diagrammbibliothek verwendet, von der Baidus ECharts die beste zu sein scheint. Canvas-Diagramme sind bei der Verarbeitung großer Datenmengen besser. Dann werde ich auch Canvas verwenden, um eine Diagrammbibliothek zu implementieren. Es fühlt sich nicht allzu schwierig an. Lassen Sie uns zuerst ein einfaches Balkendiagramm implementieren.

Der Effekt ist wie folgt:

Die Hauptfunktionspunkte umfassen:

  1. Textzeichnung

  2. XY-Achsenzeichnung;

  3. Datengruppenzeichnung;

  4. Implementierung von Datenanimationen;

  5. Behandlung von Mausereignissen.

Verwendungsmethode

Werfen wir zunächst einen Blick auf die Verwendungsmethode einiger ECharts Übergeben Sie das html-Tag

anzuzeigen, rufen Sie dann init auf und übergeben Sie Daten während der Initialisierung.

Diagrammbasisklasse Wir werden später auch Kreisdiagramme und Liniendiagramme schreiben, also extrahieren Sie die gemeinsamen Teile. Beachten Sie, dass „canvas.style.width“ und „canvas.width“ unterschiedlich sind. Ersteres streckt die Grafiken, während letzteres normalerweise verwendet wird und die Grafiken nicht streckt. Der Zweck, den Text hier zunächst zu vergrößern und dann zu verkleinern, besteht darin, das Problem der Unschärfe beim Zeichnen von Text auf der Leinwand zu lösen.
var con=document.getElementById('container');
    var chart=new Bar(con);
    chart.init({
        title:'全年降雨量柱状图',
        xAxis:{// x轴
            data:['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月']
        },
        yAxis:{//y轴
            name:'水量',
            formatter:'{value} ml'
        },
        series:[//分组数据
            {
                name:'东部降水量',
                data:[62,20,17,45,100,56,19,38,50,120,56,130]
            },
            {
                name:'西部降水量',
                data:[52,10,17,25,60,39,19,48,70,30,56,8]
            },
            {
                name:'南部降水量',
                data:[12,10,17,25,27,39,50,38,100,30,56,90]
            },
            {
                color:'hsla(270,80%,60%,1)',
                name:'北部降水量',
                data:[12,30,17,25,7,39,49,38,60,30,56,10]
            }
        ]
    });
Nach dem Login kopieren

Um das Histogramm zu initialisieren, rufen Sie Object.assign(this,opt) in es6 auf. Dies entspricht der Extend-Methode in JQ, die die Eigenschaften in die aktuelle Instanz kopiert. Gleichzeitig wird auch ein Tip-Attribut erstellt, das ein HTML-Tag ist und zur späteren Anzeige von Dateninformationen verwendet wird. Zeichnen Sie dann die Grafiken und binden Sie Mausereignisse.
class Chart{
        constructor(container){
            this.container=container;
            this.canvas=document.createElement('canvas');
            this.ctx=this.canvas.getContext('2d');
            this.W=1000*2;
            this.H=600*2;
            this.padding=120;
            this.paddingTop=50;
            this.title='';
            this.legend=[];
            this.series=[];
            //通过缩小一倍,解决字体模糊问题
            this.canvas.width=this.W;
            this.canvas.height=this.H;
            this.canvas.style.width = this.W/2 + 'px';
            this.canvas.style.height = this.H/2 + 'px';
        }
    }
Nach dem Login kopieren

Zeichnen Sie die XY-Achse
class Bar extends Chart{
    constructor(container){
        super(container);
        this.xAxis={};
        this.yAxis=[];
        this.animateArr=[];
    }
    init(opt){
        Object.assign(this,opt);
        if(!this.container)return;
        this.container.style.position='relative';
        this.tip=document.createElement('p');
        this.tip.style.cssText='display: none; position: absolute; opacity: 0.5; background: #000; color: #fff; border-radius: 5px; padding: 5px; font-size: 8px; z-index: 99;';
        this.container.appendChild(this.canvas);
        this.container.appendChild(this.tip);
        this.draw();
        this.bindEvent();
    }
    draw(){//绘制
    }
    showInfo(){//显示信息
    }
    animate(){//执行动画
    }
    showData(){//显示数据
    }
Nach dem Login kopieren

Zeichnen Sie zuerst den Titel, dann die XY-Achse, durchlaufen Sie dann die gruppierte Datenreihe, die komplexe Berechnungen enthält, und zeichnen Sie dann den Maßstab der XY-Achse. Zeichnen Sie die Gruppenbeschriftung und schließlich die aufgezeichneten Daten. Bei der Datenelementreihe handelt es sich um gruppierte Daten, die eins zu eins den xAxis.data der X-Achse entsprechen. Jedes Element kann einen benutzerdefinierten Namen und eine benutzerdefinierte Farbe haben. Wenn nicht angegeben, wird der Name an nunamed vergeben und die Farbe wird automatisch generiert. Das Legendenattribut wird hier auch zum Aufzeichnen der Tag-Listeninformationen verwendet, da es bei nachfolgenden Mausklicks nützlich ist, um festzustellen, ob der Klick korrekt ist.

Hauptwissenspunkte von Canvas:

    Das Gruppierungs-Tag verwendet die arcTo-Methode, sodass der Effekt abgerundeter Ecken gezeichnet werden kann.
  1. Zeichnungstext verwendet die Methode „measureText“, mit der die Breite des Textes gemessen werden kann, sodass die Position der nächsten Zeichnung angepasst werden kann, um Positionskonflikte zu vermeiden.
  2. Die Verschiebungsmethode übersetzen kann im Zeichnungskontext (zwischen Speichern und Wiederherstellen) platziert werden, wodurch komplexe Positionsberechnungen vermieden werden können.
draw(){
    var that=this,
        ctx=this.ctx,
        canvas=this.canvas,
        W=this.W,
        H=this.H,
        padding=this.padding,
        paddingTop=this.paddingTop,
        xl=0,xs=0,xdis=W-padding*2,//x轴单位数,每个单位长度,x轴总长度
        yl=0,ys=0,ydis=H-padding*2-paddingTop;//y轴单位数,每个单位长度,y轴总长度
    ctx.fillStyle='hsla(0,0%,20%,1)';
    ctx.strokeStyle='hsla(0,0%,10%,1)';
    ctx.lineWidth=1;
    ctx.textAlign='center';
    ctx.textBaseLine='middle';
    ctx.font='24px arial';
    ctx.clearRect(0,0,W,H);
    if(this.title){
        ctx.save();
        ctx.textAlign='left';
        ctx.font='bold 40px arial';
        ctx.fillText(this.title,padding-50,70);
        ctx.restore();
    }
    if(this.yAxis&&this.yAxis.name){
        ctx.fillText(this.yAxis.name,padding,padding+paddingTop-30);
    }
    // x轴
    ctx.save();
    ctx.beginPath();
    ctx.translate(padding,H-padding);
    ctx.moveTo(0,0);
    ctx.lineTo(W-2*padding,0);
    ctx.stroke();
    // 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.lineTo(x,10);
            ctx.stroke();
            ctx.fillText(obj,x-xs/2,40);
        });
    }
    ctx.restore();
    // y轴
    ctx.save();
    ctx.beginPath();
    ctx.strokeStyle='hsl(220,100%,50%)';
    ctx.translate(padding,H-padding);
    ctx.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=&#39;hsla(&#39;+hsl+&#39;,70%,60%,1)&#39;;
            }
            item.name=item.name||&#39;unnamed&#39;;
            // 画分组标签
            ctx.save();
            ctx.translate(padding+W/4,paddingTop+40);
            that.legend.push({
                hide:item.hide||false,
                name:item.name,
                color:item.color,
                x:padding+that.W/4+i*90+tw,
                y:paddingTop+40,
                w:60,
                h:30,
                r:5
            });
            ctx.textAlign=&#39;left&#39;;
            ctx.fillStyle=item.color;
            ctx.strokeStyle=item.color;
            roundRect(ctx,i*90+tw,0,60,30,5);
            ctx.globalAlpha=item.hide?0.3:1;
            ctx.fill();
            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));
            if(curr.max>info.max){
                info=curr;
            }
        }
        if(!info) return;
        yl=info.num;
        ys=ydis/yl;
        //画Y轴刻度
        ctx.save();
        ctx.fillStyle='hsl(200,100%,60%)';
        ctx.translate(padding,H-padding);
        for(var i=0;i<=yl;i++){
            ctx.beginPath();
            ctx.strokeStyle=&#39;hsl(220,100%,50%)&#39;;
            ctx.moveTo(-10,-Math.floor(ys*i));
            ctx.lineTo(0,-Math.floor(ys*i));
            ctx.stroke();
            ctx.beginPath();
            ctx.strokeStyle=&#39;hsla(0,0%,80%,1)&#39;;
            ctx.moveTo(0,-Math.floor(ys*i));
            ctx.lineTo(xdis,-Math.floor(ys*i));
            ctx.stroke();
            ctx.textAlign=&#39;right&#39;;
            dim=Math.min(Math.floor(info.step*i),info.max);
            txt=this.yAxis.formatter?this.yAxis.formatter.replace(&#39;{value}&#39;,dim):dim;
            ctx.fillText(txt,-20,-ys*i+10);
        }
        ctx.restore();
        //画数据
        this.showData(xl,xs,info.max);
    }
}
Nach dem Login kopieren
Daten zeichnen

Da das Datenelement nachfolgende Animationen ausführen und Inhalte anzeigen muss, wenn die Maus darüber gleitet, fügen Sie es ein Animationswarteschlange animateArr. Hier müssen wir die gruppierten Daten erweitern, die beiden vorherigen verschachtelten Arrays in eine Ebene konvertieren und die Attribute jedes Datenelements berechnen, z. B. Name, X-Koordinate, Y-Koordinate, Breite, Geschwindigkeit und Farbe. Nachdem die Daten organisiert sind, wird die Animation ausgeführt.

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];
        if(item.hide)continue;
        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
            });
        });
        index++;
    }
    this.animate();
}
Nach dem Login kopieren
Animation ausführen

Zur Ausführung einer Animation gibt es nichts zu sagen. Es handelt sich um eine selbstausführende Abschlussfunktion. Das Prinzip der Animation besteht darin, den Geschwindigkeitswert vy sequentiell auf der y-Achse zu akkumulieren. Denken Sie jedoch daran, dass die Warteschlange, wenn sie mit der Ausführung der Animation fertig ist, gestoppt werden muss. Daher gibt es ein isStop-Flag, das jedes Mal beurteilt wird, wenn die Warteschlange mit der Ausführung fertig ist.

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);
                ctx.fillStyle=item.color;
                ctx.fillRect(that.padding+item.x,that.H-that.padding-item.y,item.w,item.y);
                ctx.restore();
                isStop=false;
            }
        }
        if(isStop)return;
        requestAnimationFrame(run);
    }())
}
Nach dem Login kopieren
Bindungsereignis

Ereignis 1: Überprüfen Sie beim Bewegen der Maus, ob sich die Mausposition auf der Gruppenbeschriftung oder dem Datenelement befindet, und rufen Sie nach dem Zeichnen des Pfads isPointInPath auf (x, y), wenn true, canvas.style.cursor='pointer'; wenn es sich um ein Datenelement handelt, muss die Spalte neu gezeichnet, die Transparenz festgelegt und unterschieden werden. Hier muss auch ein p mit

absoluter Positionierung

relativ zum übergeordneten Container angezeigt werden. Es wurde bei der Initialisierung als Tip-Attribut festgelegt. Wir kapseln den Anzeigeteil in die showInfo-Methode. Ereignis 2: Bestimmen Sie beim Mousedown, auf welche Gruppenbezeichnung die Maus klickt, und legen Sie dann das Ausblenden-Attribut in der entsprechenden Gruppendatenreihe fest. Wenn es wahr ist, bedeutet dies, dass das Element nicht angezeigt wird Rufen Sie dann die Draw-Methode auf, um das Rendern und Zeichnen zu überschreiben und die Animation auszuführen.

bindEvent(){
        var that=this,
            canvas=this.canvas,
            ctx=this.ctx;
        this.canvas.addEventListener(&#39;mousemove&#39;,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=&#39;pointer&#39;;
                    ctx.restore();
                    isLegend=true;
                    break;
                }
                canvas.style.cursor=&#39;default&#39;;
                ctx.restore();
            }
            if(isLegend) return;
            //选择数据项
            for(var i=0,item,len=that.animateArr.length;i<len;i++){
                item=that.animateArr[i];
                ctx.save();
                ctx.fillStyle=item.color;
                ctx.beginPath();
                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;
                    ctx.fill();
                    canvas.style.cursor=&#39;pointer&#39;;
                    that.showInfo(pos,item);
                    ctx.restore();
                    break;
                }
                canvas.style.cursor=&#39;default&#39;;
                that.tip.style.display=&#39;none&#39;;
                ctx.globalAlpha=1;
                ctx.fill();
                ctx.restore();
            }
            
        },false);
        this.canvas.addEventListener(&#39;mousedown&#39;,function(e){
            e.preventDefault();
            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];
                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;
                    that.draw();
                    break;
                }
            }
        },false);
    }
    //显示数据
    showInfo(pos,obj){
        var txt=this.yAxis.formatter?this.yAxis.formatter.replace(&#39;{value}&#39;,obj.num):obj.num;
        var box=this.canvas.getBoundingClientRect();
        var con=this.container.getBoundingClientRect();
        this.tip.innerHTML = &#39;<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';
    }
Nach dem Login kopieren

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

H5的各种错误用法总结

H5的语义化标签

Das obige ist der detaillierte Inhalt vonDas H5-Canvas-Diagramm implementiert ein Balkendiagramm. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Tabellenrahmen in HTML Tabellenrahmen in HTML Sep 04, 2024 pm 04:49 PM

Anleitung zum Tabellenrahmen in HTML. Hier besprechen wir verschiedene Möglichkeiten zum Definieren von Tabellenrändern anhand von Beispielen für den Tabellenrand in HTML.

HTML-Rand links HTML-Rand links Sep 04, 2024 pm 04:48 PM

Anleitung zum HTML-Rand links. Hier besprechen wir einen kurzen Überblick über HTML margin-left und seine Beispiele sowie seine Code-Implementierung.

Verschachtelte Tabelle in HTML Verschachtelte Tabelle in HTML Sep 04, 2024 pm 04:49 PM

Dies ist eine Anleitung für verschachtelte Tabellen in HTML. Hier diskutieren wir anhand der entsprechenden Beispiele, wie man eine Tabelle innerhalb der Tabelle erstellt.

HTML-Tabellenlayout HTML-Tabellenlayout Sep 04, 2024 pm 04:54 PM

Leitfaden zum HTML-Tabellenlayout. Hier besprechen wir die Werte des HTML-Tabellenlayouts zusammen mit den Beispielen und Ausgaben im Detail.

HTML-Eingabeplatzhalter HTML-Eingabeplatzhalter Sep 04, 2024 pm 04:54 PM

Leitfaden für HTML-Eingabeplatzhalter. Hier besprechen wir die Beispiele für HTML-Eingabeplatzhalter zusammen mit den Codes und Ausgaben.

HTML-geordnete Liste HTML-geordnete Liste Sep 04, 2024 pm 04:43 PM

Leitfaden zur HTML-geordneten Liste. Hier besprechen wir auch die Einführung von HTML-geordneten Listen und Typen sowie deren Beispiele

Text in HTML verschieben Text in HTML verschieben Sep 04, 2024 pm 04:45 PM

Anleitung zum Verschieben von Text in HTML. Hier besprechen wir eine Einführung, wie Marquee-Tags funktionieren, mit Syntax und Beispielen für die Implementierung.

HTML-Onclick-Button HTML-Onclick-Button Sep 04, 2024 pm 04:49 PM

Anleitung zum HTML-OnClick-Button. Hier diskutieren wir deren Einführung, Funktionsweise, Beispiele und Onclick-Events in verschiedenen Veranstaltungen.

See all articles