【canvas】简易小实例(钟表和画布)

看了大佬的canvas 2d视频视频链接 通过两个小实例介绍了canvas的各项函数与功能这里放出代码供参考


画布实例

实现了鼠标可以在画板上绘制图像,且可以重置和保存为png。原理是监听鼠标的操作事件,通过不断的设定canvas的绘制起点位置从而实现连续的鼠标绘制

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

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #canvas {
            /* background: brown; */
        }
    </style>
</head>

<body>
    <div class="menu">
        <button class="button"> 画板</button>
        <button id="clear">重置</button>
        <button id="save"> 保存</button>
    </div>
    <div class="window">
        <div class="top">
            <div class="button"> </div>
            <div class="button"> </div>
            <div class="button"> </div>
        </div>
        <canvas id="canvas" width="500" height="500"></canvas>
    </div>

    <script>
        let painting = false;
        let startPoint = { x: undefined, y: undefined };
        /** @type {HTMLCanvasElement} */
        const canvas = document.getElementById("canvas");
        const clear = document.getElementById("clear");
        const save = document.getElementById("save");
        const ctx = canvas.getContext("2d");

        canvas.onmousedown = e => {
            let x = e.offsetX;
            let y = e.offsetY;
            startPoint = { x: x, y: y };
            painting = true;
        };

        // 不断的将老位置与新位置相连
        canvas.onmousemove = e => {
            let x = e.offsetX;
            let y = e.offsetY;
            newPoint = { x: x, y: y };
            if (painting) {
                drawLine(startPoint.x, startPoint.y, newPoint.x, newPoint.y);
                startPoint = newPoint; // 起始点重新设置
            }
        };

        canvas.onmouseup = () => {
            painting = false;
        };

        function drawLine(xStart, yStart, xEnd, yEnd) {
            ctx.beginPath();
            ctx.lineWidth = 3;
            ctx.moveTo(xStart, yStart);
            ctx.lineTo(xEnd, yEnd);
            ctx.stroke();
            ctx.closePath();
        }
        
        clear.onclick = () => {
            ctx.fillStyle = "#FFFFFF";
            ctx.clearRect(0, 0, canvas.width, canvas.height);
        };

        save.onclick = () => {
            const url = canvas.toDataURL("image/jpg");
            const a = document.createElement("a");
            a.href = url;
            a.download = "画板";
            a.target = "_blank";
            a.click();
        };
        // 填充颜色
        // ctx.fillStyle = "orange";
        // ctx.fillStyle = "#FFA500";
        // ctx.fillStyle = "#rgb(255,165,0)";
        // ctx.fillStyle = "#rgb(255,165,0, 0.5)";

        // 添加图片
        // var img = new Image();
        // img.src = "logo.png";
        // 当图片加载完之后运行:
        // img.onload = function () {
        //     ctx.drawImage(img, 0, 0); // 有9个参数
        // }

        // 新建文本
        // ctx.fillText("sdasdsa", 100, 100, 200);
        // ctx.strokeText("8888888", 20, 200, 500);


        // 绘制圆形
        // ctx.arc(x,y,r,startAngle, endAngle, anticClockwise);
        // ctx.arc(100, 100, 50, 0, 2 * Math.PI);
        // ctx.stroke();
        // 贝塞尔曲线
        // ctx.quadraticCurveTo(cp1x,cp2y,x,y);
        // ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y); // cp12两个控制点坐标, x与y是曲线结束点坐标

        // 绘制矩形
        // ctx.rect(0, 0, 100, 200);
        // ctx.stroke();
        // ctx.strokeRect(0, 0, 100, 300);

        // ctx.fillRect(0, 0, 100, 200);
        // ctx.clearRect(50, 50, 10, 100);

        // 绘制直线
        // ctx.beginPath();
        // ctx.moveTo(100, 100);
        // ctx.lineTo(200, 200);
        // ctx.lineTo(300, 200);
        // // ctx.lineTo(100, 100);
        // ctx.closePath();
        // ctx.stroke();
        // // ctx.fill(); 填满
    </script>
</body>

</html>

钟表实例

原理是通过requestAnimationFrame功能每秒循环渲染一次画布,再通过 new Date();不停获取当前时间,变换指针的角度位置

        // 定义一个回调函数
        function animate(time){
            // 更新动画状态
            update(time);
            // 绘制动画帧
            draw();
            // 请求下一次动画帧
            window.requestAnimationFrame(animate);
        }
        // 开始动画循环
        window.requestAnimationFrame(animate);

实现效果如下:
请添加图片描述

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <canvas id="canvas" width="600" height="600"></canvas>
    <script>

        /** @type {HTMLCanvasElement} */
        const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");

        // 定义一个回调函数
        function animate(time) {
            const now = new Date();
            const sec = now.getSeconds();
            const min = now.getHours();
            let hr = now.getHours();
            // 需要给小时换算成12小时制
            hr = hr >= 12 ? hr - 12 : hr;
            ctx.save();
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            ctx.translate(canvas.width / 2, canvas.height / 2);// 将坐标轴原点移到画布中心
            ctx.rotate(-Math.PI / 2);// 将坐标轴旋转90度,变为我们现实中常用的坐标系

            ctx.strokeStyle = "black";
            ctx.lineWidth = 5;
            ctx.lineCap = "round";

            // 绘制时针
            ctx.save();
            for (let i = 0; i < 12; i++) {
                ctx.beginPath();
                ctx.rotate(Math.PI / 6);
                ctx.moveTo(100, 0);
                ctx.lineTo(120, 0);
                ctx.stroke();
            }
            ctx.restore();

            // 绘制分针
            ctx.save();
            ctx.lineWidth = 3;
            for (let i = 0; i < 60; i++) {
                ctx.beginPath();
                ctx.rotate(Math.PI / 30);
                ctx.moveTo(110, 0);
                ctx.lineTo(120, 0);
                ctx.stroke();
            }
            ctx.restore();

            // 绘制小时指针
            ctx.save();
            // 时针的角度多走0.5度, 多一秒时针多走0.083度
            ctx.rotate(
                hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) * sec
            );
            ctx.lineWidth = 14;
            ctx.beginPath();
            ctx.moveTo(-20, 0);
            ctx.lineTo(80, 0);
            ctx.stroke();
            ctx.restore();

            // 绘制分钟指针
            ctx.save();
            ctx.rotate(
                (Math.PI / 30) * min + (Math.PI / 1800) * sec
            );
            ctx.lineWidth = 10;
            ctx.beginPath();
            ctx.moveTo(-28, 0);
            ctx.lineTo(105, 0);
            ctx.stroke();
            ctx.restore();

            // 绘制秒数指针
            ctx.save();
            ctx.rotate((sec * Math.PI) / 30);
            ctx.strokeStyle = "#D40000";
            ctx.fillStyle = "#D40000";
            ctx.lineWidth = 6;
            ctx.beginPath();
            ctx.moveTo(-30, 0);
            ctx.lineTo(110, 0);
            ctx.stroke();

            // 绘制秒针中间的那个圆点
            ctx.beginPath();
            ctx.arc(0, 0, 10, 0, Math.PI * 2, true);
            ctx.fill();
            ctx.fillStyle = "rgba(0,0,0,0)";
            ctx.arc(0, 0, 3, 0, Math.PI * 2, true);
            ctx.fill();
            ctx.stroke();
            ctx.restore();

            ctx.restore();
            // 请求下一次动画帧
            window.requestAnimationFrame(animate);
        }
        // 开始动画循环
        window.requestAnimationFrame(animate);


        // // 定义一个回调函数
        // function animate(time){
        //     // 更新动画状态
        //     update(time);
        //     // 绘制动画帧
        //     draw();
        //     // 请求下一次动画帧
        //     window.requestAnimationFrame(animate);
        // }
        // // 开始动画循环
        // window.requestAnimationFrame(animate);

    </script>
</body>

</html>

总结

  • 感觉canvas和python的小乌龟绘图差不多,但是能够实现的多了很多,尤其是动画方面
  • 自己还需要提升阅读英文原文档的能力
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网瘾中心呼唤爱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值