Canvas画板 带暂停加速回放减速功能

Canvas画板 带暂停加速回放减速功能

写这个的原因是支付宝写福字可以回放,就自己写一个试试。

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>画板</title>
</head>
<style>
    #box {
        width: 500px;
        height: 500px;
        border: 12px solid #eee;
        border-radius: 10px;
        position: relative;
    }

    #Toolbar {
        width: 100%;
        height: 100px;
        display: flex;
        justify-content: space-around;
        align-items: center;
    }

    #Toolbar p {
        width: 100px;
        margin: 0;
        padding: 0;
        text-align: center;
        cursor: pointer
    }

    #sketchpad {
        width: 100%;
        height: 400px;
        box-shadow: 0 0 0 2px #eee;
        position: relative;
    }

    #canvas {
        cursor: url(./image/pen.png)3 16, pointer;
    }
    #play_box{
        position: absolute;
        top: 0;
        right: -70px;
        display: flex;
        flex-direction: column;
    }
    #play_box > button{
        margin-top: 10px;
        border:none;
        padding: 2px;
        font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
        width: 50px;
        height: 50px;
        border-radius: 30%;
        outline:medium;
        box-shadow:0 0 8px 0 #534d4e;
        transition-property: box-shadow;
        transition-duration: 1s;
        transition-timing-function: linear;
    }
    #play_box > button:hover{
        box-shadow:0 0 8px 0 #274ee5;
    }

</style>

<body>
    <div id="box">
        <div id="Toolbar">
            <p tyle="pencil">铅笔
                <input type="color">
            </p>
            <label for="num">加粗
                <input id="num" type="number" max="50" style="width: 100px;">
            </label>

            <p tyle="Draw">画圆</p>
            <p tyle="del">擦除</p>
        </div>
        <div id="sketchpad">
            <canvas id="canvas" width="500" height="400"></canvas>
        </div>
        <div id="play_box">
            <button id="play_back">回放</button>
            <button id="play_stop">暂停</button>
            <button id="play_go_on">继续</button>
            <button id="play_accelerated">加速</button>
            <button id="play_slowdown">减速</button>
        </div>
    </div>
</body>

</html>
<script>
    // 方法类
    class Method {
        // 擦除方法
        del_canvas(e) {
            let {
                x,
                y
            } = tb.start;
            tb.ctx.moveTo(x, y);
            tb.ctx.strokeStyle = "#fff";
            tb.ctx.lineTo(e.offsetX, e.offsetY);
            tb.ctx.stroke();
            tb.start.x = e.offsetX;
            tb.start.y = e.offsetY;
            tb.canvas.style.cursor = "grabbing";

        }
        // 画圆
        draw_canvas_circle(e) {
            let {
                x,
                y
            } = tb.start;
            tb.ctx.beginPath();
            tb.ctx.arc(x, y, tb.arc_width, 50, 0, 2 * Math.PI);
            tb.ctx.stroke();
            canvas_playback.set_path([
                [x, y],
                [tb.arc_width], tb.Pencil_Color, tb.lineWidth
            ]); //添加绘制路径到canvas_playback类存储
            if(tb.arc_width === 0){
                tb.arc_start = e.x;
                ++tb.arc_width;
            }
            if(tb.arc_start < e.x){
                ++tb.arc_width;
                tb.arc_start = e.x;
            }
            if(tb.arc_start > e.x){
                --tb.arc_width;
                tb.arc_start = e.x;
            }



        }
        // 画线
        draw_canvas(e) {
            let {
                x,
                y
            } = tb.start;
            tb.ctx.beginPath();
            tb.ctx.moveTo(x, y);
            tb.ctx.strokeStyle = tb.Pencil_Color;
            tb.ctx.lineWidth = tb.lineWidth;
            tb.ctx.lineTo(e.offsetX, e.offsetY);
            tb.ctx.stroke();
            canvas_playback.set_path([
                [x, y],
                [e.offsetX, e.offsetY], tb.Pencil_Color, tb.lineWidth
            ]); //添加绘制路径到canvas_playback类存储
            tb.start.x = e.offsetX;
            tb.start.y = e.offsetY;
        }

    }
    class Toolbar extends Method {
        constructor(id) {
            super();
            this.Toolbar_func = new Map(); // 存储工具栏的方法使用 Map(key ,func) 存储
            this.Pencil_Color = "red";//默认颜色
            this.lineWidth = 1;//默认宽度
            this.current_func = "pencil"; //当前选中的工具栏
            this.Toolbar_P = Array.from(document.querySelectorAll(`${id} > p`));
            this.canvas = document.querySelector("#canvas");
            this.canvas.addEventListener("mousedown", this.canvas_mousedown.bind(this));
            this.canvas.addEventListener("mouseup", this.stop_mousemove.bind(this));
            this.init(this.Toolbar_P);
            this.ctx = this.canvas.getContext("2d");
            this.start = {
                x: 0,
                y: 0,
            }
            this.lineTo = {
                lineTo_x: 0,
                lineTo_y: 0,
            }
            this.arc_width = 0;
            this.arc_start = 0;
            this.is_mouseup = false

        };
        // 初始化切换
        init(dom) {
            for (let i in dom) {
                let tyle = dom[i].getAttribute("tyle");
                this.Toolbar_func.set(tyle, " ");
                dom[i].addEventListener("click", function tab() {
                    tb.current_func = this.getAttribute('tyle');
                    this.style.boxShadow = "0 2px 0 0 #999";
                    this.style.transition = "box-Shadow 1s";
                    for (let s in dom) {
                        if (dom[s] !== this) {
                            dom[s].style.boxShadow = "initial"

                        } else {
                            if (dom[s].getAttribute("tyle") === "del") {
                                document.querySelector("#canvas").style.cursor = "grabbing";
                            } else {
                                document.querySelector("#canvas").style.cursor =
                                    "url(./image/pen.png)3 16, pointer";
                            }
                        }
                    }
                })
            }
            // 添加工具栏的方法
            this.Toolbar_func.set("pencil", super.draw_canvas);
            this.Toolbar_func.set("Draw", super.draw_canvas_circle);
            this.Toolbar_func.set("del", super.del_canvas);

        };
        
        // 添加画布的点击事件,点击画布进行画画
        canvas_mousedown(e) {
            this.is_mouseup = false;
            this.start.x = e.offsetX;
            this.start.y = e.offsetY;
            this.canvas.addEventListener("mousemove", this.canvas_drawn)
        };
        
        // 结束鼠标事件
        stop_mousemove() {
            this.arc_width = 0;
            this.canvas.removeEventListener("mousemove", this.canvas_drawn);
        }

        // 绘制的方法
        canvas_drawn(e) {
            if (!!tb.current_func) {
                tb.Toolbar_func.get(tb.current_func)(e);
            }
        }
        // 修改笔的颜色
        Modify_Pencil_Color(type) {
            this.Pencil_Color = type ? type : "#000";
        }
        // 修改线的宽度
        Modify_line_Width(width) {
            if (!Number(width)) {
                this.lineWidth = 1;
                throw "参数错误";
            }
            this.lineWidth = width;
        }

        // 添加操作栏的方法
        add_Toolbar_func(name, func, iscover = false) {
            if (!!name && !!func && Object.prototype.toString.call(name) !== "[object String]" && Object.prototype
                .toString.call(func) !== "[object function]") {
                throw "参数不全或类型错误";
                return;
            }
            let is_has = this.Toolbar_func.has(name);
            if (is_has && !iscover) {
                throw "方法存在禁止重写,设置形参iscover 为 true可重写"
                return;
            }
            this.Toolbar_func.set(name, func);

        }
    }

    var tb = new Toolbar("#Toolbar");
    document.querySelector("[type=color]").addEventListener("change", function (e) {
        let color = this.value;
        tb.Modify_Pencil_Color(color);
    })
    document.querySelector("[type=number]").addEventListener("change", function (e) {
        let width = this.value;
        tb.Modify_line_Width(width);
    })
    // 画画回放
    class Canvas_Playback {
        constructor() {
            this.canvas_Path = new Map();
            this.stop = true;
            this.speed = 200;
        }
        set_path(path) {
            this.canvas_Path.set(this.canvas_Path.size + 1, path);
        };
        get_path() {
            return this.canvas_Path;
        }
        Playback() {
            let map_path = this.canvas_Path;
            tb.ctx.clearRect(0, 0, 500, 400);
            let lenth = map_path.size;
            let that = this;
            let a = 1;
            if (lenth ===  0) {
                alert("无可回放的图画");
                return;        
            };
            setTimeout(function go_play(){
                let p;
                if(a === lenth){
                    clearTimeout(p);
                    return;
                }
                let i = map_path.get(a);
                if(i[1].length === 1){
                    tb.ctx.beginPath();
                    tb.ctx.strokeStyle = i[2];
                    tb.ctx.arc(i[0][0], i[0][1], i[1][0], 50, 0, 2 * Math.PI);
                    tb.ctx.stroke();
                }else{
                    tb.ctx.beginPath();
                    tb.ctx.moveTo(i[0][0], i[0][1]);
                    tb.ctx.strokeStyle = i[2];
                    tb.ctx.lineWidth = i[3];
                    tb.ctx.lineTo(i[1][0], i[1][1]);
                    tb.ctx.stroke();
                }
                that.stop && ++a;
               p = setTimeout(go_play,that.speed)
            },100)

        }
        check(msg){
            let map_path = this.canvas_Path.size;
            if(map_path === 0){
                alert(msg);
                return false;
            }
            return  true;
        }
        play_stop(){

            if(this.check("没有画可操作")) this.stop = false;
        }
        play_go_on(){
            if(this.check("没有画可操作")) this.stop = true;

        }
        play_accelerated(){
            if(this.check("没有画可操作")) this.speed > 0 ? this.speed -= 100 : this.speed = 0;
           
        }
        play_slowdown(){
            if(this.check("没有画可操作")) this.speed += 100;
        }

    }
    var canvas_playback = new Canvas_Playback();
    document.querySelector("#play_box").addEventListener("click",function(e){
       let id = e.target.getAttribute("id"); 
        switch(id){
            case "play_back":
            canvas_playback.Playback();
            break;
            case "play_stop":
            canvas_playback.play_stop();
            break;
            case "play_go_on":
            canvas_playback.play_go_on();
            break;
            case "play_accelerated":
            canvas_playback.play_accelerated();
            break;
            case "play_slowdown":
            canvas_playback.play_slowdown();
            break;
            default:
                console.log(`无此方法${id}`);

        }
    },true)
</script>

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值