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>canvas</title>
</head>
<style>
    .toolbar {
        width: 200px;
        float: left;
    }

    .canvas1 {
        position: absolute;
        left: 200px;
        z-index: 101;
    }

    .canvas2 {
        background: #03A9F4;
        position: absolute;
        left: 200px;
        z-index: 100;
    }
</style>

<body>
    <div id="toolbar" class="toolbar">
        <h2>工具栏</h2>
        <input onclick="switchMark(1)" type="button" value="画笔" /><br />
        <input onclick="switchMark(2)" type="button" value="矩形" /><br />
        <input onclick="switchMark(3)" type="button" value="圆形" /><br />
        <input onclick="switchMark(4)" type="button" value="文字" /><br />
        <div id="inputText">
            <input id="text" type="input" style=" 100px;" />
            <button onclick="inputText()">确定</button><br />
        </div>
        <input onclick="switchMark(0)" type="button" value="撤销" /><br />
    </div>
    <canvas id="canvas1" class="canvas1" width="400px" height="400px">您的浏览器不支持画布!</canvas>
    <canvas id="canvas2" class="canvas2" width="400px" height="400px">您的浏览器不支持画布!</canvas>

    <script>
        var canvas1 = document.getElementById("canvas1");
        var context1 = canvas1.getContext("2d");

        var canvas2 = document.getElementById("canvas2");
        var context2 = canvas2.getContext("2d");

        var text = document.getElementById('inputText');
        text.style.display = 'none';

        var canvasWidth = 400;
        var canvasHeight = 400;
        // 图片索引
        var canvasIndex = -1;
        // 图片数据
        var canvasData = [];
        // 轨迹结束判断
        var isSameMove = false;
        // 标注类型
        var switchMarkType = null;
        // 鼠标按下状态
        var isMouseDown = false;
        // 鼠标坐标
        var mouseXY = { x1: 0, y1: 0, x2: 0, y2: 0 };

        // 保存初始图片
        canvasIndex++;
        canvasData.push(canvas2.toDataURL());

        // 标注类型切换
        function switchMark(markType) {
            if (markType === 0) {
                undo();
            }
            if (markType !== 4) {
                text.style.display = 'none';
            }
            if (switchMarkType === markType || markType === 0) {
                switchMarkType = null;
                return;
            }
            switchMarkType = markType;
        }
        // 输入文字标注
        function inputText() {
            var str = document.getElementById('text').value;
            context1.font = '24px Arial';
            context1.fillText(str, mouseXY.x1, mouseXY.y1);
            setCanvasImage(context2, canvas2, canvas1.toDataURL(), canvasWidth, canvasHeight, (url) => {
                context1.clearRect(0, 0, canvasWidth, canvasHeight);
                canvasIndex++;
                canvasData.push(url);
            })
            text.style.display = 'none';
        }
        // 撤销
        function undo() {
            if (canvasIndex > 0) {
                canvasData.pop();
                canvasIndex--;
                context2.clearRect(0, 0, canvasWidth, canvasHeight);
                setCanvasImage(context2, canvas2, canvasData[canvasIndex], canvasWidth, canvasHeight, (url) => {
                    return;
                });
            } else {
                console.log('不能再继续撤销了');
            }
        }
        // 鼠标按下
        canvas1.onmousedown = function (e) {
            isMouseDown = true;
            context1.lineWidth = '2';
            context1.strokeStyle = 'red';
            context1.fillStyle = 'red';
            setMouseXY(true, e);
            // 绘制线
            if (switchMarkType === 1) {
                context1.beginPath();
                context1.moveTo(mouseXY.x1, mouseXY.y1);
            }
            // 绘制文字
            if (switchMarkType === 4) {
                text.style.display = 'block';
            }
        }
        // 鼠标向上
        canvas1.onmouseup = function (e) {
            isMouseDown = false;
            if (switchMarkType === null || switchMarkType === 4) {
                return;
            }
            setCanvasImage(context2, canvas2, canvas1.toDataURL(), canvasWidth, canvasHeight, (url) => {
                context1.clearRect(0, 0, canvasWidth, canvasHeight);
                canvasIndex++;
                canvasData.push(url);
            })
        }
        // 鼠标移动
        canvas1.onmousemove = function (e) {
            if (isMouseDown) {
                // 清除canvas1上的图像
                context1.clearRect(0, 0, canvasWidth, canvasHeight);
                // 绘制线
                if (switchMarkType === 1) {
                    // 记录起点坐标
                    setMouseXY(true, e);
                    context1.lineTo(mouseXY.x1, mouseXY.y1);
                    context1.stroke();
                    context1.save();
                }
                // 记录终点坐标
                setMouseXY(false, e);
                // 绘制矩形
                if (switchMarkType === 2) {
                    context1.strokeRect(mouseXY.x1, mouseXY.y1, mouseXY.x2 - mouseXY.x1, mouseXY.y2 - mouseXY.y1);
                }
                // 绘制圆形
                if (switchMarkType === 3) {
                    context1.beginPath();
                    var cx = (mouseXY.x1 + mouseXY.x2) / 2;
                    var cy = (mouseXY.y1 + mouseXY.y2) / 2;
                    var rx = Math.abs((mouseXY.x1 - mouseXY.x2) / 2);
                    var ry = Math.abs((mouseXY.y1 - mouseXY.y2) / 2);
                    context1.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
                    context1.stroke();
                }
                // 在canvas1上绘制图像
                context1.drawImage(canvas1, 0, 0, canvasWidth, canvasHeight);
            }
        }
        // 根据宽高生成canvas图像
        function setCanvasImage(context, canvas, base64PImg, canvasWidth, canvasHeight, callback) {
            let img = new Image();
            img.onload = function () {
                context.drawImage(img, 0, 0, canvasWidth, canvasHeight);
                callback(canvas.toDataURL());
            }
            img.src = base64PImg;
        }
        // 求鼠标坐标函数
        function windowToCanvas(canvas, x, y) {
            const rect = canvas.getBoundingClientRect();
            return {
                x: x - rect.left * (canvas.width / rect.width),
                y: y - rect.top * (canvas.height / rect.height)
            };
        }
        // 记录坐标
        function setMouseXY(start, e) {
            const ele = windowToCanvas(canvas1, e.clientX, e.clientY);
            if (start) {
                mouseXY.x1 = ele.x;
                mouseXY.y1 = ele.y;
            } else {
                mouseXY.x2 = ele.x;
                mouseXY.y2 = ele.y;
            }
        }
    </script>
</body>

</html>
原文地址:https://www.cnblogs.com/chendongbky/p/12016602.html