Simon Hunt

GUI -- Added user feedback "flash" message function.

- flash hover mode when H key pressed.
- additional cleanup.

Change-Id: I14dd47c41842c3f6cb68d2c9fbe3ee96ad23ae86
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Feedback layer -- CSS file
@author Simon Hunt
*/
#feedback svg {
position: absolute;
bottom: 0;
opacity: 0.5;
}
#feedback svg g.feedbackItem {
background-color: teal;
}
#feedback svg g.feedbackItem rect {
fill: #888;
stroke: #666;
stroke-width: 3;
opacity: 0.5
}
#feedback svg g.feedbackItem text {
fill: #000;
stroke: none;
text-anchor: middle;
alignment-baseline: middle;
font-size: 16pt;
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Feedback layer
Defines the feedback layer for the UI. Used to give user visual feedback
of choices, typically responding to keystrokes.
@author Simon Hunt
*/
(function (onos){
'use strict';
// API's
var api = onos.api;
// Config variables
var w = '100%',
h = 200,
fade = 750,
showFor = 2000,
vb = '-200 -' + (h/2) + ' 400 ' + h,
xpad = 20,
ypad = 10;
// State variables
var timer = null,
data = [];
// DOM elements and the like
var fb = d3.select('#feedback');
var svg = fb.append('svg').attr({
width: w,
height: h,
viewBox: vb
});
function computeBox(el) {
var text = el.select('text'),
box = text.node().getBBox();
// center
box.x = -box.width / 2;
box.y = -box.height / 2;
// add some padding
box.x -= xpad;
box.width += xpad * 2;
box.y -= ypad;
box.height += ypad * 2;
return box;
}
function updateFeedback() {
var items = svg.selectAll('.feedbackItem')
.data(data);
var entering = items.enter()
.append('g')
.attr({
class: 'feedbackItem',
opacity: 0
})
.transition()
.duration(fade)
.attr('opacity', 1);
entering.each(function (d) {
var el = d3.select(this),
box;
d.el = el;
el.append('rect').attr({ rx: 10, ry: 10});
el.append('text').text(d.label);
box = computeBox(el);
el.select('rect').attr(box);
});
items.exit()
.transition()
.duration(fade)
.attr({ opacity: 0})
.remove();
}
function clearFlash() {
if (timer) {
clearInterval(timer);
}
data = [];
updateFeedback();
}
// for now, simply display some text feedback
function flash(text) {
// cancel old scheduled event if there was one
if (timer) {
clearInterval(timer);
}
timer = setInterval(function () {
clearFlash();
}, showFor);
data = [{
label: text
}];
updateFeedback();
}
onos.ui.addLib('feedback', {
flash: flash
});
}(ONOS));
......@@ -42,6 +42,7 @@
<link rel="stylesheet" href="onos2.css">
<link rel="stylesheet" href="mast2.css">
<link rel="stylesheet" href="floatPanel.css">
<link rel="stylesheet" href="feedback.css">
<!-- This is where contributed stylesheets get INJECTED -->
<!-- TODO: replace with template marker and inject refs server-side -->
......@@ -71,6 +72,9 @@
<div id="alerts">
<!-- NOTE: alert content injected here, as needed -->
</div>
<div id="feedback">
<!-- NOTE: feedback to user -->
</div>
</div>
<!-- Initialize the UI...-->
......@@ -89,6 +93,7 @@
<!-- Framework module files included here -->
<script src="mast2.js"></script>
<script src="feedback.js"></script>
<!-- View Module Templates; REMOVE THESE LINES, FOR PRODUCTION -->
<script src="module-svg-template.js"></script>
......
......@@ -64,6 +64,8 @@
font-size: 10pt;
margin: 4px 2px;
padding: 1px 6px;
-moz-border-radius: 3px;
border-radius: 3px;
cursor: pointer;
}
......@@ -102,6 +104,8 @@
#bb .btn {
margin: 0 4px;
padding: 2px 6px;
-moz-border-radius: 3px;
border-radius: 3px;
font-size: 9pt;
cursor: pointer;
}
......
......@@ -24,6 +24,19 @@ html, body {
height: 100%;
}
/* This is to ensure that the body does not expand to account for the
flyout details pane, that is positioned "off screen".
*/
body {
overflow: hidden;
}
#frame {
width: 100%;
height: 100%;
background-color: #fff;
}
div.onosView {
display: none;
}
......@@ -32,6 +45,7 @@ div.onosView.currentView {
display: block;
}
#alerts {
display: none;
position: absolute;
......@@ -42,6 +56,8 @@ div.onosView.currentView {
top: 80px;
left: 40px;
padding: 3px 6px;
-moz-border-radius: 6px;
border-radius: 6px;
box-shadow: 4px 6px 12px #777;
}
......@@ -67,90 +83,6 @@ div.onosView.currentView {
color: #66d;
}
/*
* ==============================================================
* END OF NEW ONOS.JS file
* ==============================================================
*/
/*
* === DEBUGGING ======
*/
svg {
/*border: 1px dashed red;*/
}
svg #bg {
opacity: 0.5;
}
/*
* Network Graph elements ======================================
*/
svg g.portLayer rect.port {
fill: #ccc;
}
svg g.portLayer text {
font: 8pt sans-serif;
pointer-events: none;
}
/* for debugging */
svg .node circle.debug {
fill: white;
stroke: red;
}
svg .node rect.debug {
fill: yellow;
stroke: red;
opacity: 0.35;
}
svg .link.inactive,
svg .port.inactive,
svg .portText.inactive,
svg .node.inactive rect,
svg .node.inactive circle,
svg .node.inactive text,
svg .node.inactive image {
opacity: .1;
}
svg .node.inactive.selected rect,
svg .node.inactive.selected text,
svg .node.inactive.selected image {
opacity: .6;
}
/*
* =============================================================
*/
/*
* Specific structural elements
*/
/* This is to ensure that the body does not expand to account for the
flyout details pane, that is positioned "off screen".
*/
body {
overflow: hidden;
}
#frame {
width: 100%;
height: 100%;
background-color: #fff;
}
#flyout {
position: absolute;
......@@ -200,4 +132,3 @@ body {
background-color: #ccc;
border: 0;
}
......
......@@ -588,6 +588,7 @@
setKeys: this.setKeys,
dataLoadError: this.dataLoadError,
alert: this.alert,
flash: this.flash,
theme: this.theme
}
},
......@@ -697,6 +698,10 @@
doAlert(msg);
},
flash: function (msg) {
libApi.feedback.flash(msg);
},
dataLoadError: function (err, url) {
var msg = 'Data Load Error\n\n' +
err.status + ' -- ' + err.statusText + '\n\n' +
......
......@@ -188,8 +188,13 @@ svg .node.host circle {
#topo-detail h2 {
position: absolute;
/*display: inline-block;*/
/*vertical-align: bottom;*/
margin: 0px 4px;
top: 20px;
left: 50px;
color: black;
}
#topo-detail h3 {
margin: 0px 4px;
top: 20px;
left: 50px;
......
......@@ -233,7 +233,8 @@
// Key Callbacks
function testMe(view) {
view.alert('Theme is ' + view.theme());
//view.alert('Theme is ' + view.theme());
//view.flash('This is some text');
}
function abortIfLive() {
......@@ -325,7 +326,7 @@
if (hoverMode === hoverModes.length) {
hoverMode = 0;
}
console.log('Hover Mode:' + hoverMode + ': ' + hoverModes[hoverMode]);
view.flash('Hover Mode: ' + hoverModes[hoverMode]);
}
function togglePorts(view) {
......@@ -1504,8 +1505,8 @@
node.append('rect')
.attr({
'rx': 5,
'ry': 5
rx: 5,
ry: 5
});
node.append('text')
......@@ -1513,12 +1514,8 @@
.attr('dy', '1.1em');
box = adjustRectToFitText(node);
node.select('rect')
.attr(box);
node.select('rect').attr(box);
addDeviceIcon(node, box, noLabel, iconGlyphUrl(d));
});
// TODO: better place for this configuration state
......@@ -1930,9 +1927,9 @@
function populateMultiSelect() {
detailPane.empty();
var title = detailPane.append("h2"),
table = detailPane.append("table"),
tbody = table.append("tbody");
var title = detailPane.append('h3'),
table = detailPane.append('table'),
tbody = table.append('tbody');
title.text('Selected Nodes');
......@@ -1949,9 +1946,9 @@
var svg = detailPane.append('svg'),
iid = iconGlyphUrl(data);
var title = detailPane.append("h2"),
table = detailPane.append("table"),
tbody = table.append("tbody");
var title = detailPane.append('h2'),
table = detailPane.append('table'),
tbody = table.append('tbody');
appendGlyph(svg, 0, 0, 40, iid);
title.text(data.id);
......@@ -2063,9 +2060,7 @@
// TODO: toggle button (and other widgets in the masthead) should be provided
// by the framework; not generated by the view.
var showInstances,
doPanZoom,
showTrafficOnHover;
var showInstances;
function addButtonBar(view) {
var bb = d3.select('#mast')
......