canvas圖表詳解系列(2):折線圖

 

本章建議學習時間4小時javascript

學習方式:詳細閱讀,並手動實現相關代碼(若是沒有canvas基礎,須要先學習前面的canvas基礎筆記)html

學習目標:此教程將教會你們如何使用canvas繪製各類圖表,詳細分解步驟,本次講解折線圖。前端

 

源文件下載地址:https://github.com/sutianbinde/chartsjava

 

折線圖git


折線圖是前端最基本的圖表之一,咱們的案例展現效果以下github

 

功能:橫軸月份,縱軸訪問量,圖表會根據月份和訪問量的多少自動調整高度和間距,高度會有由低到高的運動效果。點擊圖表會有刷新重載動畫效果。canvas

 

實現步驟瀏覽器


 

--新建Html文件,寫入canvas標籤,而且定義繪製圖表的方法學習

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .a{
            background: #0bfefb;
        }
    </style>
</head>
<body>
    <canvas id="chart" height="400" width="600" style="margin:50px"> 你的瀏覽器不支持HTML5 canvas </canvas>

    <script type="text/javascript">
        function goChart(dataArr){
        
            
        }
        
        var chartData = [["2017/01", 50], ["2017/02", 60], ["2017/03", 100], ["2017/04",200], ["2017/05",350], ["2017/06",600]];
        goChart(chartData);


    </script>
</body>
</html>

 

--在 goChart方法中定義須要使用的變量 並獲取 canvas上下文 ,而且初始化圖表動畫

注:這裏咱們對高清屏幕顯示模糊作了處理,具體的處理方式見代碼註釋

            // 聲明所需變量
            var canvas,ctx;
            // 圖表屬性
            var cWidth, cHeight, cMargin, cSpace;
            var originX, originY;
            // 折線圖屬性
            var tobalDots, dotSpace, maxValue;
            var totalYNomber;
            // 運動相關變量
            var ctr, numctr, speed;
        
            // 得到canvas上下文
            canvas = document.getElementById("chart");
            if(canvas && canvas.getContext){
                ctx = canvas.getContext("2d");
            }
            initChart(); // 圖表初始化
        
            // 圖表初始化
            function initChart(){
                // 圖表信息
                cMargin = 60;
                cSpace = 80;
                /*這裏是對高清屏幕的處理,
                     方法:先將canvas的width 和height設置成原本的兩倍(原本但願的寬度爲 window的寬度減去100px)
                     而後將style.height 和 style.width設置成原本的寬高
                     這樣至關於把兩倍的東西縮放到原來的大小,這樣在高清屏幕上 一個像素的位置就能夠有兩個像素的值
                     這樣須要注意的是全部的寬高間距,文字大小等都得設置成原來的兩倍才能夠。
                */
                canvas.width = Math.floor( (window.innerWidth-100)/2 ) * 2 ;
                canvas.height = 740;
                canvas.style.height = canvas.height/2 + "px";
                canvas.style.width = canvas.width/2 + "px";
                cHeight = canvas.height - cMargin - cSpace;
                cWidth = canvas.width - cMargin - cSpace;
                originX = cMargin + cSpace;
                originY = cMargin + cHeight;
        
                // 折線圖信息
                tobalDots = dataArr.length;
                dotSpace = parseInt( cWidth/tobalDots );
                maxValue = 0;
                for(var i=0; i<dataArr.length; i++){
                    var dotVal = parseInt( dataArr[i][1] );
                    if( dotVal > maxValue ){
                        maxValue = dotVal;
                    }
                }
                maxValue += 50;
                totalYNomber = 10;
                // 運動相關
                ctr = 1;
                numctr = 100;
                speed = 6;
        
                ctx.translate(0.5,0.5);  // 當只繪製1像素的線的時候,座標點須要偏移,這樣才能畫出1像素實線
            }
        

 

--繪製圖表的軸和標記 (接着上一步的代碼寫在 goChart方法中 )

            
            drawLineLabelMarkers(); // 繪製圖表軸、標籤和標記
            
            // 繪製圖表軸、標籤和標記
            function drawLineLabelMarkers(){
                ctx.font = "24px Arial";
                ctx.lineWidth = 2;
                ctx.fillStyle = "#566a80";
                ctx.strokeStyle = "#566a80";
                // y軸
                drawLine(originX, originY, originX, cMargin);
                // x軸
                drawLine(originX, originY, originX+cWidth, originY);
        
                // 繪製標記
                drawMarkers();
            }
        
            // 畫線的方法
            function drawLine(x, y, X, Y){
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.lineTo(X, Y);
                ctx.stroke();
                ctx.closePath();
            }
        
            // 繪製標記
            function drawMarkers(){
                ctx.strokeStyle = "#E0E0E0";
                // 繪製 y 軸 及中間橫線
                var oneVal = parseInt(maxValue/totalYNomber);
                ctx.textAlign = "right";
                for(var i=0; i<=totalYNomber; i++){
                    var markerVal =  i*oneVal;
                    var xMarker = originX-5;
                    var yMarker = parseInt( cHeight*(1-markerVal/maxValue) ) + cMargin;
                    
                    ctx.fillText(markerVal, xMarker, yMarker+3, cSpace); // 文字
                    if(i>0){
                        drawLine(originX+2, yMarker, originX+cWidth, yMarker);
                    }
                }
                // 繪製 x 軸 及中間豎線
                ctx.textAlign = "center";
                for(var i=0; i<tobalDots; i++){
                    var markerVal = dataArr[i][0];
                    var xMarker = originX+i*dotSpace;
                    var yMarker = originY+30;
                    ctx.fillText(markerVal, xMarker, yMarker, cSpace); // 文字
                    if(i>0){
                        drawLine(xMarker, originY-2, xMarker, cMargin    );
                    }
                }
                // 繪製標題 y
                ctx.save();
                ctx.rotate(-Math.PI/2);
                ctx.fillText("訪問量", -canvas.height/2, cSpace-10);
                ctx.restore();
                // 繪製標題 x
                ctx.fillText("月份", originX+cWidth/2, originY+cSpace/2+20);
            };
        

 

 

 -- 繪製折線圖(接着上一步的代碼寫在 goChart方法中 )

            drawLineAnimate(); // 繪製折線圖的動畫
            
            //繪製折線圖
            function drawLineAnimate(){
                ctx.strokeStyle = "#566a80";  //"#49FE79";
        
                //連線
                ctx.beginPath();
                for(var i=0; i<tobalDots; i++){
                    var dotVal = dataArr[i][1];
                    var barH = parseInt( cHeight*dotVal/maxValue* ctr/numctr );//
                    var y = originY - barH;
                    var x = originX + dotSpace*i;
                    if(i==0){
                        ctx.moveTo( x, y );
                    }else{
                        ctx.lineTo( x, y );
                    }
                }
                ctx.stroke();
        
                //背景
                ctx.lineTo( originX+dotSpace*(tobalDots-1), originY);
                ctx.lineTo( originX, originY);
                //背景漸變色
                //柱狀圖漸變色
                var gradient = ctx.createLinearGradient(0, 0, 0, 300);
                gradient.addColorStop(0, 'rgba(133,171,212,0.6)');
                gradient.addColorStop(1, 'rgba(133,171,212,0.1)');
                ctx.fillStyle = gradient;
                ctx.fill();
                ctx.closePath();
                ctx.fillStyle = "#566a80";
        
                //繪製點
                for(var i=0; i<tobalDots; i++){
                    var dotVal = dataArr[i][1];
                    var barH = parseInt( cHeight*dotVal/maxValue * ctr/numctr );
                    var y = originY - barH;
                    var x = originX + dotSpace*i;
                    drawArc( x, y );  //繪製點
                    ctx.fillText(parseInt(dotVal*ctr/numctr), x+15, y-8); // 文字
                }
        
                if(ctr<numctr){
                    ctr++;
                    setTimeout(function(){
                        ctx.clearRect(0,0,canvas.width, canvas.height);
                        drawLineLabelMarkers();
                        drawLineAnimate();
                    }, speed);
                }
            }
        
            //繪製圓點
            function drawArc( x, y, X, Y ){
                ctx.beginPath();
                ctx.arc( x, y, 3, 0, Math.PI*2 );
                ctx.fill();
                ctx.closePath();
            }
        

 

--當點擊canvas的時候從新刷新圖表(接着上一步的代碼寫在 goChart方法中 )

            
            //點擊刷新圖表
            canvas.onclick = function(){
                initChart(); // 圖表初始化
                drawLineLabelMarkers(); // 繪製圖表軸、標籤和標記
                drawLineAnimate(); // 繪製折線圖的動畫
            };

 

 

 

這樣咱們整個代碼就編寫完成了,爲了代碼更便於閱讀,咱們能夠將全部方法放到後面,把調用方法的代碼放到前面,通過調整的所有代碼以下

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .a{
            background: #0bfefb;
        }
    </style>
</head>
<body>
    <canvas id="chart" height="400" width="600" style="margin:50px"> 你的瀏覽器不支持HTML5 canvas </canvas>

    <script type="text/javascript">
        function goChart(dataArr){
        
        
            // 聲明所需變量
            var canvas,ctx;
            // 圖表屬性
            var cWidth, cHeight, cMargin, cSpace;
            var originX, originY;
            // 折線圖屬性
            var tobalDots, dotSpace, maxValue;
            var totalYNomber;
            // 運動相關變量
            var ctr, numctr, speed;
        
            // 得到canvas上下文
            canvas = document.getElementById("chart");
            if(canvas && canvas.getContext){
                ctx = canvas.getContext("2d");
            }
            initChart(); // 圖表初始化
            drawLineLabelMarkers(); // 繪製圖表軸、標籤和標記
            drawLineAnimate(); // 繪製折線圖的動畫
        
            //點擊刷新圖表
            canvas.onclick = function(){
                initChart(); // 圖表初始化
                drawLineLabelMarkers(); // 繪製圖表軸、標籤和標記
                drawLineAnimate(); // 繪製折線圖的動畫
            };
        
            // 圖表初始化
            function initChart(){
                // 圖表信息
                cMargin = 60;
                cSpace = 80;
                /*這裏是對高清屏幕的處理,
                     方法:先將canvas的width 和height設置成原本的兩倍
                     而後將style.height 和 style.width設置成原本的寬高
                     這樣至關於把兩倍的東西縮放到原來的 1/2,這樣在高清屏幕上 一個像素的位置就能夠有兩個像素的值
                     這樣須要注意的是全部的寬高間距,文字大小等都得設置成原來的兩倍才能夠。
                */
                canvas.width = Math.floor( (window.innerWidth-100)/2 ) * 2 ;
                canvas.height = 740;
                canvas.style.height = canvas.height/2 + "px";
                canvas.style.width = canvas.width/2 + "px";
                cHeight = canvas.height - cMargin - cSpace;
                cWidth = canvas.width - cMargin - cSpace;
                originX = cMargin + cSpace;
                originY = cMargin + cHeight;
        
                // 折線圖信息
                tobalDots = dataArr.length;
                dotSpace = parseInt( cWidth/tobalDots );
                maxValue = 0;
                for(var i=0; i<dataArr.length; i++){
                    var dotVal = parseInt( dataArr[i][1] );
                    if( dotVal > maxValue ){
                        maxValue = dotVal;
                    }
                }
                maxValue += 50;
                totalYNomber = 10;
                // 運動相關
                ctr = 1;
                numctr = 100;
                speed = 6;
        
                ctx.translate(0.5,0.5);  // 當只繪製1像素的線的時候,座標點須要偏移,這樣才能畫出1像素實線
            }
        
            // 繪製圖表軸、標籤和標記
            function drawLineLabelMarkers(){
                ctx.font = "24px Arial";
                ctx.lineWidth = 2;
                ctx.fillStyle = "#566a80";
                ctx.strokeStyle = "#566a80";
                // y軸
                drawLine(originX, originY, originX, cMargin);
                // x軸
                drawLine(originX, originY, originX+cWidth, originY);
        
                // 繪製標記
                drawMarkers();
            }
        
            // 畫線的方法
            function drawLine(x, y, X, Y){
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.lineTo(X, Y);
                ctx.stroke();
                ctx.closePath();
            }
        
            // 繪製標記
            function drawMarkers(){
                ctx.strokeStyle = "#E0E0E0";
                // 繪製 y 軸 及中間橫線
                var oneVal = parseInt(maxValue/totalYNomber);
                ctx.textAlign = "right";
                for(var i=0; i<=totalYNomber; i++){
                    var markerVal =  i*oneVal;
                    var xMarker = originX-5;
                    var yMarker = parseInt( cHeight*(1-markerVal/maxValue) ) + cMargin;
                    
                    ctx.fillText(markerVal, xMarker, yMarker+3, cSpace); // 文字
                    if(i>0){
                        drawLine(originX+2, yMarker, originX+cWidth, yMarker);
                    }
                }
                // 繪製 x 軸 及中間豎線
                ctx.textAlign = "center";
                for(var i=0; i<tobalDots; i++){
                    var markerVal = dataArr[i][0];
                    var xMarker = originX+i*dotSpace;
                    var yMarker = originY+30;
                    ctx.fillText(markerVal, xMarker, yMarker, cSpace); // 文字
                    if(i>0){
                        drawLine(xMarker, originY-2, xMarker, cMargin    );
                    }
                }
                // 繪製標題 y
                ctx.save();
                ctx.rotate(-Math.PI/2);
                ctx.fillText("訪問量", -canvas.height/2, cSpace-10);
                ctx.restore();
                // 繪製標題 x
                ctx.fillText("月份", originX+cWidth/2, originY+cSpace/2+20);
            };
        
            //繪製折線圖
            function drawLineAnimate(){
                ctx.strokeStyle = "#566a80";  //"#49FE79";
        
                //連線
                ctx.beginPath();
                for(var i=0; i<tobalDots; i++){
                    var dotVal = dataArr[i][1];
                    var barH = parseInt( cHeight*dotVal/maxValue* ctr/numctr );//
                    var y = originY - barH;
                    var x = originX + dotSpace*i;
                    if(i==0){
                        ctx.moveTo( x, y );
                    }else{
                        ctx.lineTo( x, y );
                    }
                }
                ctx.stroke();
        
                //背景
                ctx.lineTo( originX+dotSpace*(tobalDots-1), originY);
                ctx.lineTo( originX, originY);
                //背景漸變色
                //柱狀圖漸變色
                var gradient = ctx.createLinearGradient(0, 0, 0, 300);
                gradient.addColorStop(0, 'rgba(133,171,212,0.6)');
                gradient.addColorStop(1, 'rgba(133,171,212,0.1)');
                ctx.fillStyle = gradient;
                ctx.fill();
                ctx.closePath();
                ctx.fillStyle = "#566a80";
        
                //繪製點
                for(var i=0; i<tobalDots; i++){
                    var dotVal = dataArr[i][1];
                    var barH = parseInt( cHeight*dotVal/maxValue * ctr/numctr );
                    var y = originY - barH;
                    var x = originX + dotSpace*i;
                    drawArc( x, y );  //繪製點
                    ctx.fillText(parseInt(dotVal*ctr/numctr), x+15, y-8); // 文字
                }
        
                if(ctr<numctr){
                    ctr++;
                    setTimeout(function(){
                        ctx.clearRect(0,0,canvas.width, canvas.height);
                        drawLineLabelMarkers();
                        drawLineAnimate();
                    }, speed);
                }
            }
        
            //繪製圓點
            function drawArc( x, y, X, Y ){
                ctx.beginPath();
                ctx.arc( x, y, 3, 0, Math.PI*2 );
                ctx.fill();
                ctx.closePath();
            }
    
    
        }
        
        var chartData = [["2017/01", 50], ["2017/02", 60], ["2017/03", 100], ["2017/04",200], ["2017/05",350], ["2017/06",600]];
        goChart(chartData);


    </script>
</body>
</html>

 

 

好了,今天就講到這裏,但願你們把代碼都本身敲一遍。

 

 

關注公衆號,博客更新便可收到推送

相關文章
相關標籤/搜索