canvas绘制形状
栅格
之前简单模板中有个宽/高150px的canvas元素。如下图所示,canvas元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas元素中的一像素。栅格的起点为左上角(坐标为(0,0))。所有元素的位置都相对于原点定位。所以图中蓝色方形左上角的坐标为距离左边(Y轴)x像素,距离上边(X轴)y像素(坐标为(x,y))。

绘制矩形
不同于SVG,HTML中的元素canvas只支持一种原生的图形绘制:矩形。所有其他的图形的绘制都至少需要生成一条路径。
canvas提供了三种方法绘制矩形:
fillRect(x, y, width, height) 绘制一个填充的矩形
strokeRect(x, y, width, height) 绘制一个矩形的边框
clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明
参数解释:x与y指定了在canvas画布上所绘制的矩形的左上角(相对于原点)的坐标。width和height设置矩形的尺寸。
这三个函数绘制之后会马上显现在canvas上,即时生效。
例子1:矩形
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.fillRect(25,25,100,100); //在x轴25,y轴25处,绘制一个宽高为100px的黑色正方形
ctx.clearRect(45,45,60,60); //从正方形的中心开始擦除了一个60*60px的正方形
ctx.strokeRect(50,50,50,50); //在清除区域内生成一个50*50的正方形边框。
}
}
结果如下:

接下来我们能够看到clearRect()的两个可选方法,然后我们会知道如何改变渲染图形的填充颜色及描边颜色。
绘制路径
图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。一个路径,甚至一个子路径,都是闭合的。使用路径绘制图形需要一些额外的步骤。
- 首先,需要创建路径起始点。
- 然后使用画图命令去画出路径。
- 把路径封闭。
- 一旦路径生成,通过描边或填充路径区域来渲染图形。
以下是所要用到的函数:
beginPath()新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。closePath()闭合路径之后图形绘制命令又重新指向到上下文中。stroke()通过线条来绘制图形轮廓。fill()通过填充路径的内容区域生成实心的图形。
生成路径的第一步叫做beginPath()。本质上,路径是由很多子路径构成,这些子路径都是在一个列表中,所有的子路径(线、弧形、等等)构成图形。而每次这个方法调用之后,列表清空重置,然后就可以重新绘制新的图形。
注意:当前路径为空,即调用beginPath()之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo(),无论最后的是什么。出于这个原因,几乎总是要在设置路径之后专门指定起始位置。
第二步就是调用函数指定绘制路径,本文稍后我们就能看到了。
第三,就是闭合路径closePath(),不是必需的。这个方法会通过绘制一条从当前点到开始点的直线来闭合图形。如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。
例子2:三角形
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(75,50);
ctx.lineTo(100,75);
ctx.lineTo(100,25);
ctx.fill();
}
}

移动笔触
moveTo(x, y)将笔触移动到指定的坐标x以及y上。
当canvas初始化或者beginPath()调用后,通常会使用moveTo()函数设置起点。也能够使用moveTo()绘制一些不连续的路径。
例子3:笑脸
用到moveTo()方法(红线处)的地方标记了,想看到连续的线,移除调用的moveTo()就可以了。
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(75,75,50,0,Math.PI*2,true); // 绘制
ctx.moveTo(110,75); //红色线标记位置
ctx.arc(75,75,35,0,Math.PI,false); // 口(顺时针)
ctx.moveTo(65,65); //红色线标记位置
ctx.arc(60,65,5,0,Math.PI*2,true); // 左眼
ctx.moveTo(95,65); //红色线标记位置
ctx.arc(90,65,5,0,Math.PI*2,true); // 右眼
ctx.stroke();
}
}
效果如下:

线
绘制直线,需要用到的方法lineTo()。
lineTo(x, y)绘制一条从当前位置到指定x以及y位置的直线。
该方法有两个参数:x以及y ,代表坐标系中直线结束的点。开始点和之前的绘制路径有关,之前路径的结束点就是接下来的开始点,等等。。。开始点也可以通过moveTo()函数改变。
例子4:三角形(填充)+三角形(描边)
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
// 填充三角形
ctx.beginPath();
ctx.moveTo(25,25);
ctx.lineTo(105,25);
ctx.lineTo(25,105);
ctx.fill();
// 描边三角形
ctx.beginPath();
ctx.moveTo(125,125);
ctx.lineTo(125,45);
ctx.lineTo(45,125);
ctx.closePath();
ctx.stroke();
}
}

圆弧
绘制圆弧或者圆,使用arc()方法。
arc(x, y, radius, startAngle, endAngle, anticlockwise)- 画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。
arcTo(x1, y1, x2, y2, radius)- 根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
参数详解:x,y 绘制圆弧所在圆上的圆心坐标。
radius 半径
startAngle / endAngle 开始以及结束的弧度(以x轴为基准)
anticlockwise 为一个布尔值。为true时,是逆时针方向,否则顺时针方向。
注意:arc()函数中的角度单位是弧度,不是度数。角度与弧度的js表达式:radians=(Math.PI/180)*degrees。
下面两个for循环,生成圆弧的行列(x,y)坐标。每一段圆弧的开始都调用beginPath()。代码中,每个圆弧的参数都是可变的,实际生活中,并不需要这样做。
x,y坐标是可变的。半径(radius)和开始角度(startAngle)都是固定的。结束角度(endAngle)在第一列开始时是180度(半圆)然后每列增加90度。最后一列形成一个完整的圆。
clockwise 语句作用于第一、三行是顺时针的圆弧,anticlockwise作用于二、四行为逆时针圆弧。if 语句让一、二行描边圆弧,下面两行填充路径。
注意: 这个示例所需的画布大小略大于本页面的其他例子: 150 x 200 像素。
例子5: 12个不同的角度以及填充的圆弧
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
for(var i=0;i<4;i++){
for(var j=0;j<3;j++){
ctx.beginPath();
var x = 25 + j*50; // x 坐标值
var y = 25 + i*50; // y 坐标值
var radius = 20; // 圆弧半径
var startAngle = 0; // 开始点
var endAngle = Math.PI+(Math.PI*j)/2; // 结束点
var anticlockwise = i%2==0 ? false : true; // 顺时针或逆时针
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
if (i>1){
ctx.fill();
} else {
ctx.stroke();
}
}
}
}
}

贝塞尔以及二次贝塞尔
一次以及二次贝塞尔曲线都十分有用,一般用来绘制复杂有规律的图形。
quadraticCurveTo(cp1x, cp1y, x, y)绘制贝塞尔曲线,cp1x,cp1y为控制点,x,y为结束点。bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)绘制二次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
下图能够很好的描述两者的关系,贝塞尔曲线有一个开始、结束点(蓝色)以及一个控制点(红色),而二次贝塞尔曲线使用两个控制点。

使用一次以及二次贝塞尔曲线是有一定的难度的,不同于Adobe Illustrators这样的矢量软件,绘制的曲线没有直接的视觉反馈给我们。这让绘制复杂的图形十分的困难。
贝塞尔曲线
例子6: 多个贝塞尔曲线来渲染对话气泡
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
// 贝尔赛曲线
ctx.beginPath();
ctx.moveTo(75,25);
ctx.quadraticCurveTo(25,25,25,62.5);
ctx.quadraticCurveTo(25,100,50,100);
ctx.quadraticCurveTo(50,120,30,125);
ctx.quadraticCurveTo(60,120,65,100);
ctx.quadraticCurveTo(125,100,125,62.5);
ctx.quadraticCurveTo(125,25,75,25);
ctx.stroke();
}
}
二次贝塞尔曲线
例子6:贝塞尔曲线绘制心形

矩形
直接在画布上绘制矩形的三个额外方法, Drawing rectangles,同样,也有rect()方法,将一个矩形路径增加到当前路径上。
rect(x, y, width, height)绘制一个左上角坐标为(x,y),宽高为width以及height的矩形。
当该方法执行的时候,moveTo()方法自动设置坐标参数(0,0)。也就是说,当前笔触自动重置会默认坐标。
组合使用
例子6:组合使用所有的路径函数来重现一组著名的游戏人物
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
roundedRect(ctx,12,12,150,150,15);
roundedRect(ctx,19,19,150,150,9);
roundedRect(ctx,53,53,49,33,10);
roundedRect(ctx,53,119,49,16,6);
roundedRect(ctx,135,53,49,33,10);
roundedRect(ctx,135,119,25,49,10);
ctx.beginPath();
ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false);
ctx.lineTo(31,37);
ctx.fill();
for(var i=0;i<8;i++){
ctx.fillRect(51+i*16,35,4,4);
}
for(i=0;i<6;i++){
ctx.fillRect(115,51+i*16,4,4);
}
for(i=0;i<8;i++){
ctx.fillRect(51+i*16,99,4,4);
}
ctx.beginPath();
ctx.moveTo(83,116);
ctx.lineTo(83,102);
ctx.bezierCurveTo(83,94,89,88,97,88);
ctx.bezierCurveTo(105,88,111,94,111,102);
ctx.lineTo(111,116);
ctx.lineTo(106.333,111.333);
ctx.lineTo(101.666,116);
ctx.lineTo(97,111.333);
ctx.lineTo(92.333,116);
ctx.lineTo(87.666,111.333);
ctx.lineTo(83,116);
ctx.fill();
ctx.fillStyle = "white";
ctx.beginPath();
ctx.moveTo(91,96);
ctx.bezierCurveTo(88,96,87,99,87,101);
ctx.bezierCurveTo(87,103,88,106,91,106);
ctx.bezierCurveTo(94,106,95,103,95,101);
ctx.bezierCurveTo(95,99,94,96,91,96);
ctx.moveTo(103,96);
ctx.bezierCurveTo(100,96,99,99,99,101);
ctx.bezierCurveTo(99,103,100,106,103,106);
ctx.bezierCurveTo(106,106,107,103,107,101);
ctx.bezierCurveTo(107,99,106,96,103,96);
ctx.fill();
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(101,102,2,0,Math.PI*2,true);
ctx.fill();
ctx.beginPath();
ctx.arc(89,102,2,0,Math.PI*2,true);
ctx.fill();
}
}
// 封装的一个用于绘制圆角矩形的函数.
function roundedRect(ctx,x,y,width,height,radius){
ctx.beginPath();
ctx.moveTo(x,y+radius);
ctx.lineTo(x,y+height-radius);
ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
ctx.lineTo(x+width-radius,y+height);
ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
ctx.lineTo(x+width,y+radius);
ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
ctx.lineTo(x+radius,y);
ctx.quadraticCurveTo(x,y,x,y+radius);
ctx.stroke();
}

重要的一点是绘制上下文中使用到了fillStyle属性,以及封装函数(例子中的 roundedRect())。使用封装函数对于减少代码量以及复杂度十分有用。
Path2D 对象
为了简化代码和提高性能,Path2D对象已可以在较新版本的浏览器中使用,用来缓存或记录绘画命令,快速地回顾路径。
怎样产生一个Path2D对象呢?
Path2D()Path2D()会返回一个新初始化的Path2D对象(可能将某一个路径作为变量——创建一个它的副本,或者将一个包含SVG path数据的字符串作为变量)。-
new Path2D(); // 空的Path对象所有的路径方法比如
new Path2D(path); // 克隆Path对象
new Path2D(d); // 从SVG建立Path对象moveTo,rect,arc或quadraticCurveTo等,如我们前面见过的,都可以在Path2D中使用。Path2D API 添加了
addPath作为将path结合起来的方法。当你想要从几个元素中来创建对象时,这将会很实用。比如:Path2D.addPath(path [, transform]) 添加了一条路径到当前路径(可能添加了一个变换矩阵)。例子6:
创造了一个矩形和一个圆。都被存为Path2D对象,后面再派上用场。随着新的Path2D API产生,几种方法也相应地被更新来使用Path2D对象而不是当前路径。在这里,带路径参数的
stroke和fill可以把对象画在画布上。function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d'); var rectangle = new Path2D();
rectangle.rect(10, 10, 50, 50); var circle = new Path2D();
circle.moveTo(125, 35);
circle.arc(100, 35, 25, 0, 2 * Math.PI); ctx.stroke(rectangle);
ctx.fill(circle);
}
}
使用 SVG paths
新的Path2D API有另一个强大的特点,就是使用SVG path data来初始化canvas上的路径。获取路径时可以以SVG或canvas的方式来重用它们。
这条路径将先移动到点
(M10 10)然后再水平移动80个单位(h 80),然后下移80个单位(v 80),接着左移80个单位(h -80),再回到起点处 (z)。var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
canvas绘制形状的更多相关文章
- 学习笔记:HTML5 Canvas绘制简单图形
HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" ...
- Canvas绘制图形
1.Canvas绘制一个蓝色的矩形 <!DOCTYPE html> <html> <head lang="en"> <meta chars ...
- html5 canvas绘制圆形印章,以及与页面交互
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- canvas绘制五角星详细过程
canvas绘制 <canvas id="straight"></canvas> <script> var canvas = document. ...
- 第165天:canvas绘制圆环旋转动画
canvas绘制圆环旋转动画——面向对象版 1.HTML 注意引入Konva.js库 <!DOCTYPE html> <html lang="en"> &l ...
- canvas绘制路径
canvas绘制路径 方法 beginPath() 创建一个新的路径 lineTo() 描绘路径 closePath() 沿着路径画直线,并且画点移动到路径开头 stroke() 绘制形状 fill( ...
- 【朝花夕拾】Android自定义View篇之(三)Canvas绘制文字
前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10968358.html],谢谢! 前面的文章中在介绍Canvas的时候,提到过后续单独讲Can ...
- Canvas学习:封装Canvas绘制基本图形API
Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习 从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...
- 怎样用JavaScript和HTML5 Canvas绘制图表
原文:https://code.tutsplus.com/zh-...原作:John Negoita翻译:Stypstive 在这篇教程中,我将展示用JavaScript和canvas作为手段,在饼状 ...
随机推荐
- Python和shell中Base64编码使用那些事
做开发第一个接触的编码方式就是Base64,当时是用url来传输一些参数,传输的两端会用Base64来编码和解码,保证数据不被url转义破坏. 下面是 维基百科 Base64 中的介绍,其实自己实现起 ...
- OpenCV——RGB三通道分离
opencv 和 matlab 在处理彩色图像的时候,通道的存储顺序是不同的. matlab 的排列顺序是R,G,B: 而在opencv中,排列顺序是B,G,R. 下面通过一个小程序看看opencv中 ...
- 复位windows网络参数的方法
使用电脑的时候,经常会遇到网络相关的问题,以前读大学的时候就知道怎么解决,就是下面这个方案. 开始-全部程序-附件-命令提示符-右键-以管理员身份运行出来一个黑底白字的窗口,在里面输入: netsh ...
- obj-c编程13:归档
这篇归档内容的博文也挺有趣的,笨猫对好玩的东西一向感兴趣啊!如果用过ruby就会知道,obj-c里的归档类似于ruby中的序列化概念,不过从语法的简洁度来说,我只能又一次呵呵了. 下面大家将会看到2种 ...
- linux_熟悉常用Linux命令
man :任何时候你觉得对一个命令行不是很确定,都可以通过输入"man + 命令"来了解这个命令能确切是做什么的. ls :列出目录内容. pwd :在终端中显示当前工作目录的全路 ...
- 修改flume源码,使其HTTPSource具备访问路径功能
目前有一个需求,就是Flume可以作为一个类似于tomcat的服务器,可以通过post请求进行访问,并且路径需要:ip:port/contextPath格式. 经过一些资料获悉,httpSource只 ...
- 初识Java——日期的格式化
import java.util.*; class DateTest{ static{ System.out.println("谢谢使用!");//代码块,在初始化类时,先执行代码 ...
- Hyper Text Transfer Protocol(超文本传输协议)
HTTP简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送 ...
- MySQL的日志(一)
本文目录:1.日志刷新操作2.错误日志3.一般查询日志4.慢查询日志5.二进制日志 5.1 二进制日志文件 5.2 查看二进制日志 5.2.1 mysqlbinlog 5.2.2 show binar ...
- CSS后代选择器“空格”和“>”的使用辨析
要点: 1. "空格":包含子孙 2. ">":含子不含孙 举个栗子: html代码如下 <body> <div class=" ...
