前段时间在公司没什么事干,研究了一下canvas,在实际开发中还没正式应用过,但是已经深深感觉到其魅力之处。下面写一写我认为canvas中比较重要的点,如有理解错误,欢迎指正。

首先canvas是h5中的新增一个元素,先创建一个h5文件,然后像写一个div一样,在页面初始化一个canvas,由于之后canvas的操作都是由js完成,为了操作方便,赋予canvas一个id值,给width和height作为canvas的宽高。话不多说,上代码先

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<canvas id="drawing" width="200" height="200"> A draw of something</canvas>
<script>
var drawing = document.getElementById('drawing'); //确定浏览器支持canvas元素
if(drawing.getContext) {
var context = drawing.getContext("2d");
}
</script>
</body>
</html>

  上面就是初始化一个包含canvas元素的最基础写法啦,然后我们就要动手画了。

  canvas画图我给分为了两种,一种是canvas自身创建,另外一种就是canvas中引用了img,先说canvas自身创建。canvas自身创建方式首先有两种,一种是描边即stroke,另外一种是填充fill,两种方式均可以定义使用的样式,包括描边或填充的色值、效果(如渐变)等;另外canvas自身创建可以使用canvas提供的现有的图形矩形和弧形也可以通过定义路径来形成图形。比较规则的直线或可以通过lineTo()方法,不规则的曲线可以通过贝塞尔曲线来完成。

  下面讲一下绘制图形过程中,比较重要的几个概念。

  1.beginPath()

beginPath()即开始或重置一条路径,我们在实际应用中,会经常用到。我们在单纯使用arc或rect相关方法,并不涉及到路径时可以不用beginPath(),但是当我们使用如lineTo(),贝塞尔曲线等这种使用路径的方法绘制图形时,则必须要使用beginPath();当然了,有beginPath(),就有closePath();如果我们使用的是stroke()方法,调用了beginPah(),就要相应地调用closePath()才可以把路径闭合,比如绘制下面一个三角形

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>canvas小试牛刀</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body onload = "draw();">
<canvas id="tutorial" width="450" height="250"></canvas>
<script>
function draw(){
var canvas = document.getElementById('tutorial'); if(canvas.getContext) {
var ctx = canvas.getContext('2d'); // 绘制一个三角形
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(100, 50);
ctx.lineTo(75, 100);
// ctx.fillStyle = "rgba(0,0,255,0.2)";
ctx.closePath();//闭合路径
ctx.stroke();//默认描边的颜色是黑色
}
} </script>
</body>
</html>

当前代码运行完毕之后的效果是这样的

如果我们去掉closePath(),效果是这样

因为我们在代码中实际只绘制了两条直线,closePath()帮我们把最后一个点连接到起点以达到闭合路径的作用,当然,也可以不调用closePath(),选择自行写代码闭合也是完全可以的。而当我们把closePath()和stroke()分别注掉,把fillStyle()放出来,再加上ctx.fill(),效果是这样的

所以在使用填充的时候closePath()就没什么卵用了,使用填充的时候,会自动闭合路径,另外友情提示一下,虽然是自动闭合,但是所谓自动闭合就是最后一个点与起点的连线,所以说,如果你的图形是曲线或是不规则的还是自己闭合吧

2关于moveTo与translate()

moveTo()是把坐标移动到某一点,其主要作用是避免出现不必要的线,嗯,来个例子吧,比较直观一点

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>canvas小试牛刀</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body onload = "draw();">
<canvas id="tutorial" width="450" height="250"></canvas>
<script>
function draw(){
var canvas = document.getElementById('tutorial'); if(canvas.getContext) {
var ctx = canvas.getContext('2d'); // 绘制一个笑脸
ctx.beginPath();
ctx.arc(75,75,50,0,2*Math.PI,false); ctx.moveTo(110,75);
ctx.arc(75,75,35,0,Math.PI,false); ctx.moveTo(65,65);
ctx.arc(60,65,5,0,2*Math.PI,true); ctx.moveTo(95,65);
ctx.arc(90,65,5,0,2*Math.PI,true);
ctx.stroke();
}
} </script>
</body>
</html>

上面代码运行后的效果是这样

如果我去掉第一个moteTo()方法即

ctx.moveTo(110,75);

效果会是这样,

两个路径的终点和起点之间会连在一起,多出没用的线。就像我们在用笔画一个笑脸时,先画了一个圆作为头,此时笔尖先不要动,我们接下来要画嘴巴那个半圆,如果我们的笔尖这个时候不提起,那我们只能在当前点连接到嘴巴半圆的起点多出了没用的线,当然,如果你的这个嘴巴起点是在外面圆上一点,就没什么所谓了。综上,其实moveTo()的作用就相当于我们在画画时提笔换下笔位置的作用是一样的。

然后就是translate了,translate的作用更霸道一点,相当于变换原点,啥意思呢,还是比如你在画画,一开始从左上角画,接下来你要画右下角的东西了,但是你懒,自己希望保持当前优雅的姿势不想动,可是现在直接这么画又太费劲,那咋整,把纸挪一下,让右下角的位置到你面前就好啦,translate()的作用就是这个,变换原点是啥意思呢,就是一开始默认都以(0,0)作为原点,不管是moveTo还是直接画圆画矩形都是以(0,0)作为参考点,而translate(),比如说translate(30,40),当前的(30,40)就相当于(0,0),(32,45)此时应该写成(2,5),跟物理里面的相对位置是一样的,懂否?

3、save() restore()

虽然最后明白了是干啥的,但是后来我在练习中save()了好多次而restore()很少,总体来说save()次数并不受限制,但是restore()的次数一定要小于等于save()的次数,先来段代码帮助大家理解

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>移动,旋转,缩放,变形</title>
</head>
<body>
<canvas id="myCanvas" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d'); // save resore
ctx.fillRect(0,0,150,150);
ctx.save(); ctx.fillStyle = "#09f";
ctx.fillRect(15,15,120,120);
ctx.save(); ctx.fillStyle = "#fff";
ctx.globalAlpha = 0.5;
ctx.fillRect(30,30,90,90); ctx.restore();
ctx.fillRect(45,45,60,60); ctx.restore();
ctx.fillRect(60,60,30,30);
</script>
</body>
</html>

❑ save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。

❑ restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。

save和restore要配和使用(restore可以比save少,但不能多),如果restore调用次数比save多,会引发Error。

好吧,我承认上面的三句话是我摘抄过来的,因为感觉这三句写的真的不错啊。。。然后我们结合我附的代码来理解一下,先看下上面那段代码运行之后的效果

其实矩形1,2,3不使用save()和restore()依然可以被绘制出来,但是4,5是使用了2,1的填充状态绘制出来的。当我们操作canvas时默认是对所有的元素进行操作,但是有时候我们可能只是这一步或是只是这一个路径或图形需要这个操作,完成这个操作之后,我们希望回到之前的状态再进行下一步的绘制,那么这个时候就是restore()出场了,当然我们自己手动恢复也是可以的,比如说画完矩形3之后,填充颜色是白色,透明度是0.5,我们回到上一步则会变成填充颜色是“#09f“,透明度为1,而在绘制矩形4时仅对矩形的坐标和大小进行了重新定义,并没有对填充方式定义,所以矩形4和矩形2的填充方式是相同的,换句话说,我们是想复用矩形2的状态才使用restore(),如果想用新的方式,那么restore()就没什么卵用。所以综上,我认为,可以常save(),万一能用上呢?

别打我,你敢说你写代码不是常save?

关于绘制图形就说这么多,但是并不是只有这么多,我只是挑一些当时让我有些迷惑的内容来讲一下,更多的内容大家自己摸索就好。

下面说下。。。嗯 ,引用img

好像没啥可说。。。看教程就没啥问题了。。。。

还有一些其他酷炫的效果,比如什么旋转移动变形缩放啥的,还有什么组合啊之类的还有很多,但是我。。。。懒得写了。。。。其实基本按照教程来就没问题的

附个教程链接https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial

如果以后在项目中应用了,会再补充使用体验,请期待吧~

canvas小结的更多相关文章

  1. Android开发之漫漫长途 XIV——RecyclerView

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  2. Android开发之漫漫长途 XV——RecyclerView

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  3. Canvas:技术小结

    Canvas:技术小结 资料 [教程:MDN官方中文教程] https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial [ ...

  4. Android canvas rotate():平移旋转坐标系至任意原点任意角度-------附:android反三角函数小结

    自然状态下,坐标系以屏幕左上角为原点,向右是x正轴,向下是y正轴.现在要使坐标系的原点平移至任一点O(x,y),且旋转a角度,如何实现? 交待下我的问题背景,已知屏幕上有两点p1和p2,构成直线l.我 ...

  5. 今天写动态canvas柱状图小结

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

  6. 【HTML】canvas学习小结

    1. 绘制基本图形 -----上下文---------------------------------------------------------- canvas.getContext('2d') ...

  7. canvas的api小结

    HTML <canvas id="canvas"></canvas> Javascript var canvas=document.getElementBy ...

  8. 前台图片Canvas压缩上传小结

    需求来源:之前有个提交审核表单的业务,表单中含有大量附件图片,大约有20多张吧,为了省事,采用的同步上传,一次需要上传很多照片,本来单张图片限制为200KB,这样子总图片大小约为5MB左右,想想也可以 ...

  9. HTML5学习总结——canvas绘制象棋(canvas绘图)

    一.HTML5学习总结——canvas绘制象棋 1.第一次:canvas绘制象棋(笨方法)示例代码: <!DOCTYPE html> <html> <head> & ...

随机推荐

  1. Sql Server函数全解<三>数据类型转换函数和文本图像函数

    阅读目录 一:数据类型转换函数 二:文本和图像函数 一:数据类型转换函数 在同时处理不同数据类型的值时,SQL Server一般会自动进行隐士类型转换.对于数据类型相近的值是有效的,比如int和flo ...

  2. 《转载》使用org.w3c.dom.Element的setTextContent()、getTextContent()方法时出现编译错误

    今天在更新项目后进行编译时,出现如下错误一堆: 编译错误 Google之,在stackoverflow上看到如下的解决方法: I came here with the same problem. Ev ...

  3. Git的用法

    Git的用法 Git 的也可以理解为版本控制器.版本控制器(维基的解释):维护工程蓝图的标准作法,能追踪工程蓝图从诞生一直到定案的过程.此外,版本控制也是一种软件工程技巧,借此能在软件开发的过程中,确 ...

  4. linux下php-mysql拓展安装

    今天遇到一个奇怪的问题: 在服务器A上部署应用,在服务器B上部署数据库和缓存. 服务器A:apache2.2,php5.3 服务器B:mysql5.5,redis2.4 问题现象: 本地远程连接服务器 ...

  5. MVC 导出Excel 的其中一方法(View导出excel)

    场景:mvc下导出excel 思路:使用View导出excel 步骤: 1.导出标签添加事件 $("#export_A").click(function(){ //省略代码.... ...

  6. git整理

    git图形客户端:SourceTree bash: 先初始化: git init 添加远程仓库: git remote add sae https://git.sinacloud.com/newapp

  7. UML大战需求分析——阅读笔记05

    最近看过几个程序员大学后一起创业,与大公司抢项目并成功逆袭的视频,感触颇深:第一.技术是关键:第二.有一群可靠并且技术超群的队友,在关键时刻不会掉链子:第三.善于部署谨慎周密的计划:第四.一流的口才+ ...

  8. 与你相遇好幸运,使用redis设置定时任务

    参考链接: Nodejs中使用Redis来完成定时任务 自己在 window 7下编码实现: 1 > 首先查看redis版本: redis-server -v , 版本要求大于等于2.8 2&g ...

  9. "Fatal error: Call to undefined function: file_put_contents()"

    打开页面时提示这个错误: Fatal error: Call to undefined function: file_put_contents() 意思是请求未定义的函数,出现这个提示通常有两种情况: ...

  10. git客服端基本操作

    以下操作基于git+gerrit 1.生成公钥 ssh -keygen -t rsa 默认公钥生成路径  C:\Documents and Settings\用户名\.ssh 2.配置姓名和邮箱地址 ...