blob: d57e65dc86a46ddfb0bceeca0e2724f957c03dca [file] [log] [blame]
Simon Hunt7ac7be92015-01-06 10:47:56 -08001/*
2 * Copyright 2015 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 -- SVG -- Map Service
19
20 @author Simon Hunt
21 */
Simon Huntf044d8a2015-01-07 17:53:04 -080022
23/*
Simon Huntf8173382015-01-13 14:12:09 -080024 The Map Service provides a simple API for loading geographical maps into
25 an SVG layer. For example, as a background to the Topology View.
Simon Huntf044d8a2015-01-07 17:53:04 -080026
Simon Huntf8173382015-01-13 14:12:09 -080027 e.g. var ok = MapService.loadMapInto(svgLayer, '*continental-us');
Simon Huntf044d8a2015-01-07 17:53:04 -080028
Simon Huntf8173382015-01-13 14:12:09 -080029 The Map Service makes use of the GeoDataService to load the required data
30 from the server.
31*/
Simon Huntf044d8a2015-01-07 17:53:04 -080032
Simon Hunt7ac7be92015-01-06 10:47:56 -080033(function () {
34 'use strict';
35
Simon Huntf044d8a2015-01-07 17:53:04 -080036 // injected references
Simon Hunt404e54c2015-01-09 11:58:49 -080037 var $log, $http, fs;
Simon Huntf044d8a2015-01-07 17:53:04 -080038
39 // internal state
Simon Hunt404e54c2015-01-09 11:58:49 -080040 var mapCache = d3.map(),
Simon Hunt1e8eff42015-01-08 17:19:02 -080041 bundledUrlPrefix = '../data/map/';
Simon Huntf044d8a2015-01-07 17:53:04 -080042
43 function getUrl(id) {
44 if (id[0] === '*') {
45 return bundledUrlPrefix + id.slice(1) + '.json';
46 }
47 return id + '.json';
48 }
Simon Hunt7ac7be92015-01-06 10:47:56 -080049
50 angular.module('onosSvg')
Simon Hunt404e54c2015-01-09 11:58:49 -080051 .factory('MapService', ['$log', '$http', 'FnService',
52 function (_$log_, _$http_, _fs_) {
Simon Hunt7ac7be92015-01-06 10:47:56 -080053 $log = _$log_;
Simon Hunt1e8eff42015-01-08 17:19:02 -080054 $http = _$http_;
Simon Huntf044d8a2015-01-07 17:53:04 -080055 fs = _fs_;
56
Simon Hunt1e8eff42015-01-08 17:19:02 -080057
Simon Huntf044d8a2015-01-07 17:53:04 -080058 function fetchGeoMap(id) {
59 if (!fs.isS(id)) {
60 return null;
61 }
Simon Hunt404e54c2015-01-09 11:58:49 -080062 var url = getUrl(id),
63 promise = mapCache.get(id);
Simon Huntf044d8a2015-01-07 17:53:04 -080064
Simon Hunt1e8eff42015-01-08 17:19:02 -080065 if (!promise) {
Simon Hunt404e54c2015-01-09 11:58:49 -080066 // need to fetch the data, build the object,
67 // cache it, and return it.
68 promise = $http.get(url);
Simon Hunt1e8eff42015-01-08 17:19:02 -080069
70 promise.meta = {
71 id: id,
72 url: url,
Simon Hunt404e54c2015-01-09 11:58:49 -080073 wasCached: false
Simon Hunt1e8eff42015-01-08 17:19:02 -080074 };
75
Simon Hunt404e54c2015-01-09 11:58:49 -080076 promise.then(function (response) {
77 // success
78 promise.mapdata = response.data;
79 }, function (response) {
80 // error
81 $log.warn('Failed to retrieve map data: ' + url,
82 response.status, response.data);
83 });
84
85 mapCache.set(id, promise);
86
Simon Huntf044d8a2015-01-07 17:53:04 -080087 } else {
Simon Hunt1e8eff42015-01-08 17:19:02 -080088 promise.meta.wasCached = true;
Simon Huntf044d8a2015-01-07 17:53:04 -080089 }
90
Simon Hunt1e8eff42015-01-08 17:19:02 -080091 return promise;
Simon Huntf044d8a2015-01-07 17:53:04 -080092 }
Simon Hunt7ac7be92015-01-06 10:47:56 -080093
Simon Hunt404e54c2015-01-09 11:58:49 -080094 var geoMapProj;
95
96 function setProjForView(path, topoData) {
97 var dim = 1000;
98
99 // start with unit scale, no translation..
100 geoMapProj.scale(1).translate([0, 0]);
101
102 // figure out dimensions of map data..
103 var b = path.bounds(topoData),
104 x1 = b[0][0],
105 y1 = b[0][1],
106 x2 = b[1][0],
107 y2 = b[1][1],
108 dx = x2 - x1,
109 dy = y2 - y1,
110 x = (x1 + x2) / 2,
111 y = (y1 + y2) / 2;
112
113 // size map to 95% of minimum dimension to fill space..
114 var s = .95 / Math.min(dx / dim, dy / dim);
115 var t = [dim / 2 - s * x, dim / 2 - s * y];
116
117 // set new scale, translation on the projection..
118 geoMapProj.scale(s).translate(t);
119 }
120
121
122 function loadMapInto(mapLayer, id) {
123 var mapObject = fetchGeoMap(id);
124 if (!mapObject) {
125 $log.warn('Failed to load map: ' + id);
126 return null;
127 }
128
129 var mapdata = mapObject.mapdata,
130 topoData, path;
131
132 mapObject.then(function () {
133 // extracts the topojson data into geocoordinate-based geometry
134 topoData = topojson.feature(mapdata, mapdata.objects.states);
135
136 // see: http://bl.ocks.org/mbostock/4707858
137 geoMapProj = d3.geo.mercator();
138 path = d3.geo.path().projection(geoMapProj);
139
140 setProjForView(path, topoData);
141
142 mapLayer.selectAll('path')
143 .data(topoData.features)
144 .enter()
145 .append('path')
146 .attr('d', path);
147 });
148 // TODO: review whether we should just return true (not the map object)
149 return mapObject;
150 }
151
Simon Hunt7ac7be92015-01-06 10:47:56 -0800152 return {
Simon Hunt404e54c2015-01-09 11:58:49 -0800153 loadMapInto: loadMapInto
Simon Hunt7ac7be92015-01-06 10:47:56 -0800154 };
155 }]);
156
157}());