Simon Hunt

GUI -- Fixed turbulent behavior of incoming nodes with no fixed position.

Change-Id: Ic73c0c8b91bd5ab07faec84ffcd0b67d2e357b29
...@@ -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) {
......