GUI -- Topo View - Added ability to define different background maps of world regions.
Change-Id: I937106c1c7c9e045230fce88dc7e5a5849b5cb3f
diff --git a/web/gui/src/main/webapp/app/fw/svg/geodata.js b/web/gui/src/main/webapp/app/fw/svg/geodata.js
index bc6b296..6c54bb4 100644
--- a/web/gui/src/main/webapp/app/fw/svg/geodata.js
+++ b/web/gui/src/main/webapp/app/fw/svg/geodata.js
@@ -63,9 +63,109 @@
function getUrl(id) {
if (id[0] === '*') {
- return bundledUrlPrefix + id.slice(1) + '.json';
+ return bundledUrlPrefix + id.slice(1) + '.topojson';
}
- return id + '.json';
+ return id + '.topojson';
+ }
+
+
+ // start afresh...
+ function clearCache() {
+ cache = d3.map();
+ }
+
+ // returns a promise decorated with:
+ // .meta -- id, url, and whether the data was cached
+ // .topodata -- TopoJSON data (on response from server)
+
+ function fetchTopoData(id) {
+ if (!fs.isS(id)) {
+ return null;
+ }
+ var url = getUrl(id),
+ promise = cache.get(id);
+
+ if (!promise) {
+ // need to fetch the data, build the object,
+ // cache it, and return it.
+ promise = $http.get(url);
+
+ promise.meta = {
+ id: id,
+ url: url,
+ wasCached: false
+ };
+
+ promise.then(function (response) {
+ // success
+ promise.topodata = response.data;
+ }, function (response) {
+ // error
+ $log.warn('Failed to retrieve map TopoJSON data: ' + url,
+ response.status, response.data);
+ });
+
+ cache.set(id, promise);
+
+ } else {
+ promise.meta.wasCached = true;
+ }
+
+ return promise;
+ }
+
+ var defaultGenSettings = {
+ objectTag: 'states',
+ projection: d3.geo.mercator(),
+ logicalSize: 1000,
+ mapFillScale: .95
+ };
+
+ // converts given TopoJSON-format data into corresponding GeoJSON
+ // data, and creates a path generator for that data.
+ function createPathGenerator(topoData, opts) {
+ var settings = angular.extend({}, defaultGenSettings, opts),
+ topoObject = topoData.objects[settings.objectTag],
+ geoData = topojson.feature(topoData, topoObject),
+ proj = settings.projection,
+ dim = settings.logicalSize,
+ mfs = settings.mapFillScale,
+ path = d3.geo.path().projection(proj);
+
+ rescaleProjection(proj, mfs, dim, path, geoData);
+
+ // return the results
+ return {
+ geodata: geoData,
+ pathgen: path,
+ settings: settings
+ };
+ }
+
+ function rescaleProjection(proj, mfs, dim, path, geoData) {
+ // adjust projection scale and translation to fill the view
+ // with the map
+
+ // start with unit scale, no translation..
+ proj.scale(1).translate([0, 0]);
+
+ // figure out dimensions of map data..
+ var b = path.bounds(geoData),
+ x1 = b[0][0],
+ y1 = b[0][1],
+ x2 = b[1][0],
+ y2 = b[1][1],
+ dx = x2 - x1,
+ dy = y2 - y1,
+ x = (x1 + x2) / 2,
+ y = (y1 + y2) / 2;
+
+ // size map to 95% of minimum dimension to fill space..
+ var s = mfs / Math.min(dx / dim, dy / dim),
+ t = [dim / 2 - s * x, dim / 2 - s * y];
+
+ // set new scale, translation on the projection..
+ proj.scale(s).translate(t);
}
angular.module('onosSvg')
@@ -75,105 +175,12 @@
$http = _$http_;
fs = _fs_;
- // start afresh...
- function clearCache() {
- cache = d3.map();
- }
-
- // returns a promise decorated with:
- // .meta -- id, url, and whether the data was cached
- // .topodata -- TopoJSON data (on response from server)
-
- function fetchTopoData(id) {
- if (!fs.isS(id)) {
- return null;
- }
- var url = getUrl(id),
- promise = cache.get(id);
-
- if (!promise) {
- // need to fetch the data, build the object,
- // cache it, and return it.
- promise = $http.get(url);
-
- promise.meta = {
- id: id,
- url: url,
- wasCached: false
- };
-
- promise.then(function (response) {
- // success
- promise.topodata = response.data;
- }, function (response) {
- // error
- $log.warn('Failed to retrieve map TopoJSON data: ' + url,
- response.status, response.data);
- });
-
- cache.set(id, promise);
-
- } else {
- promise.meta.wasCached = true;
- }
-
- return promise;
- }
-
- var defaultGenSettings = {
- objectTag: 'states',
- projection: d3.geo.mercator(),
- logicalSize: 1000,
- mapFillScale: .95
- };
-
- // converts given TopoJSON-format data into corresponding GeoJSON
- // data, and creates a path generator for that data.
- function createPathGenerator(topoData, opts) {
- var settings = angular.extend({}, defaultGenSettings, opts),
- topoObject = topoData.objects[settings.objectTag],
- geoData = topojson.feature(topoData, topoObject),
- proj = settings.projection,
- dim = settings.logicalSize,
- mfs = settings.mapFillScale,
- path = d3.geo.path().projection(proj);
-
- // adjust projection scale and translation to fill the view
- // with the map
-
- // start with unit scale, no translation..
- proj.scale(1).translate([0, 0]);
-
- // figure out dimensions of map data..
- var b = path.bounds(geoData),
- x1 = b[0][0],
- y1 = b[0][1],
- x2 = b[1][0],
- y2 = b[1][1],
- dx = x2 - x1,
- dy = y2 - y1,
- x = (x1 + x2) / 2,
- y = (y1 + y2) / 2;
-
- // size map to 95% of minimum dimension to fill space..
- var s = mfs / Math.min(dx / dim, dy / dim),
- t = [dim / 2 - s * x, dim / 2 - s * y];
-
- // set new scale, translation on the projection..
- proj.scale(s).translate(t);
-
- // return the results
- return {
- geodata: geoData,
- pathgen: path,
- settings: settings
- };
- }
return {
clearCache: clearCache,
fetchTopoData: fetchTopoData,
- createPathGenerator: createPathGenerator
+ createPathGenerator: createPathGenerator,
+ rescaleProjection: rescaleProjection
};
}]);
}());
\ No newline at end of file
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 1faf6e2..f8d40f9 100644
--- a/web/gui/src/main/webapp/app/fw/svg/map.js
+++ b/web/gui/src/main/webapp/app/fw/svg/map.js
@@ -37,6 +37,11 @@
// injected references
var $log, $q, fs, gds;
+ // NOTE: This method assumes the datafile has exactly the map data
+ // that you want to load; for example id="*continental_us"
+ // mapping to ~/data/map/continental_us.topojson contains
+ // exactly the paths for the continental US.
+
function loadMapInto(mapLayer, id, opts) {
var promise = gds.fetchTopoData(id),
deferredProjection = $q.defer();
@@ -60,6 +65,52 @@
return deferredProjection.promise;
}
+ // ---
+
+ // NOTE: This method uses the countries.topojson data file, and then
+ // filters the results based on the supplied options.
+ // Usage:
+ // promise = loadMapRegionInto(svgGroup, {
+ // countryFilter: function (country) {
+ // return country.properties.continent === 'South America';
+ // }
+ // });
+
+ function loadMapRegionInto(mapLayer, filterOpts) {
+ var promise = gds.fetchTopoData("*countries"),
+ deferredProjection = $q.defer();
+
+ if (!promise) {
+ $log.warn('Failed to load countries TopoJSON data');
+ return false;
+ }
+
+ promise.then(function () {
+ var width = 1000,
+ height = 1000,
+ proj = d3.geo.mercator().translate([width/2, height/2]),
+ pathGen = d3.geo.path().projection(proj),
+ data = promise.topodata,
+ features = topojson.feature(data, data.objects.countries).features,
+ country = features.filter(filterOpts.countryFilter),
+ countryFeature = {
+ type: 'FeatureCollection',
+ features: country
+ },
+ path = d3.geo.path().projection(proj);
+
+ gds.rescaleProjection(proj, 0.95, 1000, path, countryFeature);
+
+ deferredProjection.resolve(proj);
+
+ mapLayer.selectAll('path.country')
+ .data([countryFeature])
+ .enter()
+ .append('path').classed('country', true)
+ .attr('d', pathGen);
+ });
+ return deferredProjection.promise;
+ }
angular.module('onosSvg')
.factory('MapService', ['$log', '$q', 'FnService', 'GeoDataService',
@@ -70,6 +121,7 @@
gds = _gds_;
return {
+ loadMapRegionInto: loadMapRegionInto,
loadMapInto: loadMapInto
};
}]);