blob: 596276b42a57ed06b3870a1574dfaa76ba99321c [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: '/',
58 leftArrow: 'L-arrow',
59 upArrow: 'U-arrow',
60 rightArrow: 'R-arrow',
61 downArrow: 'D-arrow'
62 };
Simon Hunt56ef0fe2014-11-21 08:24:43 -080063
Simon Hunt5cef9062014-11-24 15:24:35 -080064 function cap(s) {
65 return s.replace(/^[a-z]/, function (m) { return m.toUpperCase(); });
66 }
Simon Hunt56ef0fe2014-11-21 08:24:43 -080067
Simon Hunt5cef9062014-11-24 15:24:35 -080068 function mkKeyDisp(id) {
69 var v = keyDisp[id] || id;
70 return cap(v);
71 }
72
73 // layout configuration
74 var pad = 8,
75 offy = 45,
76 dy = 14,
Simon Hunt87514342014-11-24 16:41:27 -080077 offDesc = 8;
Simon Hunt5cef9062014-11-24 15:24:35 -080078
79 // D3 magic
Simon Hunt56ef0fe2014-11-21 08:24:43 -080080 function updateKeyItems() {
Simon Hunt5cef9062014-11-24 15:24:35 -080081 var keyItems = items.selectAll('.keyItem')
Simon Hunt988c6fc2014-11-20 17:43:03 -080082 .data(data);
83
Simon Hunt5cef9062014-11-24 15:24:35 -080084 var entering = keyItems.enter()
Simon Hunt988c6fc2014-11-20 17:43:03 -080085 .append('g')
86 .attr({
Simon Hunt56ef0fe2014-11-21 08:24:43 -080087 id: function (d) { return d.id; },
88 class: 'keyItem'
89 });
Simon Hunt988c6fc2014-11-20 17:43:03 -080090
Simon Hunt56ef0fe2014-11-21 08:24:43 -080091 entering.each(function (d, i) {
Simon Hunt988c6fc2014-11-20 17:43:03 -080092 var el = d3.select(this),
Simon Hunt56ef0fe2014-11-21 08:24:43 -080093 y = offy + dy * i;
Simon Hunt988c6fc2014-11-20 17:43:03 -080094
Simon Hunt87514342014-11-24 16:41:27 -080095 if (d.id[0] === '_') {
Simon Hunt56ef0fe2014-11-21 08:24:43 -080096 el.append('line')
Simon Hunt5cef9062014-11-24 15:24:35 -080097 .attr({ x1: 0, y1: y, x2: 1, y2: y});
Simon Hunt56ef0fe2014-11-21 08:24:43 -080098 } else {
99 el.append('text')
100 .text(d.key)
101 .attr({
102 class: 'key',
Simon Hunt5cef9062014-11-24 15:24:35 -0800103 x: 0,
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800104 y: y
105 });
Simon Hunt87514342014-11-24 16:41:27 -0800106 // NOTE: used for sizing column width...
107 keyAgg.append('text').text(d.key).attr('class', 'key');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800108
109 el.append('text')
110 .text(d.desc)
111 .attr({
112 class: 'desc',
113 x: offDesc,
114 y: y
115 });
116 }
117 });
Simon Hunt5cef9062014-11-24 15:24:35 -0800118
Simon Hunt87514342014-11-24 16:41:27 -0800119 var kbox = keyAgg.node().getBBox();
120 items.selectAll('.desc').attr('x', kbox.width + offDesc);
121
Simon Hunt5cef9062014-11-24 15:24:35 -0800122 var box = items.node().getBBox(),
123 paneW = box.width + pad * 2,
124 paneH = box.height + offy;
125
Simon Hunt87514342014-11-24 16:41:27 -0800126 items.selectAll('line').attr('x2', box.width);
Simon Hunt5cef9062014-11-24 15:24:35 -0800127 items.attr('transform', translate(-paneW/2, -pad));
128 rect.attr({
129 width: paneW,
130 height: paneH,
131 transform: translate(-paneW/2-pad, 0)
132 });
133 }
134
135 function translate(x, y) {
136 return 'translate(' + x + ',' + y + ')';
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800137 }
138
139 function aggregateData(bindings) {
140 var gmap = d3.map(bindings.globalKeys),
141 vmap = d3.map(bindings.viewKeys),
142 gkeys = gmap.keys(),
Simon Hunt87514342014-11-24 16:41:27 -0800143 vkeys = vmap.keys(),
144 vgest = bindings.viewGestures,
145 sep = 0;
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800146
147 gkeys.sort();
148 vkeys.sort();
149
150 data = [];
151 gkeys.forEach(function (k) {
Simon Hunt87514342014-11-24 16:41:27 -0800152 addItem('glob', k, gmap.get(k));
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800153 });
Simon Hunt87514342014-11-24 16:41:27 -0800154 addItem('sep');
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800155 vkeys.forEach(function (k) {
156 addItem('view', k, vmap.get(k));
Simon Hunt988c6fc2014-11-20 17:43:03 -0800157 });
Simon Hunt87514342014-11-24 16:41:27 -0800158 addItem('sep');
159 vgest.forEach(function (g) {
160 if (g.length === 2) {
161 addItem('gest', g[0], g[1]);
162 }
163 });
164
Simon Hunt988c6fc2014-11-20 17:43:03 -0800165
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800166 function addItem(type, k, d) {
167 var id = type + '-' + k,
168 a = isA(d),
169 desc = a && a[1];
Simon Hunt87514342014-11-24 16:41:27 -0800170
171 if (type === 'sep') {
172 data.push({
173 id: '_' + sep++,
174 type: type
175 });
176 } else if (type === 'gest') {
177 data.push({
178 id: id,
179 type: type,
180 key: k,
181 desc: d
182 });
183 } else if (desc) {
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800184 data.push(
185 {
186 id: id,
187 type: type,
Simon Hunt5cef9062014-11-24 15:24:35 -0800188 key: mkKeyDisp(k),
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800189 desc: desc
190 }
191 );
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800192 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800193 }
Simon Hunt988c6fc2014-11-20 17:43:03 -0800194 }
195
Simon Hunt5cef9062014-11-24 15:24:35 -0800196 function popBind(bindings) {
197 pane = svg.append('g')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800198 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800199 class: 'help',
Simon Hunt988c6fc2014-11-20 17:43:03 -0800200 opacity: 0
Simon Hunt988c6fc2014-11-20 17:43:03 -0800201 });
202
Simon Hunt5cef9062014-11-24 15:24:35 -0800203 rect = pane.append('rect')
204 .attr('rx', 8);
205
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800206 pane.append('text')
Simon Hunt5cef9062014-11-24 15:24:35 -0800207 .text('Quick Help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800208 .attr({
Simon Hunt5cef9062014-11-24 15:24:35 -0800209 class: 'title',
210 dy: '1.2em',
211 transform: translate(-pad,0)
Simon Hunt988c6fc2014-11-20 17:43:03 -0800212 });
213
Simon Hunt5cef9062014-11-24 15:24:35 -0800214 items = pane.append('g');
Simon Hunt87514342014-11-24 16:41:27 -0800215 keyAgg = pane.append('g').style('visibility', 'hidden');
Simon Hunt5cef9062014-11-24 15:24:35 -0800216
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800217 aggregateData(bindings);
218 updateKeyItems();
Simon Hunt5cef9062014-11-24 15:24:35 -0800219
220 _fade(1);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800221 }
222
223 function fadeBindings() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800224 _fade(0);
225 }
226
227 function _fade(o) {
228 svg.selectAll('g.help')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800229 .transition()
230 .duration(fade)
Simon Hunt5cef9062014-11-24 15:24:35 -0800231 .attr('opacity', o);
Simon Hunt988c6fc2014-11-20 17:43:03 -0800232 }
233
234 function addSvg() {
Simon Hunt5cef9062014-11-24 15:24:35 -0800235 svg = qhdiv.append('svg')
Simon Hunt988c6fc2014-11-20 17:43:03 -0800236 .attr({
237 width: w,
238 height: h,
239 viewBox: vb
240 });
241 }
242
243 function removeSvg() {
244 svg.transition()
245 .delay(fade + 20)
246 .remove();
247 }
248
Simon Hunt5cef9062014-11-24 15:24:35 -0800249 function showQuickHelp(bindings) {
250 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800251 if (svg.empty()) {
252 addSvg();
Simon Hunt5cef9062014-11-24 15:24:35 -0800253 popBind(bindings);
Simon Hunt56ef0fe2014-11-21 08:24:43 -0800254 } else {
Simon Hunt5cef9062014-11-24 15:24:35 -0800255 hideQuickHelp();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800256 }
257 }
258
Simon Hunt5cef9062014-11-24 15:24:35 -0800259 function hideQuickHelp() {
260 svg = qhdiv.select('svg');
Simon Hunt988c6fc2014-11-20 17:43:03 -0800261 if (!svg.empty()) {
262 fadeBindings();
263 removeSvg();
Simon Hunt988c6fc2014-11-20 17:43:03 -0800264 return true;
265 }
266 return false;
267 }
268
Simon Hunt5cef9062014-11-24 15:24:35 -0800269 onos.ui.addLib('quickHelp', {
270 show: showQuickHelp,
271 hide: hideQuickHelp
Simon Hunt988c6fc2014-11-20 17:43:03 -0800272 });
273}(ONOS));