初学者也许会误认为canvas中save方法是用来保存绘图状态的图形,而restore方法是用来还原之前保存的绘图状态的图形,其实不然。

  save():保存当前的绘图状态。

  restore():恢复之前保存的绘图状态。

  在Canvas环境中绘图时,可以利用所谓的绘图堆栈状态。每个状态随时存储Canvas上下文数据。下面是存储在状态堆栈的数据列表。

  • 当前的坐标变换(变换矩阵)信息,比如旋转或平移时使用的rotate()setTransform()方法
  • 当前剪贴区域clip()
  • 图形上下文对象(CanvasRenderingContext2D)的当前属性值

  CanvasRenderingContext2D的当前属性值主要包括:

属性 描述
canvas 取得画布<canvas>元素
fillStyle 填充路径的当前的颜色、模式或渐变
globalCompositeOperation 指定颜色如何与画布上已有颜色组合(合成)
lineCap 指定线段端点的绘制方式
lineJoin 指定线段连接的绘制方式
lineWidth 绘制线段的宽度
miterLimit lineJoinmiter时,这个属性指定斜连接长度和二分之一线宽的最大比率
shadowBlur 指定阴影模糊度
shadowColor 指定阴影颜色
shadowOffsetX 指定阴影水平偏移值
shadowOffsetY 指定阴影垂直偏移值
strokeStyle 指定线段颜色

  上面是Canvas绘图中的状态,那么什么情形不属于Canvas状态?

  在Canvas中当前路径和当前位图受Canvas环境控制,不属于保存状态。这个重要的功能允许在画布上对单个对象进行绘画和制作动画。

  如上所述用堆栈的原理来解释,就是调用save()方法时,将记录当前的绘图状态,并压入一个堆栈中;接着调用restore()方法时,就会把上一次记录的绘图状态从堆栈中弹出。

  需要注意的是,出栈的次数不能多于入栈的次数,故程序中restore()方法调用的次数不应该比save()方法多。

  画张图来帮助理解:

  

  如果上面的描述还是无法帮助你理解save()restore()两个方法的话,那我们来写一个简单的示例来帮助大家理解:

 <body>
<!--创建一个边长为200的正方形画布-->
<canvas id="mc" width="200" height="200" style="border:1px solid black"></canvas> <script type="text/javascript">
var canvas = document.getElementById('mc'); //获取Canvas元素对应的DOM对象
var ctx = canvas.getContext('2d');//获取Canvas上的绘图的CanvasRenderingContext2D对象
ctx.lineWidth=3; //设置笔触线条的宽度
ctx.translate(100,100); //将原点左边设置到画布的中间
ctx.save(); //保存当前画布的状态,该状态包含了lineWidth=3,translate(100,100),然后其他那些属性为默认值.
ctx.strokeStyle='red'; //设置线条颜色为红色
//坐标系统旋转90°
ctx.rotate(Math.PI/2);
//画第一条直线
ctx.beginPath();
ctx.moveTo(-100,0);
ctx.lineTo(100,0);
ctx.closePath();
ctx.stroke();
//恢复之前保存的绘图状态
ctx.restore();
//再画第二条直线
ctx.beginPath();
ctx.moveTo(-100,0);
ctx.lineTo(100,0);
ctx.closePath();
ctx.stroke();
</script>
</body>

  在浏览器中看到的效果如下:

看代码可知,画两条线的代码是一样的,可是画出来的一条是垂直的红线,一条是水平的黑线。调用save()方法时,保存的状态是lineWidth=3,translate(100,100),然后其他那些属性为默认值,如默认的lineStyle为黑色。

画第一条线时,是将坐标系统旋转了90°,设置了lineStyle="red",故画出来的是垂直的红色线;画第二条线前调用了restore()方法,即恢复为了之前保存的绘图状态,该绘图状态是坐标系统没有经过旋转的,线条颜色也默认为黑色,所以画出来的先就是我们想要得到的水平的黑色线。

Canvas中的save方法和restore方法的更多相关文章

  1. Java8新特性(一)_interface中的static方法和default方法

    什么要单独写个Java8新特性,一个原因是我目前所在的公司用的是jdk8,并且框架中用了大量的Java8的新特性,如上篇文章写到的stream方法进行过滤map集合.stream方法就是接口Colle ...

  2. JS中的call()方法和apply()方法用法总结

    原文引自:https://blog.csdn.net/ganyingxie123456/article/details/70855586 最近又遇到了JacvaScript中的call()方法和app ...

  3. MongoDB save()方法和insert()方法的区别

    MongoDB save()方法和insert()方法的区别 首先看官方文档怎么说的 Updates an existing document or inserts a new document, d ...

  4. js中的splice方法和slice方法简单总结

    slice:是截取用的 splice:是做删除 插入 替换用的 slice(start,end): 参数: start:开始位置的索引 end:结束位置的索引(但不包含该索引位置的元素) 例如: va ...

  5. JS中的call()方法和apply()方法用法总结(挺好 转载下)

    最近又遇到了JacvaScript中的call()方法和apply()方法,而在某些时候这两个方法还确实是十分重要的,那么就让我总结这两个方法的使用和区别吧. 1. 每个函数都包含两个非继承而来的方法 ...

  6. Mapper类/Reducer类中的setup方法和cleanup方法以及run方法的介绍

    在hadoop的源码中,基类Mapper类和Reducer类中都是只包含四个方法:setup方法,cleanup方法,run方法,map方法.如下所示: 其方法的调用方式是在run方法中,如下所示: ...

  7. java 中的set方法和get方法的理解

    get的意思是获取,set的意思是设置. get方法和set方法是实现类的封装访问的很好的工具. 当类中的变量设为private 时,他的意思就是说,只能通过自身和子类的访问,但是对于别的其他的类来说 ...

  8. java8新特性:interface中的static方法和default方法

    java8中接口有两个新特性,一个是静态方法,一个是默认方法. static方法 java8中为接口新增了一项功能:定义一个或者多个静态方法. 定义用法和普通的static方法一样: public i ...

  9. Java8新特性interface中的static方法和default方法

    static方法 java8中为接口新增了一项功能:定义一个或者更多个静态方法.用法和普通的static方法一样. 代码示例 public interface InterfaceA { /** * 静 ...

随机推荐

  1. c语言数据结构学习心得——二叉树

    二叉树 n(n>=0)个结点的有限集合:(五种形态) 1.或者为空二叉树,n=0: 2.或者由一个根结点和两个互不相交的被称为根的左子树和右子树组成.左子树和右子树又分别是一棵二叉树. 3.每个 ...

  2. 如何在NSDocumentDirectory内新建一个文件夹

    iOS下载文件一般保存到NSDocumentDirectory内,但是为了更好整理文件内容,那就要自定义的生成一些文件夹,和做一些删除文件夹的操作. - (NSString *)pathToPatie ...

  3. 虚拟机上使用 opecnv 读取USB摄像头无法显示

    使用opecv读取USB摄像头时候,无法显示图像. 设置 首先查看虚拟机Ubuntu检测摄像头是否已正常插入: ls /dev/video* 结果为: 设置虚拟机USB属性: USB的兼容性设置为US ...

  4. C#集合之可观察的集合

    如果需要集合中的元素何时删除或添加的信息,可以使用ObservableCollection<T>类.这个类是为WPF定义的,这样UI就可以得知集合的变化.这个类在程序集WindowsBas ...

  5. 苹果Air A1466进入系统黑屏

    现象:苹果Air A1466笔记本安装Windows 7系统后,安装官网对应型号的bootcamp后,重启机器,在Windows滚动条完成后随即进入黑屏状态,安全模式能够进入,在安全模式下卸载删除显卡 ...

  6. nginx响应码

    ngx.status = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)ngx.status = ngx.HTTP_SWITC ...

  7. sencha touch 手势识别左右滑动

    sencha touch 中添加手势识别非常简单,就是监听 dom 元素的 move 事件: 1. 为你的 view 注册 swipe 事件 // 为当前 view 注册手势滑动事件 Ext.get( ...

  8. 转 WINXP VBOX 给UBUNTU 加共享目录方法

    1. 安装增强功能包(Guest Additions)安装好Ubuntu 9.04后,运行Ubuntu并登录.然后在VirtualBox的菜单里选择"设备(Devices)" -& ...

  9. ASP.NET MVC 域名泛解析设置

    最近有个需求要做一个动态二级域名的网站,我们可以通过这样的方式去访问我们的网站 http://用户名.blog.com.而这里的用户名是根据程序的需要动态生成的.这里就会涉及到DNS服务器,要做相应的 ...

  10. log4j DailyRollingFileAppender, DatePattern 配置

    在DailyRollingFileAppender中可以指定monthly(每月). weekly(每周).daily(每天).half-daily(每半天).hourly(每小时)和minutely ...