1. 程式人生 > >原生js和canvas實現的 柱狀圖、餅狀圖、折線圖

原生js和canvas實現的 柱狀圖、餅狀圖、折線圖

轉載來自https://blog.csdn.net/u013302113/article/details/77985744
<html>
<head lang="en">


</head>


   <body>
      <canvas id="bar" width="450" height="250">
      </canvas>
      <canvas id="pie" width="450" height="250"></canvas>
      <br />
      <
canvas id="line" width="450" height="250"></canvas> <canvas id="curve" width="450" height="250"></canvas> <script> window.onload = function() { var bar = document.getElementById("bar"), data = { label: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],//x軸的標題
dataSets: [{ bDistance: 30, //繪製的邊框距離畫布邊框的距離 bInterval: 20, //兩個柱狀圖之間的距離 values: [300, 50, 100, 50, 80, 150, 120], //對應標籤的值 fillColor: "rgba(0,0,255,0.5)" //矩形填充顏色 }, { txtfont: "14px microsoft yahei",//繪製文字的字型 txtalgin: "center",//文字對齊方式
txtbaseline: "middle"//文字的基線 }, { fillColor: "black", //矩形填充顏色 xtitle: "訂單總數(個)", //x軸標題 ytitle: "星期幾" //y軸標題 }] }; barChart(bar, data); //畫柱狀圖 var pie = document.getElementById("pie"), datasets = { colors: ["blue", "yellow", "black", "red", "green"], //顏色 labels: ["第一週", "第二週", "第三週", "第四周", "第五週"], //標籤 values: [30, 60, 80, 70, 150], //值 x: 125, //圓心x座標 y: 125, //圓心y座標 radius: 100 //半徑 }; pieChart(pie, datasets); //畫餅狀圖 var line = document.getElementById("line"), datas = { labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],//標籤 values: [50, 180, 100, 150, 110, 130, 30],//值 txtSet: {//繪製文字設定 txtfont: "14px microsoft yahei", txtalgin: "center", txtbaseline: "middle", txtColor:"#000000" }, bgSet:{//繪製背景線設定 lineColor:"#C0C0C0", lineWidth:1, }, lineColor:"#000000",//折線顏色 circleColor:"blue",//折線上原點顏色 yAxis:{//y軸表示什麼,及繪製文字的位置 x:50, y:11, title:"完成件數(個)" } }, newData = { labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], values: [100, 40, 200, 50, 10, 80, 100], txtSet: { txtfont: "14px microsoft yahei", txtalgin: "center", txtbaseline: "middle", txtColor:"#000000" }, bgSet:{ lineColor:"#C0C0C0", lineWidth:1, }, lineColor:"blue", circleColor:"red", yAxis:{ x:50, y:11, title:"完成件數(個)" } }; lineChart(line,datas);//畫折線圖 //lineChart(line,newData);//在同一個canvas畫第二條折線圖 //curveChart();//繪製曲線 var bg = document.getElementById("curve") linedata = { labels: ["1月", "2月", "3月", "4月", "5月", "6月", "7月"],//標籤 datas: [115, 35, 210, 100, 300, 220, 40],//資料 xTitle: "月份",//x軸標題 yTitle: "產量(個)",//y軸標題 ctxSets:{ strokeColor:"#C0C0C0",//背景線顏色 lineWidth:1,//線的寬度 txtColor:"#000000",//繪製文字顏色 txtFont:"12px microsoft yahei",//字型 txtAlign:"center",//對齊方式 txtBase:"middle",//基線 lineColor:"blue",//折線顏色 circleColor:"#FF0000"//折線上圓點顏色 } }; setBg(bg,linedata);//繪製圖標背景及折線 } //陣列sort()排序傳的引數為該函式(降序排列),繪製柱狀圖需要 function compare(value1, value2) { return value2 - value1; } /*柱狀圖 * elem:要操作的畫布元素 * data:所需格式的資料*/ function barChart(elem, data) { if (elem.getContext) { var ctx = elem.getContext("2d"), mywidth = elem.width, //畫布的寬高 myheight = elem.height, bDistance = parseInt(data.dataSets[0].bDistance), //圖示邊框到畫布間距 bInterval = data.dataSets[0].bInterval, //矩形間間距 labels = data.label, //矩形對應標題 len = labels.length,//標籤/資料個數 //矩形寬度 bWidth = Math.floor((mywidth - bDistance * 2 - (len + 1) * bInterval) / len), bheight = myheight - bDistance * 2, //邊框高度 values = data.dataSets[0].values, //繪圖的值 sortValues = values.slice(0), //基於當前陣列中的一個或多個項建立一個新陣列(解決了該陣列排序原陣列也被排序的問題) serialValues = new Array(); //用於儲存序列化後的值 sortValues.sort(compare); if (sortValues[0] > bheight) { (function() { //數值超過邊框高度時序列化值 for (var i = 0; i < len; i++) { serialValues[i] = values[i] * bheight / sortValues[0]; } })(); //塊級作用域 } //繪製邊框 ctx.beginPath(); //要繪製路徑,必須先呼叫該方法,表示開始繪製新路徑 ctx.moveTo(bDistance, bDistance); ctx.lineTo(bDistance, myheight - bDistance); ctx.lineTo(mywidth - bDistance, myheight - bDistance); ctx.stroke(); //把圖形繪製到畫布上 //繪製矩形,組成條形圖 ctx.fillStyle = data.dataSets[0].fillColor; //繪製文字 ctx.font = data.dataSets[1].txtfont; //字型樣式、大小、字型 ctx.textAlign = data.dataSets[1].txtalgin; //文字對齊方式 ctx.textBaseline = data.dataSets[1].txtbaseline; //文字的基線 for (var i = 0; i < len; i++) { var x = (bInterval + bDistance) + i * (bWidth + bInterval), y = myheight - serialValues[i] - bDistance, x1 = x + Math.round(bWidth / 2); y1 = myheight - bDistance + 15, y2 = y - 10; ctx.fillRect(x, y, bWidth, serialValues[i]); //x,y,width,height單位都為px ctx.fillText(labels[i], x1, y1); //繪製標題文字 ctx.fillText(values[i], x1, y2); //繪製柱狀圖資料 } ctx.fillStyle = data.dataSets[2].fillColor; ctx.fillText(data.dataSets[2].xtitle, 49, 7); //x軸代表什麼 ctx.fillText(data.dataSets[2].ytitle, mywidth - bDistance, myheight - bDistance + 15); //y軸代表什麼 } } //求和,計算百分比(畫餅圖時需要) function sumFunc(data) { var sum = 0; for (var i = 0, len = data.length; i < len; i++) { sum += data[i]; } return sum; } /*餅圖 * elem:要操作的畫布元素 * data:所需格式的資料*/ function pieChart(elem, data) { if (elem.getContext) { var ctx = elem.getContext("2d"), vdata = data.values, //繪圖資料 sum = sumFunc(vdata), //對繪圖資料求和,用於計算百分比 startangle = 0, //繪製扇形的開始角度 labels = data.labels, //繪圖的對應文字 x = data.x, //圓心x座標 y = data.y, //圓心y座標 rad = data.radius, //圓半徑 x1 = x + rad + 30, //繪製右側文字和標註的x座標 y1 = y - rad, //繪製右側文字和標註的y座標 endangle; //繪製扇形的結束角度 for (var i = 0, len = vdata.length; i < len; i++) { //繪製餅圖 //計算下一次繪製扇形的結束角度,即根據繪製資料佔有總資料和的比例求的弧度 var percent = vdata[i] / sum; endangle = startangle + Math.PI * 2 * (percent); ctx.beginPath(); //開始繪製新路徑 ctx.fillStyle = data.colors[i]; //繪製顏色 ctx.moveTo(x, y); //移動到圓心(注:畫餅圖一定要回到圓心,不然會有問題) ctx.arc(x, y, rad, startangle, endangle, false); //畫扇形 //繪製右側文字和標註 ctx.moveTo(x1, y1); //移動到繪製文字和標註的位置 ctx.fillRect(x1, y1, 30, 14); //繪製矩形表示比列圖 //計算四捨五入後的扇形每份的百分比 var perc = (percent * 100).toFixed(2) + "%"; //tofixed()自動四捨五入返回指定小數位數的字串 //設定繪製文字的屬性 ctx.font = "bold 12px microsoft yahei"; ctx.txtalgin = "center"; ctx.textBaseline = "top"; //繪製文字 ctx.fillText(labels[i] + ":" + perc, x1 + 35, y1); ctx.fill(); //指定顏色填充以上繪製 startangle = endangle; //下一次繪製扇形的開始角度 y1 += 20; //下一次繪製文字和標註的y座標 } } } /*繪製折線 elem:操作的元素 data:所需格式資料*/ function lineChart(elem, data) { if (elem.getContext) { var ctx = elem.getContext("2d"), labels = data.labels,//數值對應標籤 values = data.values,//數值 len = labels.length,//標籤/數值個數 elemWidth = elem.width,//畫布寬度 elemHeight = elem.height,//畫布高度 gridHeight = Math.ceil(elemHeight / 5),//每行之間高度 gridWidth = Math.floor(elemWidth / len),//每列之間看度 actualHeight = 4 * gridHeight + 20;//繪製區域實際高度 //設定繪製直線的屬性 ctx.strokeStyle = data.bgSet.lineColor; ctx.lineWidth = data.bgSet.lineWidth; //設定繪製文字的屬性 ctx.font = data.txtSet.txtfont; ctx.textAlign = data.txtSet.txtalgin; ctx.txtbaseline = data.txtSet.txtbaseline; //繪製背景 //繪製背景橫線 ctx.beginPath(); for (var i = 0; i < 5; i++) { var hgridY = gridHeight * i + 20, hgridX = gridWidth * len; ctx.moveTo(0, hgridY); ctx.lineTo(hgridX, hgridY); } ctx.stroke(); //繪製背景的豎線,表示每個label ctx.beginPath(); for (var j = 0; j < len + 1; j++) { var vgridX = gridWidth * j, vgridY = actualHeight; ctx.moveTo(vgridX, vgridY); ctx.lineTo(vgridX, vgridY + 10); } ctx.stroke(); //繪製標籤文字 ctx.fillStyle = data.txtSet.txtColor; for (var k = 0; k < len; k++) { var txtX = gridWidth * (k + 0.5), txtY = actualHeight + 15; ctx.fillText(labels[k], txtX, txtY); } ctx.fill(); //獲取畫圖資料的最大值用於序列換資料 var maxValue = 0, cData = new Array(); for (var i = 0; i < len; i++) { if (values[i] > maxValue) { maxValue = values[i]; } } //當最大值大於畫布可繪製區域的高度時,對資料進行轉化,然後進行畫圖 if ((4 * gridHeight) < maxValue) { for (var i = 0; i < len; i++) { //轉換後的資料 cData[i] = values[i] * 4 * gridHeight / maxValue; } } else { cData = values; } //繪製折線 ctx.strokeStyle = data.lineColor; ctx.beginPath(); var pointX = gridWidth / 2, pointY = actualHeight - cData[0]; ctx.moveTo(pointX, pointY); for (var i = 1; i < len; i++) { pointX += gridWidth; pointY = actualHeight - cData[i]; ctx.lineTo(pointX, pointY); } ctx.stroke(); //繪製座標圓形 ctx.beginPath(); ctx.fillStyle = data.circleColor; //圓點的顏色 for (var i = 0; i < len; i++) { var circleX = gridWidth / 2 + gridWidth * i, circleY = actualHeight - cData[i]; ctx.moveTo(circleX, circleY); //假如不每次繪製之前確定開始繪製新路徑,可以每次繪製之前移動到新的圓心 ctx.arc(circleX, circleY, 4, 0, Math.PI * 2, false); } ctx.fill(); //繪製座標圓形對應的值 ctx.beginPath(); ctx.fillStyle = data.txtSet.txtColor;; //文字顏色 for (var i = 0; i < len; i++) { var circleX = gridWidth / 2 + gridWidth * i, circleY = actualHeight - cData[i]; ctx.fillText(values[i], circleX, circleY - 8); } ctx.fill(); //繪製y軸代表什麼 ctx.fillText(data.yAxis.title, data.yAxis.x, data.yAxis.y); ctx.fill(); } } function curveChart() { var elem = document.getElementById("curve"); if (elem.getContext) { var ctx = elem.getContext("2d"); // ctx.lineWidth = 2; ctx.lineCap = "square"; ctx.beginPath(); ctx.moveTo(100, 70); ctx.bezierCurveTo(120, 150, 150, 150, 200, 60); //三次貝賽爾曲線 ctx.moveTo(40, 100); ctx.quadraticCurveTo(60, 60, 100, 70); //二次貝塞爾曲線 ctx.moveTo(200, 60); ctx.arcTo(240, 40, 300, 50, 50); //繪製弧線 ctx.stroke(); } } /* 繪製背景 * elem:要操作的元素 * data:所需格式的資料*/ function setBg(elem, data) { if (elem.getContext) { var ctx = elem.getContext("2d"),//獲取元素上下文 startX = 40,//左上角開始繪製的x座標 startY = 40,//左上角開始繪製的y座標 labels = data.labels,//對應資料的標籤,即列數 cols = labels.length,//資料個數 datas = data.datas,//資料 gWidth = elem.width - 80,//背景總寬度,elem.width為畫布寬度 gHeight = elem.height - 80,//背景總長度 pgWidth = gWidth / cols,//背景每個格的寬度 rows = 10,//背景表格行數 pgHeight = gHeight / rows;//背景表格高度 //繪製背景 ctx.beginPath(); //開始繪製新路徑 ctx.strokeStyle = data.ctxSets.strokeColor;//描邊顏色 ctx.lineWidth = data.ctxSets.lineWidth;//描邊線條寬度 //繪製橫線 for (var i = 0; i < rows; i++) { var pY = startX + pgHeight * i; ctx.moveTo(startX, pY); //移動到繪製的起點 ctx.lineTo(gWidth + startX, pY); } //最後一根橫線 var pY1 = startY + pgHeight * rows; ctx.moveTo(startX, pY1); //移動到繪製的起點 ctx.lineTo(gWidth + startX + 20, pY1); //繪製豎線 //第一根豎線 ctx.moveTo(startX, startY - 20); //移動到繪製的起點 ctx.lineTo(startX, gHeight + startY + 10); for (var i = 1; i < cols + 1; i++) { var pX = startX + pgWidth * i; ctx.moveTo(pX, startY); //移動到繪製的起點 ctx.lineTo(pX, gHeight + startY + 10); } ctx.stroke();//把圖形繪製到畫布上 //繪製文字 ctx.fillStyle = data.ctxSets.txtColor;//填充顏色 ctx.font = data.ctxSets.txtFont;//文字字型 ctx.textAlign = data.ctxSets.txtAlign;//文字對齊方式 ctx.textBaseline = data.ctxSets.txtBase;//文字基線 //繪製橫軸文字 for (var i = 0; i < cols; i++) { var px = startX + pgWidth / 2 + pgWidth * i; ctx.fillText(labels[i], px, startY + gHeight + 10); } //繪製豎軸文字 //判斷最大值是否大於行高,確定每行的數值 var maxValue = 0, newValues = new Array(), j = 0; for (var i = 0; i < cols; i++) { if (datas[i] > maxValue) { maxValue = datas[i]; } } //重新計算每隔資料值及轉換值 if (maxValue > gHeight) { pgValues = maxValue / rows; for (var i = 0; i < cols; i++) { newValues[i] = datas[i] * gHeight / maxValue; } } else { pgValues = pgHeight; newValues = datas; } //繪製豎軸文字 for (var i = rows; i >= 0; i--) { ctx.fillText(pgValues * i, 20, startY + pgHeight * j); j++; } //繪製標題 //x軸標題 ctx.fillText(data.xTitle, gWidth + startX + 15, gHeight + startY + 10); //y軸標題 ctx.fillText(data.yTitle, startX + 25, startY - 10); //畫圖 //繪製折線 ctx.strokeStyle = data.ctxSets.lineColor;; ctx.beginPath(); var pointX = pgWidth / 2 + startX, pointY = startY + gHeight - newValues[0]; ctx.moveTo(pointX, pointY); for (var i = 1; i < cols; i++) { pointX += pgWidth; pointY = startY + gHeight - newValues[i]; ctx.lineTo(pointX, pointY); } ctx.stroke(); //繪製座標圓形 ctx.beginPath(); ctx.fillStyle = data.ctxSets.circleColor;; //圓點的顏色 for (var i = 0; i < cols; i++) { var circleX = pgWidth / 2 + startX + pgWidth * i, circleY = startY + gHeight - newValues[i]; ctx.moveTo(circleX, circleY); //假如不每次繪製之前確定開始繪製新路徑,可以每次繪製之前移動到新的圓心 ctx.arc(circleX, circleY, 4, 0, Math.PI * 2, false); } ctx.fill(); //繪製座標圓形對應的值 ctx.beginPath(); ctx.fillStyle = data.ctxSets.txtColor; //文字顏色 for (var i = 0; i < cols; i++) { var circleX = pgWidth / 2 + startX + pgWidth * i, circleY = startY + gHeight - newValues[i]; ctx.fillText(datas[i], circleX, circleY - 10); } ctx.fill(); } } </script> </body> </html>