GUI -- Fixed turbulent behavior of incoming nodes with no fixed position.
Change-Id: Ic73c0c8b91bd5ab07faec84ffcd0b67d2e357b29
Showing
2 changed files
with
86 additions
and
31 deletions
... | @@ -24,14 +24,33 @@ | ... | @@ -24,14 +24,33 @@ |
24 | opacity: 0.5; | 24 | opacity: 0.5; |
25 | } | 25 | } |
26 | 26 | ||
27 | + | ||
27 | /* NODES */ | 28 | /* NODES */ |
28 | 29 | ||
29 | -#topo svg .node.device { | 30 | +#topo svg .node { |
30 | - stroke: none; | ||
31 | - stroke-width: 1.5px; | ||
32 | cursor: pointer; | 31 | cursor: pointer; |
33 | } | 32 | } |
34 | 33 | ||
34 | +#topo svg .node.selected rect, | ||
35 | +#topo svg .node.selected circle { | ||
36 | + filter: url(#blue-glow); | ||
37 | +} | ||
38 | + | ||
39 | +/* for debugging */ | ||
40 | +#topo svg .node circle.debug { | ||
41 | + fill: white; | ||
42 | + stroke: red; | ||
43 | +} | ||
44 | + | ||
45 | +#topo svg .node text { | ||
46 | + pointer-events: none; | ||
47 | +} | ||
48 | + | ||
49 | +/* Device Nodes */ | ||
50 | + | ||
51 | +#topo svg .node.device { | ||
52 | +} | ||
53 | + | ||
35 | #topo svg .node.device rect { | 54 | #topo svg .node.device rect { |
36 | stroke-width: 1.5px; | 55 | stroke-width: 1.5px; |
37 | } | 56 | } |
... | @@ -54,31 +73,28 @@ | ... | @@ -54,31 +73,28 @@ |
54 | fill: #03c; | 73 | fill: #03c; |
55 | } | 74 | } |
56 | 75 | ||
57 | -#topo svg .node.host { | ||
58 | - fill: #846; | ||
59 | -} | ||
60 | - | ||
61 | /* note: device is offline without the 'online' class */ | 76 | /* note: device is offline without the 'online' class */ |
62 | #topo svg .node.device text { | 77 | #topo svg .node.device text { |
63 | fill: #aaa; | 78 | fill: #aaa; |
64 | font: 10pt sans-serif; | 79 | font: 10pt sans-serif; |
65 | - pointer-events: none; | ||
66 | } | 80 | } |
67 | 81 | ||
68 | #topo svg .node.device.online text { | 82 | #topo svg .node.device.online text { |
69 | fill: white; | 83 | fill: white; |
70 | } | 84 | } |
71 | 85 | ||
86 | + | ||
87 | +/* Host Nodes */ | ||
88 | + | ||
89 | +#topo svg .node.host { | ||
90 | + fill: #846; | ||
91 | +} | ||
92 | + | ||
72 | #topo svg .node.host text { | 93 | #topo svg .node.host text { |
73 | fill: #846; | 94 | fill: #846; |
74 | font: 9pt sans-serif; | 95 | font: 9pt sans-serif; |
75 | - pointer-events: none; | ||
76 | } | 96 | } |
77 | 97 | ||
78 | -#topo svg .node.selected rect, | ||
79 | -#topo svg .node.selected circle { | ||
80 | - filter: url(#blue-glow); | ||
81 | -} | ||
82 | 98 | ||
83 | /* LINKS */ | 99 | /* LINKS */ |
84 | 100 | ||
... | @@ -91,20 +107,13 @@ | ... | @@ -91,20 +107,13 @@ |
91 | stroke-width: 6px; | 107 | stroke-width: 6px; |
92 | } | 108 | } |
93 | 109 | ||
94 | -/* for debugging */ | ||
95 | -#topo svg .node circle.debug { | ||
96 | - fill: white; | ||
97 | - stroke: red; | ||
98 | -} | ||
99 | - | ||
100 | 110 | ||
101 | -/* detail topo-detail pane */ | 111 | +/* Fly-in details pane */ |
102 | 112 | ||
103 | #topo-detail { | 113 | #topo-detail { |
104 | /* gets base CSS from .fpanel in floatPanel.css */ | 114 | /* gets base CSS from .fpanel in floatPanel.css */ |
105 | } | 115 | } |
106 | 116 | ||
107 | - | ||
108 | #topo-detail h2 { | 117 | #topo-detail h2 { |
109 | margin: 8px 4px; | 118 | margin: 8px 4px; |
110 | color: black; | 119 | color: black; |
... | @@ -128,7 +137,6 @@ | ... | @@ -128,7 +137,6 @@ |
128 | } | 137 | } |
129 | 138 | ||
130 | #topo-detail td.value { | 139 | #topo-detail td.value { |
131 | - | ||
132 | } | 140 | } |
133 | 141 | ||
134 | #topo-detail hr { | 142 | #topo-detail hr { | ... | ... |
... | @@ -127,7 +127,8 @@ | ... | @@ -127,7 +127,8 @@ |
127 | P: togglePorts, | 127 | P: togglePorts, |
128 | U: unpin, | 128 | U: unpin, |
129 | 129 | ||
130 | - X: requestPath | 130 | + Z: requestPath, |
131 | + X: cancelMonitor | ||
131 | }; | 132 | }; |
132 | 133 | ||
133 | // state variables | 134 | // state variables |
... | @@ -518,6 +519,13 @@ | ... | @@ -518,6 +519,13 @@ |
518 | sendMessage('requestPath', payload); | 519 | sendMessage('requestPath', payload); |
519 | } | 520 | } |
520 | 521 | ||
522 | + function cancelMonitor() { | ||
523 | + var payload = { | ||
524 | + id: "need_the_intent_id" // FIXME: where are we storing this? | ||
525 | + }; | ||
526 | + sendMessage('cancelMonitor', payload); | ||
527 | + } | ||
528 | + | ||
521 | // request details for the selected element | 529 | // request details for the selected element |
522 | function requestDetails() { | 530 | function requestDetails() { |
523 | var data = getSel(0).obj, | 531 | var data = getSel(0).obj, |
... | @@ -701,18 +709,57 @@ | ... | @@ -701,18 +709,57 @@ |
701 | 709 | ||
702 | function positionNode(node) { | 710 | function positionNode(node) { |
703 | var meta = node.metaUi, | 711 | var meta = node.metaUi, |
704 | - x = 0, | 712 | + x = meta && meta.x, |
705 | - y = 0; | 713 | + y = meta && meta.y, |
714 | + xy; | ||
706 | 715 | ||
707 | - if (meta) { | 716 | + // If we have [x,y] already, use that... |
708 | - x = meta.x; | ||
709 | - y = meta.y; | ||
710 | - } | ||
711 | if (x && y) { | 717 | if (x && y) { |
712 | node.fixed = true; | 718 | node.fixed = true; |
719 | + node.x = x; | ||
720 | + node.y = y; | ||
721 | + return; | ||
722 | + } | ||
723 | + | ||
724 | + // Note: Placing incoming unpinned nodes at exactly the same point | ||
725 | + // (center of the view) causes them to explode outwards when | ||
726 | + // the force layout kicks in. So, we spread them out a bit | ||
727 | + // initially, to provide a more serene layout convergence. | ||
728 | + // Additionally, if the node is a host, we place it near | ||
729 | + // the device it is connected to. | ||
730 | + | ||
731 | + function spread(s) { | ||
732 | + return Math.floor((Math.random() * s) - s/2); | ||
733 | + } | ||
734 | + | ||
735 | + function randDim(dim) { | ||
736 | + return dim / 2 + spread(dim * 0.7071); | ||
713 | } | 737 | } |
714 | - node.x = x || network.view.width() / 2; | 738 | + |
715 | - node.y = y || network.view.height() / 2; | 739 | + function rand() { |
740 | + return { | ||
741 | + x: randDim(network.view.width()), | ||
742 | + y: randDim(network.view.height()) | ||
743 | + }; | ||
744 | + } | ||
745 | + | ||
746 | + function near(node) { | ||
747 | + var min = 12, | ||
748 | + dx = spread(12), | ||
749 | + dy = spread(12); | ||
750 | + return { | ||
751 | + x: node.x + min + dx, | ||
752 | + y: node.y + min + dy | ||
753 | + }; | ||
754 | + } | ||
755 | + | ||
756 | + function getDevice(cp) { | ||
757 | + var d = network.lookup[cp.device]; | ||
758 | + return d || rand(); | ||
759 | + } | ||
760 | + | ||
761 | + xy = (node.class === 'host') ? near(getDevice(node.cp)) : rand(); | ||
762 | + $.extend(node, xy); | ||
716 | } | 763 | } |
717 | 764 | ||
718 | function iconUrl(d) { | 765 | function iconUrl(d) { | ... | ... |
-
Please register or login to post a comment