摘要:示例代碼托管在博客園地址大史住在大前端原創博文目錄華為云社區地址你要的前端打怪升級指南一任務說明使用原生繪制柱狀圖。
示例代碼托管在:http://www.github.com/dashnowords/blogs博客園地址:《大史住在大前端》原創博文目錄
華為云社區地址:【你要的前端打怪升級指南】
[TOC]
一. 任務說明使用原生canvasAPI繪制柱狀圖。(柱狀圖截圖來自于百度Echarts官方示例庫【查看示例鏈接】)
二. 重點提示柱狀圖或許是最容易實現的圖表類型了,矩形的部分直接使用fillRect()來繪制即可,為了將坐標軸標簽文字繪制在小分割線中間,需要用measureText()來測量文本的寬度,然后進行相應的偏移,否則直接繪制的話文字的左邊界會和直線相對齊。其他部分都是一些基本API的使用,希望各位小伙伴通過做練習來熟悉這些API的用法。
三. 示例代碼提示:代碼中將個別圖表參數直接寫在了函數里(也就是所謂的“魔鬼數字”),這種做法是不提倡的,因為它違反了開發的基本原則之一“開放封閉原則”。如果你使用過Echarts圖表庫就會發現,圖表中幾乎所有要素都可以通過參數來定制,此處只需要關注canvasAPI的實現方法即可。
/** * 獲取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"http://柱狀圖顏色 } } /*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); }); }
瀏覽器中可查看效果:
四. 思考題如果希望在坐標軸末端加一個箭頭,需要怎么做呢?
/*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();//恢復繪圖上下文樣式設置 }
箭頭效果:
y軸的箭頭請自行完成即可。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104319.html
閱讀 989·2023-04-26 01:47
閱讀 1674·2021-11-18 13:19
閱讀 2047·2019-08-30 15:44
閱讀 654·2019-08-30 15:44
閱讀 2299·2019-08-30 15:44
閱讀 1236·2019-08-30 14:06
閱讀 1427·2019-08-30 12:59
閱讀 1904·2019-08-29 12:49