有关 canvas 之前有写过两篇文章
1,Canvas(1)--- 概述 + 简单示例
2,Canvas(2)--- 绘制折线图
在绘制饼状图之前, 我们先要理解什么是圆弧, 如何在画布中绘制文字等等. 所以这里将绘制饼状图理解拆分成以下几个步骤:
, 理解圆弧
, 绘制一段圆弧
, 绘制一个扇形
, 绘制一个六等圆
, 绘制一个根据数据的饼图
, 绘制在画布中心的一段文字
, 绘制完整饼状图
什么是弧度 弧度是一种长度的描述单位, 一个半径的长度就表示一弧度, 所以一个圆有 2*π个弧度.
一, 绘制一段圆弧
效果
代码
- <!DOCTYPE html>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Title
- </title>
- <style>
- canvas { border: 1px solid #00CED1; }
- </style>
- </head>
- <body>
- <canvas width="600" height="400">
- </canvas>
- <script>
- var myCanvas = document.querySelector('canvas');
- var ctx = myCanvas.getContext('2d');
- /* 参数 */
- /* 坐标 x y 确定圆心 */
- /* 确定圆半径 r */
- /* 确定起始绘制的位置和结束绘制的位置 Math.PI=π 也就是 180 度 */
- /* 取得绘制的方向 direction 默认是顺时针 false 逆时针 true */
- var w = ctx.canvas.width;
- var h = ctx.canvas.height;
- ctx.arc(w / 2, h / 2, 150, Math.PI / 2, Math.PI, false);
- ctx.stroke();
- </script>
- </body>
- </HTML>
思考 为什么这里四分之一的弧度是这个方向的, 那是因为 canvas 指定了规则
所以上面 Math.PI/2 到 Math.PI, 且是 顺时针 的. 由这两点最终绘制的就是上面的效果了.
二, 绘制一个扇形
效果
代码
- <!-- 上面部分代码和上面一致, 这里就不重复写了 -->
- <script>
- var myCanvas = document.querySelector('canvas');
- var ctx = myCanvas.getContext('2d');
- /* 在中心位置画一个半径 150px 的圆弧右上角 扇形 边 填充 */
- var w = ctx.canvas.width;
- var h = ctx.canvas.height;
- /* 把起点放到圆心位置 */
- ctx.moveTo(w/2,h/2);
- ctx.arc(w/2,h/2,150,0,-Math.PI/2,true);
- // 注意这里采用的是填充 , 而不是闭合 ctx.closePath()
- ctx.fill();
- </script>
三, 绘制一个圆分成六等分颜色随机
效果
代码
- <!-- 上面部分代码和上面一致, 这里就不重复写了 -->
- <script>
- var myCanvas = document.querySelector('canvas');
- var ctx = myCanvas.getContext('2d');
- var w = ctx.canvas.width;
- var h = ctx.canvas.height;
- /* 分成几等分 */
- var num = 6;
- /* 一份多少弧度 */
- var angle = Math.PI * 2 / num;
- /* 原点坐标 */
- var x0 = w / 2;
- var y0 = h / 2;
- /* 获取随机颜色 */
- var getRandomColor = function () {
- var r = Math.floor(Math.random() * 256);
- var g = Math.floor(Math.random() * 256);
- var b = Math.floor(Math.random() * 256);
- return 'rgb(' + r + ',' + g + ',' + b + ')';
- }
- /* 上一次绘制的结束弧度等于当前次的起始弧度 */
- for (var i = 0; i <num; i++) {
- var startAngle = i * angle;
- var endAngle = (i + 1) * angle;
- ctx.beginPath();
- ctx.moveTo(x0, y0);
- ctx.arc(x0, y0, 150, startAngle, endAngle);
- /* 随机颜色 */
- ctx.fillStyle = getRandomColor();
- ctx.fill();
- }
- </script>
四, 绘制一个根据数据的饼图
上面是平均分成了 6 等分, 这里是根据具体的数据来按比例分成若干份.
效果
代码
- <!-- 上面部分代码和上面一致, 这里就不重复写了 -->
- <script>
- var myCanvas = document.querySelector('canvas');
- var ctx = myCanvas.getContext('2d');
- // 数据
- var data = [5, 10, 15, 20];
- /*1. 需要把数据转出弧度 先计算总数 */
- var total = 0;
- data.forEach(function (item, i) {
- total += item;
- });
- //2, 计算每个数据所占的弧度
- var angleList = [];
- data.forEach(function (item, i) {
- var angle = Math.PI * 2 * (item/total);
- angleList.push(angle);
- });
- /* 3, 获取随机颜色 */
- var getRandomColor = function () {
- var r = Math.floor(Math.random() * 256);
- var g = Math.floor(Math.random() * 256);
- var b = Math.floor(Math.random() * 256);
- return 'rgb(' + r + ',' + g + ',' + b + ')';
- }
- /*4. 根据弧度绘制扇形 */
- var w = ctx.canvas.width;
- var h = ctx.canvas.height;
- var x0 = w/2;
- var y0 = h/2;
- var startAngle = 0;
- angleList.forEach(function (item,i) {
- /* 上一次绘制的结束弧度等于当前次的起始弧度 */
- var endAngle = startAngle + item;
- ctx.beginPath();
- ctx.moveTo(x0,y0);
- ctx.arc(x0,y0,150,startAngle,endAngle);
- ctx.fillStyle = getRandomColor();
- ctx.fill();
- /* 记录当前的结束位置作为下一次的起始位置 */
- startAngle = endAngle;
- });
- </script>
五, 绘制在画布中心的一段文字
效果
代码
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <style>
- canvas {
- border: 1px solid #00CED1;
- display: block;
- margin: 100px auto;
- }
- </style>
- </head>
- <body>
- <canvas width="600" height="400"></canvas>
- <script>
- var myCanvas = document.querySelector('canvas');
- var ctx = myCanvas.getContext('2d');
- /*1. 在画布的中心绘制一段文字 */
- /*2. 申明一段文字 */
- var str = '武汉加油';
- /*3. 确定画布的中心 */
- var w = ctx.canvas.width;
- var h = ctx.canvas.height;
- /*4. 画一个十字架在画布的中心 */
- ctx.beginPath();
- ctx.moveTo(0, h / 2);
- ctx.lineTo(w, h / 2);
- ctx.moveTo(w / 2, 0);
- ctx.lineTo(w / 2, h);
- ctx.strokeStyle = '#eee';
- ctx.stroke();
- /*5. 绘制文本 */
- ctx.beginPath();
- ctx.strokeStyle = '#000';
- var x0 = w/2;
- var y0 = h/2;
- /* 注意: 起点位置在文字的左下角 */
- /* 有文本的属性 尺寸 字体 左右对齐方式 垂直对齐的方式 */
- ctx.font = '40px Microsoft YaHei';
- /* 左右对齐方式 (center left right start end) 基准起始坐标 */
- ctx.textAlign = 'center';
- /* 垂直对齐的方式 基线 baseline(top,bottom,middle) 基准起始坐标 */
- ctx.textBaseline = 'middle';
- //ctx.direction = 'rtl';
- //ctx.strokeText(str,x0,y0);
- ctx.fillText(str,x0,y0);
- /*6. 画一个下划线和文字一样长 */
- ctx.beginPath();
- /* 获取文本的宽度 */
- console.log(ctx.measureText(str));
- var width = ctx.measureText(str).width;
- ctx.moveTo(x0-width/2,y0 + 20);
- ctx.lineTo(x0+width/2,y0 + 20);
- ctx.stroke();
- </script>
- </body>
- </HTML>
六, 绘制完整饼状图
上面所做的都是为了整个饼状图做铺垫的.
效果
代码
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- Title
- </title>
- <style>
- canvas { border: 1px solid #00CED1; display: block; margin: 100px auto;
- }
- </style>
- </head>
- <body>
- <canvas width="600" height="400">
- </canvas>
- <script>
- var myCanvas = document.querySelector('canvas');
- var ctx = myCanvas.getContext('2d');
- /*1. 在画布的中心绘制一段文字 */
- /*2. 申明一段文字 */
- var str = '武汉加油';
- /*3. 确定画布的中心 */
- var w = ctx.canvas.width;
- var h = ctx.canvas.height;
- /*4. 画一个十字架在画布的中心 */
- ctx.beginPath();
- ctx.moveTo(0, h / 2);
- ctx.lineTo(w, h / 2);
- ctx.moveTo(w / 2, 0);
- ctx.lineTo(w / 2, h);
- ctx.strokeStyle = '#eee';
- ctx.stroke();
- /*5. 绘制文本 */
- ctx.beginPath();
- ctx.strokeStyle = '#000';
- var x0 = w / 2;
- var y0 = h / 2;
- /* 注意: 起点位置在文字的左下角 */
- /* 有文本的属性 尺寸 字体 左右对齐方式 垂直对齐的方式 */
- ctx.font = '40px Microsoft YaHei';
- /* 左右对齐方式 (center left right start end) 基准起始坐标 */
- ctx.textAlign = 'center';
- /* 垂直对齐的方式 基线 baseline(top,bottom,middle) 基准起始坐标 */
- ctx.textBaseline = 'middle';
- //ctx.direction = 'rtl';
- //ctx.strokeText(str,x0,y0);
- ctx.fillText(str, x0, y0);
- /*6. 画一个下划线和文字一样长 */
- ctx.beginPath();
- /* 获取文本的宽度 */
- console.log(ctx.measureText(str));
- var width = ctx.measureText(str).width;
- ctx.moveTo(x0 - width / 2, y0 + 20);
- ctx.lineTo(x0 + width / 2, y0 + 20);
- ctx.stroke();
- </script>
- </body>
- </HTML>
别人骂我胖, 我会生气, 因为我心里承认了我胖. 别人说我矮, 我就会觉得好笑, 因为我心里知道我不可能矮. 这就是我们为什么会对别人的攻击生气.
攻我盾者, 乃我内心之矛 (11)
来源: https://www.cnblogs.com/qdhxhz/p/12405780.html