canvas圖表詳解系列(5):雷達(面積)圖


雷達(面積)圖

 

本章建議學習時間4小時

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

學習目標:此教程將教會大家如何使用canvas繪制各種圖表,本次講解雷達(面積)圖。

 

演示地址:https://sutianbinde.github.io/charts/%E9%9B%B7%E8%BE%BE%EF%BC%88%E9%9D%A2%E7%A7%AF%EF%BC%89%E5%9B%BE-%E9%AB%98%E6%B8%85.html

 

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

 

雷達(面積)圖


雷達(面積)圖,我們的案例展示效果如下

功能:圖表可以根據數據自動變換比例,繪制中間范圍的時候有由小到大的動畫,鼠標移入到對應值會實現顏色變化,並且顯示當前項的詳細信息。

 

實現代碼相對來說比前面講的幾個圖表要簡單些些,具體代碼如下,相應的說明在代碼注釋中

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style type="text/css">
        canvas{border: 1px solid #A4E2F9;}
    </style>
</head>
<body>
    <div id="chart" height="400" width="600" style="margin:30px;"></div>
    
    <script type="text/javascript">
        function goChart(cBox,dataArr,textArr,ifFill){
            // 聲明所需變量
            var canvas,ctx;
            // 圖表屬性
            var cWidth, cHeight, cMargin, cSpace;
            var originX, originY;
            // 主圖屬性
            var tobalDots, maxValue;
            var lineStartAngle,radius;
            var colorArr;

            // 運動相關變量
            var ctr, numctr, speed;
            //鼠標移動
            var mousePosition = {};
            
            // 創建canvas並獲得canvas上下文
               canvas = document.createElement("canvas");
               if(canvas && canvas.getContext){
                ctx = canvas.getContext("2d");
            }
               
               canvas.innerHTML = "你的瀏覽器不支持HTML5 canvas";
               cBox.appendChild(canvas);
            
            initChart(); // 圖表初始化

            // 圖表初始化
            function initChart(){
                // 圖表信息
                cMargin = 60;
                cSpace = 60;
                //將canvas擴大2倍,然后縮小,以適應高清屏幕
                canvas.width = cBox.getAttribute("width")* 2 ;
                canvas.height = cBox.getAttribute("height")* 2;
                canvas.style.height = canvas.height/2 + "px";
                canvas.style.width = canvas.width/2 + "px";
                //cHeight = canvas.height - cMargin*2-cSpace*2;
                //cWidth = canvas.width - cMargin*2-cSpace*2;
                originX = canvas.width/2;
                originY = canvas.height/2;

                // 柱狀圖信息
                tobalDots = textArr.length;
                var allArr = [];
                for(var i=0; i<dataArr.length; i++){
                    allArr = allArr.concat( dataArr[i].value );
                }
                maxValue = Math.max.apply(null,allArr);
                
                colorArr=["#AD93DB","#3AC9CB","#5FB2ED"]; //顏色數據
                // 運動相關
                ctr = 1;
                numctr = 40;
                speed = 1;
                
                textPadding=20;  //文字與文字基線線之間的間距
                lineStartAngle =Math.PI+ Math.PI/tobalDots; //起始繪制角度
                radius = originY-cMargin-cSpace; //半徑
                
            }

            drawLineLabelMarkers(); // 繪制圖表軸、標簽和標記
            // 繪制圖表軸、標簽和標記
            function drawLineLabelMarkers(){
                ctx.font = "24px Arial";
                ctx.lineWidth = 2;
                ctx.strokeStyle = "#DBDBDB";
                ctx.fillStyle = "#000";
                var startAngle = lineStartAngle;
                // 五個底圖環
                for(var i=0; i<6; i++){
                       R = radius*(1-i/5); //五個
                    //畫一個環
                       ctx.beginPath();
                       for(var j=0; j<tobalDots+1; j++){ //多畫一個閉合路徑
                           startAngle = startAngle+2*Math.PI/tobalDots;
                           var x = parseInt( originX+R*Math.cos(startAngle) );
                           var y = originY+R*Math.sin(startAngle);
                           
                           ctx.lineTo(x, y);//點連線
                           ctx.lineTo(originX, originY);//點到圓心連線
                           ctx.moveTo(x, y);
                           
                           //繪制文字
                           if(i==0 && textArr[j]){
                               drawMarkers(textArr[j],x,y)
                           }
                       }
                       
                       if(i%2==0){
                           ctx.fillStyle = "#ECECEC";
                       }else{
                           ctx.fillStyle = "#fff";
                       }
                    ctx.closePath();
                       ctx.fill();
                       ctx.stroke();
                }
                
            }

            // 繪制標記
            function drawMarkers(text,x,y){
                   if(x<originX && y<=originY){
                     ctx.textAlign="right";
                     ctx.fillText(text, x-textPadding, y-textPadding);
                 }else if(x<originX && y>originY){
                     ctx.textAlign="right";
                     ctx.fillText(text, x-textPadding, y+textPadding);
                 }else if(y<=originY){
                     ctx.textAlign="left";
                     ctx.fillText(text, x+textPadding, y-textPadding);
                 }else{
                     ctx.textAlign="left";
                     ctx.fillText(text, x+textPadding, y+textPadding);
                 }
            };
            
            
            drawChartAnimate(); // 繪制動畫
            //繪制動畫
            function drawChartAnimate(mouseMove){
                var ifTip = false;
                var tipArr = null;
                //循環傳入的多組數據
                   for(var i=0; i<dataArr.length; i++){
                    var startAngle = lineStartAngle;
                       var nowArr = dataArr[i].value;
                       var arcArr = [];
                    ctx.lineWidth = 4;
                       
                    ctx.fillStyle = ctx.strokeStyle = colorArr[i%colorArr.length];
                       ctx.beginPath();
                       for(var j=0; j<tobalDots; j++){
                           var R = radius*(nowArr[j]/maxValue)*ctr/numctr;
                           startAngle = startAngle+2*Math.PI/tobalDots;
                           var x = originX+R*Math.cos(startAngle);
                           var y = originY+R*Math.sin(startAngle);
                           //console.log(x,y);
                           
                           ctx.lineTo(x, y);//點連線
                           function drawArc(x,y,color,theTipArr){
                               return function(){
                                   ctx.beginPath();
                                   ctx.fillStyle = "#fff";
                                   ctx.strokeStyle = color;
                                   ctx.lineWidth = 4*ctr/numctr;
                                   ctx.arc(x,y,6*ctr/numctr,0,Math.PI*2);
                                   
                                   if(!ifTip && mouseMove && ctx.isPointInPath(mousePosition.x*2, mousePosition.y*2)){ //如果是鼠標移動的到小點上,重新繪制圖表
                                    //ctx.fillStyle = "rgba(46,199,201,1)";
                                    //是否繪制提示
                                    ifTip = true;
                                    tipArr = theTipArr;
                                    ctx.lineWidth *= 2;
                                  }
                                   
                                   ctx.fill();
                                   ctx.stroke();
                               };
                           }
                           arcArr.push( drawArc( x, y, colorArr[i%colorArr.length], [dataArr[i].name,nowArr[j],textArr[j]] ) ); //將繪制圓點方法利用閉包存起來,后面統一調用,數據多時顏色循環使用
                       }
                       
                    ctx.closePath();
                       if(ifFill){
                           ctx.globalAlpha = 0.3;
                           ctx.fill();
                           ctx.globalAlpha = 1;
                       }
                       ctx.stroke();
                       
                       for(var m=0; m<arcArr.length; m++){
                           arcArr[m]();
                       }
                       
                       canvas.style.cursor = "default";
                       ifTip && drawTips(mousePosition.x*2, mousePosition.y*2,tipArr);
                       
                   }
                   
                
                if(ctr<numctr){
                    ctr++;
                    setTimeout(function(){
                        ctx.clearRect(0,0,canvas.width, canvas.height);
                        drawLineLabelMarkers();
                        drawChartAnimate();
                    }, speed*=1.08);
                }
            }
            
            
            //繪制提示框
            function drawTips(oX,oY,valArr){
                
                canvas.style.cursor = "pointer";
                ctx.save();
                ctx.beginPath();
                ctx.fillStyle = "rgba(0,0,0,0.5)";
                var H = 120;
                roundedRect(ctx,oX+10,oY-H/2,2*H,H,5);
                
                ctx.fillStyle = "#fff";
                ctx.textAlign="left";
                ctx.fillText(valArr[0]+":", oX+20,oY-H/10);
                ctx.fillText(valArr[2]+":"+valArr[1], oX+20,oY+H/4);
                ctx.restore();
            }
            
            //繪制圓角矩形的方法
            function roundedRect(ctx,x,y,width,height,radius){
                ctx.moveTo(x,x+radius);
                ctx.beginPath();
                ctx.lineTo(x,y+height-radius);
                ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
                ctx.lineTo(x+width-radius, y+height);
                ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
                ctx.lineTo(x+width,y+radius);
                ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
                ctx.lineTo(x+radius,y);
                ctx.quadraticCurveTo(x,y,x,y+radius);
                ctx.closePath();
                ctx.fill();
            }
            
            
            
            //監聽鼠標移動
            var mouseTimer = null;
            canvas.addEventListener("mousemove",function(e){
                e = e || window.event;
                if( e.offsetX || e.offsetX==0 ){
                    mousePosition.x = e.offsetX;
                    mousePosition.y = e.offsetY;
                }else if( e.layerX || e.layerX==0 ){
                    mousePosition.x = e.layerX;
                    mousePosition.y = e.layerY;
                }
                
                clearTimeout(mouseTimer);
                mouseTimer = setTimeout(function(){
                    ctx.clearRect(0,0,canvas.width, canvas.height);
                    drawLineLabelMarkers();
                    drawChartAnimate(true);
                    
                },10);
            });
            
            

        }

        var dataArr = [
                {
                    value : [20000, 10000, 28000, 35000, 50000, 19000],
                    name : '預算分配'
                },
                 {
                    value : [15000, 14000, 28000, 31000, 42000, 21000],
                    name : '實際開銷'
                }
            ];
            
        /*
         * 參數1 :需要顯示canvas的dom  (非canvas標簽,需要指定height和width)
         * 參數2:二維數據  每個數據表示需要顯示的一組數據對象 (value表示數據數組,name表示此數據名稱)
         * 參數3:一維數組  對應上面每個數據的名字
         * 參數4:中部填充是否實心 ,默認false
         * */
        goChart(document.getElementById("chart"),dataArr,["銷售","管理","信息技術","客服","研發","市場"],true)


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




 

希望大家把代碼都自己敲一遍。

 

 

關注公眾號,博客更新即可收到推送



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM