画扇形的方法

方法一:起始角度是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. [转载]PHP开发环境 AppServ 2.5.10 安装及修改

    [转载]PHP开发环境 AppServ 2.5.10 安装及修改   原文地址:PHP开发环境 AppServ 2.5.10 安装及修改 appserv下载地址:http://www.appservn ...

  2. (办公)记事本_linux网络命令

    参考谷粒学院的linux视频教程:http://www.gulixueyuan.com/course/300/task/7091/show 阿里云ECS云服务器更换公网IP的方法:https://yq ...

  3. Etcd Learning Notes

    官网:https://etcd.io 官方项目地址:https://github.com/etcd-io/etcd 参考资料: https://www.hi-linux.com/posts/40915 ...

  4. JenKins docker 集群

    //tag 桉树有时间来搞 **阿斯蒂 啊 阿斯蒂

  5. dropna fillna

    # NaN 浮点类型   np.nan+1 =>nan Python type(None)  // NoneType类型 不能参与运算 import pandas as pd from pand ...

  6. P1426

    和上次的小鱼题差不多,但多了一些条件. 先把游到 $ s - x $ 米是第 $ a_i $ 秒求出来,然后判断之后在第 $ a_{i + 1} $ 秒内游的距离是否 $ \geq 2x $ ,大于就 ...

  7. jsp用equals判断两个字符串变量是否相等

    使用即可: s1.equals(s2) 如果使用场景: if(s1==s2){} 这样使用可能会出现判断无效的情况. 使用if(s1.equals(s2)){}就可以了.

  8. JS-判断null值

    单独判断 null var str = null; if(str === null){ alert("is null"); } 同时判断 null 和 undefined 虽然nu ...

  9. idea垂直分屏

    1.找到分屏功能 搜索keymap(注意大小写): 2.Split Vertically 垂直分屏/Split Horizontally 水平分屏 3.添加快捷方式

  10. Idea rest client 使用(全) 真香

    看了网上好多的 idea rest client 讲解,大多都只是讲了它如何如何好,都只是简单的测了一个 json 的接口而已,个人实践了一把,里面还是有挺多坑的,但不得不说,那个脚本化处理请求的功能 ...