normalize.js 2.2 KB

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