Adding ability to select geo map from the GUI.
Change-Id: I956238500f868ef59bf947cb9f0aa7fc71d3fe84
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/MapSelectorMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/MapSelectorMessageHandler.java
new file mode 100644
index 0000000..537b288
--- /dev/null
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/MapSelectorMessageHandler.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 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.
+ */
+
+package org.onosproject.ui.impl;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.ui.RequestHandler;
+import org.onosproject.ui.UiMessageHandler;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Message handler for map selection functionality.
+ */
+class MapSelectorMessageHandler extends UiMessageHandler {
+
+ private static final String MAP_LIST_REQ = "mapSelectorRequest";
+ private static final String MAP_LIST_RESP = "mapSelectorResponse";
+
+ private static final String ORDER = "order";
+ private static final String MAPS = "maps";
+ private static final String MAP_ID = "id";
+ private static final String DESCRIPTION = "description";
+ private static final String SCALE = "scale";
+
+ private static final List<Map> SUPPORTED_MAPS =
+ ImmutableList.of(new Map("australia", "Australia", 1.0),
+ new Map("ns_america", "North, Central and South America", 0.7),
+ new Map("s_america", "South America", 0.9),
+ new Map("usa", "United States", 1.0),
+ new Map("bayarea", "Bay Area, California", 1.0),
+ new Map("europe", "Europe", 2.5),
+ new Map("italy", "Italy", 0.8),
+ new Map("uk", "United Kingdom and Ireland", 0.6),
+ new Map("japan", "Japan", 0.8),
+ new Map("s_korea", "South Korea", 0.75),
+ new Map("taiwan", "Taiwan", 0.7),
+ new Map("world", "World", 1.0));
+
+ @Override
+ protected Collection<RequestHandler> createRequestHandlers() {
+ return ImmutableSet.of(
+ new MapListHandler()
+ );
+ }
+
+ private final class MapListHandler extends RequestHandler {
+ private MapListHandler() {
+ super(MAP_LIST_REQ);
+ }
+
+ @Override
+ public void process(long sid, ObjectNode payload) {
+ sendMessage(MAP_LIST_RESP, 0, mapsJson());
+ }
+ }
+
+ private ObjectNode mapsJson() {
+ ObjectNode payload = objectNode();
+ ArrayNode order = arrayNode();
+ ObjectNode maps = objectNode();
+ payload.set(ORDER, order);
+ payload.set(MAPS, maps);
+ SUPPORTED_MAPS.forEach(m -> {
+ maps.set(m.id, objectNode().put(MAP_ID, m.id)
+ .put(DESCRIPTION, m.description)
+ .put(SCALE, m.scale));
+ order.add(m.id);
+ });
+ return payload;
+ }
+
+ private static final class Map {
+ private final String id;
+ private final String description;
+ private final double scale;
+
+ private Map(String id, String description, double scale) {
+ this.id = id;
+ this.description = description;
+ this.scale = scale;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
index f402298..5006e76 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
@@ -137,6 +137,7 @@
() -> ImmutableList.of(
new UserPreferencesMessageHandler(),
new TopologyViewMessageHandler(),
+ new MapSelectorMessageHandler(),
new DeviceViewMessageHandler(),
new LinkViewMessageHandler(),
new HostViewMessageHandler(),
diff --git a/web/gui/src/main/webapp/app/fw/svg/map.js b/web/gui/src/main/webapp/app/fw/svg/map.js
index a74f95d..aadb693 100644
--- a/web/gui/src/main/webapp/app/fw/svg/map.js
+++ b/web/gui/src/main/webapp/app/fw/svg/map.js
@@ -118,20 +118,21 @@
function reshade(sh) {
var p = sh && sh.palette,
- svg, paths, stroke, fill, bg;
+ paths, stroke, fill, bg,
+ svg = d3.select('#ov-topo').select('svg');
if (sh) {
stroke = p.outline;
fill = sh.flip ? p.sea : p.land;
bg = sh.flip ? p.land : p.sea;
- svg = d3.select('#ov-topo').select('svg');
paths = d3.select('#topo-map').selectAll('path');
-
svg.style('background-color', bg);
paths.attr({
stroke: stroke,
fill: fill
});
+ } else {
+ svg.style('background-color', null);
}
}
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.css b/web/gui/src/main/webapp/app/view/topo/topo.css
index ceb0e4b..c2b81f3 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.css
+++ b/web/gui/src/main/webapp/app/view/topo/topo.css
@@ -771,3 +771,11 @@
visibility: hidden;
}
+.map-list {
+ padding: 10px;
+}
+
+.map-list select {
+ font-size: 20px;
+}
+
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js
index b6c83ce..7de4cd1 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -29,8 +29,8 @@
];
// references to injected services
- var $scope, $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps, th,
- tds, t3s, tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs, tspr,
+ var $scope, $log, $cookies, $loc, fs, ks, zs, gs, ms, sus, flash, wss, ps, th,
+ tds, t3s, tes, tfs, tps, tis, tms, tss, tls, tts, tos, fltr, ttbs, tspr,
ttip, tov;
// DOM elements
@@ -53,7 +53,8 @@
M: [toggleOffline, 'Toggle offline visibility'],
P: [togglePorts, 'Toggle Port Highlighting'],
dash: [tfs.showBadLinks, 'Show bad links'],
- B: [toggleMap, 'Toggle background map'],
+ B: [toggleMap, 'Toggle background geo map'],
+ G: [openMapSelection, 'Select background geo map'],
S: [toggleSprites, 'Toggle sprite layer'],
X: [tfs.resetAllLocations, 'Reset node locations'],
@@ -78,7 +79,7 @@
_keyListener: ttbs.keyListener,
_helpFormat: [
- ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B', 'S' ],
+ ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B', 'G', 'S' ],
['X', 'Z', 'N', 'L', 'U', 'R', '-', 'E', '-', 'dot'],
[] // this column reserved for overlay actions
]
@@ -157,6 +158,10 @@
_togSvgLayer(x, mapG, 'bg', 'background map');
}
+ function openMapSelection() {
+ tms.openMapSelection();
+ }
+
function toggleSprites(x) {
_togSvgLayer(x, spriteG, 'spr', 'sprite layer');
}
@@ -368,12 +373,22 @@
} : '';
}
+ function setMap(map) {
+ ps.setPrefs('topo_mapid', map);
+ setUpMap($loc);
+ opacifyMap(true);
+ }
+
+ function currentMap() {
+ return ps.getPrefs(
+ 'topo_mapid',
+ { mapid: 'usa', mapscale: 1, tint: 'off'},
+ $loc.search()
+ );
+ }
+
function setUpMap($loc) {
- var prefs = ps.getPrefs(
- 'topo_mapid',
- { mapid: 'usa', mapscale: 1, tint: 'off'},
- $loc.search()
- ),
+ var prefs = currentMap(),
mapId = prefs.mapid,
mapScale = prefs.mapscale,
tint = prefs.tint,
@@ -385,7 +400,14 @@
$log.debug('setUpMap() mapId:', mapId, ', mapScale:', mapScale,
', tint:', tint);
- mapG = zoomLayer.append('g').attr('id', 'topo-map');
+ mapG = d3.select('#topo-map');
+ if (mapG.empty()) {
+ mapG = zoomLayer.append('g').attr('id', 'topo-map');
+ } else {
+ mapG.each(function(d,i) {
+ d3.selectAll(this.childNodes).remove();
+ });
+ }
if (mapId === 'usa') {
shadeFlip = 0;
promise = ms.loadMapInto(mapG, '*continental_us', {
@@ -508,15 +530,15 @@
'TopoEventService', 'TopoForceService', 'TopoPanelService',
'TopoInstService', 'TopoSelectService', 'TopoLinkService',
'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService',
- 'TopoToolbarService', 'TopoSpriteService', 'TooltipService',
- 'TopoOverlayService',
+ 'TopoToolbarService', 'TopoMapService', 'TopoSpriteService',
+ 'TooltipService', 'TopoOverlayService',
- function (_$scope_, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_,
+ function (_$scope_, _$log_, _$loc_, $timeout, _$cookies_, _fs_, mast, _ks_,
_zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _th_,
_tds_, _t3s_, _tes_,
_tfs_, _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_,
- _ttbs_, _tspr_, _ttip_, _tov_) {
- var params = $loc.search(),
+ _ttbs_, _tms_, _tspr_, _ttip_, _tov_) {
+ var params = _$loc_.search(),
projection,
dim,
uplink = {
@@ -531,6 +553,7 @@
$scope = _$scope_;
$log = _$log_;
+ $loc = _$loc_;
$cookies = _$cookies_;
fs = _fs_;
ks = _ks_;
@@ -551,6 +574,7 @@
// just so we can invoke functions on them.
tps = _tps_;
tis = _tis_;
+ tms = _tms_;
tss = _tss_;
tls = _tls_;
tts = _tts_;
@@ -561,6 +585,12 @@
ttip = _ttip_;
tov = _tov_;
+ tms.start({
+ toggleMap: toggleMap,
+ currentMap: currentMap,
+ setMap: setMap
+ });
+
if (params.intentKey && params.intentAppId && params.intentAppName) {
$scope.intentData = {
key: params.intentKey,
@@ -577,6 +607,7 @@
$scope.$on('$destroy', function () {
$log.log('OvTopoCtrl is saying Buh-Bye!');
tes.stop();
+ tms.stop();
ks.unbindKeys();
tps.destroyPanels();
tds.closeDialog();
diff --git a/web/gui/src/main/webapp/app/view/topo/topoMap.js b/web/gui/src/main/webapp/app/view/topo/topoMap.js
new file mode 100644
index 0000000..407d394
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo/topoMap.js
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2016 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 -- Topology Map Module.
+ Defines behavior for loading geographical maps into the map layer.
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, $loc, fs, flash, wss, tds, delegate;
+
+ // constants
+ var mapRequest = 'mapSelectorRequest';
+
+ // internal state
+ var order, maps, map, mapItems, tintCheck, msgHandlers;
+
+ // === ---------------------------
+ // === Helper functions
+
+
+ // === ---------------------------
+ // === Main API functions
+
+ function openMapSelection() {
+ wss.sendEvent(mapRequest);
+ }
+
+ function closeMapSelection() {
+ tds.closeDialog();
+ }
+
+ function start(d) {
+ delegate = d;
+ wss.bindHandlers(msgHandlers);
+ }
+
+ function stop() {
+ wss.unbindHandlers(msgHandlers);
+ }
+
+ function dOk() {
+ var p = {
+ mapid: map.id,
+ mapscale: map.scale,
+ tint: tintCheck.property('checked') ? 'on' : 'off'
+ };
+ setMap(p);
+ $log.debug('Dialog OK button clicked');
+ }
+
+ function dClose() {
+ $log.debug('Dialog Close button clicked (or Esc pressed)');
+ }
+
+ function selectMap() {
+ map = maps[this.options[this.selectedIndex].value];
+ $log.info('Selected map', map);
+ }
+
+ function createListContent() {
+ var content = tds.createDiv('map-list'),
+ form = content.append('form'),
+ current = currentMap();
+ map = maps[current.mapid];
+ mapItems = form.append('select').on('change', selectMap);
+ order.forEach(function (id) {
+ var m = maps[id];
+ mapItems.append('option')
+ .attr('value', m.id)
+ .attr('selected', m.id === current.mapid ? true : null)
+ .text(m.description);
+ });
+ var p = form.append('p');
+ tintCheck = p.append('input').attr('type', 'checkbox').attr('name', 'tint');
+ if (current.tint == 'on') {
+ tintCheck.attr('checked', 'true');
+ }
+ p.append('span').text('Enable map tint');
+ return content;
+ }
+
+ function handleMapResponse(data) {
+ $log.info('Got response', data);
+ order = data.order;
+ maps = data.maps;
+ tds.openDialog()
+ .setTitle('Select Map')
+ .addContent(createListContent())
+ .addOk(dOk, 'OK')
+ .addCancel(dClose, 'Close')
+ .bindKeys();
+ }
+
+ function toggleMap() {
+ delegate.toggleMap();
+ }
+
+ function currentMap() {
+ return delegate.currentMap();
+ }
+
+ function setMap(map) {
+ delegate.setMap(map);
+ }
+
+ // === -----------------------------------------------------
+ // === MODULE DEFINITION ===
+
+ angular.module('ovTopo')
+ .factory('TopoMapService',
+ ['$log', '$location', 'FnService', 'FlashService', 'WebSocketService',
+ 'TopoDialogService',
+
+ function (_$log_, _$loc_, _fs_, _flash_, _wss_, _tds_) {
+ $log = _$log_;
+ $loc = _$loc_;
+ fs = _fs_;
+ flash = _flash_;
+ wss = _wss_;
+ tds = _tds_;
+
+ msgHandlers = {
+ mapSelectorResponse: handleMapResponse
+ };
+
+ return {
+ toggleMap: toggleMap,
+ currentMap: currentMap,
+ setMap: setMap,
+
+ openMapSelection: openMapSelection,
+ closeMapSelection: closeMapSelection,
+ start: start,
+ stop: stop
+ };
+ }]);
+
+}());
diff --git a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
index 535cd17..f2ea324 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
@@ -49,6 +49,7 @@
M: { id: 'offline-tog', gid: 'switch', isel: true },
P: { id: 'ports-tog', gid: 'ports', isel: true },
B: { id: 'bkgrnd-tog', gid: 'map', isel: false },
+ G: { id: 'bkgrnd-sel', gid: 'filters' },
S: { id: 'sprite-tog', gid: 'cloud', isel: false },
// TODO: add reset-node-locations button to toolbar
@@ -151,6 +152,7 @@
addToggle('M');
addToggle('P', true);
addToggle('B');
+ addButton('G');
addToggle('S', true);
}
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 1a645ad..52f6c2b 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -122,6 +122,7 @@
<script src="app/view/topo/topoOverlay.js"></script>
<script src="app/view/topo/topoPanel.js"></script>
<script src="app/view/topo/topoSelect.js"></script>
+ <script src="app/view/topo/topoMap.js"></script>
<script src="app/view/topo/topoSprite.js"></script>
<script src="app/view/topo/topoTraffic.js"></script>
<script src="app/view/topo/topoTrafficNew.js"></script>