Browse Source

support tiles in GeoJSON

Maurits van der Schee 5 years ago
parent
commit
b08f63320c

+ 167
- 0
examples/clients/leaflet/GeoJSONGridLayer.js View File

@@ -0,0 +1,167 @@
1
+/*
2
+ * Leaflet.GeoJSONGridLayer 
3
+ */
4
+
5
+(function () {
6
+
7
+    var console = window.console || {
8
+        error: function () {},
9
+        warn: function () {}
10
+    };
11
+
12
+    function defineLeafletGeoJSONGridLayer(L) {
13
+        L.GeoJSONGridLayer = L.GridLayer.extend({
14
+            initialize: function (url, options) {
15
+                L.GridLayer.prototype.initialize.call(this, options);
16
+
17
+                this._url = url;
18
+                this._geojsons = {};
19
+                this._features = {};
20
+                this.geoJsonClass = (this.options.geoJsonClass ? this.options.geoJsonClass : L.GeoJSON);
21
+            },
22
+
23
+            onAdd: function (map) {
24
+                var layers = this._geojsons;
25
+                Object.keys(layers).forEach(function (key) {
26
+                    map.addLayer(layers[key]);
27
+                });
28
+
29
+                L.GridLayer.prototype.onAdd.call(this, map);
30
+                this.zoomanimHandler = this._handleZoom.bind(this);
31
+                map.on('zoomanim', this.zoomanimHandler);
32
+            },
33
+
34
+            onRemove: function (map) {
35
+                var layers = this._geojsons;
36
+                Object.keys(layers).forEach(function (key) {
37
+                    map.removeLayer(layers[key]);
38
+                });
39
+
40
+                L.GridLayer.prototype.onRemove.call(this, map);
41
+                map.off('zoomanim', this.zoomanimHandler);
42
+            },
43
+
44
+            _handleZoom: function (e) {
45
+                this.checkZoomConditions(e.zoom);
46
+            },
47
+
48
+            createTile: function (coords, done) {
49
+                var tile = L.DomUtil.create('div', 'leaflet-tile');
50
+                var size = this.getTileSize();
51
+                tile.width = size.x;
52
+                tile.height = size.y;
53
+
54
+                this.fetchTile(coords, function (error) {
55
+                    done(error, tile);
56
+                });
57
+                return tile;
58
+            },
59
+
60
+            fetchTile: function (coords, done) {
61
+                var tileUrl = L.Util.template(this._url, coords);
62
+                var tileLayer = this;
63
+
64
+                var request = new XMLHttpRequest();
65
+                request.open('GET', tileUrl, true);
66
+
67
+                request.onload = function () {
68
+                    if (request.status >= 200 && request.status < 400) {
69
+                        var data = JSON.parse(request.responseText);
70
+                        tileLayer.addData(data);
71
+                        done(null);
72
+                    } else {
73
+                        // We reached our target server, but it returned an error
74
+                        done(request.statusText);
75
+                    }
76
+                };
77
+
78
+                request.onerror = function () {
79
+                    done(request.statusText);
80
+                };
81
+
82
+                request.send();
83
+            },
84
+
85
+            getLayers: function () {
86
+                var geojsons = this._geojsons,
87
+                    layers = [];
88
+                Object.keys(geojsons).forEach(function (key) {
89
+                    layers.push(geojsons[key]);
90
+                });
91
+                return layers;
92
+            },
93
+
94
+            hasLayerWithId: function (sublayer, id) {
95
+                if (!this._geojsons[sublayer] || !this._features[sublayer]) return false;
96
+                return this._features[sublayer].hasOwnProperty(id);
97
+            },
98
+
99
+            addData: function (data) {
100
+                if (data.type === 'FeatureCollection') {
101
+                    this.addSubLayerData('default', data);
102
+                }
103
+                else {
104
+                    var tileLayer = this;
105
+                    Object.keys(data).forEach(function (key) {
106
+                        tileLayer.addSubLayerData(key, data[key]);
107
+                    });
108
+                }
109
+            },
110
+
111
+            addSubLayerData: function (sublayer, data) {
112
+                if (!this._geojsons[sublayer]) {
113
+                    this._geojsons[sublayer] = new this.geoJsonClass(null, this.options.layers[sublayer]).addTo(this._map);
114
+                    this.checkZoomConditions(this._map.getZoom());
115
+                }
116
+                var toAdd = data.features.filter(function (feature) {
117
+                    return !this.hasLayerWithId(sublayer, feature.id ? feature.id : feature.properties.id);
118
+                }, this);
119
+
120
+                if (!this._features[sublayer]) {
121
+                    this._features[sublayer] = {};
122
+                }
123
+                toAdd.forEach(function (feature) {
124
+                    var id = feature.id ? feature.id : feature.properties.id;
125
+                    this._features[sublayer][id] = feature;
126
+                }, this);
127
+
128
+                this._geojsons[sublayer].addData({
129
+                    type: 'FeatureCollection',
130
+                    features: toAdd
131
+                });
132
+            },
133
+
134
+            checkZoomConditions: function (zoom) {
135
+                var layers = this._geojsons,
136
+                    map = this._map;
137
+                Object.keys(layers).forEach(function (key) {
138
+                    var layer = layers[key],
139
+                        options = layer.options;
140
+                    if ((options.maxZoom && zoom > options.maxZoom) ||
141
+                        (options.minZoom && zoom < options.minZoom)) {
142
+                        map.removeLayer(layer);
143
+                    }
144
+                    else {
145
+                        map.addLayer(layer);
146
+                    }
147
+                });
148
+            }
149
+        });
150
+
151
+        L.geoJsonGridLayer = function(url, options) {
152
+            return new L.GeoJSONGridLayer(url, options);
153
+        };
154
+    }
155
+
156
+    if (typeof define === 'function' && define.amd) {
157
+        // Try to add leaflet.loading to Leaflet using AMD
158
+        define(['leaflet'], function (L) {
159
+            defineLeafletGeoJSONGridLayer(L);
160
+        });
161
+    }
162
+    else {
163
+        // Else use the global L
164
+        defineLeafletGeoJSONGridLayer(L);
165
+    }
166
+
167
+})();

+ 114
- 0
examples/clients/leaflet/geojson-tile-layer.js View File

@@ -0,0 +1,114 @@
1
+/* global L */
2
+(function() {
3
+
4
+    L.GeoJSONTileLayer = L.GeoJSON.extend({
5
+
6
+    includes: L.Evented.prototype,
7
+
8
+    map: null,
9
+
10
+    options: {
11
+    },
12
+
13
+    initialize(extraOptions, options) {
14
+        L.GeoJSON.prototype.initialize.call(this, [], options);
15
+        L.Util.setOptions(this, extraOptions);
16
+    },
17
+
18
+
19
+/*
20
+ function long2tile(lon,zoom) { return (Math.floor((lon+180)/360*Math.pow(2,zoom))); }
21
+ function lat2tile(lat,zoom)  { return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom))); }
22
+
23
+Inverse process:
24
+
25
+ function tile2long(x,z) {
26
+  return (x/Math.pow(2,z)*360-180);
27
+ }
28
+ function tile2lat(y,z) {
29
+  var n=Math.PI-2*Math.PI*y/Math.pow(2,z);
30
+  return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
31
+ }
32
+
33
+Example for calculating number of tiles within given extent and zoom-level:
34
+
35
+var zoom        = 9;
36
+var top_tile    = lat2tile(north_edge, zoom); // eg.lat2tile(34.422, 9);
37
+var left_tile   = lon2tile(west_edge, zoom);
38
+var bottom_tile = lat2tile(south_edge, zoom);
39
+var right_tile  = lon2tile(east_edge, zoom);
40
+var width       = Math.abs(left_tile - right_tile) + 1;
41
+var height      = Math.abs(top_tile - bottom_tile) + 1;
42
+
43
+// total tiles
44
+var total_tiles = width * height; // -> eg. 377
45
+*/
46
+
47
+    _reload: function() {
48
+        if (this.map) {
49
+            var urls = this._expand(this.options.url);
50
+            for (var i=0; i<urls.length; i++) {
51
+                this._ajax('GET', urls[i], false, this._update.bind(this));
52
+            }
53
+        }
54
+    },
55
+
56
+    
57
+
58
+    _update: function(geoData) {
59
+        this.clearLayers();
60
+        this.addData(geoData);
61
+    },
62
+
63
+    onAdd: function(map) {
64
+        L.GeoJSON.prototype.onAdd.call(this, map); 
65
+        this.map = map;
66
+        map.on('moveend zoomend refresh', this._reload, this);
67
+        this._reload();
68
+    },
69
+
70
+    onRemove: function(map) {
71
+        map.off('moveend zoomend refresh', this._reload, this);
72
+        this.map = null;
73
+        L.GeoJSON.prototype.onRemove.call(this, map);
74
+	},
75
+
76
+    _expand: function(template) {
77
+        var bbox = this._map.getBounds();
78
+        var southWest = bbox.getSouthWest();
79
+        var northEast = bbox.getNorthEast();
80
+        var bboxStr = bbox.toBBoxString();
81
+        var coords = { 
82
+            lat1: southWest.lat,
83
+            lon1: southWest.lng,
84
+            lat2: northEast.lat,
85
+            lon2: northEast.lng,
86
+            bbox: bboxStr
87
+        };
88
+        return [L.Util.template(template, coords)];
89
+    },
90
+
91
+    _ajax: function(method, url, data, callback) {
92
+        var request = new XMLHttpRequest();
93
+        request.open(method, url, true);
94
+		request.onreadystatechange = function() {
95
+			if (request.readyState === 4 && request.status === 200) {
96
+				callback(JSON.parse(request.responseText));
97
+		    }
98
+		};
99
+        if (data) {
100
+            request.setRequestHeader('Content-type', 'application/json');
101
+            request.send(JSON.stringify(data));
102
+        } else {
103
+            request.send();
104
+        }		
105
+		return request;
106
+    },
107
+
108
+});
109
+
110
+L.geoJSONTileLayer = function (options) {
111
+    return new L.GeoJSONTileLayer(options);
112
+};
113
+
114
+}).call(this);

Loading…
Cancel
Save