栅格

之前简单模板中有个宽/高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()的两个可选方法,然后我们会知道如何改变渲染图形的填充颜色及描边颜色。

绘制路径

图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。一个路径,甚至一个子路径,都是闭合的。使用路径绘制图形需要一些额外的步骤。

  1. 首先,需要创建路径起始点。
  2. 然后使用画图命令去画出路径。
  3. 把路径封闭。
  4. 一旦路径生成,通过描边或填充路径区域来渲染图形。

以下是所要用到的函数:

beginPath()     新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
closePath()     闭合路径之后图形绘制命令又重新指向到上下文中。
stroke()       通过线条来绘制图形轮廓。
fill()        通过填充路径的内容区域生成实心的图形。

生成路径的第一步叫做beginPath()。本质上,路径是由很多子路径构成,这些子路径都是在一个列表中,所有的子路径(线、弧形、等等)构成图形。而每次这个方法调用之后,列表清空重置,然后就可以重新绘制新的图形。

注意:当前路径为空,即调用beginPath()之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo(),无论最后的是什么。出于这个原因,几乎总是要在设置路径之后专门指定起始位置。

第二步就是调用函数指定绘制路径,本文稍后我们就能看到了。

第三,就是闭合路径closePath(),不是必需的。这个方法会通过绘制一条从当前点到开始点的直线来闭合图形。如果图形是已经闭合了的,即当前点为开始点,该函数什么也不做。

注意:当调用 fill() 函数时,所有没有闭合的形状都会自动闭合,所以不需要调用 closePath() 函数。但是调用 stroke() 时不会自动闭合。

例子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对象
所有的路径方法比如 moveTorectarc 或 quadraticCurveTo等,如我们前面见过的,都可以在Path2D中使用。

Path2D API 添加了 addPath作为将path结合起来的方法。当你想要从几个元素中来创建对象时,这将会很实用。比如:

Path2D.addPath(path [, transform])​    添加了一条路径到当前路径(可能添加了一个变换矩阵)。

例子6:

创造了一个矩形和一个圆。都被存为Path2D对象,后面再派上用场。随着新的Path2D API产生,几种方法也相应地被更新来使用Path2D对象而不是当前路径。在这里,带路径参数的strokefill可以把对象画在画布上。

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绘制形状的更多相关文章

  1. 学习笔记:HTML5 Canvas绘制简单图形

    HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" ...

  2. Canvas绘制图形

    1.Canvas绘制一个蓝色的矩形 <!DOCTYPE html> <html> <head lang="en"> <meta chars ...

  3. html5 canvas绘制圆形印章,以及与页面交互

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. canvas绘制五角星详细过程

    canvas绘制 <canvas id="straight"></canvas> <script> var canvas = document. ...

  5. 第165天:canvas绘制圆环旋转动画

    canvas绘制圆环旋转动画——面向对象版 1.HTML 注意引入Konva.js库 <!DOCTYPE html> <html lang="en"> &l ...

  6. canvas绘制路径

    canvas绘制路径 方法 beginPath() 创建一个新的路径 lineTo() 描绘路径 closePath() 沿着路径画直线,并且画点移动到路径开头 stroke() 绘制形状 fill( ...

  7. 【朝花夕拾】Android自定义View篇之(三)Canvas绘制文字

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10968358.html],谢谢! 前面的文章中在介绍Canvas的时候,提到过后续单独讲Can ...

  8. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习   从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...

  9. 怎样用JavaScript和HTML5 Canvas绘制图表

    原文:https://code.tutsplus.com/zh-...原作:John Negoita翻译:Stypstive 在这篇教程中,我将展示用JavaScript和canvas作为手段,在饼状 ...

随机推荐

  1. DB Query Analyzer 6.01 is released, SQL Execute Schedule function can be used

       DB Query Analyzer is presented by Master Gen feng, Ma from Chinese Mainland. It has English versi ...

  2. 和菜鸟一起学linux之linux性能分析工具oprofile移植

    一.内核编译选项 make menuconfig General setup---> [*] Profiling support <*> OProfile system profil ...

  3. C# 中的线程安全集合类

    C# 的集合类型中, 都有Synchronized静态方法, 和SyncRoot实例方法 对于ArrayList以及Hashtable 集合类来讲,当需要做到线程安全的时候,最好利用其自带的属性Syn ...

  4. CF633G

    题目大意: 给你一棵树,根节点为1 有2种操作,第一种是给u节点所在的子树的所有节点的权值+x 第二种是询问,假设v是子树u中的节点,有多少种质数满足av = p + m·k 做法:维护子树信息显然d ...

  5. 使用XStream是实现XML与Java对象的转换(1)--简介及入门示例

    一.简单介绍 XStream是thoughtworks开发的开源框架,用于实现XML数据于Java对象.Json数据的转换.它不需要schema或其他的mapping文件就可以进行java对象和xml ...

  6. ## 分享一下Mac(苹果电脑)里面好用的软件!

    该文章主要分享 Mac电脑常用的软件 文章来源于 github小弟调调™的仓库转载 说明 [Open-Source Software][OSS Icon] 表示 开源软件 ,点击进入 开源 仓库: ...

  7. Loader转换器

    一.简介 webpack本身只能处理js模块,Loader可以理解为模块和资源的转换器,它本身是一个函数,接受文件作为参数,返回转换的结果.因此,我们就能通过require来加载任何类型的模块和文件. ...

  8. ajax-------封装

    function ajax(url, fnSucc, fnFaild){ //1.创建Ajax对象 var oAjax=null; if(window.XMLHttpRequest) { oAjax= ...

  9. js获取Session的值

    纯htm页面必须采用AJAX了, ASP页面:var manager='<%=session("manager")%>', ASPX页面:var manager='&l ...

  10. 简单剖析Node中的事件监听机制(一)

    使用js的class类简单的实现一个事件监听机制,不同于浏览器中的时间绑定与监听,类似于node中的时间监听,并且会在接下来的文章中去根据自己的理解去写一下Event模块中的原理. Node.js使用 ...