最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 图形编辑器开发(1)—— 模块设计

    正文概述 掘金(Fstar)   2021-03-15   510

    如果你要开发一款编辑器,但是你之前完全没有这方面的经验,完全不知道从什么地方下手,那么这系列文章就是为你准备的。文章主要针对的是图形编辑器,如果你想了解富文本编辑器,这系列文章不会涉及,但是还是有很多相通的逻辑和模块。

    本文首发于我的个人博客网站:图形编辑器开发(1)——模块设计与认识

    目前本人正在开发一款自己的一款 SVG 编辑器,还有许多工作有做。你可以参考一下我这个项目的源码,大概了解一下编辑器的架构。

    图形编辑器开发(1)—— 模块设计

    模块拆分

    编辑器开发是一项比较复杂的工程,遵循单一职责原则,进行模块化解耦降低开发复杂度是非常重要的事项,即使只有一个人开发。

    涉及的基本模块有:

    • 编辑器(Editor):编辑器类,所有其他模块会挂载到这个类下。
    • 历史(CommandManager):记录操作,并提供撤销重做功能。一般是使用 命令模式 来实现,所以我在自己的项目中,将其命名为 CommandManager(命令管理类)。
    • 工具(ToolManager):管理各种工具的切换和使用,设置当前工具。如选择工具下可以选中画布中的图形;拖拽工具可以移动画布。
    • 图形库:对图形元素底层方法的抽象封装。
    • 快捷键(Shortcut):设置快捷键对应事件响应方法
    • 视口(Viewport):如果编辑器需要支持缩放、获取缩放、画布偏移信息,可以考虑放在这个类里进行管理。
    • 选中元素管理(ActivedElsManager):记录要进行操作的一个或多个元素。
    • 设置(Setting):编辑器的参数设置,如默认填充色、描边色。
    • 辅助线(HudManger):一些辅助线的绘制,如选中图形高亮图形轮廓,这个轮廓其实就是最顶部的辅助线层的图形。
    • UI 层:前面的模块都是是编辑器内核部分,至于 UI 层,则是游离在编辑器内核之外。它的作用是在进行一些操作时,去调用编辑器内核对外提供的 API。我的 SVG 编辑器的 UI 层使用的是 React,其他框架也完全可以。

    编辑器(Editor)

    首先需要一个挂载所有模块的地方,那就是编辑器模块(类)。它也是用于暴露方法给外部使用的类。另外,通过给这些模块 依赖注入 Editor 实例的方式,我们可以实现多个模块之间的通信。下面是调用 activedElsManager.clear() 时,清空记录的选中图形,并消除它们高亮线的例子:

    class Editor() {
      // ...
      constructor() {
        this.activedElsManager = new ActivedElsManager(this)
        this.hudManager = new HudManager(this)
      }
    }
    
    export class HudManager {
      constructor(private editor: Editor) {
        // ...
      }
      clear() {
        // ...
      }
    }
    
    class ActivedElsManager {
      constructor(private editor: Editor) {
        // ...
      }
      clear() {
        this.els = []
        this.editor.hudManager.outlineBoxHud.clear() // ActivedElsManager 与 HudManager 通信:前者调用后者的 clear 方法
      }
    }
    

    你可能会发现上面这种实现类之间依赖的方式违反了 迪米特法则(LOD,也称为最小知识原则),因为 ActivedElsManager 只需要依赖 HudManager,而不需要依赖 Editor。迪米特法则的思想是:模块只应该和它有密切关系的模块有依赖,对 “陌生” 类则不应该有依赖,这样一些类被修改时,被波及的情况就会减少。

    之所以这里没有遵循迪米特法则,是因为我开发的这款编辑器并不是稳定的状态,随时可能添加或修改一些模块,模块也可能在开发过程中发现要依赖更多的模块。这样我们开发时就要时常变动构造函数,传入大量的依赖类来进行依赖注入,这显然并不方便,所以最后采取注入一个充当连接任何一个模块桥梁作用的 Editor 类。

    历史模块(CommandManager)

    历史模块,记录用户的所有操作的模块,并提供这些操作的撤销(undo)以及重做(redo)功能。该模块使用了 命令模式 的实现。

    命令模式的核心思想是:通过对象的方式来代表实际行动。

    对于编辑器,我们要实现不同操作(如移动元素、删除元素)的命令类,需要实现它们的 第一次执行(exec,可以选择实例化的时候进行)、撤销(undo)和 重做(redo)。

    在 “执行第一次执行” 的时候,会保存操作元素需要用的的一些必要信息。比如修改一个元素的颜色,我们需要保存被修改元素的原本颜色值,新颜色值,以及这个元素,就是所谓的对象,而实际行动则封装到共用的模板方法中了。

    图形编辑器开发(1)—— 模块设计

    如果你对实现撤销重做功能很感兴趣,可以看看我很久之前写的文章:基于Web的svg编辑器(1)——撤销重做功能。

    工具模块(ToolManager)

    一般编辑器都有很多工具。选择不同的工具可以进入不同模式,并绑定对应的操作逻辑。比如 VIM 编辑器就有普通模式(normal)、插入模式(insert)、观察模式(visual)。之所以有分成多个模式,是因为用户的操作行为是有限的:按键按下释放以及组合、鼠标的按下释放和移动、图形按钮的点击等,而功能却很多。对此的一个常用的策略就是将功能拆分为多个工具,使用不同工具则进入不同的模式,同样的用户动作带来不同的效果。

    一款图形编辑器基本工具有:

    • 拖拽画布:因为是高频操作,一般也会提供快捷键,如 Ctrl+Space 或按住鼠标右键;
    • 选择工具:用于选中一个或多个元素,这些元素会被记录下来,然后可以进行后续的操作,如设置颜色、删除、移动到顶部等
    • 缩放工具:对画布的内容进行缩小或放大,用于处理一些细节和总览全局
    • 绘制图形工具:绘制矩形、圆形、路径等。

    图形库

    开发图形编辑器,本质就是操作元素达到用户想要的视觉效果。编辑器可以基于 SVG,或者是 Canvas,或者直接基于我们最熟悉的 HTML DOM。对一些元素的操作时,如果我们直接调用操作底层的方法,写起来会很繁琐。我们会对元素底层方法进行抽象封装,减少重复的工作量并提高可读性。可以使用一些比较流行第三方库(如 svgjs、paperjs),也可以自己写一套,优点是契合自己的项目,方便修改底层实现算法提高性能并更方便进行扩展。

    对底层方法进行抽象非常重要,它将难用的繁琐的底层逻辑进行了封装,让使用者对底层无感知,提供更粗粒度的方法给使用者 。将来如果要提高性能,则不需要修改业务代码,只需修改抽象层方法底下的实现即可。甚至如果你想修改图形化方案,进行重构,如使用 Canvas 取代 SVG,完全可以重写抽象层下的底层实现,而不必修改遍布在项目各处调用抽象层方法的代码。

    快捷键(Shortcut)

    该模块负责绑定一些快捷键的操作。常见的有:

    • 撤销(Ctrl + Z)、重做(Ctrl + Y)
    • 删除元素(Delete or Backspace)
    • 保存(Ctrl + S)
    • 单按键切换工具:如按下 B,工具栏切换为笔刷工具。

    视口(Viewport)

    视口指的是用户能看到的区域,通常为画布的一部分。我建议把缩放、移动画布等操作放到视口模块里,方便管理。另外,还提供监听缩放的功能,实现与 UI 层的解耦。

    选中元素管理(ActivedElsManager)

    该模块存储被选中的元素,提供对选中元素高亮现实、判断其中是否包含某元素等方法。

    设置(Setting)

    管理编辑器的参数,如填充色、描边色、描边宽度等。一般会监听这些值的变化,一旦发生变化,通知对应的监听器函数。

    辅助线(HudManger)

    辅助线管理模块,用于高亮被选中的元素。因为元素有可能会被更上层的元素给遮挡,所以对选中元素自身修改描边颜色来实现高亮并不合适,这样的高亮依旧会被上层的元素挡住,于是我们需要在最高的层级放置辅助线。辅助线的种类也有很多:

    • 被选中元素的轮廓线
    • 多个元素形成的盒子轮廓线
    • 绘制贝塞尔曲线的控制线、控制点、路径线
    • ...

    为了更好地管理,我们抽离出辅助线模块,用于管理各种辅助线的绘制。

    UI 层

    UI 层游离在编辑器内核之外,负责和编辑器内核进行交互。UI 层负责提供一些必要的按钮,点击它们调用浏览器内核的方法。另外,UI 层也通过绑定监听的方式拿到编辑器参数。

    图形编辑器开发(1)—— 模块设计

    结尾

    当然这不是所有的模块,当你的功能变得日趋复杂的时候,会有越来越多的模块会被加入进 Editor 类下。当你希望引入标尺功能时,你会加入 Rule 模块;当你希望可以添加图层功能,就像 Photoshop 一样,你会加入 Layer 模块;当你希望加入录制动作并将其重放到其他元素,你需要加入 Action 模块。如果你一开始没有做足够好的底层架构设计,你一定会为引入它们而感到焦头烂额,但如果你看了我的这篇文章,你可能就有了模块化的意识,可能我的实现不是最佳实践,但能够帮助到你更好地管理代码,那便足够了。

    这篇文章是系列文章的第一篇文章,后续会陆陆续续写本系列的其他文章。


    起源地下载网 » 图形编辑器开发(1)—— 模块设计

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元