摘要
本次演讲通过对百度脑图的解析,展现了如何进行web应用的渐进式开发。具体分别讲解了百度脑图的总体结构、kity坐标交换、kityminder-core的命令模式、渲染和布局等。
嘉宾演讲视频及PPT回顾:http://suo.im/5a7RLl
百度脑图是什么?
百度脑图是一款在线思维导图编辑工具,常被用在工作规划、头脑风暴、会议记录、读书笔记、考试大纲等方面。
百度脑图结构
百度脑图的底层是基于SVG矢量图形库,在此基础上是一个思维导图的封装——Kityminder-core,还有一个完善导图功能的hotbox,它是一个上下文本快捷菜单。最后的完全体就是一个编辑器——Kityminder-editor。
以上是功能性的结构,除此之外还有业务上的应用,比如文件管理、用户认证、分享、历史版本管理等等。可以看出整个构造从里往外通用性不断降低、定制程度也随之增加。这就是一个渐进的过程,不同的目标人群能够找到所需的功能。
Kity
Kity是一款矢量图形库,它的最底层特性是面向对象支持。众所周知JavaScript是弱类型语言,要想用它完成工程化的产出,就需要面向对象的支持。因此我们基于ES5构建了一套面向对象语言的实现,包括定义类、扩展类、继承以及混合。下图就是Kity类的继承关系。
Kity坐标系
Kity的一个核心内容就是坐标系的概念,它的坐标系分为自身坐标系和参考坐标系。自身坐标系只存在一个,用于定义图形。参考坐标系由观察者选取,针对不同的参考有不同的坐标系,它的目的是用来观察图形。
Kity坐标变换
上图中的二维线性变换矩阵能够很清楚的将二维空间中的图形变换呈现出来。
Kity坐标变换函数
相对于指定坐标系的线性变换:Shape.getTransform(refer):matrix
相对于图形自身坐标系的区域:Shape.getBoundaryBox():box
相对于指定坐标系的区域:Shape.getRenderBox(refer):box
事件发生时相对指定坐标系的位置:ShapeEvent.getPosition(refer):Point
Kityminder-core
Kityminder-core命令
1.执行命令:execCommand(command,args)
2.查询命令状态:queryCommandState(command),可执行返回0,不可执行返回-1,已执行返回1
3.查询命令结果:queryCommandValue(Command)
这三个函数中Command参数表示需要传入的命令,args补充参数。例如minder.execCommand(‘expand’)就表示展开当前节点。
Kityminder-core常见命令
AppendChildNode:添加子节点到选中的节点中
Arrange:调整选中节点的位置
Camera:设置当前视野中心点的当前样式
Image:为选中的节点添加图片
Progress:设置节点的进度信息
Kityminder-core节点数据结构
Parent:父节点
Children:子节点数组
Root:根节点
Data:节点数据,如:文字、备注 、优先级
Rc:renderContainer,节点渲染出的容器
Attached:是否独立节点
Type:root,main,sub
Kityminder-core节点图示
Kityminder-core渲染
Kityminder-core中渲染就是决定节点外观,并在渲染后提供contentBox,目前共提供了10个渲染器。
渲染的实现基于渲染器基类core/render提供的运行时支持,能够相对自身坐标系分别对center、top、bottom、left、right、outline、outside位置进行渲染。
Kityminder-core布局
布局就是决定一个节点相对父节点的位置,并提供一个layoutBox,它默认是相对于父节点的坐标系,每个节点data均有layout属性。Kityminder-core提供了5种主要布局和10中子布局。
Kityminder-core模板
模板是布局和连线的集合,目前脑图提供了上图中的6种模板。
Kityminder-editor
Kityminder-editor基于Angular1.x,依赖于execCommand函数,并添加了hotbox和UI。
Kityminder-editor hotbox
Hotbox又叫做热盒UI,是一种高效的上下文交互方式。可以说是一种快捷菜单,选中节点后敲击空格就会展现,接着就可以使用方向键选中需要的功能。这样就能摆脱频繁使用鼠标点击工具栏的情况。
Kityminder-editor有限状态机
有限状态机是计算理论的入门概念,是表示有限个状态以及在这些状态之间转移的数学模型。脑图中的初始状态为normal,当用户输入的时候就会切换到input状态,选择状态下敲击空格切换到hotbox状态。由此通过这种机制就能在不同状态下完成不同的交互。
One more thing
多人实时协同编辑
由于是实时协同,所以不能加锁。此外多个客户端与同一个服务器的通信,其实发送的是数据的增量,基于JSON-diff就能得到不同时刻的json增量。除此之外它的底层基于 websocket,我们用到了 js 库SocketIO。
多人实时编辑难点
必须满足:
所有客户端和服务器操作的顺序一致
所有客户端和服务器操作的集合一致
基于版本号的实时协作算法
为了解决多人实时编辑的问题,我们实现了一个基于版本号的实时协作算法。上图是服务端的操作流程,可以看到它有一个server三个客户端,a客户端首先向服务器发送请求,服务器接收到后将head部分通过patch操作更新到最新,并且版本号自更新,最后给a客户端回复确认,同时将版本号以及diff广播到其他客户端。
客户端方面为了能更方便的编辑,我们将节点分成三个状态,分别是head——已确认的快照、pending——等待确认的快照、work——正在工作的快照。客户端的版本号是严格递增的,按照版本号递增顺序合并。
今天的分享就到这里,喜欢请点赞~谢谢大家!有问题可以在评论区讨论。