首页 > 解决方案 > 如何有效地存储手绘线(画布)?

问题描述

背景

我正在制作一个简单的在线绘图应用程序,以便我可以练习我的 JS 和画布技能。进展非常顺利,可以自由绘制,也可以绘制直线。

我的绘图应用程序如何工作

它注册处理所有绘图和保存的鼠标和触摸事件。

这是一些示例代码:

var tools={
    "pencil":{
        "started": false,
        ... (some data used by the pencil tool),
        "start":function(e){
            if(currentTool!=="pencil")return;
            // Make sure that the selected tool on the toolbar is the pencil
            
            // code for mousedown/touchstart
            tools.pencil.started=true;
        },
        "move":function(e){
            if(!tools.pencil.started)return;
            // code for mousemove/touchmove
        },
        "end":function(e){
            if(!tools.pencil.started)return;
            // code for mouseup/touchend
            tools.pencil.started=false;
        }
    },
    "other tools":{
        ...
    }
};

// And here would be a function which adds the mouse and touch events

这是我的铅笔工具:

var tools={
    pencil:{
        started:false,
        start:function(e){
            if(currentTool!=="pencil")return; // Make sure the pencil tool is selected
            e.preventDefault();
            e=e.clientX?e:e.touches[0]; // Allow touch
            context.beginPath(); // Begin drawing
            context.moveTo(e.clientX-50,e.clientY); // Set the position of the pencil
            tools.pencil.started=true; // Mark the pencil tool as started
        },
        move:function(e){
            if(tools.pencil.started){ // Make sure the pencil is started
                e.preventDefault();
                e=e.clientX?e:e.touches[0];
                context.lineTo(e.clientX-50,e.clientY); // Draw a line
                context.stroke(); // Make the line visible
            }
        },
        end:function(e){
            if(tools.pencil.started){
                e.preventDefault();
                //tools.pencil.move(e); // Finish drawing the line
                tools.pencil.started=false; // Mark the pencil tool as not started
            }
        }
    }
};

忽略-50部分(它们只是用侧边栏调整)。这有效,但不能保存到localStorage.

问题

TL;DR:我需要将画布上的所有内容保存到某个存储中(我目前正在使用localStorage,但任何东西都可以,尽管我更喜欢只使用客户端)。我不知道如何有效地存储它,其中“有效”意味着快速和准确(准确,因为它存储了整条线)。线可以存,但是手绘的东西我还没弄明白。

解释:

当用户调整窗口大小时,画布会调整为窗口大小(我做到了,不是错误)。我能够做到,当您调整大小时,它首先将绘图保存到临时画布上,然后在主画布调整大小后,重新绘制它们。但是有一个问题。这是一个清楚的例子:

  1. 您打开绘图应用程序并用绘图填充屏幕。
  2. 你打开 DevTools,一些图纸被覆盖了
  3. 当你关闭 DevTools 时,那些绘图就消失了。

原因是因为画布变小了,从上面掉下来的图纸就丢失了,当它恢复到原来的大小时,它们就看不见了(因为它们已经消失了)。我决定保存所有内容localStorage以便我可以保留它们(以及我可能添加的更多功能)。线条正在工作(因为他们只需要说,“我是一条线,我从 x,y 开始,在 x,y 结束”。对于任何大小的线条都是如此。但对于手绘图像,他们可以去任何地方,所以他们需要说,“我是一个像素,我在 x,y 处”,但对于即使是远程复杂的图像也有很多次。

尝试的解决方案

每当他们移动鼠标时,它都会保存到一个变量中,然后更新为localStorage. 这样做的问题是,如果你走得很快,那么这些行就不完整(里面有洞)并且localStorage会存储大量文本。

问题

如何有效地存储用户的所有手绘(铅笔工具)图像(首选客户端操作)?

标签: javascriptcanvasstorage

解决方案


我的建议是考虑这个应用程序的目标用途并从它向后工作。

如果您正在做类似 MS Paint 绘图应用程序,将画布存储为位图可能会更好。为了处理裁剪问题,我建议您使用预定义的画布大小或设置阶段(具有最大大小以防止保存到 LocalStorage 的问题)。

如果您担心图像大小因内存上限而受到限制,您也可以使用压缩。

IE。

canvas.toDataURL('image/jpeg', 0.5);

将压缩图像并返回一个对 localStorage 友好的字符串

另一方面✋,如果您正在构建更像excalidraw 应用程序的东西,您希望在其中保持编辑任何绘制对象的能力,那么您需要单独存储每个对象。无论您使用画布还是 SVG 并不重要,但是 SVG 可以让它更容易一些,因为已经建立了如何存储每个元素的定义,所以您不需要重新发明轮子,可以这么说,只需要实现它。使用 SVG 并不一定会阻止您使用画布,因为有几个 SVG-in-canvas 实现,但是如果您将其作为一个学习项目(尤其是对于画布),它可能不是您想要的路线拿。


推荐阅读