normalize.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /**
  2. * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
  3. * SPDX-License-Identifier: MIT
  4. */
  5. 'use strict';
  6. import { util } from './util';
  7. export const normalize = {
  8. run,
  9. undo,
  10. };
  11. export default normalize;
  12. /*
  13. * Breaks any long edges in the graph into short segments that span 1 layer
  14. * each. This operation is undoable with the denormalize function.
  15. *
  16. * Pre-conditions:
  17. *
  18. * 1. The input graph is a DAG.
  19. * 2. Each node in the graph has a "rank" property.
  20. *
  21. * Post-condition:
  22. *
  23. * 1. All edges in the graph have a length of 1.
  24. * 2. Dummy nodes are added where edges have been split into segments.
  25. * 3. The graph is augmented with a "dummyChains" attribute which contains
  26. * the first dummy in each chain of dummy nodes produced.
  27. */
  28. function run(g) {
  29. g.graph().dummyChains = [];
  30. g.edges().forEach((edge) => normalizeEdge(g, edge));
  31. }
  32. function normalizeEdge(g, e) {
  33. let v = e.v;
  34. let vRank = g.node(v).rank;
  35. let w = e.w;
  36. let wRank = g.node(w).rank;
  37. let name = e.name;
  38. let edgeLabel = g.edge(e);
  39. let labelRank = edgeLabel.labelRank;
  40. if (wRank === vRank + 1) return;
  41. g.removeEdge(e);
  42. let dummy, attrs, i;
  43. for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
  44. edgeLabel.points = [];
  45. attrs = {
  46. width: 0,
  47. height: 0,
  48. edgeLabel: edgeLabel,
  49. edgeObj: e,
  50. rank: vRank,
  51. };
  52. dummy = util.addDummyNode(g, 'edge', attrs, '_d');
  53. if (vRank === labelRank) {
  54. attrs.width = edgeLabel.width;
  55. attrs.height = edgeLabel.height;
  56. attrs.dummy = 'edge-label';
  57. attrs.labelpos = edgeLabel.labelpos;
  58. }
  59. g.setEdge(v, dummy, { weight: edgeLabel.weight }, name);
  60. if (i === 0) {
  61. g.graph().dummyChains.push(dummy);
  62. }
  63. v = dummy;
  64. }
  65. g.setEdge(v, w, { weight: edgeLabel.weight }, name);
  66. }
  67. function undo(g) {
  68. g.graph().dummyChains.forEach((v) => {
  69. let node = g.node(v);
  70. let origLabel = node.edgeLabel;
  71. let w;
  72. g.setEdge(node.edgeObj, origLabel);
  73. while (node.dummy) {
  74. w = g.successors(v)[0];
  75. g.removeNode(v);
  76. origLabel.points.push({ x: node.x, y: node.y });
  77. if (node.dummy === 'edge-label') {
  78. origLabel.x = node.x;
  79. origLabel.y = node.y;
  80. origLabel.width = node.width;
  81. origLabel.height = node.height;
  82. }
  83. v = w;
  84. node = g.node(v);
  85. }
  86. });
  87. }