整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

html5 的 Canvas介绍

SVG是构建XML树的方式来达到绘制图形的,canvas是通过调用相关的方法来绘制图形的。

区别:SVG绘制图形,通过移除或者更改DOM方式来而使用canvas需要把图片从新擦除。

绘制的API在绘制上下文中定义。而不在画布中定义。

需要获得上下文对象的时候,需要调用画布的getContext方法,获得绘画的上下文。

画布元素和上下文,属于两个不同的对象,其中画布元素为canvas画布,而上下文对象为绘制需要的上下文。

关于3D图形,即,webGL 为封装了基本的OPENGL,当调用webGL的时候,其浏览器会调用OpenGL相关的API

绘制圆

<!DOCTYPE html>
<html lang="zh_CN" xmlns="http://www.w3.org/1999/html">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
<div>第一个园</br>
 <canvas id="square" width="10" height="100">
 </canvas>
</div>
<div>
 第二个园
 <canvas id="circle" width="10" height="10">
 </canvas>
</div>
<script src="./js/index.js" charset="UTF-8"></script>
</body>
</html>
// 获取画布元素
let canvas = document.getElementById("square");
// 获取绘制2D元素上下文
let context = canvas.getContext("2d");
// 设置填充颜色为红色
context.fillStyle = "#f00";
// 填充一个正方形
context.fillRect(10,0,10,10);

绘制线段,填充多边形

// 获取画布元素

let canvas = document.getElementById("square");

// 获取绘制2D元素上下文

let context = canvas.getContext("2d");

// 开始一条路径

context.beginPath();

// 从100,100 开始定义一条新的子路径

context.moveTo(100,100);

// 从100 100 到 200 200 绘制一条线段

context.lineTo(200,200);

// 从200 200 到 100 200 绘制一条线段

context.lineTo(100,200);

// 从100 200 到 100 100 绘制一条路径

context.lineTo(100,100);

// 绘制边

context.stroke();

// 进行填充

context.fill();

绘制多边形

以五边形为例子,

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 绘制一个以100,100为中心,半径为20的柜子N变形,每个定点均匀分布在圆角上,第一个定点放置在最上下
// 偏转角度为0
// 开始定义一条子路径
context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0));
// 计算两个顶点之间夹角
// 其中2π为一个园,除以边数,得到需要旋转的角度
var delta = 2 * Math.PI/5;
console.log(delta);
// 循环剩余每个顶点
var angle = 0;
for(var i = 1; i < 5; i++){
 // 角度累加
 angle += delta;
 // 通过旋转绘制下一个顶点,不断的旋转绘制
 context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle));
}
// 最后一个顶点和起点进行连接
context.closePath();
// 从新开始一条新路径
context.stroke();
context.fill();

同理,画圆

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 绘制一个以100,100为中心,半径为20的柜子N变形,每个定点均匀分布在圆角上,第一个定点放置在最上下
// 偏转角度为0
// 开始定义一条子路径
context.moveTo(100 + 20 * Math.sin(0), 100 - 20 * Math.cos(0));
// 计算两个顶点之间夹角
// 其中2π为一个园,除以边数,得到需要旋转的角度
var delta = 2 * Math.PI/500000;
console.log(delta);
// 循环剩余每个顶点
var angle = 0;
for(var i = 1; i < 500000; i++){
 // 角度累加
 angle += delta;
 // 通过旋转绘制下一个顶点,不断的旋转绘制
 context.lineTo(100 + 20 * Math.sin(angle), 100 - 20*Math.cos(angle));
}
// 最后一个顶点和起点进行连接
context.closePath();
// 从新开始一条新路径
context.stroke();
context.fill();

非零绕数原则

要检测一个点p是否在路径内部,使用非零绕数原则,即,一条从点p出发沿着任意方向无限延伸,或者一直延伸到路径所在的区域外某点的射线,现在从0开始初始化一个计数器,对穿过这条射线的路径进行枚举,每当一条路径顺时针方向穿过射线的时候,计数器加1,逆时针减1,最后,枚举完所有路径以后,如果计时器的值不是0,那么就认为p在路径内,反过来,计数器的值为0,p在路径外。

js根据非零绕数原则确定那个在路径内,那个在路径外,用于进行填充。

图形属性

可以通过设置画布上下文的fillStyle等属性,设置图形的属性,例如对画布上下文的fillStyle的属性进行设置,即,可以设置出填充时的颜色,渐变,图案等样式。

对于canvas来说,每次获取上下文对象的时候,都会返回同一个上下文对象,即,上下文对象为单例的。

还可以使用save方法,把当前的状态,压入已经保存的栈中,调用restore方法,把状态进行恢复,即弹栈。

画布尺寸坐标

画布的默认的坐标系为左上角的坐标原点(0,0),右边数值大,下数值大,使用浮点数指定坐标,但不会自动转换为整数,会用反锯齿的方式,模拟填充部分元素。

画布尺寸不能随意改变,对任意属性进行操作,都会清空整个画布。

坐标系变换

每一个点的坐标都会映射到css像素上,css像素会映射到一个或多个设备像素。

画布中的特定操作,属性使用默认坐标系。

画布还有当前变换矩阵。

画布还有当前变换矩阵,当前变换矩阵作为图形状态的一部分。矩阵定义了当前画布的坐标系。

画布的操作会把该点映射到当前的坐标系中。

坐标变换

当调用c.translate(dx,dy)方法的时候,会进行如下变换

translate会进行坐标的上下移动

x' = x + dy;
y' = y + dy;

缩放

如要进行缩放,进行的是如下的变换

x' = sx * x;
y' = sy * y;

进行旋转操作,进行的是如下变换

x' = x * cos(a) - y * sin(a);
y' = y * cos(a) - x * sin(a);

如果要先变换再伸缩,进行如下变换

需要先把现有坐标系映射成为坐标系中的点x’, y’ 然后再变换到x‘’ , y‘’

x'' = sx*x + dx;
y'' = sy*y + dy;

如果变换顺序相反进行如下变换

x'' = sx*(x + dx);
y'' = sy*(y + dy);

这种变换称为仿射变换,并且仿射变换会修改点的距离和线段间的夹角。对于平行线来说,仿射变换也会保持平行。仿射变换用6个参数描述成为如下表述

x' = ax + cy + e;
y' = bx + dy + f;

通过传入参数实现仿射变换

对于坐标变换来说,除非进行刷新,否则,已经绘制的图形,不会进行消失,所有的变换,都不能对已经绘制的图形进行更改。栗子如下

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 通过坐标变换实现科赫雪花
// 开始一条路径
context.beginPath();
// 开始绘制子路径
context.moveTo(100,100);
// 继续绘制
context.lineTo(200,200);
// 继续绘制
context.lineTo(200,200);
// 进行绘制边
context.stroke();
context.translate(200,200);
// 开始一条路径
context.beginPath();
// 开始绘制子路径
context.moveTo(100,100);
// 继续绘制
context.lineTo(200,200);
// 继续绘制
context.lineTo(200,200);
// 进行绘制边
context.stroke();

已经绘制的图形不会进行改变,改变的是已经绘制的图形

科赫雪花

var canvas = document.getElementById("square");

var context = canvas.getContext("2d");

// 通过坐标变换实现科赫雪花

// 当前状态入栈

function leg(n) {

// 保存状态

context.save();

// 递归画

if(n == 0){

context.lineTo(50, 0);

}else{

// 定义为v字型

context.scale(1/2,1/2);

// 递归第一条

context.rotate(60 * (Math.PI / 180));

leg(n - 1);

context.rotate(-120 * (Math.PI / 180));

leg(n - 1);

}

// 坐标恢复变换

context.restore();

// 恢复下一个坐标为0,0

context.translate(50, 0);

}

context.save();

context.moveTo(50, 50);

// 绘制第一条

leg(1);

context.stroke();

绘制填充曲线

绘制一些常见的图形

var canvas = document.getElementById("square");
var context = canvas.getContext("2d");
// 工具函数,角度转弧度
function rads(x) {
 return Math.PI * x / 180;
}
// 绘制园
context.beginPath();
context.arc(100,100,40, 0, rads(360), false);
context.stroke();
context.fill();

同理绘制贝塞尔曲线也是同理。

颜色,透明度,渐变,图案

绘制一个渐变

需要使用createLinearGradient获取一个进行渐变的上下文,对这个上下文进行处理。然后其颜色设置为这个渐变的上下文,即,fillStyle属性。

线段绘制

封顶

对于线段,有三种封顶方式,即,butt,square,round

在绘制图形以后,会参数尖角,圆角,平角,三种。

lineCap属性

文本

和css类似,基线问题。

裁剪

直接调动clip即可,当前路径也会被裁剪进入,路径外的统统不会显示。

阴影

设置shadow属性即可

图片

画布API支持位图图片,同时也支持canvas导出成为图片。

// 创建一个img元素
let img = document.createElement("img");
// 设置src属性
img.src = canvas.toDataURL();
// 追加到文档后面
document.body.appendChild(img);

合成

一些api不在阐述

像素操作

调用getImageDate方法返回ImageDate对象

使用createImageDate()可以创建像素容器

进行动态模糊先获取像素的ImageDate对象,然后再获取该对象的data属性,该data为一个数组。为一个维数组。每四个元素代表红色分量,绿色分量,蓝色分量,透明度分量。(Alpha分量)

其色素直为0-1,即,数组元素中保存的数组为色素值。

每四个每四个元素遍历。然后把其色素值的1/ n + 上一个色块的m/n 然后赋值给新的色块,代码如下

// row为行数
for(var row = 0; row < height; row++){
 // 获得每行第二个元素的偏移量,其中width为行的色素块。
 var i = row * width * 4;
 // 每4个的色素值进行处理
 for(var col = 1; col < width; col++, i+=4){
 // 对红色分量处理
 data[i] = (data[i] + data[i - 4] * m) / n;
 // 对绿色分量处理
 data[i + 1] = (data[i + 1] + data[i + 1 - 4] * m) / n;
 // 对蓝色分量处理
 data[i + 2] = (data[i + 2] + data[i + 2 - 4] * m) / n;
 // 对透明度分量处理
 data[i + 3] = (data[i + 3] + data[i + 3 - 4] * m) / n;
 }
}

然后把其色素块进行复制回去即可。

其中每个像素占据一个字节,一个四个字节。

命中检测

isPointInPath方法用来确定一个点是否落在当前路径中。

即命中检测。

命中检测可以和鼠标事件相互转化

但是坐标需要进行转换。

TML5 的 canvas 元素使用 JavaScript 在网页上绘制图像。

画布是一个矩形区域,您可以控制其每一像素。

canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。

下面是一个用 HTML5 的 canvas 绘制的 3D 玫瑰花。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>3D玫瑰花</title>

<meta name="Generator" content="EditPlus">

<meta name="Author" content="">

<meta name="Keywords" content="">

<meta name="Description" content="">

</head>

<body>

<div id="demo" style="width:520; height:500px;"><canvas id="c" height="500" width="500"></canvas></div>

<script>

var b = document.body;

var c = document.getElementsByTagName('canvas')[0];

var a = c.getContext('2d');

var canvas = document.getElementsByTagName('canvas')[0];

var ctx = canvas.getContext('2d');

document.body.clientWidth;

with(m=Math)C=cos,S=sin,P=pow,R=random;

c.width=c.height=f=500;h=-250;

function p(a,b,c){

if(c>60)

return[S(a*7)*(13+5/(.2+P(b*4,4)))-S(b)*50,b*f+50,625+C(a*7)*(13+5/(.2+P(b*4,4)))+b*400,a*1-b/2,a];

A=a*2-1;

B=b*2-1;

if(A*A+B*B<1){

if(c>37){

n=(j=c&1)?6:4;o=.5/(a+.01)+C(b*125)*3-a*300;

w=b*h;

return[o*C(n)+w*S(n)+j*610-390,o*S(n)-w*C(n)+550-j*350,1180+C(B+A)*99-j*300,.4-a*.1+P(1-B*B,-h*6)*.15-a*b*.4+C(a+b)/5+P(C((o*(a+1)+(B>0?w:-w))/25),30)*.1*(1-B*B),o/1e3+.7-o*w*3e-6]

}

if(c>32){

c=c*1.16-.15;o=a*45-20;w=b*b*h;z=o*S(c)+w*C(c)+620;

return[o*C(c)-w*S(c),28+C(B*.5)*99-b*b*b*60-z/2-h,z,(b*b*.3+P((1-(A*A)),7)*.15+.3)*b,b*.7]

}

o=A*(2-b)*(80-c*2);

w=99-C(A)*120-C(b)*(-h-c*4.9)+C(P(1-b,7))*50+c*2;z=o*S(c)+w*C(c)+700;

return[o*C(c)-w*S(c),B*99-C(P(b, 7))*50-c/3-z/1.35+450,z,(1-b/1.2)*.9+a*.1, P((1-b),20)/4+.05]

}

}

var draw = setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%46/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z-h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle="rgb("+~(s[3]*h)+","+~(s[4]*h)+","+~(s[3]*s[3]*-80)+")",a.fillRect(x,y,1,1)}',0);

var demo = document.getElementById('demo');

function redraw(){

/*

var d_c = document.createElement("canvas");

d_c.setAttribute("id","c");

d_c.setAttribute("width","520");

d_c.setAttribute("height","500");

demo.appendChild(d_c);

*/

draw = setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%46/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z-h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle="rgb("+~(s[3]*h)+","+~(s[4]*h)+","+~(s[3]*s[3]*-80)+")",a.fillRect(x,y,1,1)}',0);

//alert(d_c);

}

function clear_canvas()

{

ctx.clearRect(0,0,520,500);

//canvas.parentNode.removeChild(canvas); //删除

}

function stop_draw(obj){

clearInterval(obj);

}

</script>

</body>

</html>

门可以通过啃书,但书本上的东西很多都已经过时了,在啃书的同时,也要持续关注技术的新动态。这里推几本不错的书:

  《JavaScript高级编程》:可以作为入门书籍,但同时也是高级书籍,可以快速吸收基础,等到提升再回来重新看

《JavaScript权威指南》:不太适合入门,但是必备,不理解的地方就去查阅一下,很有帮助

  《编写可维护的JavaScript》和:

  《Node.js开发指南》:不错的Nodejs入门书籍

  《深入浅出Node.js》:Nodejs进阶书籍,必备

  《JavaScript异步编程》:理解JS异步的编程理念

  《JavaScript模式》和《JavaScript设计模式》:JavaScript的代码模式和设计模式,将开发思维转变到JavaScript,非常好的书

  《JavaScript框架设计》:在用轮子同时,应当知道轮子是怎么转起来的,讲解很详细,从源码级别讲解框架的各个部分的实现,配合一个现有框架阅读,可以学到很多东西

  《Dont make me think》:网页设计的理念,了解用户行为,非常不错

  《CSS禅意花园》:经久不衰的一部著作,同样传递了网页设计中的理念以及设计中需要注意的问题

  《高性能JavaScript》和《高性能HTML5》:强调性能的书,其中不只是性能优化,还有很多原理层面的东西值得学习

  《HTML5 Canvas核心技术》:我正在读的一本书,对于canvas的使用,动画的实现,以及动画框架的开发都非常有帮助

  《HTTP权威指南》:HTTP协议相关必备,前端开发调试的时候也会经常涉及到其中的知识

  《响应式Web设计》:技术本身不难,重要的是响应式网页的设计理念,以及移动先行的思想

  《JavaScript语言精粹》:老道的书,也是普及JavaScript的开发思维的一本好书,非常适合入门

一些不错的网站

  github:没啥好说的,多阅读别人的源码,多上传自己的源码,向世界各地的大牛学习

  codepen:感受前端之美的必选之地,里面有很多酷炫的效果和优秀的插件

  echojs:快速了解js新资讯的网站

  stackoverflow和segmentfault:基本上各种问题都能在上面获得解答

  google web fundamentals:每篇文章都适合仔细阅读

  static files:开放的CDN,很好用

  iconfont:阿里的矢量图标库,非常不错,支持CDN而且支持项目

  html5 rocks: 一个不错的网站,很多浏览器的新特性以及前沿的技术,都能在这上面找到文章

  css tricks:如何活用CSS,以及了解CSS新特性,这里可以满足你

  JavaScript 秘密花园 JavaScript初学必看,非常不错

  w3cplus:一个前端学习的网站,里面的文章质量都挺不错的

  node school:一个不错的node学习网站

  learn git branch:一个git学习网站,交互很棒

  前端乱炖:一个前端文章分享的社区,有很多优秀文章

  正则表达式:一个正则表达式入门教程,非常值得一看

喜欢的可以收藏,希望能够对你有所帮助

切图网(qietu.com)专业从事web前端开发的公司,专注we前端开发,响应式布局,webapp手机端网页制作,微信html5页面制作,bootstrap布局等,关注用户体验。