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); | ||
| 737 | + } | ||
| 738 | + | ||
| 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 | + }; | ||
| 713 | } | 754 | } |
| 714 | - node.x = x || network.view.width() / 2; | 755 | + |
| 715 | - node.y = y || network.view.height() / 2; | 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