Thomas Vachuska
Committed by Gerrit Code Review

Adding ability to select geo map from the GUI.

Change-Id: I956238500f868ef59bf947cb9f0aa7fc71d3fe84
...@@ -56,6 +56,7 @@ public abstract class UiMessageHandler { ...@@ -56,6 +56,7 @@ public abstract class UiMessageHandler {
56 56
57 private final Logger log = LoggerFactory.getLogger(getClass()); 57 private final Logger log = LoggerFactory.getLogger(getClass());
58 private final Map<String, RequestHandler> handlerMap = new HashMap<>(); 58 private final Map<String, RequestHandler> handlerMap = new HashMap<>();
59 +
59 private final ObjectMapper mapper = new ObjectMapper(); 60 private final ObjectMapper mapper = new ObjectMapper();
60 61
61 private UiConnection connection; 62 private UiConnection connection;
......
1 +/*
2 + * Copyright 2016 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 +package org.onosproject.ui.impl;
18 +
19 +import com.fasterxml.jackson.databind.node.ArrayNode;
20 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 +import com.google.common.collect.ImmutableList;
22 +import com.google.common.collect.ImmutableSet;
23 +import org.onosproject.ui.RequestHandler;
24 +import org.onosproject.ui.UiMessageHandler;
25 +
26 +import java.util.Collection;
27 +import java.util.List;
28 +
29 +/**
30 + * Message handler for map selection functionality.
31 + */
32 +class MapSelectorMessageHandler extends UiMessageHandler {
33 +
34 + private static final String MAP_LIST_REQ = "mapSelectorRequest";
35 + private static final String MAP_LIST_RESP = "mapSelectorResponse";
36 +
37 + private static final String ORDER = "order";
38 + private static final String MAPS = "maps";
39 + private static final String MAP_ID = "id";
40 + private static final String DESCRIPTION = "description";
41 + private static final String SCALE = "scale";
42 +
43 + private static final List<Map> SUPPORTED_MAPS =
44 + ImmutableList.of(new Map("australia", "Australia", 1.0),
45 + new Map("ns_america", "North, Central and South America", 0.7),
46 + new Map("s_america", "South America", 0.9),
47 + new Map("usa", "United States", 1.0),
48 + new Map("bayarea", "Bay Area, California", 1.0),
49 + new Map("europe", "Europe", 2.5),
50 + new Map("italy", "Italy", 0.8),
51 + new Map("uk", "United Kingdom and Ireland", 0.6),
52 + new Map("japan", "Japan", 0.8),
53 + new Map("s_korea", "South Korea", 0.75),
54 + new Map("taiwan", "Taiwan", 0.7),
55 + new Map("world", "World", 1.0));
56 +
57 + @Override
58 + protected Collection<RequestHandler> createRequestHandlers() {
59 + return ImmutableSet.of(
60 + new MapListHandler()
61 + );
62 + }
63 +
64 + private final class MapListHandler extends RequestHandler {
65 + private MapListHandler() {
66 + super(MAP_LIST_REQ);
67 + }
68 +
69 + @Override
70 + public void process(long sid, ObjectNode payload) {
71 + sendMessage(MAP_LIST_RESP, 0, mapsJson());
72 + }
73 + }
74 +
75 + private ObjectNode mapsJson() {
76 + ObjectNode payload = objectNode();
77 + ArrayNode order = arrayNode();
78 + ObjectNode maps = objectNode();
79 + payload.set(ORDER, order);
80 + payload.set(MAPS, maps);
81 + SUPPORTED_MAPS.forEach(m -> {
82 + maps.set(m.id, objectNode().put(MAP_ID, m.id)
83 + .put(DESCRIPTION, m.description)
84 + .put(SCALE, m.scale));
85 + order.add(m.id);
86 + });
87 + return payload;
88 + }
89 +
90 + private static final class Map {
91 + private final String id;
92 + private final String description;
93 + private final double scale;
94 +
95 + private Map(String id, String description, double scale) {
96 + this.id = id;
97 + this.description = description;
98 + this.scale = scale;
99 + }
100 + }
101 +
102 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -137,6 +137,7 @@ public class UiExtensionManager ...@@ -137,6 +137,7 @@ public class UiExtensionManager
137 () -> ImmutableList.of( 137 () -> ImmutableList.of(
138 new UserPreferencesMessageHandler(), 138 new UserPreferencesMessageHandler(),
139 new TopologyViewMessageHandler(), 139 new TopologyViewMessageHandler(),
140 + new MapSelectorMessageHandler(),
140 new DeviceViewMessageHandler(), 141 new DeviceViewMessageHandler(),
141 new LinkViewMessageHandler(), 142 new LinkViewMessageHandler(),
142 new HostViewMessageHandler(), 143 new HostViewMessageHandler(),
......
...@@ -118,20 +118,21 @@ ...@@ -118,20 +118,21 @@
118 118
119 function reshade(sh) { 119 function reshade(sh) {
120 var p = sh && sh.palette, 120 var p = sh && sh.palette,
121 - svg, paths, stroke, fill, bg; 121 + paths, stroke, fill, bg,
122 + svg = d3.select('#ov-topo').select('svg');
122 if (sh) { 123 if (sh) {
123 stroke = p.outline; 124 stroke = p.outline;
124 fill = sh.flip ? p.sea : p.land; 125 fill = sh.flip ? p.sea : p.land;
125 bg = sh.flip ? p.land : p.sea; 126 bg = sh.flip ? p.land : p.sea;
126 127
127 - svg = d3.select('#ov-topo').select('svg');
128 paths = d3.select('#topo-map').selectAll('path'); 128 paths = d3.select('#topo-map').selectAll('path');
129 -
130 svg.style('background-color', bg); 129 svg.style('background-color', bg);
131 paths.attr({ 130 paths.attr({
132 stroke: stroke, 131 stroke: stroke,
133 fill: fill 132 fill: fill
134 }); 133 });
134 + } else {
135 + svg.style('background-color', null);
135 } 136 }
136 } 137 }
137 138
......
...@@ -771,3 +771,11 @@ html[data-platform='iPad'] #topo-p-detail { ...@@ -771,3 +771,11 @@ html[data-platform='iPad'] #topo-p-detail {
771 visibility: hidden; 771 visibility: hidden;
772 } 772 }
773 773
774 +.map-list {
775 + padding: 10px;
776 +}
777 +
778 +.map-list select {
779 + font-size: 20px;
780 +}
781 +
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
29 ]; 29 ];
30 30
31 // references to injected services 31 // references to injected services
32 - var $scope, $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps, th, 32 + var $scope, $log, $cookies, $loc, fs, ks, zs, gs, ms, sus, flash, wss, ps, th,
33 - tds, t3s, tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs, tspr, 33 + tds, t3s, tes, tfs, tps, tis, tms, tss, tls, tts, tos, fltr, ttbs, tspr,
34 ttip, tov; 34 ttip, tov;
35 35
36 // DOM elements 36 // DOM elements
...@@ -53,7 +53,8 @@ ...@@ -53,7 +53,8 @@
53 M: [toggleOffline, 'Toggle offline visibility'], 53 M: [toggleOffline, 'Toggle offline visibility'],
54 P: [togglePorts, 'Toggle Port Highlighting'], 54 P: [togglePorts, 'Toggle Port Highlighting'],
55 dash: [tfs.showBadLinks, 'Show bad links'], 55 dash: [tfs.showBadLinks, 'Show bad links'],
56 - B: [toggleMap, 'Toggle background map'], 56 + B: [toggleMap, 'Toggle background geo map'],
57 + G: [openMapSelection, 'Select background geo map'],
57 S: [toggleSprites, 'Toggle sprite layer'], 58 S: [toggleSprites, 'Toggle sprite layer'],
58 59
59 X: [tfs.resetAllLocations, 'Reset node locations'], 60 X: [tfs.resetAllLocations, 'Reset node locations'],
...@@ -78,7 +79,7 @@ ...@@ -78,7 +79,7 @@
78 _keyListener: ttbs.keyListener, 79 _keyListener: ttbs.keyListener,
79 80
80 _helpFormat: [ 81 _helpFormat: [
81 - ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B', 'S' ], 82 + ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B', 'G', 'S' ],
82 ['X', 'Z', 'N', 'L', 'U', 'R', '-', 'E', '-', 'dot'], 83 ['X', 'Z', 'N', 'L', 'U', 'R', '-', 'E', '-', 'dot'],
83 [] // this column reserved for overlay actions 84 [] // this column reserved for overlay actions
84 ] 85 ]
...@@ -157,6 +158,10 @@ ...@@ -157,6 +158,10 @@
157 _togSvgLayer(x, mapG, 'bg', 'background map'); 158 _togSvgLayer(x, mapG, 'bg', 'background map');
158 } 159 }
159 160
161 + function openMapSelection() {
162 + tms.openMapSelection();
163 + }
164 +
160 function toggleSprites(x) { 165 function toggleSprites(x) {
161 _togSvgLayer(x, spriteG, 'spr', 'sprite layer'); 166 _togSvgLayer(x, spriteG, 'spr', 'sprite layer');
162 } 167 }
...@@ -368,12 +373,22 @@ ...@@ -368,12 +373,22 @@
368 } : ''; 373 } : '';
369 } 374 }
370 375
376 + function setMap(map) {
377 + ps.setPrefs('topo_mapid', map);
378 + setUpMap($loc);
379 + opacifyMap(true);
380 + }
381 +
382 + function currentMap() {
383 + return ps.getPrefs(
384 + 'topo_mapid',
385 + { mapid: 'usa', mapscale: 1, tint: 'off'},
386 + $loc.search()
387 + );
388 + }
389 +
371 function setUpMap($loc) { 390 function setUpMap($loc) {
372 - var prefs = ps.getPrefs( 391 + var prefs = currentMap(),
373 - 'topo_mapid',
374 - { mapid: 'usa', mapscale: 1, tint: 'off'},
375 - $loc.search()
376 - ),
377 mapId = prefs.mapid, 392 mapId = prefs.mapid,
378 mapScale = prefs.mapscale, 393 mapScale = prefs.mapscale,
379 tint = prefs.tint, 394 tint = prefs.tint,
...@@ -385,7 +400,14 @@ ...@@ -385,7 +400,14 @@
385 $log.debug('setUpMap() mapId:', mapId, ', mapScale:', mapScale, 400 $log.debug('setUpMap() mapId:', mapId, ', mapScale:', mapScale,
386 ', tint:', tint); 401 ', tint:', tint);
387 402
388 - mapG = zoomLayer.append('g').attr('id', 'topo-map'); 403 + mapG = d3.select('#topo-map');
404 + if (mapG.empty()) {
405 + mapG = zoomLayer.append('g').attr('id', 'topo-map');
406 + } else {
407 + mapG.each(function(d,i) {
408 + d3.selectAll(this.childNodes).remove();
409 + });
410 + }
389 if (mapId === 'usa') { 411 if (mapId === 'usa') {
390 shadeFlip = 0; 412 shadeFlip = 0;
391 promise = ms.loadMapInto(mapG, '*continental_us', { 413 promise = ms.loadMapInto(mapG, '*continental_us', {
...@@ -508,15 +530,15 @@ ...@@ -508,15 +530,15 @@
508 'TopoEventService', 'TopoForceService', 'TopoPanelService', 530 'TopoEventService', 'TopoForceService', 'TopoPanelService',
509 'TopoInstService', 'TopoSelectService', 'TopoLinkService', 531 'TopoInstService', 'TopoSelectService', 'TopoLinkService',
510 'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService', 532 'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService',
511 - 'TopoToolbarService', 'TopoSpriteService', 'TooltipService', 533 + 'TopoToolbarService', 'TopoMapService', 'TopoSpriteService',
512 - 'TopoOverlayService', 534 + 'TooltipService', 'TopoOverlayService',
513 535
514 - function (_$scope_, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_, 536 + function (_$scope_, _$log_, _$loc_, $timeout, _$cookies_, _fs_, mast, _ks_,
515 _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _th_, 537 _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _th_,
516 _tds_, _t3s_, _tes_, 538 _tds_, _t3s_, _tes_,
517 _tfs_, _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, 539 _tfs_, _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_,
518 - _ttbs_, _tspr_, _ttip_, _tov_) { 540 + _ttbs_, _tms_, _tspr_, _ttip_, _tov_) {
519 - var params = $loc.search(), 541 + var params = _$loc_.search(),
520 projection, 542 projection,
521 dim, 543 dim,
522 uplink = { 544 uplink = {
...@@ -531,6 +553,7 @@ ...@@ -531,6 +553,7 @@
531 553
532 $scope = _$scope_; 554 $scope = _$scope_;
533 $log = _$log_; 555 $log = _$log_;
556 + $loc = _$loc_;
534 $cookies = _$cookies_; 557 $cookies = _$cookies_;
535 fs = _fs_; 558 fs = _fs_;
536 ks = _ks_; 559 ks = _ks_;
...@@ -551,6 +574,7 @@ ...@@ -551,6 +574,7 @@
551 // just so we can invoke functions on them. 574 // just so we can invoke functions on them.
552 tps = _tps_; 575 tps = _tps_;
553 tis = _tis_; 576 tis = _tis_;
577 + tms = _tms_;
554 tss = _tss_; 578 tss = _tss_;
555 tls = _tls_; 579 tls = _tls_;
556 tts = _tts_; 580 tts = _tts_;
...@@ -561,6 +585,12 @@ ...@@ -561,6 +585,12 @@
561 ttip = _ttip_; 585 ttip = _ttip_;
562 tov = _tov_; 586 tov = _tov_;
563 587
588 + tms.start({
589 + toggleMap: toggleMap,
590 + currentMap: currentMap,
591 + setMap: setMap
592 + });
593 +
564 if (params.intentKey && params.intentAppId && params.intentAppName) { 594 if (params.intentKey && params.intentAppId && params.intentAppName) {
565 $scope.intentData = { 595 $scope.intentData = {
566 key: params.intentKey, 596 key: params.intentKey,
...@@ -577,6 +607,7 @@ ...@@ -577,6 +607,7 @@
577 $scope.$on('$destroy', function () { 607 $scope.$on('$destroy', function () {
578 $log.log('OvTopoCtrl is saying Buh-Bye!'); 608 $log.log('OvTopoCtrl is saying Buh-Bye!');
579 tes.stop(); 609 tes.stop();
610 + tms.stop();
580 ks.unbindKeys(); 611 ks.unbindKeys();
581 tps.destroyPanels(); 612 tps.destroyPanels();
582 tds.closeDialog(); 613 tds.closeDialog();
......
1 +/*
2 + * Copyright 2016 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 -- Topology Map Module.
19 + Defines behavior for loading geographical maps into the map layer.
20 + */
21 +
22 +(function () {
23 + 'use strict';
24 +
25 + // injected refs
26 + var $log, $loc, fs, flash, wss, tds, delegate;
27 +
28 + // constants
29 + var mapRequest = 'mapSelectorRequest';
30 +
31 + // internal state
32 + var order, maps, map, mapItems, tintCheck, msgHandlers;
33 +
34 + // === ---------------------------
35 + // === Helper functions
36 +
37 +
38 + // === ---------------------------
39 + // === Main API functions
40 +
41 + function openMapSelection() {
42 + wss.sendEvent(mapRequest);
43 + }
44 +
45 + function closeMapSelection() {
46 + tds.closeDialog();
47 + }
48 +
49 + function start(d) {
50 + delegate = d;
51 + wss.bindHandlers(msgHandlers);
52 + }
53 +
54 + function stop() {
55 + wss.unbindHandlers(msgHandlers);
56 + }
57 +
58 + function dOk() {
59 + var p = {
60 + mapid: map.id,
61 + mapscale: map.scale,
62 + tint: tintCheck.property('checked') ? 'on' : 'off'
63 + };
64 + setMap(p);
65 + $log.debug('Dialog OK button clicked');
66 + }
67 +
68 + function dClose() {
69 + $log.debug('Dialog Close button clicked (or Esc pressed)');
70 + }
71 +
72 + function selectMap() {
73 + map = maps[this.options[this.selectedIndex].value];
74 + $log.info('Selected map', map);
75 + }
76 +
77 + function createListContent() {
78 + var content = tds.createDiv('map-list'),
79 + form = content.append('form'),
80 + current = currentMap();
81 + map = maps[current.mapid];
82 + mapItems = form.append('select').on('change', selectMap);
83 + order.forEach(function (id) {
84 + var m = maps[id];
85 + mapItems.append('option')
86 + .attr('value', m.id)
87 + .attr('selected', m.id === current.mapid ? true : null)
88 + .text(m.description);
89 + });
90 + var p = form.append('p');
91 + tintCheck = p.append('input').attr('type', 'checkbox').attr('name', 'tint');
92 + if (current.tint == 'on') {
93 + tintCheck.attr('checked', 'true');
94 + }
95 + p.append('span').text('Enable map tint');
96 + return content;
97 + }
98 +
99 + function handleMapResponse(data) {
100 + $log.info('Got response', data);
101 + order = data.order;
102 + maps = data.maps;
103 + tds.openDialog()
104 + .setTitle('Select Map')
105 + .addContent(createListContent())
106 + .addOk(dOk, 'OK')
107 + .addCancel(dClose, 'Close')
108 + .bindKeys();
109 + }
110 +
111 + function toggleMap() {
112 + delegate.toggleMap();
113 + }
114 +
115 + function currentMap() {
116 + return delegate.currentMap();
117 + }
118 +
119 + function setMap(map) {
120 + delegate.setMap(map);
121 + }
122 +
123 + // === -----------------------------------------------------
124 + // === MODULE DEFINITION ===
125 +
126 + angular.module('ovTopo')
127 + .factory('TopoMapService',
128 + ['$log', '$location', 'FnService', 'FlashService', 'WebSocketService',
129 + 'TopoDialogService',
130 +
131 + function (_$log_, _$loc_, _fs_, _flash_, _wss_, _tds_) {
132 + $log = _$log_;
133 + $loc = _$loc_;
134 + fs = _fs_;
135 + flash = _flash_;
136 + wss = _wss_;
137 + tds = _tds_;
138 +
139 + msgHandlers = {
140 + mapSelectorResponse: handleMapResponse
141 + };
142 +
143 + return {
144 + toggleMap: toggleMap,
145 + currentMap: currentMap,
146 + setMap: setMap,
147 +
148 + openMapSelection: openMapSelection,
149 + closeMapSelection: closeMapSelection,
150 + start: start,
151 + stop: stop
152 + };
153 + }]);
154 +
155 +}());
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
49 M: { id: 'offline-tog', gid: 'switch', isel: true }, 49 M: { id: 'offline-tog', gid: 'switch', isel: true },
50 P: { id: 'ports-tog', gid: 'ports', isel: true }, 50 P: { id: 'ports-tog', gid: 'ports', isel: true },
51 B: { id: 'bkgrnd-tog', gid: 'map', isel: false }, 51 B: { id: 'bkgrnd-tog', gid: 'map', isel: false },
52 + G: { id: 'bkgrnd-sel', gid: 'filters' },
52 S: { id: 'sprite-tog', gid: 'cloud', isel: false }, 53 S: { id: 'sprite-tog', gid: 'cloud', isel: false },
53 54
54 // TODO: add reset-node-locations button to toolbar 55 // TODO: add reset-node-locations button to toolbar
...@@ -151,6 +152,7 @@ ...@@ -151,6 +152,7 @@
151 addToggle('M'); 152 addToggle('M');
152 addToggle('P', true); 153 addToggle('P', true);
153 addToggle('B'); 154 addToggle('B');
155 + addButton('G');
154 addToggle('S', true); 156 addToggle('S', true);
155 } 157 }
156 158
......
...@@ -122,6 +122,7 @@ ...@@ -122,6 +122,7 @@
122 <script src="app/view/topo/topoOverlay.js"></script> 122 <script src="app/view/topo/topoOverlay.js"></script>
123 <script src="app/view/topo/topoPanel.js"></script> 123 <script src="app/view/topo/topoPanel.js"></script>
124 <script src="app/view/topo/topoSelect.js"></script> 124 <script src="app/view/topo/topoSelect.js"></script>
125 + <script src="app/view/topo/topoMap.js"></script>
125 <script src="app/view/topo/topoSprite.js"></script> 126 <script src="app/view/topo/topoSprite.js"></script>
126 <script src="app/view/topo/topoTraffic.js"></script> 127 <script src="app/view/topo/topoTraffic.js"></script>
127 <script src="app/view/topo/topoTrafficNew.js"></script> 128 <script src="app/view/topo/topoTrafficNew.js"></script>
......