前两章我们掌握了线段、矩形和多边形的绘制方法,今天我们主要是学习如何绘制圆弧和贝塞尔曲线。

圆弧的绘制

圆弧可以理解为一个圆上的某部分线段,在canvas中,绘制一条圆弧的语法如下:

ctx.arc( 圆心x坐标, 圆心y坐标, 圆的半径r , 开始角度, 结束角度 );

其中的 “开始角度” 和 “结束角度” 是相对360度的顺时针的极坐标而言的,可配合下图理解:

我们来一个例子,绘制一个圆心坐标为(80,80),半径为40,开始角度为30度,结束角度为90度,那么可以这样绘制:

<canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC;">
您的浏览器不支持canvas,建议使用最新版的Chrome
</canvas> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.arc( 80, 80, 40, 1/6*Math.PI, 1/2*Math.PI);
ctx.stroke(); //描边
</script>

其中开始角和结束角我们分别设定为“1/6*Math.PI”和“1/2*Math.PI”,是因为canvas里的角度是以PI(π)为单位的,在js中写作Math.PI,你可以把一个PI理解为180度,那么30度便是1/6个PI。上述代码效果如下:

开始角和结束角也可以是负值,则角度从0度开始以逆时针方式获取:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.arc( 80, 80, 40, -1/6*Math.PI, -1/2*Math.PI);
ctx.stroke(); //描边

我们可以很轻松地来绘制一个完整的圆,将起始角设为0度,结束角设为360度(2*Math.PI)即可:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.arc( 80, 80, 40, 0, 2*Math.PI); ctx.lineWidth = 3; //描边宽度为3px
ctx.strokeStyle = "yellow";
ctx.stroke(); //描边
ctx.fillStyle = "#4DA6FF";
ctx.fill(); //填充颜色

注意给圆填充颜色我们使用的是 .fill() 方法,和多边形的填充方式一样。

接着说说 arc() 的好兄弟 arcTo() 方法,它可以在两条线段之间连接起一条弧线,其语法如下

ctx.arcTo( 起点切线末端x坐标, 起点切线末端y坐标, 终点x坐标, 终点y坐标, 圆的半径r );

可以配合下图理解:

我们先不管什么“连接两条线段”的事情,单纯看下arcTo()绘制了怎样的一条圆弧:

<canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC;">
您的浏览器不支持canvas,建议使用最新版的Chrome
</canvas> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.moveTo(20,20); // 创建开始点
ctx.arcTo(60,20,60,60,40); // 创建圆弧路径
ctx.stroke();
</script>

效果如下:

那么我们利用arcTo()方法来连接两条直线吧:

<canvas id="myCanvas" width="200" height="200" style="border:solid 1px #CCC;">
您的浏览器不支持canvas,建议使用最新版的Chrome
</canvas> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.moveTo(20,20);
ctx.lineTo(60,20);
ctx.arcTo(100,20,100,60,40); // 创建圆弧路径
ctx.lineTo(100,100);
ctx.stroke();
</script>

效果如下:

需要知道的是 arc() 不会影响画笔的位置,而 arcTo() 会把画笔移到圆弧线的终点位置。

曲线的绘制

无论是arc()抑或arcTo(),均是绘制了一个正圆上的部分圆弧线段,下面讲讲更灵活的曲线的绘制。

首先介绍的是canvas中贝塞尔曲线的绘制。使用过AI等专业矢量制图软件的朋友相信能很好地理解这一部分。我们先看下在制图软件中用钢笔工具绘制一条贝塞尔曲线的过程:

可以看到每两点可以连成一条贝塞尔路径,且每一个点都有一条方位控制线来控制曲线的弯曲程度和走向,在canvas中也是以类似形式控制贝塞尔曲线的形状。

我们先来看看bezierCurveTo()的实现方式,它称作“三次方贝塞尔曲线”,其语法为:

ctx.bezierCurveTo( CSx, CSy, CEx, CEy, Ex, Ey );

其中CSx、CSy表示贝塞尔曲线起点方向控制线末端的x坐标和y坐标。CEx、CEy表示贝塞尔曲线终点方向控制线末端的x坐标和y坐标。Ex、Ey表示贝塞尔曲线终点坐标。

参考图如下,图中的贝塞尔曲线起点坐标为(20,20),终点坐标为(200,20),起点的方向控制线末端坐标为(20,100),终点的方向控制线末端坐标为(200,100):

有的朋友可能会问为何bezierCurveTo()方法没有起始点的参数,答案是起始点默认为bezierCurveTo()方法执行之前画笔所在的位置,我们可以通过ctx.moveTo(x,y)来确定起始点的位置。

如上图所示的贝塞尔曲线我们可以这样绘制:

<canvas id="myCanvas" width="300" height="150" style="border:solid 1px #CCC;">
您的浏览器不支持canvas,建议使用最新版的Chrome
</canvas> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.moveTo(20,20); //确定起始点
ctx.bezierCurveTo( 20, 100, 200, 100, 200, 20 );
ctx.stroke(); //描边
</script>

我们可以绘制两条或者多条连在一起的贝塞尔曲线,从而塑造我们想要的曲线:

<canvas id="myCanvas" width="400" height="250" style="border:solid 1px #CCC;">
您的浏览器不支持canvas,建议使用最新版的Chrome
</canvas> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.moveTo(20,120); //确定起始点
ctx.bezierCurveTo( 20, 200, 200, 200, 200, 120 ); //绘制第一条贝塞尔曲线
ctx.bezierCurveTo( 200, 20, 380, 20, 380, 120 ); //绘制第二条贝塞尔曲线,该曲线起点为上一条曲线终点(200,120)
ctx.stroke(); //描边
</script>

效果如下:

使用过矢量制图软件的朋友可能有个地方会困惑,那就是我们很多时候开始绘制一条曲线时(起点不做拉伸),该曲线的起点是没有任何方向控制线的,如下图:

如果我们要绘制一条起点不做方向控制的曲线,那么bezierCurveTo()方法就不再适用了。

针对这种情况,可以通过 quadraticCurveTo() 方法来解决,它称作“二次方贝塞尔曲线”,语法为

ctx.quadraticCurveTo( CEx, CEy, Ex, Ey );

其中CEx、CEy表示曲线终点方向控制线末端的x坐标和y坐标。Ex、Ey表示曲线终点坐标。至于曲线起点则跟bezierCurveTo()一样,为该方法执行前画笔所在的位置。

我们试着来绘制一条这样的曲线,它是我在AI中用钢笔工具绘制出来的:

它的矢量轮廓是这样的:

由于起点是没有方向控制线的,我们很容易知道得先绘制一条quadraticCurve,然后再紧接着绘制一条bezierCurve来完成这条曲线。

我们先确定下各点的坐标:

然后轻松写出代码:

<canvas id="myCanvas" width="490" height="270" style="border:solid 1px #CCC;">
您的浏览器不支持canvas,建议使用最新版的Chrome
</canvas> <script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d"); //获取该canvas的2D绘图环境对象
ctx.moveTo(52,37); //确定起始点
ctx.quadraticCurveTo( 45, 175, 172, 157 ); //绘制第一条曲线
ctx.bezierCurveTo( 298, 140, 337, 201, 312, 236 ); //绘制第二条曲线
ctx.stroke(); //描边
</script>

效果如下,杠杠的:

本章暂时写到这里,建议有兴趣的朋友多实践,其中贝塞尔曲线部分的知识点可以通过AI等矢量设计软件来加深理解。共勉~

HTML5- Canvas入门(三)的更多相关文章

  1. HTML5 canvas入门

    HTML5 Canvas入门 <canvas> 标签定义图形,比如图表和其他图像,您必须使用脚本来绘制图形.在画布上(Canvas)画一个红色矩形,渐变矩形,彩色矩形,和一些彩色的文字. ...

  2. html5 canvas 笔记三(绘制文本和图片)

    绘制文本 fillText(text, x, y [, maxWidth])   在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的. strokeText(text, x, y [, ma ...

  3. html5 Canvas绘制图形入门详解

    html5,这个应该就不需要多作介绍了,只要是开发人员应该都不会陌生.html5是「新兴」的网页技术标准,目前,除IE8及其以下版本的IE浏览器之外,几乎所有主流浏览器(FireFox.Chrome. ...

  4. HTML5 canvas绘制线条曲线

    HTML5 canvas入门 线条例子 1.简单线条 2.三角形 3.填充三角形背景颜色 4.线条颜色以及线条大小 5.二次贝塞尔曲线 6.三次贝塞尔曲线 <!doctype html> ...

  5. HTML5 Canvas 概述

    本文中,我们将探索如何使用HTML5的Canvas API.Canvas API很酷,我们可以通过它来动态创建生成和展示图形,图表,图像以及动画.本文将使用渲染API(rendering API)的基 ...

  6. Canvas入门笔记-实现极简画笔

    今天学习了Html5 Canvas入门,已经有大神写得很详细了http://www.cnblogs.com/tim-li/archive/2012/08/06/2580252.html#8 在学习过后 ...

  7. HTML5 Canvas 画图入门

    HTML5 Canvas 画图入门 HTML5 Canvas 画图入门,仅供学习參考 <!DOCTYPE html> <html> <head> <meta ...

  8. HTML5 canvas 在线画笔绘图工具(三)

    组装画板(TDrawBuilder) 在这一小节中我们要把工具条和画板组装起来,让他们可以协同进行工作. 画板通过一个命名为TDrawBuilder来进行组装.在详细讲解TDrawBuilder对象之 ...

  9. [js高手之路] html5 canvas系列教程 - arcTo(弧度与二次,三次贝塞尔曲线以及在线工具)

    之前,我写了一个arc函数的用法:[js高手之路] html5 canvas系列教程 - arc绘制曲线图形(曲线,弧线,圆形). arcTo: cxt.arcTo( cx, cy, x2, y2, ...

  10. 06. Web大前端时代之:HTML5+CSS3入门系列~HTML5 画布

    Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html 我们先看看画布的魅力: 初始画布 canvas默认是宽3 ...

随机推荐

  1. CSS系列:在HTML中引入CSS的方法

    HTML与CSS是两个作用不同的语言,它们同时对一个网页产生作用,因此必须将CSS与HTML链接在一起使用.在HTML中,引入CSS的方法主要有4种:行内式.内嵌式.导入式和链接式. 1. 行内式 行 ...

  2. 迭代器模式/iterator模式/对象行为型模式

    意图 又名:游标(Cursor): 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 动机 一个聚合对象,提供访问元素的方法,而有不暴露它的内部结构.如list,将对列表的访问 ...

  3. java中包的命令行(cmd)操作详解

    一.什么是包? 为了更好地组织类,防止在一个空间下出现类重名,Java提供了包机制.包是类的容器,用于分隔类名空间(类型于C++中的命名空间).如果没有指定包名,所有的示例都属于一个默认的无名包(又称 ...

  4. python 学习第二天

    由于换了博客,第一篇没有在博客园写,写在了开源中国上,链接地址为http://my.oschina.net/u/254063/blog/719289,大家有兴趣可以看看 一, python 数据类型 ...

  5. jQuery中事件绑定到bind、live、delegate、on方法的探究

    1. 给页面上的某个元素绑定事件,最初采用下面的方式实现: $(‘selector’).click(function(){ //code }); 缺点: 不能同时绑定多个事件,不能绑定动态的元素. 后 ...

  6. WPF中使用DynamicResource实现换肤

    这篇将介绍使用DynamicResource实现动态的界面切换功能.熟悉WPF的园友应该已经猜到了实现方式,简而言之就是动态替换DataTemplate,ControlTemplate,Style等等 ...

  7. Myeclipse打断点太多,不知道怎么一次性全删除

    1.打开Debug模式 2.菜单栏里面的Run.点击Remove all Breakpoints

  8. 【Hawk】入门教程(1)——从URL开始

    入门教程(1)--从URL开始 首先感谢辛苦的沙漠君 先把沙漠君的教程载过来:)可以先看一遍 Hawk-数据抓取工具:简明教程 Hawk 数据抓取工具 使用说明(二) 20分钟无编程抓取大众点评17万 ...

  9. [转]在Eclipse中使用JUnit4进行单元测试(中级篇)

    我们继续对初级篇中的例子进行分析.初级篇中我们使用Eclipse自动生成了一个测试框架,在这篇文章中,我们来仔细分析一下这个测试框架中的每一个细节,知其然更要知其所以然,才能更加熟练地应用JUnit4 ...

  10. 商贸食品车销成功应用PDA抄单 现场开单 打印销售单安卓智能手持POS应用

    中小超市配送食品,酒水饮料,业务员以往是挨家挨户抄每个超市需要哪些东西,晚上回公司再统计,打到软件里面,开单配货. 选用PDA后,人手一台,直接在超市里面抄好货物,通过网络传输到公司软件上面,加快了工 ...