1
|
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
|
2
|
* full list of contributors). Published under the 2-clause BSD license.
|
3
|
* See license.txt in the OpenLayers distribution or repository for the
|
4
|
* full text of the license. */
|
5
|
|
6
|
/**
|
7
|
* @requires OpenLayers/Layer/Vector.js
|
8
|
* @requires OpenLayers/Geometry/Polygon.js
|
9
|
*/
|
10
|
|
11
|
/**
|
12
|
* Class: OpenLayers.Layer.PointGrid
|
13
|
* A point grid layer dynamically generates a regularly spaced grid of point
|
14
|
* features. This is a specialty layer for cases where an application needs
|
15
|
* a regular grid of points. It can be used, for example, in an editing
|
16
|
* environment to snap to a grid.
|
17
|
*
|
18
|
* Create a new vector layer with the <OpenLayers.Layer.PointGrid> constructor.
|
19
|
* (code)
|
20
|
* // create a grid with points spaced at 10 map units
|
21
|
* var points = new OpenLayers.Layer.PointGrid({dx: 10, dy: 10});
|
22
|
*
|
23
|
* // create a grid with different x/y spacing rotated 15 degrees clockwise.
|
24
|
* var points = new OpenLayers.Layer.PointGrid({dx: 5, dy: 10, rotation: 15});
|
25
|
* (end)
|
26
|
*
|
27
|
* Inherits from:
|
28
|
* - <OpenLayers.Layer.Vector>
|
29
|
*/
|
30
|
OpenLayers.Layer.PointGrid = OpenLayers.Class(OpenLayers.Layer.Vector, {
|
31
|
|
32
|
/**
|
33
|
* APIProperty: dx
|
34
|
* {Number} Point grid spacing in the x-axis direction (map units).
|
35
|
* Read-only. Use the <setSpacing> method to modify this value.
|
36
|
*/
|
37
|
dx: null,
|
38
|
|
39
|
/**
|
40
|
* APIProperty: dy
|
41
|
* {Number} Point grid spacing in the y-axis direction (map units).
|
42
|
* Read-only. Use the <setSpacing> method to modify this value.
|
43
|
*/
|
44
|
dy: null,
|
45
|
|
46
|
/**
|
47
|
* APIProperty: ratio
|
48
|
* {Number} Ratio of the desired grid size to the map viewport size.
|
49
|
* Default is 1.5. Larger ratios mean the grid is recalculated less often
|
50
|
* while panning. The <maxFeatures> setting has precedence when determining
|
51
|
* grid size. Read-only. Use the <setRatio> method to modify this value.
|
52
|
*/
|
53
|
ratio: 1.5,
|
54
|
|
55
|
/**
|
56
|
* APIProperty: maxFeatures
|
57
|
* {Number} The maximum number of points to generate in the grid. Default
|
58
|
* is 250. Read-only. Use the <setMaxFeatures> method to modify this value.
|
59
|
*/
|
60
|
maxFeatures: 250,
|
61
|
|
62
|
/**
|
63
|
* APIProperty: rotation
|
64
|
* {Number} Grid rotation (in degrees clockwise from the positive x-axis).
|
65
|
* Default is 0. Read-only. Use the <setRotation> method to modify this
|
66
|
* value.
|
67
|
*/
|
68
|
rotation: 0,
|
69
|
|
70
|
/**
|
71
|
* APIProperty: origin
|
72
|
* {<OpenLayers.LonLat>} Grid origin. The grid lattice will be aligned with
|
73
|
* the origin. If not set at construction, the center of the map's maximum
|
74
|
* extent is used. Read-only. Use the <setOrigin> method to modify this
|
75
|
* value.
|
76
|
*/
|
77
|
origin: null,
|
78
|
|
79
|
/**
|
80
|
* Property: gridBounds
|
81
|
* {<OpenLayers.Bounds>} Internally cached grid bounds (with optional
|
82
|
* rotation applied).
|
83
|
*/
|
84
|
gridBounds: null,
|
85
|
|
86
|
/**
|
87
|
* Constructor: OpenLayers.Layer.PointGrid
|
88
|
* Creates a new point grid layer.
|
89
|
*
|
90
|
* Parameters:
|
91
|
* config - {Object} An object containing all configuration properties for
|
92
|
* the layer. The <dx> and <dy> properties are required to be set at
|
93
|
* construction. Any other layer properties may be set in this object.
|
94
|
*/
|
95
|
initialize: function(config) {
|
96
|
config = config || {};
|
97
|
OpenLayers.Layer.Vector.prototype.initialize.apply(this, [config.name, config]);
|
98
|
},
|
99
|
|
100
|
/**
|
101
|
* Method: setMap
|
102
|
* The layer has been added to the map.
|
103
|
*
|
104
|
* Parameters:
|
105
|
* map - {<OpenLayers.Map>}
|
106
|
*/
|
107
|
setMap: function(map) {
|
108
|
OpenLayers.Layer.Vector.prototype.setMap.apply(this, arguments);
|
109
|
map.events.register("moveend", this, this.onMoveEnd);
|
110
|
},
|
111
|
|
112
|
/**
|
113
|
* Method: removeMap
|
114
|
* The layer has been removed from the map.
|
115
|
*
|
116
|
* Parameters:
|
117
|
* map - {<OpenLayers.Map>}
|
118
|
*/
|
119
|
removeMap: function(map) {
|
120
|
map.events.unregister("moveend", this, this.onMoveEnd);
|
121
|
OpenLayers.Layer.Vector.prototype.removeMap.apply(this, arguments);
|
122
|
},
|
123
|
|
124
|
/**
|
125
|
* APIMethod: setRatio
|
126
|
* Set the grid <ratio> property and update the grid. Can only be called
|
127
|
* after the layer has been added to a map with a center/extent.
|
128
|
*
|
129
|
* Parameters:
|
130
|
* ratio - {Number}
|
131
|
*/
|
132
|
setRatio: function(ratio) {
|
133
|
this.ratio = ratio;
|
134
|
this.updateGrid(true);
|
135
|
},
|
136
|
|
137
|
/**
|
138
|
* APIMethod: setMaxFeatures
|
139
|
* Set the grid <maxFeatures> property and update the grid. Can only be
|
140
|
* called after the layer has been added to a map with a center/extent.
|
141
|
*
|
142
|
* Parameters:
|
143
|
* maxFeatures - {Number}
|
144
|
*/
|
145
|
setMaxFeatures: function(maxFeatures) {
|
146
|
this.maxFeatures = maxFeatures;
|
147
|
this.updateGrid(true);
|
148
|
},
|
149
|
|
150
|
/**
|
151
|
* APIMethod: setSpacing
|
152
|
* Set the grid <dx> and <dy> properties and update the grid. If only one
|
153
|
* argument is provided, it will be set as <dx> and <dy>. Can only be
|
154
|
* called after the layer has been added to a map with a center/extent.
|
155
|
*
|
156
|
* Parameters:
|
157
|
* dx - {Number}
|
158
|
* dy - {Number}
|
159
|
*/
|
160
|
setSpacing: function(dx, dy) {
|
161
|
this.dx = dx;
|
162
|
this.dy = dy || dx;
|
163
|
this.updateGrid(true);
|
164
|
},
|
165
|
|
166
|
/**
|
167
|
* APIMethod: setOrigin
|
168
|
* Set the grid <origin> property and update the grid. Can only be called
|
169
|
* after the layer has been added to a map with a center/extent.
|
170
|
*
|
171
|
* Parameters:
|
172
|
* origin - {<OpenLayers.LonLat>}
|
173
|
*/
|
174
|
setOrigin: function(origin) {
|
175
|
this.origin = origin;
|
176
|
this.updateGrid(true);
|
177
|
},
|
178
|
|
179
|
/**
|
180
|
* APIMethod: getOrigin
|
181
|
* Get the grid <origin> property.
|
182
|
*
|
183
|
* Returns:
|
184
|
* {<OpenLayers.LonLat>} The grid origin.
|
185
|
*/
|
186
|
getOrigin: function() {
|
187
|
if (!this.origin) {
|
188
|
this.origin = this.map.getExtent().getCenterLonLat();
|
189
|
}
|
190
|
return this.origin;
|
191
|
},
|
192
|
|
193
|
/**
|
194
|
* APIMethod: setRotation
|
195
|
* Set the grid <rotation> property and update the grid. Rotation values
|
196
|
* are in degrees clockwise from the positive x-axis (negative values
|
197
|
* for counter-clockwise rotation). Can only be called after the layer
|
198
|
* has been added to a map with a center/extent.
|
199
|
*
|
200
|
* Parameters:
|
201
|
* rotation - {Number} Degrees clockwise from the positive x-axis.
|
202
|
*/
|
203
|
setRotation: function(rotation) {
|
204
|
this.rotation = rotation;
|
205
|
this.updateGrid(true);
|
206
|
},
|
207
|
|
208
|
/**
|
209
|
* Method: onMoveEnd
|
210
|
* Listener for map "moveend" events.
|
211
|
*/
|
212
|
onMoveEnd: function() {
|
213
|
this.updateGrid();
|
214
|
},
|
215
|
|
216
|
/**
|
217
|
* Method: getViewBounds
|
218
|
* Gets the (potentially rotated) view bounds for grid calculations.
|
219
|
*
|
220
|
* Returns:
|
221
|
* {<OpenLayers.Bounds>}
|
222
|
*/
|
223
|
getViewBounds: function() {
|
224
|
var bounds = this.map.getExtent();
|
225
|
if (this.rotation) {
|
226
|
var origin = this.getOrigin();
|
227
|
var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat);
|
228
|
var rect = bounds.toGeometry();
|
229
|
rect.rotate(-this.rotation, rotationOrigin);
|
230
|
bounds = rect.getBounds();
|
231
|
}
|
232
|
return bounds;
|
233
|
},
|
234
|
|
235
|
/**
|
236
|
* Method: updateGrid
|
237
|
* Update the grid.
|
238
|
*
|
239
|
* Parameters:
|
240
|
* force - {Boolean} Update the grid even if the previous bounds are still
|
241
|
* valid.
|
242
|
*/
|
243
|
updateGrid: function(force) {
|
244
|
if (force || this.invalidBounds()) {
|
245
|
var viewBounds = this.getViewBounds();
|
246
|
var origin = this.getOrigin();
|
247
|
var rotationOrigin = new OpenLayers.Geometry.Point(origin.lon, origin.lat);
|
248
|
var viewBoundsWidth = viewBounds.getWidth();
|
249
|
var viewBoundsHeight = viewBounds.getHeight();
|
250
|
var aspectRatio = viewBoundsWidth / viewBoundsHeight;
|
251
|
var maxHeight = Math.sqrt(this.dx * this.dy * this.maxFeatures / aspectRatio);
|
252
|
var maxWidth = maxHeight * aspectRatio;
|
253
|
var gridWidth = Math.min(viewBoundsWidth * this.ratio, maxWidth);
|
254
|
var gridHeight = Math.min(viewBoundsHeight * this.ratio, maxHeight);
|
255
|
var center = viewBounds.getCenterLonLat();
|
256
|
this.gridBounds = new OpenLayers.Bounds(
|
257
|
center.lon - (gridWidth / 2),
|
258
|
center.lat - (gridHeight / 2),
|
259
|
center.lon + (gridWidth / 2),
|
260
|
center.lat + (gridHeight / 2)
|
261
|
);
|
262
|
var rows = Math.floor(gridHeight / this.dy);
|
263
|
var cols = Math.floor(gridWidth / this.dx);
|
264
|
var gridLeft = origin.lon + (this.dx * Math.ceil((this.gridBounds.left - origin.lon) / this.dx));
|
265
|
var gridBottom = origin.lat + (this.dy * Math.ceil((this.gridBounds.bottom - origin.lat) / this.dy));
|
266
|
var features = new Array(rows * cols);
|
267
|
var x, y, point;
|
268
|
for (var i=0; i<cols; ++i) {
|
269
|
x = gridLeft + (i * this.dx);
|
270
|
for (var j=0; j<rows; ++j) {
|
271
|
y = gridBottom + (j * this.dy);
|
272
|
point = new OpenLayers.Geometry.Point(x, y);
|
273
|
if (this.rotation) {
|
274
|
point.rotate(this.rotation, rotationOrigin);
|
275
|
}
|
276
|
features[(i*rows)+j] = new OpenLayers.Feature.Vector(point);
|
277
|
}
|
278
|
}
|
279
|
this.destroyFeatures(this.features, {silent: true});
|
280
|
this.addFeatures(features, {silent: true});
|
281
|
}
|
282
|
},
|
283
|
|
284
|
/**
|
285
|
* Method: invalidBounds
|
286
|
* Determine whether the previously generated point grid is invalid.
|
287
|
* This occurs when the map bounds extends beyond the previously
|
288
|
* generated grid bounds.
|
289
|
*
|
290
|
* Returns:
|
291
|
* {Boolean}
|
292
|
*/
|
293
|
invalidBounds: function() {
|
294
|
return !this.gridBounds || !this.gridBounds.containsBounds(this.getViewBounds());
|
295
|
},
|
296
|
|
297
|
CLASS_NAME: "OpenLayers.Layer.PointGrid"
|
298
|
|
299
|
});
|