图扑SDK
# 基础
# 核心概念
数据类型、数据模型以及视图组件是 HT 中最基础也是最重要的三个概念。

# 数据类型
这里的数据类型其实就是在视图中显示的各种图形组件。

# 视图组件

注意
不同的数据类型用于在同一个视图组件上可以展示不同的效果,同一个数据类型在不同的视图组件上也有着不同的展示效果:
TreeView树形组件上Data代表一个树节点;
TableView表格组件上Data代表一行记录,列代表Data对象的属性;
GraphView图形组件上Node代表一个图形元素;
定义页签时TabView采用Tab类型存储页签信息;
定义表格列时TableView采用Column存储列信息。
# 数据模型
HT 提供了数据模型以及选择模型两个概念。
数据模型 ht.DataModel 是作为承载 ht.Data 数据的容器,用来管理 ht.Data 数据的增删改查以及变化事件的派发。所有的视图组件又是通过绑定 ht.DataModel 来管理视图组件上的各种图元,以不同的形式呈现到用户界面。
选择模型 ht.SelectionModel 管理 ht.DataModel 模型中 ht.Data 对象的选中状态,每个 ht.DataModel 对象都内置一个 ht.SelectionModel 选择模型,控制这个 ht.SelectionModel 就可以控制所有绑定该 ht.DataModel 的视图组件上 ht.Data 对应的选中状态, 这也意味着共享同一 ht.DataModel 的组件默认就具有选中联动功能。
# 标准流程
每个 HT 的页面都包含视图组件、数据模型这两个部分,当创建一个新的 HT 页面时,可以遵循这样的步骤:
创建数据模型
将数据模型作为参数,创建视图组件
将视图组件挂载到 HTML 的 DOM 元素中
以下代码实例化了一个数据模型以及一个 2D 的视图组件,并且通过 addToDOM 方法将 2D 视图组件挂载到 HTML 的 DOM 元素中,这样就完成了页面初始化的搭建。之后创建了一个 ht.Node 类型的节点,并且通过数据模型上的 add 方法,把节点加入到数据模型中,这样页面上就有了第一个节点,可以对这个节点设置位置、设置大小等相关属性。
const dm = new ht.DataModel();
const gv = new ht.graph.GraphView(dm);
dm.setBackground("#000");
gv.addToDOM();
const node = new ht.Node();
dm.add(node);
node.setSize(100, 100);
node.setPosition(100, 100);
2
3
4
5
6
7
8
9
10
# ht.Data 类型
贯穿整个 HT 框架,是最基础的数据类型。

一个 Data 类型的数据元素上有很多属性,可分为三种属性类型:
property 类型:可通过 get**/set** 或者 is**/set**两种方式获取和设置属性值,用于常用属性的操作,比如:name、id、tag、toolTip 等;
style 类型: 通过 getStyle(name)和 setStyle(name, value)获取和设置属性,可简写为 s(name,value/json),图元的样式由该类型属性控制;
- 可以通过 getStyleMap()获取图元内部样式映射信息,包含所有的 style 类型的属性。
- getStyle(name)时如果 styleMap 对应值为 undefined,自动会返回 ht.Style 定义的信息。
attr 类型: 通过 getAttr(name)和 setAttr(name, value)获取和设置属性值,可简写为 a(name,value/json),该类型是 HT 预留给用户存储业务数据,默认是空的,可以按照需求任意存取属性值;
- getAttrObject()和 setAttrObject(obj)获取和设置 attr 属性对象,该属性默认为空,用于存储用户业务信息。
父子关系
- setParent()/getParent():设置和获取父节点。
- addChild()/removeChild():添加和删除子节点。
- eachChild()可用来遍历所有子节点。
- getChildren()获取到所有的子节点,返回一个内部 ht.List 类型数组对象引用。
- getChildAt()可以获取指定索引的子节点。
事件派发
Data 类型上内置了事件派发机制,当 Data 类型上的各类属性发生变化时,都会派发出相关的事件。
当 Property、Style、Attr 类型的属性发生变更时,都会触发相应的回调函数,默认是空的,可根据具体业务情况重载。
- onPropertyChanged(name, oldValue, newValue):当 property 属性变化时会回调该函数。
- onStyleChanged(name, oldValue, newValue):当 style 属性变化时会回调该函数。
- onAttrChanged(name, oldValue, newValue):当 attr 属性变化时会回调该函数。
firePropertyChange: 当节点上任意属性发生改变时,都会通过 firePropertyChange 的方式派发出相应的事件,通知数据模型,并且执行节点上的 onPropertyChanged。
序列化
在 HT 中 JSON 有着广泛的应用,视图组件、数据模型以及数据节点都是可以用 JSON 格式的数据来描述的。 HT 提供了序列化功能,可参考序列化手册,可以将数据模型中包含的 Data 对象以及属性序列化为 JSON 形式。
在数据模型序列化的过程中,默认会执行 Data 对象上的这几个方法,用来确定 Data 对象的那些属性可以被序列化,可重载进行自定义。
- getSerializableProperties()返回需要序列化的属性名称 map。
- getSerializableStyles()返回需要序列化的 style 属性名称 map。
- getSerializableAttrs()返回需要序列化的 attr 属性名称 map。
# ht.DataModel 类型
数据容器 ht.DataModel(简称 DataModel)作为承载 Data 数据的容器,管理着 Data 数据的增删以及变化事件派发, HT 中所有视图组件都是通过绑定 DataModel,以不同的形式呈现到用户界面;同时组件也会监听 DataModel 模型的变化事件, 实时同步更新界面数据信息。 使用 DataModel 时需要特别注意:一般要求有父子关系的 Data 都应逐一加入容器。常遇到 parent 加入容器,但 children 未加入, 导致组件看不到 children 的问题,因为添加 parent 并不会自动加载所有子孙,这点务必注意。
当 Data 加入容器后通过 Data#getDataModel()能获得当前所在的数据模型, 不允许一个 Data 对象同时加入多个 DataModel 容器中。
操作数据模型
- 增加
- add(data, index)添加 Data 对象,index 一般无需指定,其只在 data 的 parent 为空时才起作用,指定插入 roots 数组的索引位置。
- 删除/清空
- remove(data)删除 Data 对象,删除节点会同步执行以下操作:
- 其子孙被递归从 DataModel 中删除。
- 被断开父子关系 data.setParent(null)。
- Edge 类型通过 edge.setSource(null)和 edge.setTarget(null)断开节点关系。
- Node 类型会将其关联的连线从 DataModel 中删除。
- Node 类型通过 data.setHost(null)断开与宿主吸附节点关系。
- removeDataById(id)删除指定 id 的 Data 对象。
- removeDataByTag(tag)删除指定 tag 标示的 Data 对象。
- clear()删除容器中所有 Data 对象,该操作一次性清空,没有逐个 remove 的过程,不会影响 Data 父子关系。
- 查询/获取
DataModel 中提供 getDataByTag 和 getDataById 方法,可以快速查找到数据模型中具体的元素。
在创建一个数据元素时,HT 会自动给这个元素分配一个 id 属性,但是这个 id 属性只是作为数据模型中内部逻辑使用,一般很少获取以及修改。 在 HT 中更推荐使用标签(tag)来作为一个数据元素的唯一标识,但是并没有强调标签的唯一性,对于两个节点设置同样的标签并不会报错,不过还是建议用户在设置标签的时候,尽量保持唯一性,方便后续在具体业务操作中使用 getDataByTag 找到具体的数据元素。
- getDataById(id)返回指定 id 的 Data 对象。
- getDataByTag(tag)返回指定 tag 标识的 Data 对象。
- getRoots()返回所有 parent 为空的 Data 对象。
- getDatas()返回所有添加到容器的 Data 数据 ht.List 数组。
- toDatas(matchFunc, scope)返回筛选后的新 ht.List 对象数组,第一参数为空相当于复制全部对象数组。
- 遍历
- each(func, scope)遍历所有 Data 对象。
- eachByDepthFirst(func, data, scope)以 data 为起始深度优先遍历 Data 对象。
- eachByBreadthFirst(func, data, scope)以 data 为起始广度优先遍历 Data 对象。
监听数据模型变化
数据模型中内置了很多事件机制,当数据模型中节点上的属性发生变化时,会通知数据模型做对应的处理;当数据模型自身发生改变时,数据模型内也可以添加相应的监听函数。
- onAdded(data)图元添加时回调函数,可重载做后续处理。
- onRemoved(data)图元删除时回调函数,可重载做后续处理。
- addDataModelChangeListener(function(e){}, scope)增加数据模型自身变化事件监听器,可用简写 mm(func, scope)。
- e.kind === 'add'代表添加 Data 对象,e.data 为被添加的对象。
- e.kind === 'remove'代表删除 Data 对象,e.data 为被删除的对象。
- e.kind === 'clear'代表容器被清除。
- removeDataModelChangeListener(func, scope)删除数据模型增删变化事件监听器,可用简写 umm(func, scope)。
- addDataPropertyChangeListener(function(e){}, scope)增加对数据模型中 Data 上的数据属性变化事件监听器,可用简写 md(func, scope)
- e.data 代表属性变化的对象。
- e.property 代表变化属性的名字。
- e.newValue 代表属性的新值。
- e.oldValue 代表属性的老值。
- Data 对象在设置属性值函数内调用 firePropertyChange(property, oldValue, newValue)触发属性变化事件:
- get/set 类型属性,如 setAge(98)触发事件的 e.property 为 age。
- style 类型属性名前加 s:前缀以区分,如 setStyle('age', 98)触发事件的 e.property 为 s:age。
- attr 类型属性名前加 a:前缀以区分,如 setAttr('age', 98)触发事件的 e.property 为 a:age。
- removeDataPropertyChangeListener(func, scope)删除模型中 Data 数据属性变化事件监听器,可用简写 umd(func, scope)。
序列化
HT 对数据模型 DataModel 提供了 ht.JSONSerializer 的序列化功能,可将 DataModel 的属性以及其中包含的 Data 对象序列化为 JSON 格式,同时提供反序列化功能,可以根据 JSON 快速构建 DataModel 数据对象的功能。
- serialize(space)将数据模型序列化成 JSON 格式字符串,space 为缩进空格数。
- toJSON 将数据模型序列化成 JSON 格式对象。
- deserialize(json, rootParent, setId)反序列化数据到数据模型。
- json 数据信息对象,用于解析生成对应的 Data 对象并添加到数据容器。
- rootParent 父节点对象,如果不为空,则反序列化的对象若无父亲者,设置 rootParent 为其父亲。
- setId 指定反序列化时,是否设置 json 信息上的 id 值。
# ht.SelectionModel
ht.SelectionModel 管理 DataModel 模型中 Data 对象的选择状态, 每个 DataModel 对象都内置一个 SelectionModel 选择模型,控制这个 SelectionModel 即可控制所有绑定该 DataModel 的组件的对象选择状态, 这意味着共享同一 DataModel 的组件默认就具有选中联动功能。 如果希望某些组件不与其他组件选中联动,可通过调用 view.setSelectionModelShared(false), 这样该视图组件将创建一个专属的 SelectionModel 实例。
- 获取数据模型
有两种途径可得到 SelectionModel:
通过数据模型获取:dataModel.getSelectionModel()获取数据容器中组件共享的选中模型。
通过视图组件获取:view.getSelectionModel()获取当前组件使用的选中模型,selectionModelShared 为 false 时,返回 view 专用的选择模型。
2.设置选中模型
getSelectionMode()和 setSelectionMode(selectionMode)获取和设置选中模式。
- none:不可选中。
- single:只可单选。
- multiple:默认值,允许多选。
getFilterFunc()和 setFilterFunc(func)设置过滤器自定义可选择对象规则。
3.获取/修改选中数据
获取所有被选中对象数组:getSelection(),注意不可直接对返回数组进行增删操作。
直接设置选中对象:setSelection(datas)参数可为单个 ht.Data,也可为 ht.List 或 Array 数组,简写为 ss。
追加选中对象:appendSelection(datas),参数可为单个 ht.Data,也可为 ht.List 或 Array 数组,简写为 as。
移除某些选中对象:removeSelection(datas)取消选中对象,参数可为单个 ht.Data,也可为 ht.List 或 Array 数组,简写为 rs。
清空选中对象:clearSelection()取消所有选中对象,简写为 cs。
选中全部:selectAll()选中 DataModel 中所有对象,简写为 sa。
获取首个被选中的对象:getFirstData(),如果没有选中对象则返回空,简写为 fd。
获取最后被选中的对象:getLastData(),如果没有选中对象则返回空,简写为 ld。
- 监听选择模型变化
- addSelectionChangeListener(function(e){}, scope)增加监听器,监听选中变化事件,简写为 ms:
- e.datas 包含所有选中状态变化的对象,之前选中现在取消选中,或之前没选中现在被选中的对象。
- e.kind === 'set'代表此事件由 setSelection(datas)引发。
- e.kind === 'remove'代表此事件由 removeSelection(datas)引发。
- e.kind === 'append'代表此事件由 appendSelection(datas)引发。
- e.kind === 'clear'代表此事件由 clearSelection(datas)引发。
- removeSelectionChangeListener(function(e){}, scope)删除选中变化事件监听器,简写为 ums。
# 小结
共享数据模型
多个视图组件可以共享同一个数据模型,只需要在创建视图组件的时候,传递同一个数据模型即可。
var dm = new ht.DataModel(); // 创建数据模型
var g2d = new ht.graph.GraphView(dm); // 创建2D视图组件
g2d.addToDOM(); // 将2D视图组件添加到DOM结构中
var g3d = new ht.graph3d.Graph3dView(dm); // 创建3D视图组件,使用同一个数据模型
g3d.addToDOM(); // 将3D视图组件添加到DOM结构中
2
3
4
5
同一个数据类型在不同的视图组件上也有着不同的展示效果,由于不同的视图组件共享同一个数据模型,因此当操作这个数据模型时,不同的视图组件都会监听这个数据模型的变化,并且根据不同组件的机制,展示出不同的效果。
事件机制
HT 提供了事件通知管理器 ht.Notifier 类,可对其添加监听函数、删除监听函数,以及派发事件到所有监听函数:
- add(listener, scope)添加监听函数,scope 域参数可选。
- remove(listener, scope)删除监听函数,scope 域参数必须和 add 时的参数一致。
- contains(listener, scope)判断是否包含指定监听函数,scope 域参数必须和 add 时的参数一致。
- fire(event)派发事件到所有监听函数。
事件机制在 HT 内部有着广泛的应用,特别是在数据模型与视图组件之间。视图组件在初始化的时候就会监听数据模型的一系列事件:
- 数据模型自身属性发生改变 mp。
- 数据模型自身发生变化 mm。
- 数据模型内节点上的属性发生变化 md。