【问题标题】:Concurrent drawing with paper.js使用 paper.js 并发绘图
【发布时间】:2015-04-21 13:13:03
【问题描述】:

我有一个基于 paper.js 处理绘图小部件的应用程序。多个用户可以同时绘图,变化实时相互广播。问题是我需要在加载文档时存储更改并显示绘制的图像。

自然的解决方案是将客户端发送的命令存储在数据库中。但是绘制的图像可以包含数千个命令,而我可以有数十个图像。因此,当我打开一个从服务器获取命令列表的文档时,绘图可能会花费太多时间。

有没有更好的方法来存储图像和客户端之间的交互?

请注意,我有缩放功能,所以存储栅格不是一个选项。

更新:如果我正在存储图像(例如在 BLOB 中),则不清楚如何实时应用所做的更改。每次传递图像不是我想要的解决方案。

【问题讨论】:

标签: javascript html paperjs


【解决方案1】:

如果您要将绘图保存为图像,您有几个可能的解决方案。

  1. 将项目保存在文件夹中的某处,并将目录路径+文件名保存在数据库中
  2. 将数据库中的图像保存为blob。不过,Blob 确实是数据库密集型的。

有一些关于 blob 的有趣文章。比如来自微软的this one

按照常识,小于 256K 的对象最好存储在数据库中,而大于 1M 的对象最好存储在文件系统中。

因此,将图像保存到目录中会是一个更好的解决方案。

还可以导出绘制图像的svg文件。 (info) 我不知道这对你有没有帮助,但这是我的个人经验。我同意你的观点,将数千条命令存储到数据库中并不是最好的解决方案。因此,您可能想看看在某处保存图像,但如果您实现了该功能,您将失去编辑图像的能力。

更新:

如果您不想保存blob,最好的解决方案是在每次编辑时“渲染”图像。因此,当有人打开图形时,您可以执行所有命令。并且仅在触发编辑时应用最新命令。

有几种方法可以实现这一目标。就像 Jimmy Chandra 所说,firebase 将是一个很好的解决方案。他们还提供了一个tutorial,其中包含您想要实现的一切。 (使用xycoordinates 实时绘制图像)也许你必须看看。

更多关于 Firebase 的信息。

Firebase 是一个强大的 API,用于实时存储和同步数据

我相信这正是您想要实现的目标。你可以试试他们的完整教程here

您可能会考虑的另一个选项是nodejs。我见过有人使用nodejs 聊天系统将数据发送给所有其他用户。如果您可以发送数据,我相信您可以用它绘制图像。

最终,您可以选择要使用的技术。因此,我认为您可以像我建议的那样研究一些解决方案,并在您在集成该技术时遇到问题时提出不同的问题。

【讨论】:

  • 这是不可能的。如果我将其存储为 BLOB(无论是光栅还是 SVG),我如何存储实时所做的更改
  • 您是否考虑过将线的坐标保存在数据库中?这也意味着数据库中有很多行,但我认为操作较少。我看到您还可以选择将图像保存为 json 格式。那可能有帮助吗? Link
  • 这就是我所说的The natural solution is to store commands sent by clients in DB。动作(命令)或只是坐标无关紧要。由于主要问题是长时间或重复操作(命令)列表
  • 我认为你真的没有太多选择。我认为每次进行编辑时都必须"render" 图像。就像有人加入绘图时的完整渲染,并且仅在发生最新更改时才渲染它们。我认为这将是你最好的方法。这样您就不必执行所有命令,而只需执行最后几个命令。
【解决方案2】:

将数据保存在客户端作为辅助存储是否可以接受?

使用 html5 文件 api,应该可以在数据库中保留客户端发送的所有保存命令的副本。因此,下次打开文档时,应用程序将从二级存储渲染绘图,同时在服务器上查询最新更新,这些更新将在二级存储完成渲染后附加。

使用 websockets,您可以保存命令,它会将更改广播给其他客户端,从而实时更新他们的绘图。

【讨论】:

    【解决方案3】:

    2 年前我开发了类似的东西(在一个团队中,封闭代码)。

    首先要注意的是,谷歌文档已经解决了这样的问题。我们阅读了每篇关于他们如何做到这一点的博客文章和文章,并将其应用于像简单编辑器这样的多用户 SVG。所以这是我记得的:

    分解成简单的命令是正确的方法。 正如您所写,您可以使用它们重新创建非常详细的图像。您甚至可以准确地回答图像在每个请求的时间戳中的外观。

    示例命令可能是

    - change color
    - change color again
    - draw a line from .. to ..
    - draw a line from .. to ..
    - draw a line from .. to ..
    - draw a line from .. to ..
    - smooth that line
    - change color
    - change Stroke
    - delete those lines and draw them again ;-)
    

    回到 goolge docs 示例,它们保存并广播每一个字符更改(以及更多)。

    是的,这是一种非常清晰且可测试的方法,但要求性能需要另一个逻辑层。 有必要添加一个将这些命令简化为压缩版本的例程(见下文)

    当用户请求图像时,您的系统会查找最新的压缩图像并添加压缩例程中未包含的单个命令。

    压缩程序:

    在您最喜欢的矢量编辑器中创建虚拟图像(类似于您对用户的期望)的视频录制,您会注意到大约 60% 到 80% 的命令对最终结果无用.

    目标压缩例程可能包含以下三个步骤:

    1. 大多数情况下,您会看到自己在录制时重新定位点、手柄或移动对象,一次又一次地更改颜色,设置和撤消其他参数,如笔画粗细。甚至删除元素的重做。例程需要优化这些命令以直接绘制最终结果。我敢肯定,这会将您的命令列表减少到 10%-50%,具体取决于您要查找的图像类型。

    2. 压缩命令。上例中的路径是用线段绘制的,它需要。在第一个 onMouseDown 时,您通常不知道它将以具有 100 个段和 200 个句柄的路径结束。但还是像其他用户一样展示创建过程。向您的程序添加一个命令,该命令能够绘制诸如路径之类的复杂事物。在用户绘图过程中您将不需要它。此命令可用于更快地重新创建完整的形状。现在可以在一个命令中绘制具有 100 个点和 200 个句柄的路径。在此之前,您有一个至少包含 300 个命令的列表。

    3. 重新排序命令。两个用户同时绘制的两个路径元素不容易压缩。一个简单的解决方案是按元素对命令进行排序。创建每个形状的过程可能需要 3 分钟。动画需要真正的命令顺序才能看到每个 shpae 同时发展,但最终结果并不重要。如果按元素排序,每个形状都可以更容易压缩。

    抱歉,帖子太长了,希望对你有帮助

    【讨论】:

      【解决方案4】:

      我将通过架构建议给出更广泛的答案,所以提前向完美主义者道歉。

      我会使用 nginxnodejs 与 websockets 作为我的应用层,并通过 npm https://www.npmjs.com/package/paper 在我的服务器端使用 paperjs

      对于我的持久性级别,我不仅会使用数据库集群( mysql/mongodb 等),还会使用 redis 作为命令缓存。

      每当在画布上执行命令时,我都会将其保存在 redis 中并通过 socket.io 向所有客户端广播,最后是由任何用户引起的终止/保存/退出等事件将其作为图像保存在我的 db 中,或 fs 在我的数据库中带有路径引用。

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2016-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-21
        • 1970-01-01
        • 1970-01-01
        • 2017-08-30
        相关资源
        最近更新 更多