Canvas入门学习笔记系列之:变形 Transformations

  • 原创
  • 作者:程序员三丰
  • 发布时间:2025-01-16 00:21
  • 浏览量:548
本文介绍canvas的特性“变形”,可以将原点移动到另一点,对网格进行旋转和缩放。

canvas状态的保存和恢复

什么是canvas的状态

canvas的状态就是当前画面应用的所有样式和变形的一个快照。

canvas的状态存储在栈中。

一个绘画状态包括:

  • 当前应用的变形,即:移动、缩放和旋转;
  • 以及这些属性:strokeStyle、fillStyle、globalAlpha、lineWidth、lineCap、lineJoin、miterLimit、lineDashOffset、shadowOffsetX、shadowOffsetY、shadowBlur、shadowColor、globalCompositeOperation、font、textAlign、textBaseline、direction、imageSmoothingEnabled
  • 当前的裁切路径(后续文章会专门介绍)。
    canvas图形状态的保存和恢复,在绘制复杂图形时必不可少。在做变形之前先保存状态是一个良好的习惯。大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。

save() 保存状态

该方法保存画布canvas的所有状态。该方法可以任意多次被调用,每当save()方法被调用后,当前的状态就被推进到栈中保存。

restore() 恢复状态

该方法恢复canvas的上一个保存的状态,并应用到后续的绘画中。

每当restore()方法被调用后,上一个保存的状态就从栈中弹出,所有canvas画布当前的配置都恢复为弹出的状态中保存的配置,并在后续图像绘制中得以应用。

如果觉得难以理解,请结合下面的综合示例进行理解。

综合示例

示例效果:

实现代码:

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Canvas 状态的保存与恢复 </title>
        <style>
            body {
                height: 100vh;
                padding: 10px;
            }
        </style>
        <script>
            function draw() {
                var canvas = document.getElementById('canvas');
                if (canvas.getContext) {
                    const ctx = canvas.getContext('2d');

                    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);

                } else {
                    alert('您的浏览器不支持Canvas!');
                }
            }
        </script>
    </head>

    <body onload="draw();">
        <canvas id="canvas" width="300" height="300" style="background-color: #f3f4f8; color: chocolate"></canvas>
    </body>

</html>

移动 translate

移动是通过 translate() 方法来移动canvas和它的原点到一个不同的位置。

translate(x, y)

translate方法接受两个参数,x是左右偏移量,y 是上下偏移量。

示例

实现代码:

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Canvas 移动 translate </title>
        <style>
            body {
                height: 100vh;
                padding: 10px;
            }
        </style>
        <script>
            function draw() {
                var canvas = document.getElementById('canvas');
                if (canvas.getContext) {
                    const ctx = canvas.getContext('2d');

                    for (let i = 0; i < 7; i++) {
                        for (let j = 0; j < 7; 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();
                        }
                    }

                } else {
                    alert('您的浏览器不支持Canvas!');
                }
            }
        </script>
    </head>

    <body onload="draw();">
        <canvas id="canvas" width="300" height="300" style="background-color: #f3f4f8; color: chocolate"></canvas>
    </body>

</html>

代码解析:
这个例子显示了一些移动 canvas 原点的好处。如果不使用 translate 方法,那么所有矩形都将被绘制在相同的位置(0,0)。translate 方法同时让我们可以任意放置这些图案,而不需要在 fillRect() 方法中手工调整坐标值,既好理解也方便使用。

旋转 rorate

旋转是以原点为中心旋转canvas,如果要改变它,则需要用到上面介绍的translate()方法。

rotate(angle)

这个方法只接受一个参数:旋转的角度 (angle),它是顺时针方向的,以弧度为单位的值。

旋转rotate()方法的参数angle的单位是弧度,比较难以理解和感知,相对而言,角度对我们来说就很容易理解感知了,比如我们所熟悉的读书30度,45度等。那么我们可以通过数学公式来进行转换。
将角度转换为弧度的计算公式:弧度 = (Math.PI / 180) * 角度

示例

实现代码:

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Canvas 旋转 rotate </title>
        <style>
            body {
                height: 100vh;
                padding: 10px;
            }
        </style>
        <script>
            function draw() {
                var canvas = document.getElementById('canvas');
                if (canvas.getContext) {
                    const ctx = canvas.getContext('2d');

                    ctx.save();

                    ctx.fillStyle = '#F00';
                    ctx.translate(100, 100);
                    ctx.fillRect(0, 0, 100, 100);

                    ctx.globalAlpha = 0.5;
                    ctx.rotate((Math.PI / 180) * 45);
                    // ctx.translate(-100, -100);
                    ctx.fillStyle = '#000';
                    ctx.fillRect(0, 0, 140, 140);

                } else {
                    alert('您的浏览器不支持Canvas!');
                }
            }
        </script>
    </head>

    <body onload="draw();">
        <canvas id="canvas" width="300" height="300" style="background-color: #f3f4f8; color: chocolate"></canvas>
    </body>

</html>

缩放 scale

缩放方法scale()的语法如下:

scale(x, y)

scale方法可以缩放画布的水平和垂直的单位。两个参数都是实数,可以为负数,x 为水平缩放因子,y 为垂直缩放因子,如果比 1 小,会缩小图形,如果比 1 大会放大图形。默认值为 1,为实际大小。

示例:(下面的效果中缩放后,坐标发生变化,这里不明白,后面再找时间研究吧)

实现代码:

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Canvas 缩放 scale </title>
        <style>
            body {
                height: 100vh;
                padding: 10px;
            }
        </style>
        <script>
            function draw() {
                var canvas = document.getElementById('canvas');
                if (canvas.getContext) {
                    const ctx = canvas.getContext('2d');

                    ctx.save();
                    ctx.fillRect(10, 10, 30, 30); // 对比
                    ctx.scale(2, 1);
                    ctx.globalAlpha = 0.5;
                    ctx.fillRect(10, 40, 30, 30); // 缩放效果
                    ctx.restore();
                    ctx.fillRect(10, 70, 30, 30); // 对比

                } else {
                    alert('您的浏览器不支持Canvas!');
                }
            }
        </script>
    </head>

    <body onload="draw();">
        <canvas id="canvas" width="300" height="300" style="background-color: #f3f4f8; color: chocolate"></canvas>
    </body>

</html>

变形 transform

通过transform()方法对变形矩阵进行修改,语法如下:

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

6个参数含义如下:

  • a:水平方向的缩放
  • b:竖直方向的倾斜偏移
  • c:水平方向的倾斜偏移
  • d:竖直方向的缩放
  • e:水平方向的移动
  • f:竖直方向的移动

介绍两个设置(重置)当前变形矩阵为单位矩阵的方法:

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

resetTransform() // 该方法相当于 setTransform(1, 0, 0, 1, 0, 0)

示例

实现代码如下:

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Canvas 变形 transform </title>
        <style>
            body {
                height: 100vh;
                padding: 10px;
            }
        </style>
        <script>
            function draw() {
                var canvas = document.getElementById('canvas');
                if (canvas.getContext) {
                    const ctx = canvas.getContext('2d');

                    const sin = Math.sin(Math.PI / 6);
                    const cos = Math.cos(Math.PI / 6);
                    ctx.translate(100, 100);
                    let c = 0;
                    for (let 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, 2, 100, 100);

                } else {
                    alert('您的浏览器不支持Canvas!');
                }
            }
        </script>
    </head>

    <body onload="draw();">
        <canvas id="canvas" width="300" height="300" style="background-color: #f3f4f8; color: chocolate"></canvas>
    </body>

</html>

上面的示例中用到JavaScript的Math库的数据函数,从而实现了复杂且高级的效果,后续会补充一些相关函数的介绍,将会有利于我们实现一些高级效果。

声明:本文为原创文章,51blog.xyz和作者拥有版权,如需转载,请注明来源于51blog.xyz并保留原文链接:https://mp.51blog.xyz/article/85.html

文章归档

推荐文章

buildadmin logo
Thinkphp8 Vue3 Element PLus TypeScript Vite Pinia

🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。

热门标签

PHP ThinkPHP ThinkPHP5.1 Go Mysql Mysql5.7 Redis Linux CentOS7 Git HTML CSS CSS3 Javascript JQuery Vue LayUI VMware Uniapp 微信小程序 docker wiki Confluence7 学习笔记 uView ES6 Ant Design Pro of Vue React ThinkPHP6.0 chrome 扩展 翻译工具 Nuxt SSR 服务端渲染 scrollreveal.js ThinkPHP8.0 Mac webman 跨域CORS vscode GitHub ECharts Canvas