画扇形的方法

方法一:起始角度是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. 自定义xmlhttprequest

    /** * xhr_proxy.js * 通过劫持原生XMLHttpRequest实现对页面ajax请求的监听 * @author binaryfire */ const READY_STATE_CH ...

  2. vue动态生成组件

    单个组件引用,引入此文件js.全局使用,注册到vue的main文件Vue.prototype.create = Create create.js import Vue from 'vue';impor ...

  3. docker基础知识之挂载本地目录

    docker可以支持把一个宿主机上的目录挂载到镜像里. docker run -it -v /home/dock/Downloads:/usr/Downloads ubuntu64 /bin/bash ...

  4. idea如何提取变量(拆分变量赋值和声明)

    需求描述: 我们时常遇到某个在某个局部作用域声明的变量,想要用在另一个地方,此时就需要在作用域外部声明变量,在作用域中给变量赋值. 在eclipse中这个功能和提取变量在一起,我们可以方便的拆分变量的 ...

  5. Java入门笔记 04-异常处理

    一. 异常概述: 1. 异常体系结构图: java.lang.Throwable          |-----java.lang.Error:一般不编写针对性的代码进行处理.          |- ...

  6. 开源沙箱CuckooSandbox 介绍与部署

    1. 介绍 1.1应用  在工作中很多时候需要自己对一些可以程序,可执行文件进行检测,当然我们可以通过VT,微步,等一些开源的平台进行检测.现在我们通过自己搭建的开源的沙箱进行检测.所谓沙箱,是分离运 ...

  7. Perl 笔记

    目录 Perl 学习 常用记录 基础 1. 运行perl 2. 字符串 3. 变量 4. 条件 5. 循环 6. 运算符 7. 时间日期 8. 子程序(函数) 9. 引用 10. 格式化输出 11. ...

  8. 【代码审计】appcms 文件包含漏洞

    index.php的开头系统都做了过滤 一个是 htmlspecialchars($v), 另一个是/^[\x{4e00}-\x{9fa5}\w {0}]+$/u. 前一个过滤是把预定义的字符 &qu ...

  9. Spring Boot Thymeleaf 模板引擎的使用

    Spring Boot 中可以支持很多模板引擎,Thymeleaf 是 Spring Boot 官方推荐使用的模板引擎,虽然在社区 Thymeleaf 的性能被许多人所吐糟,但这仍然不影响大量的开发人 ...

  10. 27 JavaScript的引入&注释&弹窗&变量常量&数据类型及转换&内存&垃圾回收

    JS的引入: 1 内部引入 绑定元素事件如onclick="" 绑定锚点如href="JavaScript:void(0)" script标签引入,注意:如果标 ...