自定义边

G6 除了提供丰富的 内置边 外,还提供了自定义边的机制,方便用户开发更加定制化的边,包括含有复杂图形的边、复杂交互的边、带有动画的边等。

在本章中我们会通过四个案例,从简单到复杂讲解边的自定义:1. 从无到有的定义边;2. 扩展现有边:3. 边的交互样式;4. 自定义带箭头的边。

1. 从无到有定义边

我们来实现垂直的折线: imgimgimg

(左)直线边。(中)默认的折线边。(右)调整了节点的控制点后的折线边。

自定义边

  1. G6.registerEdge('hvh', {
  2. draw(cfg, group) {
  3. const startPoint = cfg.startPoint;
  4. const endPoint = cfg.endPoint;
  5. const shape = group.addShape('path', {
  6. attrs: {
  7. stroke: '#333',
  8. path: [
  9. ['M', startPoint.x, startPoint.y],
  10. ['L', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y], // 三分之一处
  11. ['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y], // 三分之二处
  12. ['L', endPoint.x, endPoint.y],
  13. ],
  14. },
  15. });
  16. return shape;
  17. },
  18. });
  • 默认的 startPointendPoint 是两个端点中点的连接线分别同圆的交点;
  • 修改节点的锚点可以修改 startPointendPoint 的位置。

示例数据

通过以下的数据,使用自定义的 hvh 边,就可以实现上图最右边的效果。

  1. const data = {
  2. nodes: [
  3. {
  4. id: 'node1',
  5. x: 100,
  6. y: 200,
  7. anchorPoints: [
  8. [0, 0.5],
  9. [1, 0.5],
  10. ],
  11. },
  12. {
  13. id: 'node2',
  14. x: 200,
  15. y: 100,
  16. anchorPoints: [
  17. [0, 0.5],
  18. [1, 0.5],
  19. ],
  20. },
  21. {
  22. id: 'node3',
  23. x: 200,
  24. y: 300,
  25. anchorPoints: [
  26. [0, 0.5],
  27. [1, 0.5],
  28. ],
  29. },
  30. ],
  31. edges: [
  32. {
  33. id: 'edge1',
  34. target: 'node2',
  35. source: 'node1',
  36. shape: 'hvh',
  37. },
  38. {
  39. id: 'edge2',
  40. target: 'node3',
  41. source: 'node1',
  42. shape: 'hvh',
  43. },
  44. ],
  45. };

2. 扩展现有边

通过 afterDraw 接口给现有的曲线增加动画。 img

  1. G6.registerEdge(
  2. 'line-growth',
  3. {
  4. afterDraw(cfg, group) {
  5. const shape = group.get('children')[0];
  6. const length = shape.getTotalLength();
  7. shape.animate(
  8. {
  9. onFrame(ratio) {
  10. const startLen = ratio * length;
  11. const cfg = {
  12. lineDash: [startLen, length - startLen],
  13. };
  14. return cfg;
  15. },
  16. repeat: true,
  17. },
  18. 2000,
  19. );
  20. },
  21. },
  22. 'cubic',
  23. );

3. 边的交互样式

以点击选中、鼠标 hover 到边为示例,实现如下需求:

  • 点击边时边变粗,再点击变成细;
  • 鼠标移动上去变成红色,离开变成 '#333'

效果如下图所示。 img提示:边如果过细点击时很难击中,可以设置 **lineAppendWidth** 来提升击中范围。

  1. // 基于 line 扩展出新的图形
  2. G6.registerEdge(
  3. 'custom-edge',
  4. {
  5. // 设置状态
  6. setState(name, value, item) {
  7. const group = item.getContainer();
  8. const shape = group.get('children')[0]; // 顺序根据 draw 时确定
  9. if (name === 'active') {
  10. if (value) {
  11. shape.attr('stroke', 'red');
  12. } else {
  13. shape.attr('stroke', '#333');
  14. }
  15. }
  16. if (name === 'selected') {
  17. if (value) {
  18. shape.attr('lineWidth', 3);
  19. } else {
  20. shape.attr('lineWidth', 2);
  21. }
  22. }
  23. },
  24. },
  25. 'line',
  26. );
  27. // 点击时选中,再点击时取消
  28. graph.on('edge:click', ev => {
  29. const edge = ev.item;
  30. graph.setItemState(edge, 'selected', !edge.hasState('selected')); // 切换选中
  31. });
  32. graph.on('edge:mouseenter', ev => {
  33. const edge = ev.item;
  34. graph.setItemState(edge, 'active', true);
  35. });
  36. graph.on('edge:mouseleave', ev => {
  37. const edge = ev.item;
  38. graph.setItemState(edge, 'active', false);
  39. });

4. 自定义带箭头的边

很多时候,G6 默认提供的箭头并不能满足业务上的需求,这个时候,就需要我们自定义箭头。当然了,G6 也支持箭头样式的自定义。 img

(左)G6 内置箭头。(右)自定义边带有自定义箭头。

  1. G6.registerEdge('line-arrow', {
  2. draw(cfg, group) {
  3. const { startPoint, endPoint } = cfg;
  4. const keyShape = group.addShape('path', {
  5. attrs: {
  6. path: [
  7. ['M', startPoint.x, startPoint.y],
  8. ['L', endPoint.x, endPoint.y],
  9. ],
  10. stroke: 'steelblue',
  11. lineWidth: 3,
  12. startArrow: {
  13. path: 'M 10,0 L -10,-10 L -10,10 Z',
  14. d: 10,
  15. },
  16. endArrow: {
  17. path: 'M 10,0 L -10,-10 L -10,10 Z',
  18. d: 10,
  19. },
  20. },
  21. });
  22. return keyShape;
  23. },
  24. });