Canvas学习笔记 Canvas的基础知识点(下)

举报
长路 发表于 2022/11/28 21:41:29 2022/11/28
【摘要】 文章目录前言一、导航初始化属性与方法小demo二、绘制功能2.1、绘制矩形2.1.1、非面向思想实现动画2.1.2、面向对象思维实现动画2.2、绘制路径2.3、绘制圆弧(动态圆形示例)2.4、设置线型透明度(小球碰撞案例)2.5、线型的属性2.6、设置文字2.7、渐变(线型与径向)2.8、设置阴影三、绘制图片四、资源管理器(手动创建类进行管理)五、变形5.1、transloate(移动画布)5.2

三、绘制图片

核心:必须要onload之后才能够绘制图片。

//实例化image属性
const img = new Image();
img.src = "./images/test.png";
// 必须要在onload挂载之后绘制图片
img.onload = function () {
    ctx.drawImage(img, 0, 0); //后两个参数为绘画的路径位置
}

上面是三个参数的,若是有五个参数,多出来的参数能够设置宽、高:

ctx.drawImage(img, 0, 0, 600, 400);

若是有9个参数,除开第一个前面四个指的是原图进行的切片,后面四个指的是切片放置的位置:

image-20210806222027654

  • 含义:从原图上的(408,81)位置切下来宽147、高182的切片图放置到canvas中(200,200)位置的宽147、高182。

image-20210806222006961

切片结果:

image-20210806222201217

目的:就是截取原图上指定区域并且最终绘制到我们的指定canvas画布上!

实操

我们实操一下:

//实例化image属性
const img = new Image();
img.src = "./images/test.png";
// 必须要在onload挂载之后绘制图片
img.onload = function () {
    ctx.drawImage(img, 369, 435, 1181, 360, 0, 0, 1181, 360);
}

image-20210806222928921

达到目标:

image-20210806222944114



四、资源管理器(手动创建类进行管理)

设立资源管理员的原因是在开发例如游戏的时候,会有一些静态资源需要请求回来的,若是直接开始,某些静态资源没有获取到页面上就会显示空或者直接报错,举例子如游戏背景图界面等,所以我们要手动创建一个资源管理器来进行管理我们的整个进程。

示例:一旦我们的资源加载完毕了,就可以开始使用资源了如下图的绘制多张图片操作!

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

<head>
    <meta charset="UTF-8">
    <title>使用桃心形方程绘制爱心</title>
</head>

<body>
    <canvas id="mycanvas" width="1500" height="400"></canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        var canvas = document.getElementById('mycanvas');
        var ctx = canvas.getContext('2d');

        //创建资源管理器
        function Game() {
            this.dom = document.getElementById('mycanvas');
            this.ctx = this.dom.getContext("2d");
            this.R = {
                "1": "./images/1.png",
                "2": "./images/2.jpg",
                "3": "./images/3.jpg",
                "4": "./images/4.png",
            }
            // 加载资源
            const counts = Object.keys(this.R).length;
            let count = 0;
            let height = 50;
            for (let key in this.R) {

                const src = this.R[key];
                this.R[key] = new Image();
                this.R[key].src = src;
                const self = this;
                // 异步方法:游戏开始方法函数只能够写在其内部中进行!!!
                this.R[key].onload = () => {
                    count++;
                    this.ctx.clearRect(10, 10, 200, 50);
                    self.ctx.font = "12px serif";
                    self.ctx.fillText("资源" + count + "已加载完毕!", 10, 30);
                    console.log(height);
                    // self.ctx.drawImage(self.R[key], 10, height, 200, 150);
                    height += 150;
                    if (count == counts) {
                        this.start();//等待资源加载完毕之后可以开始游戏!
                    }
                }

            }

        }

        // 等待资源结束之后开始执行......
        Game.prototype.start = function () {
            let width = 10;
            //业务逻辑
            for (let item in this.R) {
                this.ctx.drawImage(this.R[item], width, 50, 200, 150)
                width += 220;
            }
        }
        console.log(new Game());;

    </script>
</body>

</html>

image-20210807002112043



五、变形

5.1、transloate(移动画布)

核心API

//变形
ctx.transloate(50,50); //将canvas画布进行x轴、y轴平移,平移之后绘制图时就需要按照平移后的坐标进行
//保存当前状态
ctx.save();//举个例子吧你是用translate进行画布平移前使用保存,之后恢复状态再
//回复到以前的状态(包含画布原本位置,线、填充样式等等),已经绘画好的不会消失
ctx.restore();

通常进行变形的画布会不可控,所以我们需要配合save与restore来进行保存与恢复状态,从而可控。

示例

<body>
    <canvas id="mycanvas" width="1500" height="400"></canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        var canvas = document.getElementById('mycanvas');
        var ctx = canvas.getContext('2d');
        // 保存画布状态
        ctx.save();
        ctx.fillStyle = "red";
        // 移动画布位置
        ctx.translate(100, 40);
        // ctx.rotate(0.5);
        ctx.arc(0, 0, 40, 0, Math.PI * 2, false);
        ctx.fill();
        // 恢复画布之前状态
        ctx.restore();
        ctx.fillRect(0, 100, 50, 50);
    </script>
</body>

image-20210807174546554



5.2、rotate(画布旋转)

效果:将整个画布来进行来进行指定角度的旋转,左上角为中心点。

核心API:

ctx.rotate(0.5);   //表示整个画布顺时针旋转5°

注意点:对于restore之前的绘制的图片好像木有影响!

示例

<body>
    <canvas id="mycanvas" width="1500" height="400"></canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        var canvas = document.getElementById('mycanvas');
        var ctx = canvas.getContext('2d');
        ctx.save();
        ctx.fillStyle = "red";
        ctx.translate(100, 40);
        // ctx.rotate(0.5);
        ctx.arc(0, 0, 40, 0, Math.PI * 2, false);
        ctx.fill();
        ctx.restore();
        // 进行旋转,需要在绘制前进行旋转才有效果
        ctx.rotate(5 * Math.PI / 180);
        ctx.fillRect(0, 100, 50, 50);
    </script>
</body>

image-20210807175151736



5.3、scale(缩小绘制目标)

包含两个参数:分别表示宽、高缩小的比例。

核心API

ctx.scale(0.8, 0.8);//缩小80%,注意不能够进行放大!

示例

<body>
    <canvas id="mycanvas" width="1500" height="400"></canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        var canvas = document.getElementById('mycanvas');
        var ctx = canvas.getContext('2d');
        ctx.fillStyle = "black";
        ctx.scale(1.0, 1.0);//初始状态
        ctx.fillRect(0, 0, 100, 100);
        ctx.scale(0.8, 0.8);//缩小80%
        ctx.fillStyle = "blue";
        ctx.fillRect(0, 0, 100, 100);
        ctx.scale(.5, .5)// 缩小50%
        ctx.fillStyle = "red";
        ctx.fillRect(0, 0, 100, 100);
    </script>
</body>


transform(三个元素统一写)

核心API:可以对指定待绘制的元素进行移动、倾斜(旋转)、缩放的设置,就正好对应了前面的三个属性

ctx.setTransform(a, b, c, d, e, f);
a (m11)
    水平缩放。
b (m12)
    垂直倾斜。
c (m21)
    水平倾斜。
d (m22)
    垂直缩放。
e (dx)
    水平移动。
f (dy)
    垂直移动。 

示例

<body>
    <canvas id="mycanvas" width="1500" height="400"></canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        var canvas = document.getElementById('mycanvas');
        var ctx = canvas.getContext('2d');
        //水平缩放:1  垂直倾斜:1  水平倾斜:0  1-3  垂直倾斜指的是垂直向下倾斜;反之平行向右
        //垂直缩放:1  水平移动:0  垂直移动:0  4-6
        ctx.setTransform(1, 0, 1, 1, 0, 0);
        ctx.fillRect(0, 0, 100, 100);
    </script>
</body>

image-20210807181318404



六、合成(globalCompositeOperation)

官文:组合 Compositing

核心API

# 在绘制的两个图案之间设置属性,不仅可以在已有图形后面再画新图形,还可以用来遮盖指定区域,清除画布中的某些部分
ctx.globalCompositeOperation = "destination-out";   # 该属性就是后面绘制的图案会压盖掉原本的图案

示例

<body>
    <canvas id="mycanvas" width="400px" height="400px">
    </canvas>
    <div class="mbody"></div>
    <script>
        /** @type {HTMLCanvasElement} */
        const mcanvas = document.getElementById("mycanvas");
        const ctx = mcanvas.getContext("2d");

        //绘制的第一个图案
        ctx.fillRect(50, 50, 100, 100);

		//设置合成属性  ctx=globalCompositeOperation = "destination-out"; 

        // 绘制的第二个图案
        ctx.beginPath();
        ctx.fillStyle = "red";
        ctx.arc(150, 150, 50, 0, 7, false);
        ctx.fill();

    </script>
</body>

当在canvas板上绘制多个图案时,如下图后绘制的会有压盖效果:

image-20210807210130360

若是我们想要对压盖的内容做一些处理,如压盖部分清除、只留下压盖部分等等等等,都可以在中间设置指定的合成样式就会有对应的效果啦!

对应案例如下:

image-20210807201443598

image-20210807201628086

image-20210807201802971

还有…



实战

1、车轮滚动(核心使用rotate)

提前知识预备

需要用到属性:rotate、translate、drawImg…

核心是rotate属性进行轮子旋转转动:我们知道rotate属性是针对于canvas画布左上角作为中心点进行顺时针移动的,我们要想让某个图片实现自转效果,需要将该图片圆心位置置于右上角,之后配合rotate属性实现滚动效果!!!

例如:图书属性为400*400,我们要想让图片中心位于画布左上角,则需要指定绘制位置

const img = new Image();
img.src = "./images/wheel.png";
img.onload = () => {
    ctx.drawImage(img, -400 / 2, -400 / 2);  //通常这里来进行指定绘画位置
}
  • 注意:若是图片过大,请直接在外部设置图片的长宽,不要使用scale属性缩小,之后在进行旋转时会出现问题!

image-20210807190120526

接着我们设置一个定时器即可让其进行转动起来!

GIF

OK了之后我们配合translate属性将其移至到我们屏幕中央,这就又需要配合save与restore属性了,直接见案例!


实际示例

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

<head>
    <meta charset="UTF-8">
    <title>使用桃心形方程绘制爱心</title>
    <style>
        canvas {
            border: 1px solid #000;
        }
    </style>
</head>

<body>
    <canvas id="mycanvas" width="1500" height="400"></canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        var canvas = document.getElementById('mycanvas');
        var ctx = canvas.getContext('2d');
        const img = new Image();
        img.src = "./images/wheel.png";//895*895
        let deg = 0.1;//旋转角度
        let movePos = 200;//初始移动位置
        let moveR = 5;//向右移动位置
        img.onload = () => {
            // ctx.scale(0.2, 0.2);   //禁止使用scale来进行图片缩放对于滚动效果,会有问题!
            setInterval(() => {
                ctx.clearRect(0, 0, canvas.width, canvas.height)
                deg += 0.5;
                movePos += moveR;
                if (movePos == 1500 || movePos == 0) {
                    moveR = -moveR;
                }
                //由于使用到了translate就一定要使用save与restore!
                ctx.save();
                ctx.translate(movePos, 400 / 2);
                ctx.rotate(deg)
                ctx.drawImage(img, -400 / 2, -400 / 2);
                ctx.restore();
            }, 30);
        }
    </script>
</body>

</html>

GIF



2、开刮刮乐(核心使用合成)

通过利用合成属性来实现的开刮刮乐效果:

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

<head>
    <meta charset="UTF-8">
    <title>使用桃心形方程绘制爱心</title>
    <style>
        div {
            width: 150px;
            height: 60px;
            font-size: 20px;
            line-height: 60px;
            /* border: 1px solid #000; */
            text-align: center;
            position: relative;
            /* 设置文字不能被选中,也就是不能选中拖动查看文字! */
            user-select: none;
        }

        canvas {
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
        }
    </style>
</head>

<body>
    <div>
        超级特等奖
        <canvas width="150px" height="60px"></canvas>
    </div>
    <script>
        /** @type {HTMLCanvasElement} */
        var canvas = document.querySelector("canvas");
        var ctx = canvas.getContext('2d');

        // 将div元素进行覆盖
        ctx.fillStyle = "gray";
        ctx.fillRect(0, 0, 150, 60);

        // 使用合成效果(当有新的绘制内容压盖上来时就会清除掉原本的内容)
        ctx.globalCompositeOperation = "destination-out";

        // 实现鼠标按下移动才能够进行刮刮乐
        //监控鼠标是否按下,只有按下了移动才会有擦除功能!
        let isDown = false;
        canvas.onmousedown = function () {
            isDown = true;
        }

        canvas.onmouseup = function () {
            isDown = false;
        }

        canvas.onmousemove = function (e) {
            if (isDown) {
                console.log(e.offsetX, e.offsetY);
                ctx.beginPath();
                ctx.arc(e.offsetX, e.offsetY, 8, 0, 7, false);
                ctx.fill();
            }
        }
    </script>
</body>

</html>

GIF



示例

用 canvas 做个好玩的网站背景:网站背景粒子效果。


参考文章

[1]. 廖雪峰canvas

</head> <body>
超级特等奖 <canvas width="150px" height="60px"></canvas>
<script> /** @type {HTMLCanvasElement} */ var canvas = document.querySelector("canvas"); var ctx = canvas.getContext('2d');
    // 将div元素进行覆盖
    ctx.fillStyle = "gray";
    ctx.fillRect(0, 0, 150, 60);

    // 使用合成效果(当有新的绘制内容压盖上来时就会清除掉原本的内容)
    ctx.globalCompositeOperation = "destination-out";

    // 实现鼠标按下移动才能够进行刮刮乐
    //监控鼠标是否按下,只有按下了移动才会有擦除功能!
    let isDown = false;
    canvas.onmousedown = function () {
        isDown = true;
    }

    canvas.onmouseup = function () {
        isDown = false;
    }

    canvas.onmousemove = function (e) {
        if (isDown) {
            console.log(e.offsetX, e.offsetY);
            ctx.beginPath();
            ctx.arc(e.offsetX, e.offsetY, 8, 0, 7, false);
            ctx.fill();
        }
    }
</script>
</body> </html> ```

[外链图片转存中…(img-WInbZUfD-1652052808606)]



示例

用 canvas 做个好玩的网站背景:网站背景粒子效果。


参考文章

[1]. 廖雪峰canvas

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。