canvas小结
前段时间在公司没什么事干,研究了一下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小结的更多相关文章
- Android开发之漫漫长途 XIV——RecyclerView
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android开发之漫漫长途 XV——RecyclerView
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Canvas:技术小结
Canvas:技术小结 资料 [教程:MDN官方中文教程] https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial [ ...
- Android canvas rotate():平移旋转坐标系至任意原点任意角度-------附:android反三角函数小结
自然状态下,坐标系以屏幕左上角为原点,向右是x正轴,向下是y正轴.现在要使坐标系的原点平移至任一点O(x,y),且旋转a角度,如何实现? 交待下我的问题背景,已知屏幕上有两点p1和p2,构成直线l.我 ...
- 今天写动态canvas柱状图小结
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 【HTML】canvas学习小结
1. 绘制基本图形 -----上下文---------------------------------------------------------- canvas.getContext('2d') ...
- canvas的api小结
HTML <canvas id="canvas"></canvas> Javascript var canvas=document.getElementBy ...
- 前台图片Canvas压缩上传小结
需求来源:之前有个提交审核表单的业务,表单中含有大量附件图片,大约有20多张吧,为了省事,采用的同步上传,一次需要上传很多照片,本来单张图片限制为200KB,这样子总图片大小约为5MB左右,想想也可以 ...
- HTML5学习总结——canvas绘制象棋(canvas绘图)
一.HTML5学习总结——canvas绘制象棋 1.第一次:canvas绘制象棋(笨方法)示例代码: <!DOCTYPE html> <html> <head> & ...
随机推荐
- PCA、ZCA白化
白化是一种重要的预处理过程,其目的就是降低输入数据的冗余性,使得经过白化处理的输入数据具有如下性质:(i)特征之间相关性较低:(ii)所有特征具有相同的方差. 白化又分为PCA白化和ZCA白化,在数据 ...
- Linux下的压缩和解压缩命令——jar
原文链接:http://blog.chinaunix.net/uid-692788-id-2681136.htmlJAR包是Java中所特有一种压缩文档,其实大家就可以把它理解为.zip包.当然也是有 ...
- 基于webapi的移动互联架构
又到了一年最后一次上班了,写下这篇日志作为本年总结. 首先总体介绍一下项目背景,今年公司开发了一款app,本人一个人负责app的接口服务.微信开放平台搭建以及系统后台,上线半年,如今活跃用户数3W+. ...
- R语言进阶
一.初学入门:<R in Action><The Art of_R Programming>入门者可首选两本,前者从统计角度入手,分高中低三部分由浅入深的讲解了如何用R来实现统 ...
- linux 批量删除进程
2016年11月18日 13:11:10 星期五 ps -ef | grep pname | awk '{print $2}' | xargs kill 解释: 杀掉所有包含 'pname' 的进程
- 响应者链条,如何获取最佳的点击view 以及内部实现
事件的产生与传递 事件是如何产生与传递的? 当发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中. UIApplication会从时间队列中取出最前面的时间,并将事件 ...
- mac个人设置
修改spotlight快捷键 mac默认的command+space和我windows下的习惯冲突,修改为ctrl+space 删除输入法切换的快捷键 因为我不需要切换不同语言的快捷键.中英文切换直接 ...
- Log4Net记录日志的使用
Log4net 基本样式: <log4net> <appender name="LogFileAppender" type="log4net.Appen ...
- C语言的一些小知识
注:本文讨论的"C语言"为GNU C,而非ANSI C 标准库 语法 switch语句中的case关键词可以放在任何地方 switch (a) { case 1:; if (b== ...
- Python-断言
断言: assert这个关键字称之为断言,当这个关键字后面的条件为假的时候,程序自动崩溃并抛出AssertionError的异常 例子: >>>assert 3 < 4 Tra ...