save()和restore()

save()

保存当前状态,将当前canvas的状态存入栈中。

restore()

恢复之前save的一个状态,将之前的状态从栈中弹出。

保存的当前状态包含以下信息:

  • 变换(平移、旋转、缩放)
  • 属性: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, direction, imageSmoothingEnabled
  • 剪裁路径

save()和restore()的用处就是有时候用canvas绘图会经过很多操作,然后可以用restore()直接恢复原先的状态,而不用再变换到原来的状态。这个API在需要进行很多变换的时候特别有用。

比如说在一开始先用save()保存了canvas最先的状态,也就是没经过任何操作的状态,然后开始用canvas绘图API绘图,中间对strokeStyle、lineWidth、globalAlpha等很多属性进行了修改,还进行了平移、旋转等等变换操作,这时,如果又要重新再画某个图形,而画这个图形要变换回原来最先的状态才方便画,那么直接restore()变回最初保存的状态就行,否则,又要重新平移、旋转,对各种属性赋值,才变回需要的状态,会非常麻烦。而save()和restore()两行就解决了这个问题。

例子

function draw() {
var ctx = document.getElementById('canvas').getContext('2d'); ctx.fillRect(0, 0, 150, 150); // Draw a rectangle with default settings
ctx.save(); // Save the default state ctx.fillStyle = '#09F'; // Make changes to the settings
ctx.fillRect(15, 15, 120, 120); // Draw a rectangle with new settings ctx.save(); // Save the current state
ctx.fillStyle = '#FFF'; // Make changes to the settings
ctx.globalAlpha = 0.5;
ctx.fillRect(30, 30, 90, 90); // Draw a rectangle with new settings ctx.restore(); // Restore previous state
ctx.fillRect(45, 45, 60, 60); // Draw a rectangle with restored settings ctx.restore(); // Restore original state
ctx.fillRect(60, 60, 30, 30); // Draw a rectangle with restored settings
}

结果

平移

translate(x, y)

将canvas沿x轴平移x个单位,沿y轴平移y个单位。

平移是会移动画布的,是画布的位置变了。

例子

function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
ctx.save();
ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
ctx.translate(10 + j * 50, 10 + i * 50);
ctx.fillRect(0, 0, 25, 25);
ctx.restore();
}
}
}

结果

旋转

rotate(angle)

以原点(0, 0)为中心点,旋转angle弧度。

如果要以画布的中心点为旋转点,需要用translate()平移画布。

旋转也是针对画布的。

例子

function draw() {
var ctx = document.getElementById('canvas').getContext('2d'); // left rectangles, rotate from canvas origin
ctx.save();
// blue rect
ctx.fillStyle = '#0095DD';
ctx.fillRect(30, 30, 100, 100);
ctx.rotate((Math.PI / 180) * 25);
// grey rect
ctx.fillStyle = '#4D4E53';
ctx.fillRect(30, 30, 100, 100);
ctx.restore(); // right rectangles, rotate from rectangle center
// draw blue rect
ctx.fillStyle = '#0095DD';
ctx.fillRect(150, 30, 100, 100); ctx.translate(200, 80); // translate to rectangle center
// x = x + 0.5 * width
// y = y + 0.5 * height
ctx.rotate((Math.PI / 180) * 25); // rotate
ctx.translate(-200, -80); // translate back // draw grey rect
ctx.fillStyle = '#4D4E53';
ctx.fillRect(150, 30, 100, 100);
}

结果

缩放

scale(x, y)

在水平方向缩放x个单位,在垂直方向缩放y个单位。

x, y可以是负数,如果是负数的话,图片就会呈镜像。比如这行代码translate(0,canvas.height); scale(1,-1); 就将canvas垂直翻转,坐标原点变成了左下角。

function draw() {
var ctx = document.getElementById('canvas').getContext('2d'); // draw a simple rectangle, but scale it.
ctx.save();
ctx.scale(10, 3);
ctx.fillRect(1, 10, 10, 10);
ctx.restore(); // mirror horizontally
ctx.scale(-1, 1);
ctx.font = '48px serif';
ctx.fillText('MDN', -135, 120);
}

结果

变换矩阵

transform(a, b, c, d, e, f)

将当前的变换矩阵乘上 [a, b, c, d, e, f, 0, 0, 1] (是个3X3的矩阵)。

各个参数表示的变换如下:

a (m11)

水平缩放。

b (m12)

水平斜切。

c (m21)

垂直斜切。

d (m22)

垂直缩放。

e (dx)

水平平移。

f (dy)

垂直平移。

要实现斜切的话,只能用变换矩阵。

setTransform(a, b, c, d, e, f)

重设当前变换矩阵,并进行变换。

resetTransform()

将当前矩阵设置为同等变换矩阵。相当于这行ctx.setTransform(1, 0, 0, 1, 0, 0);

例子

function draw() {
var ctx = document.getElementById('canvas').getContext('2d'); var sin = Math.sin(Math.PI / 6);
var cos = Math.cos(Math.PI / 6);
ctx.translate(100, 100);
var c = 0;
for (var i = 0; i <= 12; i++) {
c = Math.floor(255 / 12 * i);
ctx.fillStyle = 'rgb(' + c + ', ' + c + ', ' + c + ')';
ctx.fillRect(0, 0, 100, 10);
ctx.transform(cos, sin, -sin, cos, 0, 0);
} ctx.setTransform(-1, 0, 0, 1, 100, 100);
ctx.fillStyle = 'rgba(255, 128, 255, 0.5)';
ctx.fillRect(0, 50, 100, 100);
}

结果

【canvas学习笔记六】状态保存和变换的更多相关文章

  1. canvas学习笔记、小函数整理

    http://bbs.csdn.net/topics/391493648 canvas实例分享 2016-3-16 http://bbs.csdn.net/topics/390582151 html5 ...

  2. Java IO学习笔记六:NIO到多路复用

    作者:Grey 原文地址:Java IO学习笔记六:NIO到多路复用 虽然NIO性能上比BIO要好,参考:Java IO学习笔记五:BIO到NIO 但是NIO也有问题,NIO服务端的示例代码中往往会包 ...

  3. Typescript 学习笔记六:接口

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  4. python3.4学习笔记(六) 常用快捷键使用技巧,持续更新

    python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...

  5. Linux学习笔记(六) 进程管理

    1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...

  6. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  7. Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  8. Go语言学习笔记六: 循环语句

    Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...

  9. 【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

随机推荐

  1. Shell 变量详解教程之位置变量与预定义变量

    Shell 变量分为3部分,分别是用户自定义变量.位置变量和预定义变量. 一.   自定义变量 那么,什么是变量呢?简单的说,就是让某一个特定字符串代表不固定的内容,用户定义的变量是最普通的Shell ...

  2. python-day18(正式学习)

    目录 numpy模块 numpy简介 为什么要用numpy 创建numpy数组 numpy数组的基本属性 获取numpy数组的行列数 切割numpy数组 numpy数组元素替换 numpy数组的合并 ...

  3. mac系统homebrew安装mysql

    homebrew 安装 mysql homebrew 是 macOS 缺失的软件包管理器,譬如可以下载 mysql.redis.wget 等等.操作系统:macOS High Sierra Versi ...

  4. tornado源码简单实现

    首先基本的同步流程是: class Index(tornado.web.RequestHandle): def get(self): self.write('hellow,word') app = t ...

  5. 18.AutoMapper 之条件映射(Conditional Mapping)

    https://www.jianshu.com/p/8ed758ed3c63 条件映射(Conditional Mapping) AutoMapper 允许你给属性添加条件,只有在条件成立的情况下该成 ...

  6. qt嵌入式html和本地c++通信方式

    前沿:我们在做qt项目的时候,通常会把某个html网页直接显示到应用程序中.比如绘图.直接把html形式的图标嵌入到应用程序中 但是我们需要把数据从后台c++端传到html端,实现显示.qt实现了相关 ...

  7. 国内高速下载Docker

    一般情况下,我们可以从Docker官网下载docker安装文件,但是官方网站由于众所周知的原因,不是访问慢,就是下载慢.下载docker安装包动不动就要个把小时,真是极大的影响工作效率. 在这里推荐一 ...

  8. npm工作流 与webpack 分同环境配置

    npm:http://www.ruanyifeng.com/blog/2016/10/npm_scripts.html process.env.npm_lifecycle_event process. ...

  9. SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作的解决办法

    SQL2005 还原数据库失败,提示如下: SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作的解决办法 出现错误时操作步骤为:右击数据库--->任务- ...

  10. 有理想的中国IT企业,正在全球攻城略地 - 阅读笔记

    文章来源:https://mp.weixin.qq.com/s/xc5Uqe4WmEEgI03dPR4Orw 中资手机崛起 大部分国人对传音不熟悉,这家深圳公司由前波导高管创立,是非洲手机市场的老大. ...