blob: 9e2a5ec0e1f14e3536252d92d45eb67323bcb90d [file] [log] [blame]
Simon Hunt988c6fc2014-11-20 17:43:03 -08001/*
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/*
Simon Hunt5cef9062014-11-24 15:24:35 -080018 ONOS GUI -- Quick Help Layer
Simon Hunt988c6fc2014-11-20 17:43:03 -080019
20 Defines the key-map layer for the UI. Used to give user a list of
21 key bindings; both global, and for the current view.
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 = '80%',
Simon Hunt209155e2014-11-21 12:16:09 -080035 fade = 500,
Simon Hunt5cef9062014-11-24 15:24:35 -080036 vb = '-200 0 400 400';
Simon Hunt988c6fc2014-11-20 17:43:03 -080037
38 // State variables
39 var data = [];
40
41 // DOM elements and the like
Simon Hunt5cef9062014-11-24 15:24:35 -080042 var qhdiv = d3.select('#quickhelp'),
43 svg = qhdiv.select('svg'),
44 pane,
45 rect,
Simon Hunt87514342014-11-24 16:41:27 -080046 items,
47 keyAgg;
Simon Hunt988c6fc2014-11-20 17:43:03 -080048
Simon Hunt5cef9062014-11-24 15:24:35 -080049 // General functions
Simon Hunt56ef0fe2014-11-21 08:24:43 -080050 function isA(a) {
51 return $.isArray(a) ? a : null;
Simon Hunt988c6fc2014-11-20 17:43:03 -080052 }
53
Simon Hunt5cef9062014-11-24 15:24:35 -080054 var keyDisp = {
55 equals: '=',
56 dash: '-',
57 slash: '/',
Thomas Vachuska1e68bdd2014-11-29 13:53:10 -080058 backQuote: '`',
Simon Hunt5cef9062014-11-24 15:24:35 -080059 leftArrow: 'L-arrow',
60 upArrow: 'U-arrow',
61 rightArrow: 'R-arrow',
62 downArrow: 'D-arrow'
63 };
Simon Hunt56ef0fe2014-11-21 08:24:43 -080064
Simon Hunt5cef9062014-11-24 15:24:35 -080065 function cap(s) {
66 return s.replace(/^[a-z]/, function (m) { return m.toUpperCase(); });
67 }
Simon Hunt56ef0fe2014-11-21 08:24:43 -080068
Simon Hunt5cef9062014-11-24 15:24:35 -080069 function mkKeyDisp(id) {
70 var v = keyDisp[id] || id;
71 return cap(v);
72 }
73
74 // layout configuration
75 var pad = 8,
76 offy = 45,
77 dy = 14,
Simon Hunt87514342014-11-24 16:41:27 -080078 offDesc = 8;
Simon Hunt5cef9062014-11-24 15:24:35 -080079
80 // D3 magic
Simon Hunt56ef0fe2014-11-21 08:24:43 -080081 function updateKeyItems() {
Simon Hunt5cef9062014-11-24 15:24:35 -080082 var keyItems = items.selectAll('.keyItem')
Simon Hunt988c6fc2014-11-20 17:43:03 -080083 .data(data);
84
Simon Hunt5cef9062014-11-24 15:24:35 -080085 var entering = keyItems.enter()
Simon Hunt988c6fc2014-11-20 17:43:03 -080086 .append('g')
87 .attr({
Simon Hunt56ef0fe2014-11-21 08:24:43 -080088 id: function (d) { return d.id; },
89 class: 'keyItem'
90 });
Simon Hunt988c6fc2014-11-20 17:43:03 -080091
Simon Hunt56ef0fe2014-11-21 08:24:43 -080092 entering.each(function (d, i) {
Simon Hunt988c6fc2014-11-20 17:43:03 -080093 var el = d3.select(this),
Simon Hunt56ef0fe2014-11-21 08:24:43 -080094 y = offy + dy * i;
Simon Hunt988c6fc2014-11-20 17:43:03 -080095
Simon Hunt87514342014-11-24 16:41:27 -080096 if (d.id[0] === '_') {
Simon Hunt56ef0fe2014-11-21 08:24:43 -080097 el.append('line')
Simon Hunt5cef9062014-11-24 15:24:35 -080098 .attr({ x1: 0, y1: y, x2: 1, y2: y});
Simon Hunt56ef0fe2014-11-21 08:24:43 -080099 } else {
100 el.append('text')
101 .text(d.key)
102 .attr({
103 class: 'key',
Simon Hunt5cef9062014-11-24 15:24:35 -0800104 x: 0,
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800105 y: y
106 });
Simon Hunt87514342014-11-24 16:41:27 -0800107 // NOTE: used for sizing column width...
108 keyAgg.append('text').text(d.key).attr('class', 'key');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800109
110 el.append('text')
111 .text(d.desc)
112 .attr({
113 class: 'desc',
114 x: offDesc,
115 y: y
116 });
117 }
118 });
Simon Hunt5cef9062014-11-24 15:24:35 -0800119
Simon Hunt87514342014-11-24 16:41:27 -0800120 var kbox = keyAgg.node().getBBox();
121 items.selectAll('.desc').attr('x', kbox.width + offDesc);
122
Simon Hunt5cef9062014-11-24 15:24:35 -0800123 var box = items.node().getBBox(),
124 paneW = box.width + pad * 2,
125 paneH = box.height + offy;
126
Simon Hunt87514342014-11-24 16:41:27 -0800127 items.selectAll('line').attr('x2', box.width);
Simon Hunt5cef9062014-11-24 15:24:35 -0800128 items.attr('transform', translate(-paneW/2, -pad));
129 rect.attr({
130 width: paneW,
131 height: paneH,
132 transform: translate(-paneW/2-pad, 0)
133 });
134 }
135
136 function translate(x, y) {
137 return 'translate(' + x + ',' + y + ')';
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800138 }
139
140 function aggregateData(bindings) {
141 var gmap = d3.map(bindings.globalKeys),
142 vmap = d3.map(bindings.viewKeys),
143 gkeys = gmap.keys(),
Simon Hunt87514342014-11-24 16:41:27 -0800144 vkeys = vmap.keys(),
145 vgest = bindings.viewGestures,
146 sep = 0;
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800147
148 gkeys.sort();
149 vkeys.sort();
150
151 data = [];
152 gkeys.forEach(function (k) {
Simon Hunt87514342014-11-24 16:41:27 -0800153 addItem('glob', k, gmap.get(k));
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800154 });
Simon Hunt87514342014-11-24 16:41:27 -0800155 addItem('sep');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800156 vkeys.forEach(function (k) {
157 addItem('view', k, vmap.get(k));
Simon Hunt988c6fc2014-11-20 17:43:03 -0800158 });
Simon Hunt87514342014-11-24 16:41:27 -0800159 addItem('sep');
160 vgest.forEach(function (g) {
161 if (g.length === 2) {
162 addItem('gest', g[0], g[1]);
163 }
164 });
165
Simon Hunt988c6fc2014-11-20 17:43:03 -0800166
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800167 function addItem(type, k, d) {
168 var id = type + '-' + k,
169 a = isA(d),
170 desc = a && a[1];
Simon Hunt87514342014-11-24 16:41:27 -0800171
172 if (type === 'sep') {
173 data.push({
174 id: '_' + sep++,
175 type: type
176 });
177 } else if (type === 'gest') {
178 data.push({
179 id: id,
180 type: type,
181 key: k,
182 desc: d
183 });
184 } else if (desc) {
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800185 data.push(
186 {
187 id: id,
188 type: type,
Simon Hunt5cef9062014-11-24 15:24:35 -0800189 key: mkKeyDisp(k),
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800190 desc: desc
191 }
192 );
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800193 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800194 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800195 }
196
Simon Hunt5cef9062014-11-24 15:24:35 -0800197 function popBind(bindings) {
198 pane = svg.append('g')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800199 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800200 class: 'help',
Simon Hunt988c6fc2014-11-20 17:43:03 -0800201 opacity: 0
Simon Hunt988c6fc2014-11-20 17:43:03 -0800202 });
203
Simon Hunt5cef9062014-11-24 15:24:35 -0800204 rect = pane.append('rect')
205 .attr('rx', 8);
206
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800207 pane.append('text')
Simon Hunt5cef9062014-11-24 15:24:35 -0800208 .text('Quick Help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800209 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800210 class: 'title',
211 dy: '1.2em',
212 transform: translate(-pad,0)
Simon Hunt988c6fc2014-11-20 17:43:03 -0800213 });
214
Simon Hunt5cef9062014-11-24 15:24:35 -0800215 items = pane.append('g');
Simon Hunt87514342014-11-24 16:41:27 -0800216 keyAgg = pane.append('g').style('visibility', 'hidden');
Simon Hunt5cef9062014-11-24 15:24:35 -0800217
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800218 aggregateData(bindings);
219 updateKeyItems();
Simon Hunt5cef9062014-11-24 15:24:35 -0800220
221 _fade(1);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800222 }
223
224 function fadeBindings() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800225 _fade(0);
226 }
227
228 function _fade(o) {
229 svg.selectAll('g.help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800230 .transition()
231 .duration(fade)
Simon Hunt5cef9062014-11-24 15:24:35 -0800232 .attr('opacity', o);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800233 }
234
235 function addSvg() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800236 svg = qhdiv.append('svg')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800237 .attr({
238 width: w,
239 height: h,
240 viewBox: vb
241 });
242 }
243
244 function removeSvg() {
245 svg.transition()
246 .delay(fade + 20)
247 .remove();
248 }
249
Simon Hunt5cef9062014-11-24 15:24:35 -0800250 function showQuickHelp(bindings) {
251 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800252 if (svg.empty()) {
253 addSvg();
Simon Hunt5cef9062014-11-24 15:24:35 -0800254 popBind(bindings);
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800255 } else {
Simon Hunt5cef9062014-11-24 15:24:35 -0800256 hideQuickHelp();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800257 }
258 }
259
Simon Hunt5cef9062014-11-24 15:24:35 -0800260 function hideQuickHelp() {
261 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800262 if (!svg.empty()) {
263 fadeBindings();
264 removeSvg();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800265 return true;
266 }
267 return false;
268 }
269
Simon Hunt5cef9062014-11-24 15:24:35 -0800270 onos.ui.addLib('quickHelp', {
271 show: showQuickHelp,
272 hide: hideQuickHelp
Simon Hunt988c6fc2014-11-20 17:43:03 -0800273 });
274}(ONOS));