重构方案.md 4.6 KB

KityMinder 渲染和布局重构方案

背景

当前的节点渲染和布局把很多部分的功能都揉在一起来实现,维护和添加新功能都比较困难,所以决定把现有的 layout.js、layout.default.js 和 layout.bottom.js 重构。

约定

为了不产生误会,下面约定一些词汇的意思。

样式:对节点或脑图其他内容的外观的描述。

渲染:对节点的绘制的过程。渲染参照的坐标系是节点画布的坐标系。

布局:对节点定位的过程,发生在渲染之后。定位使用的坐标系是脑图画布的坐标系。

节点树多边形:表示一个节点以及其子树所占的多边形区域。

样式、渲染和布局的梳理

Theme

负责注册和管理样式。

注册样式:

KityMinder.registerTheme( 'default', {
    'root-padding': [30, 20],
    'root-color': 'black',
    'root-background': '#A4c5c0',
    'root-stroke': 'none',
    'root-radius': 4,
    'root-space': [10, 5],
    'root-font-family': 'Arial',
    'root-font-size': 14,
    'main-connect-width': 2,
    'main-connect-color': 'white',
    'main-connect-type': 'arc',
    'sub-connect-type': 'fold'
    ...
});

切换样式:

minder.useTheme('default');

读取样式:

minder.getStyle('root-radius'); // returns 4
node.getStyle('radius'); // node.getType() 返回 'root', 会自动拼接样式项,返回 4
node.getStyle('padding-left'); // returns 20 发现结尾是 '-left'、'-right' 等的会自动找到样式表描述的数组按照 CSS 的方式查找值

Render

Render 负责渲染工作。

对于一个节点,有两个渲染容器(以前是多个),一个是通过 getContentGroup() 来获取的内容容器,一个是通过 getDecorationGroup() 来获得的装饰容器。布局的时候,内容容器最终决定该节点的渲染大小,装饰容器里的内容会被忽略。

节点的渲染分步进行,按顺序描述是:center, left, right, top, bottom。之前渲染这五个步骤是通过事件的形式来通知,每次渲染都清除了原本的内容重新创建节点,造成性能浪费。修改渲染的机制,改成从模块直接注册渲染的节:

KityMinder.registerModule( 'MyModule', {
    commands: { ... },
    events: { ... },
    renderers: {
        left: kity.createClass( 'MyRenderer', {
            base: Renderer,

            create: function(node) {
                this.content = new kity.Group();
                // 添加元素
                node.getContentGroup().addShape(this.content);
            },

            update: function(node) {
                var content = this.content;
                // update content
                // 需要返回更新后内容所占的矩形区域,简单的返回形式是 return this.content.getRenderBox();
                return {
                    x: 30,
                    y: -30,
                    width: 24,
                    height: 24
                };
            }
        }
    }
});

renderers 节来描述渲染器,节的 key 指定渲染器使用的阶段,节的 value 给出渲染器的类。渲染器需要继承 Renderer 类,并且实现两个抽象方法:create()update()

create 方法只会在节点创建的时候调用一次,此时应该创建渲染所需要的元素,并且附加到节点上。

update 方法会在节点需要重新渲染的时候被调用,此时可以选择隐藏、显示或更新元素。

在渲染过程中,节点提供下述信息:

  • node.getStyle(name) 获得节点当前的某个样式描述
  • node.getContentBox() 获得节点当前已渲染的内容在节点的 ConentGroup 的坐标系中所占的矩形区域。
  • node.getType() 获得节点的类型('root' | 'main' | 'sub')

要触发一个节点的渲染,直接调用 'node.render()' 即可。

Layout

Layout 负责布局工作,布局一般发生在渲染之后。对一个节点的布局,指的是排列其子树。

允许多种布局,布局注册的方式如下:

KityMinder.registerLayout('default', kity.createClass('DefaultLayout', {
    base: Layout,
    doLayout: function(node) {
        // do layout
    }
}));

让节点布局的方式是调用节点的 node.layout([name]) 方法。该方法的执行过程如下:

  • 调用 node.getLayout() 获得节点的布局名称
    • 如果节点中的 data 包含布局名称,返回该布局名称,否则下一步
    • 如果节点是根节点,返回 KityMinder.getDefaultLayout()
    • 返回父节点的 getLayout()
  • 根据布局名称获得相应的布局方法,把节点作为参数传进去调用