GUI -- Added user feedback "flash" message function.
- flash hover mode when H key pressed. - additional cleanup. Change-Id: I14dd47c41842c3f6cb68d2c9fbe3ee96ad23ae86
Showing
8 changed files
with
227 additions
and
105 deletions
web/gui/src/main/webapp/feedback.css
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/* | ||
| 18 | + ONOS GUI -- Feedback layer -- CSS file | ||
| 19 | + | ||
| 20 | + @author Simon Hunt | ||
| 21 | + */ | ||
| 22 | + | ||
| 23 | +#feedback svg { | ||
| 24 | + position: absolute; | ||
| 25 | + bottom: 0; | ||
| 26 | + opacity: 0.5; | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +#feedback svg g.feedbackItem { | ||
| 30 | + background-color: teal; | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +#feedback svg g.feedbackItem rect { | ||
| 34 | + fill: #888; | ||
| 35 | + stroke: #666; | ||
| 36 | + stroke-width: 3; | ||
| 37 | + opacity: 0.5 | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +#feedback svg g.feedbackItem text { | ||
| 41 | + fill: #000; | ||
| 42 | + stroke: none; | ||
| 43 | + text-anchor: middle; | ||
| 44 | + alignment-baseline: middle; | ||
| 45 | + | ||
| 46 | + font-size: 16pt; | ||
| 47 | +} |
web/gui/src/main/webapp/feedback.js
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/* | ||
| 18 | + ONOS GUI -- Feedback layer | ||
| 19 | + | ||
| 20 | + Defines the feedback layer for the UI. Used to give user visual feedback | ||
| 21 | + of choices, typically responding to keystrokes. | ||
| 22 | + | ||
| 23 | + @author Simon Hunt | ||
| 24 | + */ | ||
| 25 | + | ||
| 26 | +(function (onos){ | ||
| 27 | + 'use strict'; | ||
| 28 | + | ||
| 29 | + // API's | ||
| 30 | + var api = onos.api; | ||
| 31 | + | ||
| 32 | + // Config variables | ||
| 33 | + var w = '100%', | ||
| 34 | + h = 200, | ||
| 35 | + fade = 750, | ||
| 36 | + showFor = 2000, | ||
| 37 | + vb = '-200 -' + (h/2) + ' 400 ' + h, | ||
| 38 | + xpad = 20, | ||
| 39 | + ypad = 10; | ||
| 40 | + | ||
| 41 | + // State variables | ||
| 42 | + var timer = null, | ||
| 43 | + data = []; | ||
| 44 | + | ||
| 45 | + // DOM elements and the like | ||
| 46 | + var fb = d3.select('#feedback'); | ||
| 47 | + | ||
| 48 | + var svg = fb.append('svg').attr({ | ||
| 49 | + width: w, | ||
| 50 | + height: h, | ||
| 51 | + viewBox: vb | ||
| 52 | + }); | ||
| 53 | + | ||
| 54 | + function computeBox(el) { | ||
| 55 | + var text = el.select('text'), | ||
| 56 | + box = text.node().getBBox(); | ||
| 57 | + | ||
| 58 | + // center | ||
| 59 | + box.x = -box.width / 2; | ||
| 60 | + box.y = -box.height / 2; | ||
| 61 | + | ||
| 62 | + // add some padding | ||
| 63 | + box.x -= xpad; | ||
| 64 | + box.width += xpad * 2; | ||
| 65 | + box.y -= ypad; | ||
| 66 | + box.height += ypad * 2; | ||
| 67 | + | ||
| 68 | + return box; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + function updateFeedback() { | ||
| 72 | + var items = svg.selectAll('.feedbackItem') | ||
| 73 | + .data(data); | ||
| 74 | + | ||
| 75 | + var entering = items.enter() | ||
| 76 | + .append('g') | ||
| 77 | + .attr({ | ||
| 78 | + class: 'feedbackItem', | ||
| 79 | + opacity: 0 | ||
| 80 | + }) | ||
| 81 | + .transition() | ||
| 82 | + .duration(fade) | ||
| 83 | + .attr('opacity', 1); | ||
| 84 | + | ||
| 85 | + entering.each(function (d) { | ||
| 86 | + var el = d3.select(this), | ||
| 87 | + box; | ||
| 88 | + | ||
| 89 | + d.el = el; | ||
| 90 | + el.append('rect').attr({ rx: 10, ry: 10}); | ||
| 91 | + el.append('text').text(d.label); | ||
| 92 | + box = computeBox(el); | ||
| 93 | + el.select('rect').attr(box); | ||
| 94 | + }); | ||
| 95 | + | ||
| 96 | + items.exit() | ||
| 97 | + .transition() | ||
| 98 | + .duration(fade) | ||
| 99 | + .attr({ opacity: 0}) | ||
| 100 | + .remove(); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + function clearFlash() { | ||
| 104 | + if (timer) { | ||
| 105 | + clearInterval(timer); | ||
| 106 | + } | ||
| 107 | + data = []; | ||
| 108 | + updateFeedback(); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + // for now, simply display some text feedback | ||
| 112 | + function flash(text) { | ||
| 113 | + // cancel old scheduled event if there was one | ||
| 114 | + if (timer) { | ||
| 115 | + clearInterval(timer); | ||
| 116 | + } | ||
| 117 | + timer = setInterval(function () { | ||
| 118 | + clearFlash(); | ||
| 119 | + }, showFor); | ||
| 120 | + | ||
| 121 | + data = [{ | ||
| 122 | + label: text | ||
| 123 | + }]; | ||
| 124 | + updateFeedback(); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + onos.ui.addLib('feedback', { | ||
| 128 | + flash: flash | ||
| 129 | + }); | ||
| 130 | +}(ONOS)); |
| ... | @@ -42,6 +42,7 @@ | ... | @@ -42,6 +42,7 @@ |
| 42 | <link rel="stylesheet" href="onos2.css"> | 42 | <link rel="stylesheet" href="onos2.css"> |
| 43 | <link rel="stylesheet" href="mast2.css"> | 43 | <link rel="stylesheet" href="mast2.css"> |
| 44 | <link rel="stylesheet" href="floatPanel.css"> | 44 | <link rel="stylesheet" href="floatPanel.css"> |
| 45 | + <link rel="stylesheet" href="feedback.css"> | ||
| 45 | 46 | ||
| 46 | <!-- This is where contributed stylesheets get INJECTED --> | 47 | <!-- This is where contributed stylesheets get INJECTED --> |
| 47 | <!-- TODO: replace with template marker and inject refs server-side --> | 48 | <!-- TODO: replace with template marker and inject refs server-side --> |
| ... | @@ -71,6 +72,9 @@ | ... | @@ -71,6 +72,9 @@ |
| 71 | <div id="alerts"> | 72 | <div id="alerts"> |
| 72 | <!-- NOTE: alert content injected here, as needed --> | 73 | <!-- NOTE: alert content injected here, as needed --> |
| 73 | </div> | 74 | </div> |
| 75 | + <div id="feedback"> | ||
| 76 | + <!-- NOTE: feedback to user --> | ||
| 77 | + </div> | ||
| 74 | </div> | 78 | </div> |
| 75 | 79 | ||
| 76 | <!-- Initialize the UI...--> | 80 | <!-- Initialize the UI...--> |
| ... | @@ -89,6 +93,7 @@ | ... | @@ -89,6 +93,7 @@ |
| 89 | 93 | ||
| 90 | <!-- Framework module files included here --> | 94 | <!-- Framework module files included here --> |
| 91 | <script src="mast2.js"></script> | 95 | <script src="mast2.js"></script> |
| 96 | + <script src="feedback.js"></script> | ||
| 92 | 97 | ||
| 93 | <!-- View Module Templates; REMOVE THESE LINES, FOR PRODUCTION --> | 98 | <!-- View Module Templates; REMOVE THESE LINES, FOR PRODUCTION --> |
| 94 | <script src="module-svg-template.js"></script> | 99 | <script src="module-svg-template.js"></script> | ... | ... |
| ... | @@ -64,6 +64,8 @@ | ... | @@ -64,6 +64,8 @@ |
| 64 | font-size: 10pt; | 64 | font-size: 10pt; |
| 65 | margin: 4px 2px; | 65 | margin: 4px 2px; |
| 66 | padding: 1px 6px; | 66 | padding: 1px 6px; |
| 67 | + -moz-border-radius: 3px; | ||
| 68 | + border-radius: 3px; | ||
| 67 | cursor: pointer; | 69 | cursor: pointer; |
| 68 | } | 70 | } |
| 69 | 71 | ||
| ... | @@ -102,6 +104,8 @@ | ... | @@ -102,6 +104,8 @@ |
| 102 | #bb .btn { | 104 | #bb .btn { |
| 103 | margin: 0 4px; | 105 | margin: 0 4px; |
| 104 | padding: 2px 6px; | 106 | padding: 2px 6px; |
| 107 | + -moz-border-radius: 3px; | ||
| 108 | + border-radius: 3px; | ||
| 105 | font-size: 9pt; | 109 | font-size: 9pt; |
| 106 | cursor: pointer; | 110 | cursor: pointer; |
| 107 | } | 111 | } | ... | ... |
| ... | @@ -24,6 +24,19 @@ html, body { | ... | @@ -24,6 +24,19 @@ html, body { |
| 24 | height: 100%; | 24 | height: 100%; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | +/* This is to ensure that the body does not expand to account for the | ||
| 28 | + flyout details pane, that is positioned "off screen". | ||
| 29 | + */ | ||
| 30 | +body { | ||
| 31 | + overflow: hidden; | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +#frame { | ||
| 35 | + width: 100%; | ||
| 36 | + height: 100%; | ||
| 37 | + background-color: #fff; | ||
| 38 | +} | ||
| 39 | + | ||
| 27 | div.onosView { | 40 | div.onosView { |
| 28 | display: none; | 41 | display: none; |
| 29 | } | 42 | } |
| ... | @@ -32,6 +45,7 @@ div.onosView.currentView { | ... | @@ -32,6 +45,7 @@ div.onosView.currentView { |
| 32 | display: block; | 45 | display: block; |
| 33 | } | 46 | } |
| 34 | 47 | ||
| 48 | + | ||
| 35 | #alerts { | 49 | #alerts { |
| 36 | display: none; | 50 | display: none; |
| 37 | position: absolute; | 51 | position: absolute; |
| ... | @@ -42,6 +56,8 @@ div.onosView.currentView { | ... | @@ -42,6 +56,8 @@ div.onosView.currentView { |
| 42 | top: 80px; | 56 | top: 80px; |
| 43 | left: 40px; | 57 | left: 40px; |
| 44 | padding: 3px 6px; | 58 | padding: 3px 6px; |
| 59 | + -moz-border-radius: 6px; | ||
| 60 | + border-radius: 6px; | ||
| 45 | box-shadow: 4px 6px 12px #777; | 61 | box-shadow: 4px 6px 12px #777; |
| 46 | } | 62 | } |
| 47 | 63 | ||
| ... | @@ -67,90 +83,6 @@ div.onosView.currentView { | ... | @@ -67,90 +83,6 @@ div.onosView.currentView { |
| 67 | color: #66d; | 83 | color: #66d; |
| 68 | } | 84 | } |
| 69 | 85 | ||
| 70 | -/* | ||
| 71 | - * ============================================================== | ||
| 72 | - * END OF NEW ONOS.JS file | ||
| 73 | - * ============================================================== | ||
| 74 | - */ | ||
| 75 | - | ||
| 76 | -/* | ||
| 77 | - * === DEBUGGING ====== | ||
| 78 | - */ | ||
| 79 | -svg { | ||
| 80 | - /*border: 1px dashed red;*/ | ||
| 81 | -} | ||
| 82 | - | ||
| 83 | -svg #bg { | ||
| 84 | - opacity: 0.5; | ||
| 85 | -} | ||
| 86 | - | ||
| 87 | - | ||
| 88 | -/* | ||
| 89 | - * Network Graph elements ====================================== | ||
| 90 | - */ | ||
| 91 | - | ||
| 92 | - | ||
| 93 | -svg g.portLayer rect.port { | ||
| 94 | - fill: #ccc; | ||
| 95 | -} | ||
| 96 | - | ||
| 97 | -svg g.portLayer text { | ||
| 98 | - font: 8pt sans-serif; | ||
| 99 | - pointer-events: none; | ||
| 100 | -} | ||
| 101 | - | ||
| 102 | - | ||
| 103 | - | ||
| 104 | -/* for debugging */ | ||
| 105 | -svg .node circle.debug { | ||
| 106 | - fill: white; | ||
| 107 | - stroke: red; | ||
| 108 | -} | ||
| 109 | -svg .node rect.debug { | ||
| 110 | - fill: yellow; | ||
| 111 | - stroke: red; | ||
| 112 | - opacity: 0.35; | ||
| 113 | -} | ||
| 114 | - | ||
| 115 | - | ||
| 116 | - | ||
| 117 | -svg .link.inactive, | ||
| 118 | -svg .port.inactive, | ||
| 119 | -svg .portText.inactive, | ||
| 120 | -svg .node.inactive rect, | ||
| 121 | -svg .node.inactive circle, | ||
| 122 | -svg .node.inactive text, | ||
| 123 | -svg .node.inactive image { | ||
| 124 | - opacity: .1; | ||
| 125 | -} | ||
| 126 | - | ||
| 127 | -svg .node.inactive.selected rect, | ||
| 128 | -svg .node.inactive.selected text, | ||
| 129 | -svg .node.inactive.selected image { | ||
| 130 | - opacity: .6; | ||
| 131 | -} | ||
| 132 | - | ||
| 133 | -/* | ||
| 134 | - * ============================================================= | ||
| 135 | - */ | ||
| 136 | - | ||
| 137 | -/* | ||
| 138 | - * Specific structural elements | ||
| 139 | - */ | ||
| 140 | - | ||
| 141 | -/* This is to ensure that the body does not expand to account for the | ||
| 142 | - flyout details pane, that is positioned "off screen". | ||
| 143 | - */ | ||
| 144 | -body { | ||
| 145 | - overflow: hidden; | ||
| 146 | -} | ||
| 147 | - | ||
| 148 | - | ||
| 149 | -#frame { | ||
| 150 | - width: 100%; | ||
| 151 | - height: 100%; | ||
| 152 | - background-color: #fff; | ||
| 153 | -} | ||
| 154 | 86 | ||
| 155 | #flyout { | 87 | #flyout { |
| 156 | position: absolute; | 88 | position: absolute; |
| ... | @@ -200,4 +132,3 @@ body { | ... | @@ -200,4 +132,3 @@ body { |
| 200 | background-color: #ccc; | 132 | background-color: #ccc; |
| 201 | border: 0; | 133 | border: 0; |
| 202 | } | 134 | } |
| 203 | - | ... | ... |
| ... | @@ -588,6 +588,7 @@ | ... | @@ -588,6 +588,7 @@ |
| 588 | setKeys: this.setKeys, | 588 | setKeys: this.setKeys, |
| 589 | dataLoadError: this.dataLoadError, | 589 | dataLoadError: this.dataLoadError, |
| 590 | alert: this.alert, | 590 | alert: this.alert, |
| 591 | + flash: this.flash, | ||
| 591 | theme: this.theme | 592 | theme: this.theme |
| 592 | } | 593 | } |
| 593 | }, | 594 | }, |
| ... | @@ -697,6 +698,10 @@ | ... | @@ -697,6 +698,10 @@ |
| 697 | doAlert(msg); | 698 | doAlert(msg); |
| 698 | }, | 699 | }, |
| 699 | 700 | ||
| 701 | + flash: function (msg) { | ||
| 702 | + libApi.feedback.flash(msg); | ||
| 703 | + }, | ||
| 704 | + | ||
| 700 | dataLoadError: function (err, url) { | 705 | dataLoadError: function (err, url) { |
| 701 | var msg = 'Data Load Error\n\n' + | 706 | var msg = 'Data Load Error\n\n' + |
| 702 | err.status + ' -- ' + err.statusText + '\n\n' + | 707 | err.status + ' -- ' + err.statusText + '\n\n' + | ... | ... |
| ... | @@ -188,8 +188,13 @@ svg .node.host circle { | ... | @@ -188,8 +188,13 @@ svg .node.host circle { |
| 188 | 188 | ||
| 189 | #topo-detail h2 { | 189 | #topo-detail h2 { |
| 190 | position: absolute; | 190 | position: absolute; |
| 191 | - /*display: inline-block;*/ | 191 | + margin: 0px 4px; |
| 192 | - /*vertical-align: bottom;*/ | 192 | + top: 20px; |
| 193 | + left: 50px; | ||
| 194 | + color: black; | ||
| 195 | +} | ||
| 196 | + | ||
| 197 | +#topo-detail h3 { | ||
| 193 | margin: 0px 4px; | 198 | margin: 0px 4px; |
| 194 | top: 20px; | 199 | top: 20px; |
| 195 | left: 50px; | 200 | left: 50px; | ... | ... |
| ... | @@ -233,7 +233,8 @@ | ... | @@ -233,7 +233,8 @@ |
| 233 | // Key Callbacks | 233 | // Key Callbacks |
| 234 | 234 | ||
| 235 | function testMe(view) { | 235 | function testMe(view) { |
| 236 | - view.alert('Theme is ' + view.theme()); | 236 | + //view.alert('Theme is ' + view.theme()); |
| 237 | + //view.flash('This is some text'); | ||
| 237 | } | 238 | } |
| 238 | 239 | ||
| 239 | function abortIfLive() { | 240 | function abortIfLive() { |
| ... | @@ -325,7 +326,7 @@ | ... | @@ -325,7 +326,7 @@ |
| 325 | if (hoverMode === hoverModes.length) { | 326 | if (hoverMode === hoverModes.length) { |
| 326 | hoverMode = 0; | 327 | hoverMode = 0; |
| 327 | } | 328 | } |
| 328 | - console.log('Hover Mode:' + hoverMode + ': ' + hoverModes[hoverMode]); | 329 | + view.flash('Hover Mode: ' + hoverModes[hoverMode]); |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 331 | function togglePorts(view) { | 332 | function togglePorts(view) { |
| ... | @@ -1504,8 +1505,8 @@ | ... | @@ -1504,8 +1505,8 @@ |
| 1504 | 1505 | ||
| 1505 | node.append('rect') | 1506 | node.append('rect') |
| 1506 | .attr({ | 1507 | .attr({ |
| 1507 | - 'rx': 5, | 1508 | + rx: 5, |
| 1508 | - 'ry': 5 | 1509 | + ry: 5 |
| 1509 | }); | 1510 | }); |
| 1510 | 1511 | ||
| 1511 | node.append('text') | 1512 | node.append('text') |
| ... | @@ -1513,12 +1514,8 @@ | ... | @@ -1513,12 +1514,8 @@ |
| 1513 | .attr('dy', '1.1em'); | 1514 | .attr('dy', '1.1em'); |
| 1514 | 1515 | ||
| 1515 | box = adjustRectToFitText(node); | 1516 | box = adjustRectToFitText(node); |
| 1516 | - | 1517 | + node.select('rect').attr(box); |
| 1517 | - node.select('rect') | ||
| 1518 | - .attr(box); | ||
| 1519 | - | ||
| 1520 | addDeviceIcon(node, box, noLabel, iconGlyphUrl(d)); | 1518 | addDeviceIcon(node, box, noLabel, iconGlyphUrl(d)); |
| 1521 | - | ||
| 1522 | }); | 1519 | }); |
| 1523 | 1520 | ||
| 1524 | // TODO: better place for this configuration state | 1521 | // TODO: better place for this configuration state |
| ... | @@ -1930,9 +1927,9 @@ | ... | @@ -1930,9 +1927,9 @@ |
| 1930 | function populateMultiSelect() { | 1927 | function populateMultiSelect() { |
| 1931 | detailPane.empty(); | 1928 | detailPane.empty(); |
| 1932 | 1929 | ||
| 1933 | - var title = detailPane.append("h2"), | 1930 | + var title = detailPane.append('h3'), |
| 1934 | - table = detailPane.append("table"), | 1931 | + table = detailPane.append('table'), |
| 1935 | - tbody = table.append("tbody"); | 1932 | + tbody = table.append('tbody'); |
| 1936 | 1933 | ||
| 1937 | title.text('Selected Nodes'); | 1934 | title.text('Selected Nodes'); |
| 1938 | 1935 | ||
| ... | @@ -1949,9 +1946,9 @@ | ... | @@ -1949,9 +1946,9 @@ |
| 1949 | var svg = detailPane.append('svg'), | 1946 | var svg = detailPane.append('svg'), |
| 1950 | iid = iconGlyphUrl(data); | 1947 | iid = iconGlyphUrl(data); |
| 1951 | 1948 | ||
| 1952 | - var title = detailPane.append("h2"), | 1949 | + var title = detailPane.append('h2'), |
| 1953 | - table = detailPane.append("table"), | 1950 | + table = detailPane.append('table'), |
| 1954 | - tbody = table.append("tbody"); | 1951 | + tbody = table.append('tbody'); |
| 1955 | 1952 | ||
| 1956 | appendGlyph(svg, 0, 0, 40, iid); | 1953 | appendGlyph(svg, 0, 0, 40, iid); |
| 1957 | title.text(data.id); | 1954 | title.text(data.id); |
| ... | @@ -2063,9 +2060,7 @@ | ... | @@ -2063,9 +2060,7 @@ |
| 2063 | // TODO: toggle button (and other widgets in the masthead) should be provided | 2060 | // TODO: toggle button (and other widgets in the masthead) should be provided |
| 2064 | // by the framework; not generated by the view. | 2061 | // by the framework; not generated by the view. |
| 2065 | 2062 | ||
| 2066 | - var showInstances, | 2063 | + var showInstances; |
| 2067 | - doPanZoom, | ||
| 2068 | - showTrafficOnHover; | ||
| 2069 | 2064 | ||
| 2070 | function addButtonBar(view) { | 2065 | function addButtonBar(view) { |
| 2071 | var bb = d3.select('#mast') | 2066 | var bb = d3.select('#mast') | ... | ... |
-
Please register or login to post a comment