JavaScript

HTML5 Canvas的简单使用

Nick · 4月4日 · 2020年 · 本文13322字 · 阅读34分钟942

Canvas教程文档

参考这里
https://www.runoob.com/w3cnote/html5-canvas-intro.html

Canvas的使用

1. Canvas基本绘画

<!DOCTYPE html>
<html>

<head lang="en">
    <meta charset="UTF-8">
    <title>Canvas基本绘制</title>
</head>

<body>
    <canvas id="cavsElem" width='1200' height="600">
        你的浏览器不支持canvas,请升级浏览器
    </canvas>
    <script>
        /* 绘制圆形*/
        //获得画布并上下文对象
        var context = document.getElementById('cavsElem').getContext('2d');
        context.beginPath(); //开始路径
        context.strokeStyle = "yellow"; //设置描边颜色
        context.lineWidth = 5; //设置线的粗细
        context.arc(100, 100, 100, 0, 2 * Math.PI, true); //绘制圆形,true为逆时针
        context.closePath(); //关闭路径
        context.fillStyle = 'green'; //设置填充颜色
        context.fill(); //填充
        context.stroke(); //描边
        /* 绘制弧形*/
        context.beginPath(); //开始路径
        context.strokeStyle = "#fff"; //设置描边颜色
        context.lineWidth = 5; //设置线的粗细
        context.arc(100, 150, 25, Math.PI / 6, 5 * Math.PI / 6, false); //绘制弧形,false为顺时针
        context.stroke(); //描边

        //绘制矩形
        context.strokeStyle = "blue"; //设置描边颜色
        context.strokeRect(190, 190, 210, 120); //矩形边框
        context.fillRect(200, 200, 200, 100); //填充矩形

        //清除矩形
        context.clearRect(300, 50, 200, 200);

        //绘制三角形
        context.beginPath(); //开始路径
        context.moveTo(700, 100); //三角形,左顶点,画笔移动到100,100
        context.lineTo(400, 100); //右顶点,画一条线,从100,100 到 300,100
        context.lineTo(700, 300); //底部的点,从100,100 到 300,300
        context.closePath(); //结束路径
        context.stroke(); //描边路径

        //绘制图片
        //创建图片对象
        var img = new Image();
        //设置图片路径
        img.src = "../images/draw.jpg";
        img.onload = function () {
            //使用canvas绘制图片
            context.drawImage(img, 750, 0);
        };
    </script>
</body>
</html>

效果如下
在这里插入图片描述

2. Canvas画一个时钟

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>drawClock</title>
</head>

<body>
    <!-- 定义canvas画布,包括宽度和高度,还有背景颜色 -->
    <canvas id="clock" width="1350" height="620"
        style="display: block; position: relative; background:black;margin: 20px auto;">
        你的浏览器不支持canvas标!
    </canvas>

    <!-- js脚本 -->
    <script>
        //获取上下文文档对象
        var clock = document.getElementById('clock');
        var cxt = clock.getContext('2d');

        //画指针
        function drawPointer(width, color, value, angle, startx, starty, endx, endy) {
            cxt.save(); //先保存当前画布
            cxt.lineWidth = width; //设置画笔的宽度
            cxt.strokeStyle = color; //设置画笔的颜色
            cxt.translate(550, 310); //重置异次元空间的原点坐标
            cxt.rotate(value * angle * Math.PI / 180); //设置旋转的角度,参数是弧度
            cxt.beginPath();
            cxt.moveTo(startx, starty);
            cxt.lineTo(endx, endy);
            cxt.closePath(); //先闭合路径,再画线
            cxt.stroke(); //开始画线
            cxt.restore(); //将旋转后的线段返回给画布
        }

        //画刻度
        function drawScale(size, width, color, value, startx, starty, endx, endy) {
            for (var i = 0; i < size; i++) {
                drawPointer(width, color, value, i, startx, starty, endx, endy);
            }
        }

        //为表盘的中心填充颜色
        function drawFill() {
            cxt.save();
            cxt.beginPath();
            cxt.arc(550, 310, 7, 0, 360, false);
            cxt.closePath();
            cxt.fillStyle = "red";
            cxt.fill();
            cxt.restore();
        }

        //画时钟
        function drawClock() {
            cxt.clearRect(0, 0, 1350, 620); //清空整个画布

            var now = new Date(); //获取系统时间,取出时,分,秒
            var sec = now.getSeconds();
            var min = now.getMinutes();
            var hour = now.getHours();
            min += sec / 60;
            hour += min / 60;
            if (hour > 12) hour -= 12;

            cxt.beginPath();
            cxt.lineWidth = 10;
            cxt.strokeStyle = "blue";
            cxt.arc(550, 310, 300, 0, 360, false);
            cxt.closePath();
            cxt.stroke();

            drawScale(12, 7, "pink", 30, 0, -280, 0, -260); //画时刻度
            drawScale(60, 5, "pink", 6, 0, -280, 0, -270); //画分刻度
            drawPointer(7, "purple", hour, 30, 0, 12, 0, -210); //画时针
            drawPointer(5, "yellow", min, 6, 0, 15, 0, -240); //画分针
            drawPointer(4, "red", sec, 6, 0, 17, 0, -250); //画秒针

            //细化秒针,为秒针加箭头
            drawPointer(3, "red", sec, 6, -7, -235, 0, -255);
            drawPointer(3, "red", sec, 6, 7, -235, 0, -255);
            drawFill();
        }

        drawClock();
        setInterval(drawClock, 1000); //setInterval()方法中表示每隔1000ms,就执行drawClock一次
    </script>
</body>
</html>

效果如下
在这里插入图片描述

3. Canvas绘制黑客入侵效果

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

<head>
    <meta charset="UTF-8">
    <title>黑客入侵</title>
    <style>
        * {
            margin: 0
        }

        canvas {
            background: black;
            display: block
        }
    </style>
</head>

<body>
    <canvas></canvas>
    <script>
        var oC = document.querySelector('canvas');
        var cxt = oC.getContext('2d');
        var w = oC.width = window.innerWidth;
        var h = oC.height = window.innerHeight;
        var onOff = true;
        window.addEventListener('resize', function () {
            w = oC.width = window.innerWidth;
            h = oC.height = window.innerHeight;
        });

        var arr = new Array(255).join('1').split('');
        console.log(arr)
        draw();

        function draw() {
            if (onOff) {
                cxt.fillStyle = 'rgba(0,0,0,0.05)';
                cxt.fillRect(0, 0, w, h);
            } else {
                cxt.clearRect(0, 0, w, h);
            }
            cxt.fillStyle = randomColor();
            arr.map(function (value, index) {
                cxt.font = '16px 宋体';
                text = String.fromCharCode(65 + Math.random() * 57); // 把ASCII转换成对应的字符串;
                x = index * 10;

                cxt.fillText(text, x, value);
                arr[index] = ((value > h + Math.random() * 500) ? 0 : value + 15);
            })
            requestAnimationFrame(draw);
        }

        function randomColor() {
            var r = Math.floor(Math.random() * 256);
            var g = Math.floor(Math.random() * 256);
            var b = Math.floor(Math.random() * 256);
            return 'rgb(' + r + ',' + g + ',' + b + ')';
        }
    </script>
</body>
</html>

效果如下
在这里插入图片描述

4. Canvas绘制星星特效

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>stars</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            overflow: hidden;
        }

        html,
        body {
            width: 100%;
            height: 100%;
            /* background: linear-gradient(to top, palevioletred 0%, #fff 100%); */
            background: no-repeat linear-gradient(to bottom, #dcdcdc 0%, #000 100%);
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script>
    (function (win, doc) {
        const maxW = win.innerWidth;
        const maxH = win.innerHeight;
        const maxSize = 5;
        const minSize = 1;
        let isMoving = false;
        let timer = null;

        let canvas = doc.getElementById('canvas');
        canvas.width = maxW;
        canvas.height = maxH;
        let ctx = canvas.getContext('2d');

        let stars = []; // 存放作为背景使用的星星
        let move_stars = []; // 存放鼠标移动时绘制的星星

        function CanvasStar(num) {
            this.num = num;
        };

        CanvasStar.prototype = {
            render() {
                for (let i = 0; i < this.num; i++) {
                    let alpha = Math.random() + 0.1;
                    stars[i] = new Star(i, getOneRandom(maxW), getOneRandom(maxH), getOneRandom(maxSize,
                        minSize), true, alpha);
                }
                animate();
            }
        };

        function Star(id, x, y, r, isCache, dot_alpha) {
            this.id = id;
            this.x = x;
            this.y = y;
            this.r = r;
            this.dot_alpha = dot_alpha;
            this.show = .5; // 作用:控制 鼠标绘制点的隐藏
            this.direct = getOneRandom(180) + 180;
            this.isCache = isCache;
            this.cacheCanvas = doc.createElement('canvas');
            this.ctx_cache = this.cacheCanvas.getContext('2d');
            if (isCache) {
                this.cache();
            }
        };

        Star.prototype = {

            draw() {
                // 绘制一个Star
                if (!this.isCache) {
                    let alpha = Math.random() + 0.1;
                    ctx.save();
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
                    ctx.closePath();

                    ctx.shadowColor = '#fff';
                    ctx.shadowBlur = 2 * this.r;
                    ctx.fillStyle = `rgba(255, 255, 255, ${ this.dot_alpha })`;
                    ctx.fill();
                    ctx.restore();
                } else {
                    ctx.drawImage(this.cacheCanvas, this.x - 3 * this.r, this.y - 3 * this.r)
                }
            },

            move() {
                this.y -= 0.25;
                if (this.y < -10) {
                    this.y = maxH + 10;
                }
                this.draw();
            },

            // 使鼠标绘制的点抖动起来
            shake(arr) {
                this.show -= 0.01;
                if (this.show < 0) {
                    return;
                }
                let speed = .5;
                this.x += Math.cos(this.direct * Math.PI / 180) * speed;
                this.y += Math.sin(this.direct * Math.PI / 180) * speed;
                this.draw();
                this.link();
            },

            link() {
                if (!this.id) return;
                let len = move_stars.length;
                // 关键思想:取当前id,之前的4个点,每绘制一次就向前取4个点,以此类推
                // 而不是move_stars最后的四个点,否则的话只有最后几个点会被连接起来
                let arr = move_stars.slice(this.id - 3, this.id);
                let endIdx = arr.length - 1;

                ctx.save();
                for (let i = endIdx; i >= 0; i--) {
                    if (i == endIdx && !!arr[endIdx]) {
                        ctx.moveTo(arr[endIdx].x, arr[endIdx].y);
                        ctx.beginPath();
                        ctx.lineTo(this.x, this.y);
                    }
                    if (i != endIdx && !!arr[i] && arr[i].show > 0) ctx.lineTo(arr[i].x, arr[i].y);
                }
                ctx.closePath();

                ctx.strokeStyle = 'rgba(81, 196, 211, 0.6)';
                ctx.stroke();
                ctx.restore();
            },
            cache() {
                this.cacheCanvas.width = 6 * this.r;
                this.cacheCanvas.height = 6 * this.r;

                this.ctx_cache.save();
                this.ctx_cache.beginPath();
                this.ctx_cache.arc(this.r * 3, this.r * 3, this.r, 0, 2 * Math.PI, false);
                this.ctx_cache.closePath();

                this.ctx_cache.shadowColor = '#fff';
                this.ctx_cache.shadowBlur = 2 * this.r;
                this.ctx_cache.fillStyle = `rgba(255, 255, 255, ${this.dot_alpha})`;
                this.ctx_cache.fill();
                this.ctx_cache.restore();
            }
        };

        // 动画
        function animate() {
            ctx.clearRect(0, 0, maxW, maxH);
            let len = stars.length;
            for (let i = 0; i < len; i++) {
                stars[i].move();
            }

            let len2 = move_stars.length;
            if (isMoving) {
                for (let i = 0; i < len2; i++) {
                    if (move_stars[i]) move_stars[i].shake(move_stars);
                }
            } else {
                move_stars = []
            }
            requestAnimationFrame(animate);
        };

        // 获取区间内的随机数
        function getOneRandom(max, min = 0) {
            return Math.floor(Math.random() * (max - min) + min);
        };

        // 获取正负号
        function getSign() {
            return Math.random() > .5 ? -1 : 1;
        };

        // 鼠标移动事件
        doc.addEventListener('mousemove', function (e) {
            let x = e.clientX,
                y = e.clientY;
            // 控制绘制密度 以及点之间的距离    两个重要的点
            // 密度是控制绘制的数量     dis_x = Math.abs(x - pre_star.x);
            // 距离是在已绘制的点基础上、控制点的间距

            // 控制绘制密度 和 控制点之间的距离  不是一个功能哦(需要实际操作去体会, 文字很难表述~.~)
            // 没有控制距离的话 绘制的图形,太规则了,不够分散    x = x + getSign() * getOneRandom(50)

            let len = move_stars.length;
            let dis_x, dis_y;
            if (!len) {
                move_stars.push(new Star(len, x, y, getOneRandom(maxSize, 3), true, 1));
            }

            if (move_stars[len - 1]) {
                // 当前的星还没有push到move_stars里,所以上个星是move_stars[len - 1]
                let pre_star = move_stars[len - 1];
                if (pre_star) {
                    dis_x = Math.abs(x - pre_star.x);
                    dis_y = Math.abs(y - pre_star.y);
                }
                x = x + getSign() * getOneRandom(50);
                y = y + getSign() * getOneRandom(50);
                if (dis_x > 5 && dis_y > 5) move_stars.push(new Star(len, x, y, getOneRandom(maxSize,
                    minSize), true, 1));
            }

            isMoving = true;
            clearInterval(timer); // 清除上一次的定时器(此时还没触发)
            timer = setInterval(function () {
                isMoving = false;
                clearInterval(timer); // 鼠标停止再清除下定时器
            }, 500)

        }, false);

        window.CanvasStar = CanvasStar;
    })(window, document);
</script>
<script>
    let canvasStar = new CanvasStar(200);
    canvasStar.render();
</script>

</html>

效果如下
在这里插入图片描述

5. Canvas网页涂鸦板增强版

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

<head>
    <meta charset="UTF-8">
    <title>Canvas案例-网页涂鸦板</title>
</head>

<body>
    <!--<center></center>表示将标签内所有的内容居中-->
    <center>
        <canvas id="cavsElem">
            你的浏览器不支持canvas,请升级浏览器
        </canvas><br>
        选择画笔颜色:<input type="color" value="#ff0000" id="mycolor" onchange=colorChange() />   
        <input type="button" value="清除" id="clear" onclick=clearAll()>    
        选择画笔粗细:<input type="number" id="gsize" value="1" min="1" onchange=sizeChange()>
    </center>
    <script>
        //获得画布
        var canvas = document.getElementById('cavsElem');
        //准备画笔(获取上下文对象)
        var context = canvas.getContext('2d');
        //设置标签的宽高和边框
        canvas.width = 900;
        canvas.height = 600;
        context.strokeStyle = document.getElementById("mycolor").value; //设置描边颜色
        canvas.style.border = "1px solid #000";
        //当鼠标按下触发onmousedown事件时,定义一个函数获取鼠标起始坐标
        canvas.onmousedown = function (e) {
            var x = e.clientX - canvas.getBoundingClientRect().left;
            var y = e.clientY - canvas.getBoundingClientRect().top;
            context.beginPath(); //开始规划路径
            context.moveTo(x, y); //移动起始点
            //当鼠标移动触发onmousemove事件时,定义一个函数获取绘制线条的坐标
            canvas.onmousemove = function (event) {
                var x = event.clientX - canvas.getBoundingClientRect().left;
                var y = event.clientY - canvas.getBoundingClientRect().top;
                // canvas.clearRect(0, 0, 900, 600);
                context.lineTo(x, y); //绘制线条
                context.stroke(); //绘制描边
            };
            //当鼠标按键被松开时,onmousemovet函数返回null
            canvas.onmouseup = function (event) {
                canvas.onmousemove = null;
            };
        };
        /* 清除画布 */
        function clearAll() {
            //清除矩形
            context.clearRect(0, 0, 900, 600);
        }
        /* 颜色选择 */
        function colorChange() {
            var mycolor = document.getElementById("mycolor");
            var x = mycolor.value;
            // console.log('x :', x);
            context.strokeStyle = x; //设置描边颜色
        }
        /* 画笔粗细 */
        function sizeChange() {
            var mycolor = document.getElementById("gsize");
            var x = mycolor.value;
            context.lineWidth = x; //设置线的粗细
        }
    </script>
</body>
</html>

效果如下
在这里插入图片描述

6. 3D炫酷特效

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D特效</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background: #FFF;
        }

        canvas {
            position: absolute;
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
    <script>
        var canvas;
        var context;
        var screenWidth;
        var screenHeight;
        var doublePI = Math.PI * 2;
        var step = 0;
        var points = [];
        var focalLength = 500;
        var bgGradient;

        window.onload = function () {
            canvas = document.getElementById('canvas');
            context = canvas.getContext('2d');

            window.onresize = function () {
                screenWidth = window.innerWidth;
                screenHeight = window.innerHeight;

                canvas.width = screenWidth;
                canvas.height = screenHeight;

                bgGradient = context.createRadialGradient((screenWidth >> 1), screenHeight >> 1, screenWidth,
                    screenWidth >> 1, screenHeight >> 1, 0);
                bgGradient.addColorStop(1, '#000');
                bgGradient.addColorStop(0.2, '#900');
            };

            generatePoints();

            window.onresize();

            loop();
        };

        function generatePoints() {
            var i = 2000;

            for (i; i > -1; --i) {
                var point3D = {
                    x: (1 - Math.random() * 2) * 600,
                    y: (1 - Math.random() * 2) * 600,
                    z: (1 - Math.random() * 2) * 600,
                    vx: 0,
                    vy: 0,
                    vz: 0
                };

                points.push(point3D);
            }
        }

        window.getAnimationFrame =
            window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function (callback) {
                window.setTimeout(callback, 16.6);
            };

        function loop() {
            context.globalAlpha = 0.4;
            context.fillStyle = bgGradient;
            context.fillRect(0, 0, screenWidth, screenHeight);
            context.globalAlpha = 1;

            updatePoints();
            renderPoints();
            renderWire();

            step += 0.02;

            getAnimationFrame(loop);
        }

        function renderPoints() {
            var i = points.length - 1;

            for (i; i > -1; --i) {
                var point = points[i];
                var scale = focalLength / (point.z + focalLength);

                var px = (point.x * scale + (screenWidth >> 1));
                var py = point.y * scale + (screenHeight >> 1);

                drawPoint({
                    x: px,
                    y: py
                }, scale);
            }
        }

        function renderWire() {
            context.globalAlpha = 0.02;
            context.lineWidth = 1;
            context.strokeStyle = '#FFF';
            context.beginPath();

            var i = points.length - 1;

            for (i; i > -1; --i) {
                var point = points[i];
                var scale = focalLength / (point.z + focalLength);

                if (i === points.length - 1) context.moveTo(point.x * scale + (screenWidth >> 1), point.y * scale + (
                    screenHeight >> 1));
                else context.lineTo(point.x * scale + (screenWidth >> 1), point.y * scale + (screenHeight >> 1));
            }

            if (Math.random() > 0.4) context.stroke();
            context.closePath();
            context.globalAlpha = 1;
        }

        function updatePoints() {
            var i = points.length - 1;

            for (i; i > -1; --i) {
                var point = points[i];
                point.x += Math.cos(step * 0.4) * 2;
                point.y += Math.sin(step * 0.8) * 2;
                point.z -= 2;

                checkBounds(point);
            }
        }

        function checkBounds(point) {
            if (point.x < -2000) point.x = Math.random() * 2000;
            else if (point.x > 2000) point.x = Math.random() * -2000;

            if (point.y < -2000) point.y = Math.random() * 2000;
            else if (point.y > 2000) point.y = Math.random() * -2000;

            if (point.z < -500) point.z = Math.random() * 2400 + 200;
        }

        function drawPoint(point, scale) {
            context.globalAlpha = scale;
            context.fillStyle = '#FAA';
            context.beginPath();
            context.rect(point.x, point.y, (1.6 * scale > 0) ? 1.6 * scale : 1, (1.6 * scale > 0) ? 1.6 * scale : 1);
            context.fill();
            context.closePath();
            context.globalAlpha = 1;
        }
    </script>

</html>

效果如下
在这里插入图片描述

总结

总的来说Canvas真的非常强大,但是要做出炫酷的作品,难度也很大,涉及了很多算法的实现,只是刚接触,需要更多的练习。
本文章花了很多时间搜集特效代码,对搜集的代码也自己认真的改善,和谐、整理后可以直接使用的。如果大家喜欢或者对大家有帮助,可以点赞、评论、关注,长的帅的可以大方的打赏支持一下 ^ _ ^
有什么问题都可以联系我(评论就可以了!)

0 条回应
在线人数:1人 来访统计
说谎
林宥嘉
隐藏