摘要:综上,最后我们的工具函数应该长成下面这个样子首先获取绘图上下文,仍要注意先判断是否存在方法。把标题绘制在画布顶部的中间,距离页面顶部留有像素的空隙,并且根据参数,绘制具有特定内容和样式的标题。
有了canvas之后,我们可以很容易地创建一个简单图标,不需要任何插件,不过,有的小伙伴觉得它很难,笔者仔细思考一番之后,只能吐嘈一下他们的绘图技能...
于是在开始绘制之前,我们首先画一下草图~
讲解之前,先贡献出源码:https://github.com/Sue1024/Ca...
Make It Reusable为了创建一个可以重用,并且可以灵活地重用的饼图,笔者决定最终的创建饼图方法接收两个参数,分别是要显示的数据data,绘制参数options
Data在实际应用场景中,我们从后端拿到的往往是诸如几个年份的产量一类的数据,比如(这里,我们为了简化代码,将颜色也放到了后台返回的数据中):
var data = [ { data: 10, color: "red", label: "2016" }, { data: 15, color: "grey", label: "2017" }, { data: 15, color: "black", label: "2018" } ];
而绘制饼图时, 我们需要根据比例"分饼", 并且在某些地方显示出实际的数据(比如tooltip),因此我们需要一个如下的数据处理函数:
function calculateData(data) { if(data instanceof Array) { var sum = data.reduce(function(a, b) { return a + b.data; }, 0); var map = data.map(function(a) { return { label: a.label, data: a.data, color: a.color, portion: a.data/sum } }); return map; } }Options
另外,即使我们可以根据不同的数据绘制不同的图表,恐怕也只能满足个别需求,毕竟每个人的喜好都不一样,我们需要创建一个可以显示不同数据,又可以拥有不同排版、不同布局的图表,实现上述目标,我们需要如下参数列表:
var options = { legend: { font: { size: 18, family: "Arial", weight: "bold" } }, title: { text: "Pie Chart", font: { size: 18, family: "Arial", weight: "bold" } }, tooltip: { template: "CanvasYear: {{label}}Production: {{data}}", font: { size: 18, family: "Arial", weight: "bold" } } }
我们的工具函数不应该可以提前知道用户想要用来绘制图表的canvas,用户可能想在页面中的多个canvas上绘制图表,因此工具函数应该可以接受一个参数,用来确定绘制图表的canvas,很多开源库都使用id作为识别canvas的标识,笔者认为接收element更好一些,因为不是所有的用户都愿意给canvas添加ID属性, 有的时候,用户想给拥有某一个class属性的所有canvas批量绘图,并根据它们的dataset属性动态的生成数据。
综上,最后我们的工具函数应该长成下面这个样子:
function drawPie(canvas, data, option) { // To Do }Start Coding Get Context
首先获取绘图上下文,仍要注意先判断是否存在getContext()方法。
var canvas = document.getElementById("canvas"); if(canvas.getContext) { var ctx = canvas.getContext("2d"); }Generate Options
然后,我们需要将自定义的参数和默认参数合并在一起,组成一个新的完整的参数列表,原则就是没有自定义的都采用默认值。
function mergeJSON(source1,source2){ var mergedJSON = JSON.parse(JSON.stringify(source2)); for (var attrname in source1) { if(mergedJSON.hasOwnProperty(attrname)) { if ( source1[attrname]!=null && source1[attrname].constructor==Object ) { mergedJSON[attrname] = mergeJSON(source1[attrname], mergedJSON[attrname]); } } else { mergedJSON[attrname] = source1[attrname]; } } return mergedJSON; } function generateOptions(givenOptions, defaultOptions) { return mergeJSON(defaultOptions, givenOptions); }Draw Title
把标题绘制在画布顶部的中间,距离页面顶部留有20像素的空隙,并且根据参数,绘制具有特定内容和样式的标题。
var width = canvas.width, height = canvas.height, op = generateOptions(options, defaultOptions), title_text = op.title.text, title_position = {}; ctx.font = op.title.font.weight + " " + op.title.font.size+"px " + op.title.font.family; title_position .x = (width - title_width)/2; title_position.y = 20 + op.title.font.size; title_width = ctx.measureText(title_text).width, title_height = op.title.font.size; ctx.fillText(title_text, title_position.x, title_position.y);Radius & Center
笔者决定使饼图距离标题有30像素的空隙,距离左边框和底部分别留有20像素的空隙,因此它的半径和圆心分别是:
var radius = (height - title_height - title_position.y - 20) / 2 ; var center = { x: radius + 20, y: radius + 30 + title_position.y };Legend
图例的高设置为图例字体大小的1.2倍,宽设置为图例字体大小的2.5倍,距离饼图40像素的间隙,第一个图例顶部距离页面顶端80像素,文字距离图例5像素,垂直居中,于是图例的大体信息总结如下:
var legend_width = op.legend.font.size * 2.5, legend_height = op.legend.font.size * 1.2, legend_posX = center.x * 2 +20, legend_posY = 80, legend_textX = legend_posX + legend_width + 5, legend_textY = legend_posY + op.legend.font.size * 0.9;Draw Pie & Legends
先给图表加一个边框
ctx.strokeStyle = "grey"; ctx.lineWidth = 3; ctx.strokeRect(0, 0, canvas.width, canvas.height);
遍历数据绘图。
var data_c = calculateData(data); var startAngle = 0, endAngle = 0; for(var i=0, len=data.length; iLet"s try it! 我们的工具函数已经做到一半啦,可以画出一个带有图例的饼图,并且标题和图例文字大小 粗细 字体均可配置,下面试一下灵不灵~
var init = function(){ var data = [ { data: 10, color: "red", label: "2016" }, { data: 15, color: "grey", label: "2017" }, { data: 15, color: "black", label: "2018" } ]; var options = { title: { text: "Production By Year", font: { size: 30 } } } drawCircle(data, document.getElementById("drawing"), options); }; init();画出来的饼图长这个样子~
下一篇笔者会加上Tooltip的绘制哦,那部分比较复杂,默默地给自己加油~
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/94957.html
摘要:继上一篇实战绘制饼图之后,笔者研究了一下如何给饼图加鼠标停留时显示的提示框。为了方便保存,创建一个构造函数。最终我们的方法成品图源码地址 继上一篇HTML5 Canvas(实战:绘制饼图)之后,笔者研究了一下如何给饼图加鼠标停留时显示的提示框。 Plot对象 在开始Coding之前,笔者能够想到的最easy的方式,就是给饼图的每一个区域添加mousemove事件,鼠标在其上移动时则显示...
摘要:继上一篇实战绘制饼图之后,笔者研究了一下如何给饼图加鼠标停留时显示的提示框。为了方便保存,创建一个构造函数。最终我们的方法成品图源码地址 继上一篇HTML5 Canvas(实战:绘制饼图)之后,笔者研究了一下如何给饼图加鼠标停留时显示的提示框。 Plot对象 在开始Coding之前,笔者能够想到的最easy的方式,就是给饼图的每一个区域添加mousemove事件,鼠标在其上移动时则显示...
阅读 1824·2023-04-25 14:49
阅读 3099·2021-09-30 09:47
阅读 3072·2021-09-06 15:00
阅读 2206·2019-08-30 13:16
阅读 1419·2019-08-30 10:48
阅读 2651·2019-08-29 15:11
阅读 1257·2019-08-26 14:06
阅读 1649·2019-08-26 13:30