GUI -- TopoView - added node selection logic.
- added inArray() and removeFromArray() functions to FnService. Change-Id: I0e9631fa9e5865cb171e8d505f45c1963a1903dc
Showing
4 changed files
with
169 additions
and
14 deletions
| ... | @@ -117,6 +117,32 @@ | ... | @@ -117,6 +117,32 @@ |
| 117 | return -1; | 117 | return -1; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | + // search through array to find (the first occurrence of) item, | ||
| 121 | + // returning its index if found; otherwise returning -1. | ||
| 122 | + function inArray(item, array) { | ||
| 123 | + var i; | ||
| 124 | + if (isA(array)) { | ||
| 125 | + for (i=0; i<array.length; i++) { | ||
| 126 | + if (array[i] === item) { | ||
| 127 | + return i; | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + } | ||
| 131 | + return -1; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + // remove (the first occurrence of) the specified item from the given | ||
| 135 | + // array, if any. Return true if the removal was made; false otherwise. | ||
| 136 | + function removeFromArray(item, array) { | ||
| 137 | + var found = false, | ||
| 138 | + i = inArray(item, array); | ||
| 139 | + if (i >= 0) { | ||
| 140 | + array.splice(i, 1); | ||
| 141 | + found = true; | ||
| 142 | + } | ||
| 143 | + return found; | ||
| 144 | + } | ||
| 145 | + | ||
| 120 | angular.module('onosUtil') | 146 | angular.module('onosUtil') |
| 121 | .factory('FnService', ['$window', function (_$window_) { | 147 | .factory('FnService', ['$window', function (_$window_) { |
| 122 | $window = _$window_; | 148 | $window = _$window_; |
| ... | @@ -130,7 +156,9 @@ | ... | @@ -130,7 +156,9 @@ |
| 130 | areFunctions: areFunctions, | 156 | areFunctions: areFunctions, |
| 131 | areFunctionsNonStrict: areFunctionsNonStrict, | 157 | areFunctionsNonStrict: areFunctionsNonStrict, |
| 132 | windowSize: windowSize, | 158 | windowSize: windowSize, |
| 133 | - find: find | 159 | + find: find, |
| 160 | + inArray: inArray, | ||
| 161 | + removeFromArray: removeFromArray | ||
| 134 | }; | 162 | }; |
| 135 | }]); | 163 | }]); |
| 136 | 164 | ... | ... |
| ... | @@ -111,8 +111,7 @@ | ... | @@ -111,8 +111,7 @@ |
| 111 | <div id="quickhelp"></div> | 111 | <div id="quickhelp"></div> |
| 112 | <div id="veil" | 112 | <div id="veil" |
| 113 | resize | 113 | resize |
| 114 | - ng-style="resizeWithOffset(0, 0)" | 114 | + ng-style="resizeWithOffset(0, 0)"></div> |
| 115 | - ></div> | ||
| 116 | </div> | 115 | </div> |
| 117 | </body> | 116 | </body> |
| 118 | </html> | 117 | </html> | ... | ... |
| ... | @@ -77,7 +77,9 @@ | ... | @@ -77,7 +77,9 @@ |
| 77 | oblique = false, // whether we are in the oblique view | 77 | oblique = false, // whether we are in the oblique view |
| 78 | nodeLock = false, // whether nodes can be dragged or not (locked) | 78 | nodeLock = false, // whether nodes can be dragged or not (locked) |
| 79 | width, height, // the width and height of the force layout | 79 | width, height, // the width and height of the force layout |
| 80 | - hovered; // the node over which the mouse is hovering | 80 | + hovered, // the node over which the mouse is hovering |
| 81 | + selections = {}, // what is currently selected | ||
| 82 | + selectOrder = []; // the order in which we made selections | ||
| 81 | 83 | ||
| 82 | // SVG elements; | 84 | // SVG elements; |
| 83 | var linkG, linkLabelG, nodeG; | 85 | var linkG, linkLabelG, nodeG; |
| ... | @@ -1323,15 +1325,77 @@ | ... | @@ -1323,15 +1325,77 @@ |
| 1323 | } | 1325 | } |
| 1324 | 1326 | ||
| 1325 | 1327 | ||
| 1328 | + function updateDetailPanel() { | ||
| 1329 | + // TODO update detail panel | ||
| 1330 | + $log.debug("TODO: updateDetailPanel() ..."); | ||
| 1331 | + } | ||
| 1332 | + | ||
| 1333 | + | ||
| 1334 | + // ========================== | ||
| 1335 | + // === SELECTION / DESELECTION | ||
| 1336 | + | ||
| 1337 | + function selectObject(obj) { | ||
| 1338 | + var el = this, | ||
| 1339 | + ev = d3.event.sourceEvent, | ||
| 1340 | + n; | ||
| 1341 | + | ||
| 1342 | + if (zoomingOrPanning(ev)) { | ||
| 1343 | + return; | ||
| 1344 | + } | ||
| 1345 | + | ||
| 1346 | + if (el) { | ||
| 1347 | + n = d3.select(el); | ||
| 1348 | + } else { | ||
| 1349 | + node.each(function (d) { | ||
| 1350 | + if (d == obj) { | ||
| 1351 | + n = d3.select(el = this); | ||
| 1352 | + } | ||
| 1353 | + }); | ||
| 1354 | + } | ||
| 1355 | + if (!n) return; | ||
| 1356 | + | ||
| 1357 | + if (ev.shiftKey && n.classed('selected')) { | ||
| 1358 | + deselectObject(obj.id); | ||
| 1359 | + updateDetailPanel(); | ||
| 1360 | + return; | ||
| 1361 | + } | ||
| 1362 | + | ||
| 1363 | + if (!ev.shiftKey) { | ||
| 1364 | + deselectAll(); | ||
| 1365 | + } | ||
| 1366 | + | ||
| 1367 | + selections[obj.id] = { obj: obj, el: el }; | ||
| 1368 | + selectOrder.push(obj.id); | ||
| 1369 | + | ||
| 1370 | + n.classed('selected', true); | ||
| 1371 | + updateDeviceColors(obj); | ||
| 1372 | + updateDetailPanel(); | ||
| 1373 | + } | ||
| 1374 | + | ||
| 1375 | + function deselectObject(id) { | ||
| 1376 | + var obj = selections[id]; | ||
| 1377 | + if (obj) { | ||
| 1378 | + d3.select(obj.el).classed('selected', false); | ||
| 1379 | + delete selections[id]; | ||
| 1380 | + fs.removeFromArray(id, selectOrder); | ||
| 1381 | + updateDeviceColors(obj.obj); | ||
| 1382 | + } | ||
| 1383 | + } | ||
| 1384 | + | ||
| 1385 | + function deselectAll() { | ||
| 1386 | + // deselect all nodes in the network... | ||
| 1387 | + node.classed('selected', false); | ||
| 1388 | + selections = {}; | ||
| 1389 | + selectOrder = []; | ||
| 1390 | + updateDeviceColors(); | ||
| 1391 | + updateDetailPanel(); | ||
| 1392 | + } | ||
| 1393 | + | ||
| 1326 | // ========================== | 1394 | // ========================== |
| 1327 | // === MOUSE GESTURE HANDLERS | 1395 | // === MOUSE GESTURE HANDLERS |
| 1328 | 1396 | ||
| 1329 | - function selectCb(d) { | 1397 | + function zoomingOrPanning(ev) { |
| 1330 | - // this is the selected node | 1398 | + return ev.metaKey || ev.altKey; |
| 1331 | - $log.debug("\n\n\nSelect Object: "); | ||
| 1332 | - $log.debug("d is ", d); | ||
| 1333 | - $log.debug("this is ", this); | ||
| 1334 | - $log.debug('\n\n'); | ||
| 1335 | } | 1399 | } |
| 1336 | 1400 | ||
| 1337 | function atDragEnd(d) { | 1401 | function atDragEnd(d) { |
| ... | @@ -1345,8 +1409,7 @@ | ... | @@ -1345,8 +1409,7 @@ |
| 1345 | function dragEnabled() { | 1409 | function dragEnabled() { |
| 1346 | var ev = d3.event.sourceEvent; | 1410 | var ev = d3.event.sourceEvent; |
| 1347 | // nodeLock means we aren't allowing nodes to be dragged... | 1411 | // nodeLock means we aren't allowing nodes to be dragged... |
| 1348 | - // meta or alt key pressed means we are zooming/panning... | 1412 | + return !nodeLock && !zoomingOrPanning(ev); |
| 1349 | - return !nodeLock && !(ev.metaKey || ev.altKey); | ||
| 1350 | } | 1413 | } |
| 1351 | 1414 | ||
| 1352 | // predicate that indicates when clicking is active | 1415 | // predicate that indicates when clicking is active |
| ... | @@ -1406,7 +1469,7 @@ | ... | @@ -1406,7 +1469,7 @@ |
| 1406 | .on('tick', tick); | 1469 | .on('tick', tick); |
| 1407 | 1470 | ||
| 1408 | drag = sus.createDragBehavior(force, | 1471 | drag = sus.createDragBehavior(force, |
| 1409 | - selectCb, atDragEnd, dragEnabled, clickEnabled); | 1472 | + selectObject, atDragEnd, dragEnabled, clickEnabled); |
| 1410 | } | 1473 | } |
| 1411 | 1474 | ||
| 1412 | function resize(dim) { | 1475 | function resize(dim) { | ... | ... |
| ... | @@ -201,7 +201,8 @@ describe('factory: fw/util/fn.js', function() { | ... | @@ -201,7 +201,8 @@ describe('factory: fw/util/fn.js', function() { |
| 201 | it('should define api functions', function () { | 201 | it('should define api functions', function () { |
| 202 | expect(fs.areFunctions(fs, [ | 202 | expect(fs.areFunctions(fs, [ |
| 203 | 'isF', 'isA', 'isS', 'isO', 'contains', | 203 | 'isF', 'isA', 'isS', 'isO', 'contains', |
| 204 | - 'areFunctions', 'areFunctionsNonStrict', 'windowSize', 'find' | 204 | + 'areFunctions', 'areFunctionsNonStrict', 'windowSize', 'find', |
| 205 | + 'inArray', 'removeFromArray' | ||
| 205 | ])).toBeTruthy(); | 206 | ])).toBeTruthy(); |
| 206 | }); | 207 | }); |
| 207 | 208 | ||
| ... | @@ -260,4 +261,68 @@ describe('factory: fw/util/fn.js', function() { | ... | @@ -260,4 +261,68 @@ describe('factory: fw/util/fn.js', function() { |
| 260 | it('should find Zevvv', function () { | 261 | it('should find Zevvv', function () { |
| 261 | expect(fs.find('Zevvv', dataset, 'name')).toEqual(4); | 262 | expect(fs.find('Zevvv', dataset, 'name')).toEqual(4); |
| 262 | }); | 263 | }); |
| 264 | + | ||
| 265 | + | ||
| 266 | + // === Tests for inArray() | ||
| 267 | + var objRef = { x:1, y:2 }, | ||
| 268 | + array = [1, 3.14, 'hey', objRef, 'there', true], | ||
| 269 | + array2 = ['b', 'a', 'd', 'a', 's', 's']; | ||
| 270 | + | ||
| 271 | + it('should return -1 on non-arrays', function () { | ||
| 272 | + expect(fs.inArray(1, {x:1})).toEqual(-1); | ||
| 273 | + }); | ||
| 274 | + it('should not find HOO', function () { | ||
| 275 | + expect(fs.inArray('HOO', array)).toEqual(-1); | ||
| 276 | + }); | ||
| 277 | + it('should find 1', function () { | ||
| 278 | + expect(fs.inArray(1, array)).toEqual(0); | ||
| 279 | + }); | ||
| 280 | + it('should find pi', function () { | ||
| 281 | + expect(fs.inArray(3.14, array)).toEqual(1); | ||
| 282 | + }); | ||
| 283 | + it('should find hey', function () { | ||
| 284 | + expect(fs.inArray('hey', array)).toEqual(2); | ||
| 285 | + }); | ||
| 286 | + it('should find the object', function () { | ||
| 287 | + expect(fs.inArray(objRef, array)).toEqual(3); | ||
| 288 | + }); | ||
| 289 | + it('should find there', function () { | ||
| 290 | + expect(fs.inArray('there', array)).toEqual(4); | ||
| 291 | + }); | ||
| 292 | + it('should find true', function () { | ||
| 293 | + expect(fs.inArray(true, array)).toEqual(5); | ||
| 294 | + }); | ||
| 295 | + | ||
| 296 | + it('should find the first occurrence A', function () { | ||
| 297 | + expect(fs.inArray('a', array2)).toEqual(1); | ||
| 298 | + }); | ||
| 299 | + it('should find the first occurrence S', function () { | ||
| 300 | + expect(fs.inArray('s', array2)).toEqual(4); | ||
| 301 | + }); | ||
| 302 | + it('should not find X', function () { | ||
| 303 | + expect(fs.inArray('x', array2)).toEqual(-1); | ||
| 304 | + }); | ||
| 305 | + | ||
| 306 | + // === Tests for removeFromArray() | ||
| 307 | + it('should ignore non-arrays', function () { | ||
| 308 | + expect(fs.removeFromArray(1, {x:1})).toBe(false); | ||
| 309 | + }); | ||
| 310 | + it('should keep the array the same, for non-match', function () { | ||
| 311 | + var array = [1, 2, 3]; | ||
| 312 | + expect(fs.removeFromArray(4, array)).toBe(false); | ||
| 313 | + expect(array).toEqual([1, 2, 3]); | ||
| 314 | + }); | ||
| 315 | + it('should remove a value', function () { | ||
| 316 | + var array = [1, 2, 3]; | ||
| 317 | + expect(fs.removeFromArray(2, array)).toBe(true); | ||
| 318 | + expect(array).toEqual([1, 3]); | ||
| 319 | + }); | ||
| 320 | + it('should remove the first occurrence', function () { | ||
| 321 | + var array = ['x', 'y', 'z', 'z', 'y']; | ||
| 322 | + expect(fs.removeFromArray('y', array)).toBe(true); | ||
| 323 | + expect(array).toEqual(['x', 'z', 'z', 'y']); | ||
| 324 | + expect(fs.removeFromArray('x', array)).toBe(true); | ||
| 325 | + expect(array).toEqual(['z', 'z', 'y']); | ||
| 326 | + }); | ||
| 327 | + | ||
| 263 | }); | 328 | }); | ... | ... |
-
Please register or login to post a comment