zoukankan      html  css  js  c++  java
  • 一个基于 canvas 的画板

    虽然我自己的定位是做后端的,但技术主管强调要搞全栈,因此工作中也要写一些前端页面。一个产品经理找我写个画板,他更不会管我的技术定位了。目标是做个画板,具有以下功能:

    • 可以更改画笔颜色、粗细,能擦除绘图
    • 撤销绘图
    • 设置画板背景色
    • 将画板保存成图片

    demo见:drawing_board。最后的效果长这样:

    所有的实现以及遇到的问题,都可以在网上找到。这里做一个总结。

    画笔粗细、颜色

    粗细通过 ctx.lineWidth 设置;颜色要设置 ctx.strokeStylectx.fillStyle 这两个参数才行。

    橡皮功能

    ctx.globalCompositeOperation 的默认值是 "source-over",这时可以正常绘制图形。将其改成 "destination-out",这时画笔可将绘制的线条擦除。橡皮其他部分与画笔的逻辑一样,因此代码可以复用。更改 lineWidth 便可调节橡皮大小。有的实现中直接将画笔的颜色改成画板的背景色,以此达到“擦除”的效果。但画板默认是透明的,这种错误实现会导致在输出的图片有问题。

    撤回功能

    想要撤回就要记住历史状态。将每次画下的图形数据粗暴地存储在一个数组中,撤销时将数组最后一个元素设置为 canvas 的图形数据即可。注意这里每次记录的都是完整的数据,而不是记录每次的修改,因此不能无限制地记录绘画历史。设置了数组的最大值 MaxSaveLimit,保存的次数超出这个值后,最早的数据将找不到。上文中提到,擦除与普通绘制无本质区别,因此“擦除”的历史也自然是可以撤回的。

    // 保存
    function saveImageData(data) {
        (lastImageData.length == MaxSaveLimit) && (lastImageData.shift());
        lastImageData.push(data);
    }
    
    function cancel() {
        if (lastImageData.length < 1)
            return false;
        ctx.putImageData(lastImageData[lastImageData.length - 1], 0, 0);
        lastImageData.pop();
    }
    

    设置背景色

    直接设置 canvas 节点的背景色不起作用,canvas 的背景实际上仍然是透明色。将 ctx.globalCompositeOperation 设置为 destination-over,通过填充实现背景色功能:

    ctx.globalCompositeOperation = "destination-over";
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    

    保存功能

    使用 canvas.toDataURL 获得用于图片展示的 URL,然后创建 a 标签,实现图片下载功能:

    function downLoad() {
        let url = canvas.toDataURL("image/png");
        let oA = document.createElement("a");
        oA.download = 'canvas';
        oA.href = url;
        document.body.appendChild(oA);
        oA.click();
        oA.remove();
    }
    

    其他问题

    canvas 尺寸

    和背景色一样,直接更改节点的样式无法设置 canvas 的尺寸,要通过 canvas.widthcanvas.height 来设置 canvas 的长和高。

    清晰度

    可能出现绘图模糊的现象,可根据实际设备的 devicePixelRatio 值对 ctx 进行缩放:

    let ratio = window.devicePixelRatio;
    let width = canvas.width, height = canvas.height;
    canvas.style.width = width + "px";
    canvas.style.height = height + "px";
    canvas.height = height * window.devicePixelRatio;
    canvas.width = width * window.devicePixelRatio;
    ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
    
  • 相关阅读:
    python中写一个求阶乘的函数
    python中filter关键字
    python中写一个求阶乘的函数
    python中如何获取函数文档
    python中lambda关键字创建匿名函数
    固态硬盘中m.2、sata、nvme、ahci、pcie是什么?
    python中lambda关键字定义匿名函数
    python中实现实参可选
    python中map()内置函数
    python中将实参变成可选的
  • 原文地址:https://www.cnblogs.com/ik-heu/p/12436221.html
Copyright © 2011-2022 走看看