示例代碼託管在:http://www.github.com/dashnowords/blogs前端
博客園地址:《大史住在大前端》原創博文目錄git
華爲雲社區地址:【你要的前端打怪升級指南】github
使用原生canvasAPI
繪製柱狀圖。(柱狀圖截圖來自於百度Echarts官方示例庫【查看示例連接】)canvas
柱狀圖或許是最容易實現的圖表類型了,矩形的部分直接使用fillRect()
來繪製便可,爲了將座標軸標籤文字繪製在小分割線中間,須要用measureText()
來測量文本的寬度,而後進行相應的偏移,不然直接繪製的話文字的左邊界會和直線相對齊。其餘部分都是一些基本API的使用,但願各位小夥伴經過作練習來熟悉這些API的用法。瀏覽器
提示:代碼中將個別圖表參數直接寫在了函數裏(也就是所謂的「魔鬼數字」),這種作法是不提倡的,由於它違反了開發的基本原則之一「開放封閉原則」。若是你使用過Echarts
圖表庫就會發現,圖表中幾乎全部要素均可以經過參數來定製,此處只須要關注canvasAPI
的實現方法便可。echarts
/** * 獲取canvas繪圖上下文 * @type {[type]} */ const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); //繪圖配置 let options = { chartZone:[50,50,1000,700],//標識繪圖區域 yAxisLabel:['0','100','200','300','400'],//標示Y軸座標 yMax:400,//Y軸最大值 xAxisLabel:['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],//X軸座標 data:[10,50,200,330,390,320,220],//柱狀圖數據 barStyle:{ width:70,//柱狀圖寬度 color:'#1abc9c'//柱狀圖顏色 } } /*Echarts使用時,會調用實例方法echartsInstance.setOptions(options)來啓動繪圖*/ drawBarChart(options); /** * 繪製柱狀圖 */ function drawBarChart(options) { drawAxis(options); //繪製座標軸 drawYLabels(options); //繪製y軸座標 drawXLabels(options); //繪製x軸座標 //drawData(options);//繪製柱狀圖 drawDataGradient(options);//繪製漸變色柱狀圖 } /** * 繪製座標軸 */ function drawAxis(options) { let chartZone = options.chartZone; context.strokeWidth = 4; context.strokeStyle = '#353535'; context.moveTo(chartZone[0],chartZone[1]); context.lineTo(chartZone[0],chartZone[3]); //y軸總高從50到700 context.lineTo(chartZone[2],chartZone[3]); //x軸總長從50到1000 context.stroke(); } /** * 繪製y軸座標 */ function drawYLabels(options) { let labels = options.yAxisLabel; let yLength = (options.chartZone[3] - options.chartZone[1])*0.98; let gap = yLength / (labels.length - 1); labels.forEach(function (label, index) { //繪製座標文字 let offset = context.measureText(label).width + 20; context.strokeStyle = '#eaeaea'; context.font = '16px'; context.fillText(label, options.chartZone[0] - offset ,options.chartZone[3] - index * gap); //繪製小間隔 context.beginPath(); context.strokeStyle = '#353535'; context.moveTo(options.chartZone[0] - 10, options.chartZone[3] - index * gap); context.lineTo(options.chartZone[0], options.chartZone[3] - index * gap); context.stroke(); //繪製輔助線 context.beginPath(); context.strokeStyle = '#eaeaea'; context.strokeWidth = 2; context.moveTo(options.chartZone[0], options.chartZone[3] - index * gap); context.lineTo(options.chartZone[2], options.chartZone[3] - index * gap); context.stroke(); }); } /** * 繪製x軸座標 */ function drawXLabels(options) { let labels = options.xAxisLabel; let xLength = (options.chartZone[2] - options.chartZone[0])*0.96; let gap = xLength / labels.length; labels.forEach(function (label, index) { //繪製座標文字 let offset = context.measureText(label).width; context.strokeStyle = '#eaeaea'; context.font = '18px'; context.fillText(label, options.chartZone[0] + (index + 1) * gap - offset ,options.chartZone[3] + 20); //繪製小間隔 context.beginPath(); context.strokeStyle = '#353535'; context.moveTo(options.chartZone[0] + (index + 1) * gap - offset / 2 ,options.chartZone[3]); context.lineTo(options.chartZone[0] + (index + 1) * gap - offset / 2,options.chartZone[3]+5); context.stroke(); //存儲偏移量 options.offsetXLabel = offset / 2; }); } /** * 繪製數據 */ function drawData(options) { let data = options.data; let xLength = (options.chartZone[2] - options.chartZone[0])*0.96; let yLength = (options.chartZone[3] - options.chartZone[1])*0.98; let gap = xLength / options.xAxisLabel.length; //繪製矩形 data.forEach(function (item, index) { context.fillStyle = options.barStyle.color || '#1abc9c'; //02BAD4 let x0 = options.chartZone[0] + (index + 1) * gap - options.barStyle.width / 2 - options.offsetXLabel; let height = item / options.yMax * (options.chartZone[3] - options.chartZone[1])*0.98; let y0 = options.chartZone[3] - height; let width = options.barStyle.width; context.fillRect(x0,y0,width,height); }); } /** * 繪製線性漸變色柱狀圖 */ function drawDataGradient(options) { let data = options.data; let xLength = (options.chartZone[2] - options.chartZone[0])*0.96; let yLength = (options.chartZone[3] - options.chartZone[1])*0.98; let gap = xLength / options.xAxisLabel.length; //建立漸變色 let fillStyleGradient = context.createLinearGradient(50,50,50,700); fillStyleGradient.addColorStop(0, options.barStyle.color); fillStyleGradient.addColorStop(1, 'rgba(1,176,241,0.6)'); //繪製矩形 data.forEach(function (item, index) { context.fillStyle = fillStyleGradient; let x0 = options.chartZone[0] + (index + 1) * gap - options.barStyle.width / 2 - options.offsetXLabel; let height = item / options.yMax * (options.chartZone[3] - options.chartZone[1])*0.98; let y0 = options.chartZone[3] - height; let width = options.barStyle.width; context.fillRect(x0,y0,width,height); }); }
瀏覽器中可查看效果:函數
若是但願在座標軸末端加一個箭頭,須要怎麼作呢?3d
/*x軸箭頭示例*/ //1.options中增長箭頭顏色和大小的設置 let options = { //... axisArrow:{ size:2, color:'#DA5961' } } //箭頭繪製函數 /** * x軸繪製箭頭 */ function drawArrow(options) { let factor = options.axisArrow.size;//獲取箭頭大小因子 context.save();//保存當前設置的繪圖上下文 context.translate(options.chartZone[2], options.chartZone[3]);//移動座標系原點至x軸末端 context.beginPath();//開始繪製箭頭 context.moveTo(0,0);//移動至新原點 context.lineTo(2 * factor,-3 * factor); context.lineTo(10 * factor,0); context.lineTo(2 * factor, 3 * factor); context.lineTo(0,0); context.globalAlpha = 0.7; //設置填充色透明度 context.fillStyle = options.axisArrow.color;//獲取箭頭顏色 context.fill();//填充箭頭路徑 context.restore();//恢復繪圖上下文樣式設置 }
箭頭效果:rest
y軸的箭頭請自行完成便可。