目标

支持节点分组,拆分群组及群组嵌套的功能。

形态

  • 支持以下Group形态:
    • rect群组;
    • Circle群组。

思路

从数据上支持group,根据数据渲染,数据结构定义如下:

  1. {
  2. nodes: [
  3. {
  4. id: 'node1',
  5. label: 'node1'
  6. },
  7. {
  8. id: 'node2',
  9. label: 'node2'
  10. },
  11. ],
  12. edges: [
  13. {
  14. source: 'node1',
  15. target: 'node2'
  16. }
  17. ],
  18. groups: [
  19. {
  20. id: 'group1',
  21. title: '',
  22. nodes: ['node1', 'node2']
  23. },
  24. {
  25. id: 'group2',
  26. title: '',
  27. nodes: ['node1'],
  28. children: [
  29. {
  30. id: 'group2.1',
  31. title: '',
  32. nodes: ['node3', 'node4']
  33. },
  34. {
  35. id: 'group2.2',
  36. title: '',
  37. children: [
  38. {
  39. id: 'group2.2.1',
  40. title: '',
  41. nodes: ['node5', 'node6']
  42. }
  43. ]
  44. }
  45. ]
  46. }
  47. ]
  48. }

数据中包括groups字段时,表示有群组存在,可能会存在多个群组的情况。每个群组中字段说明:

  • id:必填,唯一标识群组;
  • title:可选,群组名称,为空时不显示名称;
  • nodes:表示该群组中包括的节点;
  • children:表示嵌套群组,即群组中还包括其他群组。

改进后的数据结构

  1. {
  2. nodes: [
  3. {
  4. id: 'node1',
  5. label: 'node1',
  6. groupId: 'group1'
  7. },
  8. {
  9. id: 'node2',
  10. label: 'node2',
  11. groupId: 'group1'
  12. },
  13. {
  14. id: 'node3',
  15. label: 'node3',
  16. groupId: 'group2'
  17. },
  18. ],
  19. edges: [
  20. {
  21. source: 'node1',
  22. target: 'node2'
  23. }
  24. ],
  25. groups: [
  26. {
  27. id: 'group1',
  28. title: '',
  29. parentId: 'p1'
  30. },
  31. {
  32. id: 'group2',
  33. title: '',
  34. parentId: 'p1'
  35. },
  36. {
  37. id: 'p1',
  38. title: '',
  39. parentId: 'p0'
  40. },
  41. {
  42. id: 'p0',
  43. parentId: 'p'
  44. },
  45. {
  46. id: 'p'
  47. }
  48. ]
  49. }

说明:

  1. 每个node中添加一个groupId字段,表示该节点所在的群组;
  2. groups表示所有的群组,group中如果有parentId字段,表示该群组是属于parentId中的一个群组。

这种方式存在以下两个问题:

  1. 绘制单个group时,需要遍历所有node,获取到group中所有的节点,用于计算群组的宽高;
  2. group存在多层嵌套时,处理起来特别麻烦,如上面的示例中,如何确定p1, p0及p三个群组的宽高;
  3. 绘制group时如何确定绘制顺序?

实现思路

  • 绘制所有node和edge;
  • 通过groupId进行groupBy分组,获取到每个群组中的节点;
  • 根据groups中的数据,获取到每个group中的node,需要排除,计算group的边界,绘制group。

问题

  1. 群组与节点及边之间的相互遮挡问题,及节点、边、群组三者之前的层级问题;
  2. 群组中节点与群组外部的节点之间有边时,边应该是在群组上面,当群组收起时,边应该连接到群组上面;
  3. 群组收起后与节点区分的问题;
  4. 群组收起或展开后,与群组相关的其他节点及边的更新;
  5. 移动群组时,群组中所有节点都一起跟着移动,性能上会不会有问题;
  6. 如何支持群组名称,及群组上面的操作;
  7. 是否支持自定义群组上面的操作图标,如果要支持,可以通过在数据中定义,当所有群组的图标都一样时,不要每个数据中都加相同的字段;
  8. 同一个图上面群组的形态会不会不同,比如有圆形的,有矩形的:
    1. 如果同一个图上不支持多种形态,则形态可以由开发人员在渲染时候决定;
    2. 如果支持,则可能需要在每个group中增加一个type字段,表示类型。

方案

group作为一种特殊类型的Node,在原数据结构的基础上,增加groups字段,用于表示数据中存在的群组,group支持嵌套,同样是通过在数据中进行区分。
group的最终形式是展示位矩形还是圆形,由开发人员自己决定,render时需要传入一个表示类型的参数。

Group只作为辅助元素,先布局Node,再根据数据绘制Group。

通用部分

  • Group在node和edge的底层;
  • 拖动Group中的节点,Group会随着更新宽度和高度;
  • 拖动Group,Group中的节点或Group会跟着一起移动;
  • 双击或其他操作会收起Group,整个Group中缩成一个虚拟节点,连接到Group中节点的边此时会连接到虚拟节点上;
  • Rect的Group,支持自定义Group名称、图标及操作按钮;
  • 缩放时候需要重新计算位置;
  • 默认全部展开(后期考虑支持自定义);
  • 动态改变群组所属层级;
  • 节点拖入拖出到Group,动态改变节点的所属群组;
  • 【待定】第一期是否支持group拖入到其他group中。

不嵌套的Group

  • 收起Group后,位置可以不受影响,不需要重新计算;

嵌套的Group

  • 收起Group后,需要根据虚拟节点及Group中其他节点,重新计算Group大小和位置;
  • 拖动嵌套Group中的Group,最外层的Group也会随着拖动改变大小。

效果

矩形群组

1558095215842-c1d9a0fc-3950-45a9-b772-60e8582cb3c9.gif

圆形群组

editor-1.gif

参考:https://gojs.net/latest/samples/regrouping.html