画扇形的方法

方法一:起始角度是0,那么第一条线就是line(r,0),通过旋转扇形的角度,第二条线就是line(r,0)

//圆弧
ctx.save();
ctx.translate(100, 100);
ctx.arc(0,0,100,0, 30*Math.PI/180);
ctx.restore();
//第一条线
ctx.save();
ctx.moveTo(100,100);
ctx.lineTo(200,100);
ctx.restore();
//第二条线
ctx.save();
ctx.translate(100, 100);
ctx.moveTo(0,0);
ctx.rotate(30*Math.PI/180);
ctx.lineTo(100,0);
ctx.stroke();
ctx.restore();

第一步为什么是设置原点呢,为什么不用moveTo来设置起始点呢?

  因为画布的默认原点在0,0的位置上,如果用moveTo来设置起始点,原点依然还在0,0的位置,而变换是以原点为基准点的,即使你设置了起始点,但是起始点不是原点的话,图形旋转依然会围绕0,0点旋转然后自转,得到的图形就不知道是什么图形了。

方法二

//将原点设置100,100位置
ctx.translate(100,100);
//原点在100,100,则圆心设为0,0 ——> 100,100的位置
ctx.arc(0,0,100,30*Math.PI/180,60*Math.PI/180);
//save(),restore()是为了防止角度旋转的污染
ctx.save();
ctx.rotate(30*Math.PI/180);
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.restore();
ctx.rotate(60*Math.PI/180);
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.stroke();

关于save()和restore():

  其作用不只是可以防止外面的属性或方法对里面的绘制产生影响,它的本质意思是save()保存当前环境的状态,restore()返回之前保存路径的状态。在这里要注意还原的触点在什么地方,如下例子:

 //将原点设置100,100位置
ctx.translate(100,100);
//原点在100,100,则圆心设为0,0 ——> 100,100的位置
ctx.arc(0,0,100,30*Math.PI/180,60*Math.PI/180);
//save(),restore()是为了防止角度旋转的污染
ctx.save();
ctx.rotate(30*Math.PI/180);
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.restore();
ctx.rotate(60*Math.PI/180);
ctx.lineTo(100,0);
ctx.stroke();

跟上面的代码比就是少了12行的moveTo(0,0),结果如下图1:

原因是:线在旋转的时候,是从它的起点为圆心旋转的,而上面的代码是,第一条线从圆心开始,到圆弧的起点(旋转过后),自然现在的起点就是圆弧的起点了,然后再rotate(60*Math.PI/180);lineTo(100,0);就是从圆弧的起点画到(100,0)的线了

现在我们将第一条直线的起点设在(r,0)的位置,旋转后就到了圆弧的起始点,然后在画到圆心地方,那现在的起始点就是圆心了,再画一条线到圆弧,就可以了,如下:

//将原点设置100,100位置
ctx.translate(100,100);
//原点在100,100,则圆心设为0,0 ——> 100,100的位置
ctx.arc(0,0,100,30*Math.PI/180,60*Math.PI/180);
//save(),restore()是为了防止角度旋转的污染
ctx.save();
ctx.rotate(30*Math.PI/180);
ctx.moveTo(100,0);
ctx.lineTo(0,0);
ctx.restore();
ctx.rotate(60*Math.PI/180);
ctx.lineTo(100,0);
ctx.stroke();

 方法三:充分使用触点的作用,当我们再画圆弧的时候,画完之后其触点在圆弧的结束位置,为何不直接将这个触点作为起点,画一条到圆心的线,然后再画第二条线。如下代码:

//将原点设置100,100位置
ctx.translate(100,100);
//原点在100,100,则圆心设为0,0 ——> 100,100的位置
ctx.arc(0,0,100,30*Math.PI/180,60*Math.PI/180);
//以圆弧终点为起点画直线,rotate使得直角坐标系旋转了30°
ctx.lineTo(0,0);
ctx.rotate(30*Math.PI/180);
//以0,0为起点画直线
ctx.lineTo(100,0);
ctx.stroke();

方法四:配合beginPath()和closePath()

为什么要用translate,而不要moveTo,是因为如果需要旋转,所以就需要原点,现在不需要旋转,而是正常的画图,那么就不需要原点,就可以用moveTo。

配合beginPath()和closePath(),就会将一个圆弧封闭起来。

ctx.beginPath();
//定义起点
ctx.moveTo(100,100);
//以起点为圆心,画一个半径为100的圆弧
ctx.arc(100,100,100,30*Math.PI/180, 60*Math.PI/180);
ctx.closePath();
ctx.stroke();

 特别注意:

  • 使用arc()绘制图形时,如果没有设置moveTo(),那么会从圆弧的开始的点作为起始点。如果设置了moveTo(),那么该点会连线到圆弧起始点。
  • 如果使用stroke()方法,那么会从开始连线到圆弧的起始位置。 如果是 fill 方法, 会自动闭合路径填充

封装函数

CanvasRenderingContext2D.prototype.sector = function(x,y,r,angle1,angle2){
this.save();
this.beginPath();
this.moveTo(x,y);
this.arc(x,y,r,angle1*Math.PI/180,angle2*Math.PI/180,false);
this.closePath();
this.restore();
return this;
}
ctx.fillStyle = 'red';
ctx.sector(200,200,100,30,150).fill();
ctx.fillStyle = 'green';
ctx.sector(200,200,100,150,270).fill();
ctx.fillStyle = 'blue';
ctx.sector(200,200,100,270,390).fill();

画饼图

思路:

1)将每块饼的占比以整数形式储存在数组nums中,将每个饼的颜色以字符串形式储存在数组colors中,两个数组的值一一对应。将画布旋转坐标定义在即将绘制圆的中心,定义绘制圆弧(饼)的起始角度start和终止角度end均为0

2)绘制圆饼,6个不同板块,所以有6次for循环,从绘制第二个饼开始,起始角度是在上一个饼的终止角度位置,因此,每次循环开始后,要对当前的终止角度end进行累加一次,绘制圆弧直接以start开始,以end结束,当前绘制完成之后,要对起始角度start完成一次累加;同时每次绘制都给板块填充对应的颜色。封装为函数pieChart();

3)绘制圆饼对应的占比数值,也是6次for循环,为了便于代码易读,这里重新定义了一个函数。并对起始角度start和终止角度end重新利用,nums中储存的是当前数值占100的份数,将其转化为对应角度为nums[i]/50*Math.PI;让其显示在板块角度中线位置nums[i]/50*Math.PI/2;同样每次循环起始角度是在上一个饼的终止角度位置,绘制前后也要进行累加。封装为函数pieNum();

<canvas id="can1" width="800" height="600"></canvas>
<script type="text/javascript">
var can1 = document.getElementById("can1");
var ctx = can1.getContext("2d");
var nums = [26,15,12,5,25,17];
var colors = ["#983335","#77963f","#5d437c","#35859f","#d1702f","#365e96"];
var start = 0;
var end = 0;
ctx.translate(400,350);
//绘制圆饼
function pieChart(){
for (var i = 0;i < nums.length; i ++){
ctx.beginPath();
ctx.moveTo(0,0);
end += nums[i]/50*Math.PI;//终止角度
ctx.strokeStyle = "white";
ctx.fillStyle = colors[i];
ctx.arc(0,0,200,start,end);
ctx.fill();
ctx.closePath();
ctx.stroke();
start += nums[i]/50*Math.PI;//起始角度
}
}
//绘制圆饼上的数值
function pieNum(){
for (var i = 0;i < nums.length; i ++){
start = nums[i]/50*Math.PI/2;
ctx.rotate(end+start);//旋转数值
ctx.font = "25px scans-serif";
ctx.fillStyle = "#000";
ctx.fillText(nums[i]+"%",140,0);
end = nums[i]/50*Math.PI/2;
}
}
ctx.rotate(-Math.PI/6);//旋转一定角度更加自然
pieChart();
pieNum();
</script>

canvas画扇形、饼图的更多相关文章

  1. canvas画扇形图(本文来自于http://jo2.org/html5-canvas-sector/)

    1.定义画扇形的构造函数: //扇形CanvasRenderingContext2D.prototype.sector = function (x, y, radius, sDeg, eDeg) {/ ...

  2. canvas画饼图

    <style> body {    background: black;    text-align: center; } #cans {    background: white; } ...

  3. Android利用canvas画各种图形(点、直线、弧、圆、椭圆、文字、矩形、多边形、曲线、圆角矩形) .

    1.首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, ...

  4. Android利用canvas画各种图形 及Paint用法 .

    引自:http://blog.csdn.net/carlfan/article/details/8139984 1.首先说一下canvas类: Class Overview The Canvas cl ...

  5. canvas图表(3) - 饼图

    原文地址:canvas图表(3) - 饼图 这几天把canvas图表都优化了下,动画效果更加出色了,可以说很逼近echart了.刚刚写完的饼图,非常好的实现了既定的功能,交互的动画效果也是很棒的. 效 ...

  6. 关于设备与canvas画不出来的解决办法

    连续四天解决一个在三星手机上面画canvas的倒计时饼图不出来的问题,困惑了很久,用了很多办法,甚至重写了那个方法,还是没有解决,大神给的思路是给父级加 "overflow: visible ...

  7. Android利用canvas画各种图形

    Android利用canvas画各种图形(点.直线.弧.圆.椭圆.文字.矩形.多边形.曲线.圆角矩形) 本文链接:https://blog.csdn.net/rhljiayou/article/det ...

  8. 使用javascript和canvas画月半弯

    使用javascript和canvas画月半弯,月半弯好浪漫!浏览器须支持html5 查看效果:http://keleyi.com/a/bjad/8xqdm0r2.htm 以下是代码: <!do ...

  9. canvas 画圈 demo

    html代码: <canvas id="clickCanvas2"  width="180" height="180" data-to ...

随机推荐

  1. 2020 i春秋新春战疫公益赛 misc

    0x01 code_in_morse morse decode后得到: RFIE4RYNBINAUAAAAAGUSSCEKIAAAAEUAAAAA7AIAYAAAAEPFOMTWAAABANUSRCB ...

  2. VS2013 Solution Explorer can not open

    Delete content under the path: C:\Users\username\AppData\Local\Microsoft\VisualStudio\12.0\Component ...

  3. netty笔记-:EpollEventLoopGroup:Caused by: java.lang.ExceptionInInitializerError:Caused by: java.lang.IllegalStateException: Only supported on Linux

    今天在翻看netty的源码的时候发现netty对EventLoopGroup的实现有不止常用的NIOEventLoopGroup ,一共有以下几种. EpollEventLoopGroup NioEv ...

  4. powershell 无法运行一些脚本的情况

    有时候在powershell里运行脚本会报错: 无法加载文件 ******.ps1,因为在此系统中禁止执行脚本.有关详细信息,请参阅 "get-help about_signing" ...

  5. Unity中调用Windows窗口选择文件

    1.OpenFileName数据接收类,如下: using UnityEngine; using System.Collections; using System; using System.Runt ...

  6. 关于ASA的TCP MSS

    About the TCP MSS The TCP maximum segment size (MSS) is the size of the TCP payload before any TCP a ...

  7. Maven____笔记摘抄

    1 1.maven的作用 i.增加第三方Jar (spring-context.jar spring-aop.jar ....) ii.jar包之间的依赖关系 (spring-context.jar ...

  8. 高级T-SQL进阶系列 (二)【上篇】:使用 APPLY操作符

    [译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:传送门. 伴随着SQL SERVER 2005的发布,微软增加了一个新的操作符,它允许你将一个记录集与一个函数进行关联,然 ...

  9. Python笔记4

    JSON: JavaScript Object Notation,  JavaScript 对象标记 JSON 本质:是一种轻量级的数据交换格式 1. 轻量级 是 和 XML作比较 2. 数据交换格式 ...

  10. 「CF1313C Skyscrapers」

    题目大意 给出一个长度为 \(N\) 的序列 \(a\) 需要构造出一个长度为 \(N\) 的序列 \(h\) 使得 \(\forall i \in \{1,2,\ldots ,N\} h_i \le ...