pyk 0.2.6 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/app/assets/javascripts/lib/chardinjs.min.js +2 -0
- data/app/assets/javascripts/lib/crossfilter.js +1383 -1
- data/app/assets/javascripts/lib/{d3.js → d3.v3.js} +0 -0
- data/app/assets/javascripts/lib/dc.js +3492 -757
- data/app/assets/javascripts/lib/jquery.gridster.js +2 -3621
- data/app/assets/javascripts/lib/markermanager.js +2 -980
- data/app/assets/javascripts/lib/underscore.js +1276 -0
- data/app/assets/javascripts/nvd3/lib/colorbrewer.js +302 -0
- data/app/assets/javascripts/nvd3/lib/crossfilter.js +1180 -0
- data/app/assets/javascripts/nvd3/lib/crossfilter.min.js +1 -0
- data/app/assets/javascripts/nvd3/lib/d3.v2.js +7033 -0
- data/app/assets/javascripts/nvd3/lib/d3.v2.min.js +4 -0
- data/app/assets/javascripts/nvd3/lib/d3.v3.js +8436 -0
- data/app/assets/javascripts/nvd3/lib/fisheye.js +86 -0
- data/app/assets/javascripts/nvd3/lib/hive.js +80 -0
- data/app/assets/javascripts/nvd3/lib/horizon.js +192 -0
- data/app/assets/javascripts/nvd3/lib/sankey.js +292 -0
- data/app/assets/javascripts/nvd3/nv.d3.js +14312 -0
- data/app/assets/javascripts/nvd3/nv.d3.min.js +6 -0
- data/app/assets/javascripts/nvd3/src/core.js +122 -0
- data/app/assets/javascripts/nvd3/src/interactiveLayer.js +251 -0
- data/app/assets/javascripts/nvd3/src/models/axis.js +405 -0
- data/app/assets/javascripts/nvd3/src/models/backup/bullet.js +250 -0
- data/app/assets/javascripts/nvd3/src/models/backup/bulletChart.js +349 -0
- data/app/assets/javascripts/nvd3/src/models/boilerplate.js +104 -0
- data/app/assets/javascripts/nvd3/src/models/bullet.js +385 -0
- data/app/assets/javascripts/nvd3/src/models/bulletChart.js +343 -0
- data/app/assets/javascripts/nvd3/src/models/cumulativeLineChart.js +782 -0
- data/app/assets/javascripts/nvd3/src/models/discreteBar.js +349 -0
- data/app/assets/javascripts/nvd3/src/models/discreteBarChart.js +333 -0
- data/app/assets/javascripts/nvd3/src/models/distribution.js +148 -0
- data/app/assets/javascripts/nvd3/src/models/historicalBar.js +331 -0
- data/app/assets/javascripts/nvd3/src/models/historicalBarChart.js +419 -0
- data/app/assets/javascripts/nvd3/src/models/indentedTree.js +337 -0
- data/app/assets/javascripts/nvd3/src/models/legend.js +270 -0
- data/app/assets/javascripts/nvd3/src/models/line.js +284 -0
- data/app/assets/javascripts/nvd3/src/models/lineChart.js +465 -0
- data/app/assets/javascripts/nvd3/src/models/linePlusBarChart.js +433 -0
- data/app/assets/javascripts/nvd3/src/models/linePlusBarWithFocusChart.js +658 -0
- data/app/assets/javascripts/nvd3/src/models/lineWithFisheye.js +200 -0
- data/app/assets/javascripts/nvd3/src/models/lineWithFisheyeChart.js +297 -0
- data/app/assets/javascripts/nvd3/src/models/lineWithFocusChart.js +574 -0
- data/app/assets/javascripts/nvd3/src/models/multiBar.js +461 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarChart.js +524 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarHorizontal.js +424 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarHorizontalChart.js +434 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarTimeSeries.js +384 -0
- data/app/assets/javascripts/nvd3/src/models/multiBarTimeSeriesChart.js +405 -0
- data/app/assets/javascripts/nvd3/src/models/multiChart.js +452 -0
- data/app/assets/javascripts/nvd3/src/models/ohlcBar.js +380 -0
- data/app/assets/javascripts/nvd3/src/models/parallelCoordinates.js +239 -0
- data/app/assets/javascripts/nvd3/src/models/pie.js +398 -0
- data/app/assets/javascripts/nvd3/src/models/pieChart.js +292 -0
- data/app/assets/javascripts/nvd3/src/models/scatter.js +674 -0
- data/app/assets/javascripts/nvd3/src/models/scatterChart.js +628 -0
- data/app/assets/javascripts/nvd3/src/models/scatterPlusLineChart.js +620 -0
- data/app/assets/javascripts/nvd3/src/models/sparkline.js +194 -0
- data/app/assets/javascripts/nvd3/src/models/sparklinePlus.js +295 -0
- data/app/assets/javascripts/nvd3/src/models/stackedArea.js +368 -0
- data/app/assets/javascripts/nvd3/src/models/stackedAreaChart.js +629 -0
- data/app/assets/javascripts/nvd3/src/tooltip.js +490 -0
- data/app/assets/javascripts/nvd3/src/utils.js +152 -0
- data/app/assets/javascripts/pyk.js +1 -0
- data/app/assets/stylesheets/lib/chardinjs.css +82 -0
- data/app/assets/stylesheets/nvd3/nv.d3.css +769 -0
- data/app/assets/stylesheets/pyk.css.scss +1 -0
- metadata +61 -2
@@ -1,980 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* @version 1.1
|
4
|
-
* @copyright (c) 2007 Google Inc.
|
5
|
-
* @author Doug Ricket, Bjorn Brala (port to v3), others,
|
6
|
-
*
|
7
|
-
* @fileoverview Marker manager is an interface between the map and the user,
|
8
|
-
* designed to manage adding and removing many points when the viewport changes.
|
9
|
-
* <br /><br />
|
10
|
-
* <b>How it Works</b>:<br/>
|
11
|
-
* The MarkerManager places its markers onto a grid, similar to the map tiles.
|
12
|
-
* When the user moves the viewport, it computes which grid cells have
|
13
|
-
* entered or left the viewport, and shows or hides all the markers in those
|
14
|
-
* cells.
|
15
|
-
* (If the users scrolls the viewport beyond the markers that are loaded,
|
16
|
-
* no markers will be visible until the <code>EVENT_moveend</code>
|
17
|
-
* triggers an update.)
|
18
|
-
* In practical consequences, this allows 10,000 markers to be distributed over
|
19
|
-
* a large area, and as long as only 100-200 are visible in any given viewport,
|
20
|
-
* the user will see good performance corresponding to the 100 visible markers,
|
21
|
-
* rather than poor performance corresponding to the total 10,000 markers.
|
22
|
-
* Note that some code is optimized for speed over space,
|
23
|
-
* with the goal of accommodating thousands of markers.
|
24
|
-
*/
|
25
|
-
|
26
|
-
/*
|
27
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
28
|
-
* you may not use this file except in compliance with the License.
|
29
|
-
* You may obtain a copy of the License at
|
30
|
-
*
|
31
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
32
|
-
*
|
33
|
-
* Unless required by applicable law or agreed to in writing, software
|
34
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
35
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
36
|
-
* See the License for the specific language governing permissions and
|
37
|
-
* limitations under the License.
|
38
|
-
*/
|
39
|
-
|
40
|
-
/**
|
41
|
-
* @name MarkerManagerOptions
|
42
|
-
* @class This class represents optional arguments to the {@link MarkerManager}
|
43
|
-
* constructor.
|
44
|
-
* @property {Number} maxZoom Sets the maximum zoom level monitored by a
|
45
|
-
* marker manager. If not given, the manager assumes the maximum map zoom
|
46
|
-
* level. This value is also used when markers are added to the manager
|
47
|
-
* without the optional {@link maxZoom} parameter.
|
48
|
-
* @property {Number} borderPadding Specifies, in pixels, the extra padding
|
49
|
-
* outside the map's current viewport monitored by a manager. Markers that
|
50
|
-
* fall within this padding are added to the map, even if they are not fully
|
51
|
-
* visible.
|
52
|
-
* @property {Boolean} trackMarkers=false Indicates whether or not a marker
|
53
|
-
* manager should track markers' movements. If you wish to move managed
|
54
|
-
* markers using the {@link setPoint}/{@link setLatLng} methods,
|
55
|
-
* this option should be set to {@link true}.
|
56
|
-
*/
|
57
|
-
|
58
|
-
/**
|
59
|
-
* Creates a new MarkerManager that will show/hide markers on a map.
|
60
|
-
*
|
61
|
-
* Events:
|
62
|
-
* @event changed (Parameters: shown bounds, shown markers) Notify listeners when the state of what is displayed changes.
|
63
|
-
* @event loaded MarkerManager has succesfully been initialized.
|
64
|
-
*
|
65
|
-
* @constructor
|
66
|
-
* @param {Map} map The map to manage.
|
67
|
-
* @param {Object} opt_opts A container for optional arguments:
|
68
|
-
* {Number} maxZoom The maximum zoom level for which to create tiles.
|
69
|
-
* {Number} borderPadding The width in pixels beyond the map border,
|
70
|
-
* where markers should be display.
|
71
|
-
* {Boolean} trackMarkers Whether or not this manager should track marker
|
72
|
-
* movements.
|
73
|
-
*/
|
74
|
-
function MarkerManager(map, opt_opts) {
|
75
|
-
var me = this;
|
76
|
-
me.map_ = map;
|
77
|
-
me.mapZoom_ = map.getZoom();
|
78
|
-
|
79
|
-
me.projectionHelper_ = new ProjectionHelperOverlay(map);
|
80
|
-
google.maps.event.addListener(me.projectionHelper_, 'ready', function () {
|
81
|
-
me.projection_ = this.getProjection();
|
82
|
-
me.initialize(map, opt_opts);
|
83
|
-
});
|
84
|
-
}
|
85
|
-
|
86
|
-
|
87
|
-
MarkerManager.prototype.initialize = function (map, opt_opts) {
|
88
|
-
var me = this;
|
89
|
-
|
90
|
-
opt_opts = opt_opts || {};
|
91
|
-
me.tileSize_ = MarkerManager.DEFAULT_TILE_SIZE_;
|
92
|
-
|
93
|
-
var mapTypes = map.mapTypes;
|
94
|
-
|
95
|
-
// Find max zoom level
|
96
|
-
var mapMaxZoom = 1;
|
97
|
-
for (var sType in mapTypes ) {
|
98
|
-
if (mapTypes.hasOwnProperty(sType) &&
|
99
|
-
mapTypes.get(sType) && mapTypes.get(sType).maxZoom === 'number') {
|
100
|
-
var mapTypeMaxZoom = map.mapTypes.get(sType).maxZoom;
|
101
|
-
if (mapTypeMaxZoom > mapMaxZoom) {
|
102
|
-
mapMaxZoom = mapTypeMaxZoom;
|
103
|
-
}
|
104
|
-
}
|
105
|
-
}
|
106
|
-
|
107
|
-
me.maxZoom_ = opt_opts.maxZoom || 19;
|
108
|
-
|
109
|
-
me.trackMarkers_ = opt_opts.trackMarkers;
|
110
|
-
me.show_ = opt_opts.show || true;
|
111
|
-
|
112
|
-
var padding;
|
113
|
-
if (typeof opt_opts.borderPadding === 'number') {
|
114
|
-
padding = opt_opts.borderPadding;
|
115
|
-
} else {
|
116
|
-
padding = MarkerManager.DEFAULT_BORDER_PADDING_;
|
117
|
-
}
|
118
|
-
// The padding in pixels beyond the viewport, where we will pre-load markers.
|
119
|
-
me.swPadding_ = new google.maps.Size(-padding, padding);
|
120
|
-
me.nePadding_ = new google.maps.Size(padding, -padding);
|
121
|
-
me.borderPadding_ = padding;
|
122
|
-
|
123
|
-
me.gridWidth_ = {};
|
124
|
-
|
125
|
-
me.grid_ = {};
|
126
|
-
me.grid_[me.maxZoom_] = {};
|
127
|
-
me.numMarkers_ = {};
|
128
|
-
me.numMarkers_[me.maxZoom_] = 0;
|
129
|
-
|
130
|
-
|
131
|
-
google.maps.event.addListener(map, 'dragend', function () {
|
132
|
-
me.onMapMoveEnd_();
|
133
|
-
});
|
134
|
-
|
135
|
-
google.maps.event.addListener(map, 'idle', function () {
|
136
|
-
me.onMapMoveEnd_();
|
137
|
-
});
|
138
|
-
|
139
|
-
google.maps.event.addListener(map, 'zoom_changed', function () {
|
140
|
-
me.onMapMoveEnd_();
|
141
|
-
});
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
/**
|
146
|
-
* This closure provide easy access to the map.
|
147
|
-
* They are used as callbacks, not as methods.
|
148
|
-
* @param GMarker marker Marker to be removed from the map
|
149
|
-
* @private
|
150
|
-
*/
|
151
|
-
me.removeOverlay_ = function (marker) {
|
152
|
-
marker.setMap(null);
|
153
|
-
me.shownMarkers_--;
|
154
|
-
};
|
155
|
-
|
156
|
-
/**
|
157
|
-
* This closure provide easy access to the map.
|
158
|
-
* They are used as callbacks, not as methods.
|
159
|
-
* @param GMarker marker Marker to be added to the map
|
160
|
-
* @private
|
161
|
-
*/
|
162
|
-
me.addOverlay_ = function (marker) {
|
163
|
-
if (me.show_) {
|
164
|
-
marker.setMap(me.map_);
|
165
|
-
me.shownMarkers_++;
|
166
|
-
}
|
167
|
-
};
|
168
|
-
|
169
|
-
me.resetManager_();
|
170
|
-
me.shownMarkers_ = 0;
|
171
|
-
|
172
|
-
me.shownBounds_ = me.getMapGridBounds_();
|
173
|
-
|
174
|
-
google.maps.event.trigger(me, 'loaded');
|
175
|
-
|
176
|
-
};
|
177
|
-
|
178
|
-
/**
|
179
|
-
* Default tile size used for deviding the map into a grid.
|
180
|
-
*/
|
181
|
-
MarkerManager.DEFAULT_TILE_SIZE_ = 1024;
|
182
|
-
|
183
|
-
/*
|
184
|
-
* How much extra space to show around the map border so
|
185
|
-
* dragging doesn't result in an empty place.
|
186
|
-
*/
|
187
|
-
MarkerManager.DEFAULT_BORDER_PADDING_ = 100;
|
188
|
-
|
189
|
-
/**
|
190
|
-
* Default tilesize of single tile world.
|
191
|
-
*/
|
192
|
-
MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE = 256;
|
193
|
-
|
194
|
-
|
195
|
-
/**
|
196
|
-
* Initializes MarkerManager arrays for all zoom levels
|
197
|
-
* Called by constructor and by clearAllMarkers
|
198
|
-
*/
|
199
|
-
MarkerManager.prototype.resetManager_ = function () {
|
200
|
-
var mapWidth = MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;
|
201
|
-
for (var zoom = 0; zoom <= this.maxZoom_; ++zoom) {
|
202
|
-
this.grid_[zoom] = {};
|
203
|
-
this.numMarkers_[zoom] = 0;
|
204
|
-
this.gridWidth_[zoom] = Math.ceil(mapWidth / this.tileSize_);
|
205
|
-
mapWidth <<= 1;
|
206
|
-
}
|
207
|
-
|
208
|
-
};
|
209
|
-
|
210
|
-
/**
|
211
|
-
* Removes all markers in the manager, and
|
212
|
-
* removes any visible markers from the map.
|
213
|
-
*/
|
214
|
-
MarkerManager.prototype.clearMarkers = function () {
|
215
|
-
this.processAll_(this.shownBounds_, this.removeOverlay_);
|
216
|
-
this.resetManager_();
|
217
|
-
};
|
218
|
-
|
219
|
-
|
220
|
-
/**
|
221
|
-
* Gets the tile coordinate for a given latlng point.
|
222
|
-
*
|
223
|
-
* @param {LatLng} latlng The geographical point.
|
224
|
-
* @param {Number} zoom The zoom level.
|
225
|
-
* @param {google.maps.Size} padding The padding used to shift the pixel coordinate.
|
226
|
-
* Used for expanding a bounds to include an extra padding
|
227
|
-
* of pixels surrounding the bounds.
|
228
|
-
* @return {GPoint} The point in tile coordinates.
|
229
|
-
*
|
230
|
-
*/
|
231
|
-
MarkerManager.prototype.getTilePoint_ = function (latlng, zoom, padding) {
|
232
|
-
|
233
|
-
var pixelPoint = this.projectionHelper_.LatLngToPixel(latlng, zoom);
|
234
|
-
|
235
|
-
var point = new google.maps.Point(
|
236
|
-
Math.floor((pixelPoint.x + padding.width) / this.tileSize_),
|
237
|
-
Math.floor((pixelPoint.y + padding.height) / this.tileSize_)
|
238
|
-
);
|
239
|
-
|
240
|
-
return point;
|
241
|
-
};
|
242
|
-
|
243
|
-
|
244
|
-
/**
|
245
|
-
* Finds the appropriate place to add the marker to the grid.
|
246
|
-
* Optimized for speed; does not actually add the marker to the map.
|
247
|
-
* Designed for batch-processing thousands of markers.
|
248
|
-
*
|
249
|
-
* @param {Marker} marker The marker to add.
|
250
|
-
* @param {Number} minZoom The minimum zoom for displaying the marker.
|
251
|
-
* @param {Number} maxZoom The maximum zoom for displaying the marker.
|
252
|
-
*/
|
253
|
-
MarkerManager.prototype.addMarkerBatch_ = function (marker, minZoom, maxZoom) {
|
254
|
-
var me = this;
|
255
|
-
|
256
|
-
var mPoint = marker.getPosition();
|
257
|
-
marker.MarkerManager_minZoom = minZoom;
|
258
|
-
|
259
|
-
|
260
|
-
// Tracking markers is expensive, so we do this only if the
|
261
|
-
// user explicitly requested it when creating marker manager.
|
262
|
-
if (this.trackMarkers_) {
|
263
|
-
google.maps.event.addListener(marker, 'changed', function (a, b, c) {
|
264
|
-
me.onMarkerMoved_(a, b, c);
|
265
|
-
});
|
266
|
-
}
|
267
|
-
|
268
|
-
var gridPoint = this.getTilePoint_(mPoint, maxZoom, new google.maps.Size(0, 0, 0, 0));
|
269
|
-
|
270
|
-
for (var zoom = maxZoom; zoom >= minZoom; zoom--) {
|
271
|
-
var cell = this.getGridCellCreate_(gridPoint.x, gridPoint.y, zoom);
|
272
|
-
cell.push(marker);
|
273
|
-
|
274
|
-
gridPoint.x = gridPoint.x >> 1;
|
275
|
-
gridPoint.y = gridPoint.y >> 1;
|
276
|
-
}
|
277
|
-
};
|
278
|
-
|
279
|
-
|
280
|
-
/**
|
281
|
-
* Returns whether or not the given point is visible in the shown bounds. This
|
282
|
-
* is a helper method that takes care of the corner case, when shownBounds have
|
283
|
-
* negative minX value.
|
284
|
-
*
|
285
|
-
* @param {Point} point a point on a grid.
|
286
|
-
* @return {Boolean} Whether or not the given point is visible in the currently
|
287
|
-
* shown bounds.
|
288
|
-
*/
|
289
|
-
MarkerManager.prototype.isGridPointVisible_ = function (point) {
|
290
|
-
var vertical = this.shownBounds_.minY <= point.y &&
|
291
|
-
point.y <= this.shownBounds_.maxY;
|
292
|
-
var minX = this.shownBounds_.minX;
|
293
|
-
var horizontal = minX <= point.x && point.x <= this.shownBounds_.maxX;
|
294
|
-
if (!horizontal && minX < 0) {
|
295
|
-
// Shifts the negative part of the rectangle. As point.x is always less
|
296
|
-
// than grid width, only test shifted minX .. 0 part of the shown bounds.
|
297
|
-
var width = this.gridWidth_[this.shownBounds_.z];
|
298
|
-
horizontal = minX + width <= point.x && point.x <= width - 1;
|
299
|
-
}
|
300
|
-
return vertical && horizontal;
|
301
|
-
};
|
302
|
-
|
303
|
-
|
304
|
-
/**
|
305
|
-
* Reacts to a notification from a marker that it has moved to a new location.
|
306
|
-
* It scans the grid all all zoom levels and moves the marker from the old grid
|
307
|
-
* location to a new grid location.
|
308
|
-
*
|
309
|
-
* @param {Marker} marker The marker that moved.
|
310
|
-
* @param {LatLng} oldPoint The old position of the marker.
|
311
|
-
* @param {LatLng} newPoint The new position of the marker.
|
312
|
-
*/
|
313
|
-
MarkerManager.prototype.onMarkerMoved_ = function (marker, oldPoint, newPoint) {
|
314
|
-
// NOTE: We do not know the minimum or maximum zoom the marker was
|
315
|
-
// added at, so we start at the absolute maximum. Whenever we successfully
|
316
|
-
// remove a marker at a given zoom, we add it at the new grid coordinates.
|
317
|
-
var zoom = this.maxZoom_;
|
318
|
-
var changed = false;
|
319
|
-
var oldGrid = this.getTilePoint_(oldPoint, zoom, new google.maps.Size(0, 0, 0, 0));
|
320
|
-
var newGrid = this.getTilePoint_(newPoint, zoom, new google.maps.Size(0, 0, 0, 0));
|
321
|
-
while (zoom >= 0 && (oldGrid.x !== newGrid.x || oldGrid.y !== newGrid.y)) {
|
322
|
-
var cell = this.getGridCellNoCreate_(oldGrid.x, oldGrid.y, zoom);
|
323
|
-
if (cell) {
|
324
|
-
if (this.removeFromArray_(cell, marker)) {
|
325
|
-
this.getGridCellCreate_(newGrid.x, newGrid.y, zoom).push(marker);
|
326
|
-
}
|
327
|
-
}
|
328
|
-
// For the current zoom we also need to update the map. Markers that no
|
329
|
-
// longer are visible are removed from the map. Markers that moved into
|
330
|
-
// the shown bounds are added to the map. This also lets us keep the count
|
331
|
-
// of visible markers up to date.
|
332
|
-
if (zoom === this.mapZoom_) {
|
333
|
-
if (this.isGridPointVisible_(oldGrid)) {
|
334
|
-
if (!this.isGridPointVisible_(newGrid)) {
|
335
|
-
this.removeOverlay_(marker);
|
336
|
-
changed = true;
|
337
|
-
}
|
338
|
-
} else {
|
339
|
-
if (this.isGridPointVisible_(newGrid)) {
|
340
|
-
this.addOverlay_(marker);
|
341
|
-
changed = true;
|
342
|
-
}
|
343
|
-
}
|
344
|
-
}
|
345
|
-
oldGrid.x = oldGrid.x >> 1;
|
346
|
-
oldGrid.y = oldGrid.y >> 1;
|
347
|
-
newGrid.x = newGrid.x >> 1;
|
348
|
-
newGrid.y = newGrid.y >> 1;
|
349
|
-
--zoom;
|
350
|
-
}
|
351
|
-
if (changed) {
|
352
|
-
this.notifyListeners_();
|
353
|
-
}
|
354
|
-
};
|
355
|
-
|
356
|
-
|
357
|
-
/**
|
358
|
-
* Removes marker from the manager and from the map
|
359
|
-
* (if it's currently visible).
|
360
|
-
* @param {GMarker} marker The marker to delete.
|
361
|
-
*/
|
362
|
-
MarkerManager.prototype.removeMarker = function (marker) {
|
363
|
-
var zoom = this.maxZoom_;
|
364
|
-
var changed = false;
|
365
|
-
var point = marker.getPosition();
|
366
|
-
var grid = this.getTilePoint_(point, zoom, new google.maps.Size(0, 0, 0, 0));
|
367
|
-
while (zoom >= 0) {
|
368
|
-
var cell = this.getGridCellNoCreate_(grid.x, grid.y, zoom);
|
369
|
-
|
370
|
-
if (cell) {
|
371
|
-
this.removeFromArray_(cell, marker);
|
372
|
-
}
|
373
|
-
// For the current zoom we also need to update the map. Markers that no
|
374
|
-
// longer are visible are removed from the map. This also lets us keep the count
|
375
|
-
// of visible markers up to date.
|
376
|
-
if (zoom === this.mapZoom_) {
|
377
|
-
if (this.isGridPointVisible_(grid)) {
|
378
|
-
this.removeOverlay_(marker);
|
379
|
-
changed = true;
|
380
|
-
}
|
381
|
-
}
|
382
|
-
grid.x = grid.x >> 1;
|
383
|
-
grid.y = grid.y >> 1;
|
384
|
-
--zoom;
|
385
|
-
}
|
386
|
-
if (changed) {
|
387
|
-
this.notifyListeners_();
|
388
|
-
}
|
389
|
-
this.numMarkers_[marker.MarkerManager_minZoom]--;
|
390
|
-
};
|
391
|
-
|
392
|
-
|
393
|
-
/**
|
394
|
-
* Add many markers at once.
|
395
|
-
* Does not actually update the map, just the internal grid.
|
396
|
-
*
|
397
|
-
* @param {Array of Marker} markers The markers to add.
|
398
|
-
* @param {Number} minZoom The minimum zoom level to display the markers.
|
399
|
-
* @param {Number} opt_maxZoom The maximum zoom level to display the markers.
|
400
|
-
*/
|
401
|
-
MarkerManager.prototype.addMarkers = function (markers, minZoom, opt_maxZoom) {
|
402
|
-
var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
|
403
|
-
for (var i = markers.length - 1; i >= 0; i--) {
|
404
|
-
this.addMarkerBatch_(markers[i], minZoom, maxZoom);
|
405
|
-
}
|
406
|
-
|
407
|
-
this.numMarkers_[minZoom] += markers.length;
|
408
|
-
};
|
409
|
-
|
410
|
-
|
411
|
-
/**
|
412
|
-
* Returns the value of the optional maximum zoom. This method is defined so
|
413
|
-
* that we have just one place where optional maximum zoom is calculated.
|
414
|
-
*
|
415
|
-
* @param {Number} opt_maxZoom The optinal maximum zoom.
|
416
|
-
* @return The maximum zoom.
|
417
|
-
*/
|
418
|
-
MarkerManager.prototype.getOptMaxZoom_ = function (opt_maxZoom) {
|
419
|
-
return opt_maxZoom || this.maxZoom_;
|
420
|
-
};
|
421
|
-
|
422
|
-
|
423
|
-
/**
|
424
|
-
* Calculates the total number of markers potentially visible at a given
|
425
|
-
* zoom level.
|
426
|
-
*
|
427
|
-
* @param {Number} zoom The zoom level to check.
|
428
|
-
*/
|
429
|
-
MarkerManager.prototype.getMarkerCount = function (zoom) {
|
430
|
-
var total = 0;
|
431
|
-
for (var z = 0; z <= zoom; z++) {
|
432
|
-
total += this.numMarkers_[z];
|
433
|
-
}
|
434
|
-
return total;
|
435
|
-
};
|
436
|
-
|
437
|
-
/**
|
438
|
-
* Returns a marker given latitude, longitude and zoom. If the marker does not
|
439
|
-
* exist, the method will return a new marker. If a new marker is created,
|
440
|
-
* it will NOT be added to the manager.
|
441
|
-
*
|
442
|
-
* @param {Number} lat - the latitude of a marker.
|
443
|
-
* @param {Number} lng - the longitude of a marker.
|
444
|
-
* @param {Number} zoom - the zoom level
|
445
|
-
* @return {GMarker} marker - the marker found at lat and lng
|
446
|
-
*/
|
447
|
-
MarkerManager.prototype.getMarker = function (lat, lng, zoom) {
|
448
|
-
var mPoint = new google.maps.LatLng(lat, lng);
|
449
|
-
var gridPoint = this.getTilePoint_(mPoint, zoom, new google.maps.Size(0, 0, 0, 0));
|
450
|
-
|
451
|
-
var marker = new google.maps.Marker({position: mPoint});
|
452
|
-
|
453
|
-
var cellArray = this.getGridCellNoCreate_(gridPoint.x, gridPoint.y, zoom);
|
454
|
-
if (cellArray !== undefined) {
|
455
|
-
for (var i = 0; i < cellArray.length; i++)
|
456
|
-
{
|
457
|
-
if (lat === cellArray[i].getPosition().lat() && lng === cellArray[i].getPosition().lng()) {
|
458
|
-
marker = cellArray[i];
|
459
|
-
}
|
460
|
-
}
|
461
|
-
}
|
462
|
-
return marker;
|
463
|
-
};
|
464
|
-
|
465
|
-
/**
|
466
|
-
* Add a single marker to the map.
|
467
|
-
*
|
468
|
-
* @param {Marker} marker The marker to add.
|
469
|
-
* @param {Number} minZoom The minimum zoom level to display the marker.
|
470
|
-
* @param {Number} opt_maxZoom The maximum zoom level to display the marker.
|
471
|
-
*/
|
472
|
-
MarkerManager.prototype.addMarker = function (marker, minZoom, opt_maxZoom) {
|
473
|
-
var maxZoom = this.getOptMaxZoom_(opt_maxZoom);
|
474
|
-
this.addMarkerBatch_(marker, minZoom, maxZoom);
|
475
|
-
var gridPoint = this.getTilePoint_(marker.getPosition(), this.mapZoom_, new google.maps.Size(0, 0, 0, 0));
|
476
|
-
if (this.isGridPointVisible_(gridPoint) &&
|
477
|
-
minZoom <= this.shownBounds_.z &&
|
478
|
-
this.shownBounds_.z <= maxZoom) {
|
479
|
-
this.addOverlay_(marker);
|
480
|
-
this.notifyListeners_();
|
481
|
-
}
|
482
|
-
this.numMarkers_[minZoom]++;
|
483
|
-
};
|
484
|
-
|
485
|
-
|
486
|
-
/**
|
487
|
-
* Helper class to create a bounds of INT ranges.
|
488
|
-
* @param bounds Array.<Object.<string, number>> Bounds object.
|
489
|
-
* @constructor
|
490
|
-
*/
|
491
|
-
function GridBounds(bounds) {
|
492
|
-
// [sw, ne]
|
493
|
-
|
494
|
-
this.minX = Math.min(bounds[0].x, bounds[1].x);
|
495
|
-
this.maxX = Math.max(bounds[0].x, bounds[1].x);
|
496
|
-
this.minY = Math.min(bounds[0].y, bounds[1].y);
|
497
|
-
this.maxY = Math.max(bounds[0].y, bounds[1].y);
|
498
|
-
|
499
|
-
}
|
500
|
-
|
501
|
-
/**
|
502
|
-
* Returns true if this bounds equal the given bounds.
|
503
|
-
* @param {GridBounds} gridBounds GridBounds The bounds to test.
|
504
|
-
* @return {Boolean} This Bounds equals the given GridBounds.
|
505
|
-
*/
|
506
|
-
GridBounds.prototype.equals = function (gridBounds) {
|
507
|
-
if (this.maxX === gridBounds.maxX && this.maxY === gridBounds.maxY && this.minX === gridBounds.minX && this.minY === gridBounds.minY) {
|
508
|
-
return true;
|
509
|
-
} else {
|
510
|
-
return false;
|
511
|
-
}
|
512
|
-
};
|
513
|
-
|
514
|
-
/**
|
515
|
-
* Returns true if this bounds (inclusively) contains the given point.
|
516
|
-
* @param {Point} point The point to test.
|
517
|
-
* @return {Boolean} This Bounds contains the given Point.
|
518
|
-
*/
|
519
|
-
GridBounds.prototype.containsPoint = function (point) {
|
520
|
-
var outer = this;
|
521
|
-
return (outer.minX <= point.x && outer.maxX >= point.x && outer.minY <= point.y && outer.maxY >= point.y);
|
522
|
-
};
|
523
|
-
|
524
|
-
/**
|
525
|
-
* Get a cell in the grid, creating it first if necessary.
|
526
|
-
*
|
527
|
-
* Optimization candidate
|
528
|
-
*
|
529
|
-
* @param {Number} x The x coordinate of the cell.
|
530
|
-
* @param {Number} y The y coordinate of the cell.
|
531
|
-
* @param {Number} z The z coordinate of the cell.
|
532
|
-
* @return {Array} The cell in the array.
|
533
|
-
*/
|
534
|
-
MarkerManager.prototype.getGridCellCreate_ = function (x, y, z) {
|
535
|
-
var grid = this.grid_[z];
|
536
|
-
if (x < 0) {
|
537
|
-
x += this.gridWidth_[z];
|
538
|
-
}
|
539
|
-
var gridCol = grid[x];
|
540
|
-
if (!gridCol) {
|
541
|
-
gridCol = grid[x] = [];
|
542
|
-
return (gridCol[y] = []);
|
543
|
-
}
|
544
|
-
var gridCell = gridCol[y];
|
545
|
-
if (!gridCell) {
|
546
|
-
return (gridCol[y] = []);
|
547
|
-
}
|
548
|
-
return gridCell;
|
549
|
-
};
|
550
|
-
|
551
|
-
|
552
|
-
/**
|
553
|
-
* Get a cell in the grid, returning undefined if it does not exist.
|
554
|
-
*
|
555
|
-
* NOTE: Optimized for speed -- otherwise could combine with getGridCellCreate_.
|
556
|
-
*
|
557
|
-
* @param {Number} x The x coordinate of the cell.
|
558
|
-
* @param {Number} y The y coordinate of the cell.
|
559
|
-
* @param {Number} z The z coordinate of the cell.
|
560
|
-
* @return {Array} The cell in the array.
|
561
|
-
*/
|
562
|
-
MarkerManager.prototype.getGridCellNoCreate_ = function (x, y, z) {
|
563
|
-
var grid = this.grid_[z];
|
564
|
-
|
565
|
-
if (x < 0) {
|
566
|
-
x += this.gridWidth_[z];
|
567
|
-
}
|
568
|
-
var gridCol = grid[x];
|
569
|
-
return gridCol ? gridCol[y] : undefined;
|
570
|
-
};
|
571
|
-
|
572
|
-
|
573
|
-
/**
|
574
|
-
* Turns at geographical bounds into a grid-space bounds.
|
575
|
-
*
|
576
|
-
* @param {LatLngBounds} bounds The geographical bounds.
|
577
|
-
* @param {Number} zoom The zoom level of the bounds.
|
578
|
-
* @param {google.maps.Size} swPadding The padding in pixels to extend beyond the
|
579
|
-
* given bounds.
|
580
|
-
* @param {google.maps.Size} nePadding The padding in pixels to extend beyond the
|
581
|
-
* given bounds.
|
582
|
-
* @return {GridBounds} The bounds in grid space.
|
583
|
-
*/
|
584
|
-
MarkerManager.prototype.getGridBounds_ = function (bounds, zoom, swPadding, nePadding) {
|
585
|
-
zoom = Math.min(zoom, this.maxZoom_);
|
586
|
-
|
587
|
-
var bl = bounds.getSouthWest();
|
588
|
-
var tr = bounds.getNorthEast();
|
589
|
-
var sw = this.getTilePoint_(bl, zoom, swPadding);
|
590
|
-
|
591
|
-
var ne = this.getTilePoint_(tr, zoom, nePadding);
|
592
|
-
var gw = this.gridWidth_[zoom];
|
593
|
-
|
594
|
-
// Crossing the prime meridian requires correction of bounds.
|
595
|
-
if (tr.lng() < bl.lng() || ne.x < sw.x) {
|
596
|
-
sw.x -= gw;
|
597
|
-
}
|
598
|
-
if (ne.x - sw.x + 1 >= gw) {
|
599
|
-
// Computed grid bounds are larger than the world; truncate.
|
600
|
-
sw.x = 0;
|
601
|
-
ne.x = gw - 1;
|
602
|
-
}
|
603
|
-
|
604
|
-
var gridBounds = new GridBounds([sw, ne]);
|
605
|
-
gridBounds.z = zoom;
|
606
|
-
|
607
|
-
return gridBounds;
|
608
|
-
};
|
609
|
-
|
610
|
-
|
611
|
-
/**
|
612
|
-
* Gets the grid-space bounds for the current map viewport.
|
613
|
-
*
|
614
|
-
* @return {Bounds} The bounds in grid space.
|
615
|
-
*/
|
616
|
-
MarkerManager.prototype.getMapGridBounds_ = function () {
|
617
|
-
return this.getGridBounds_(this.map_.getBounds(), this.mapZoom_, this.swPadding_, this.nePadding_);
|
618
|
-
};
|
619
|
-
|
620
|
-
|
621
|
-
/**
|
622
|
-
* Event listener for map:movend.
|
623
|
-
* NOTE: Use a timeout so that the user is not blocked
|
624
|
-
* from moving the map.
|
625
|
-
*
|
626
|
-
* Removed this because a a lack of a scopy override/callback function on events.
|
627
|
-
*/
|
628
|
-
MarkerManager.prototype.onMapMoveEnd_ = function () {
|
629
|
-
this.objectSetTimeout_(this, this.updateMarkers_, 0);
|
630
|
-
};
|
631
|
-
|
632
|
-
|
633
|
-
/**
|
634
|
-
* Call a function or evaluate an expression after a specified number of
|
635
|
-
* milliseconds.
|
636
|
-
*
|
637
|
-
* Equivalent to the standard window.setTimeout function, but the given
|
638
|
-
* function executes as a method of this instance. So the function passed to
|
639
|
-
* objectSetTimeout can contain references to this.
|
640
|
-
* objectSetTimeout(this, function () { alert(this.x) }, 1000);
|
641
|
-
*
|
642
|
-
* @param {Object} object The target object.
|
643
|
-
* @param {Function} command The command to run.
|
644
|
-
* @param {Number} milliseconds The delay.
|
645
|
-
* @return {Boolean} Success.
|
646
|
-
*/
|
647
|
-
MarkerManager.prototype.objectSetTimeout_ = function (object, command, milliseconds) {
|
648
|
-
return window.setTimeout(function () {
|
649
|
-
command.call(object);
|
650
|
-
}, milliseconds);
|
651
|
-
};
|
652
|
-
|
653
|
-
|
654
|
-
/**
|
655
|
-
* Is this layer visible?
|
656
|
-
*
|
657
|
-
* Returns visibility setting
|
658
|
-
*
|
659
|
-
* @return {Boolean} Visible
|
660
|
-
*/
|
661
|
-
MarkerManager.prototype.visible = function () {
|
662
|
-
return this.show_ ? true : false;
|
663
|
-
};
|
664
|
-
|
665
|
-
|
666
|
-
/**
|
667
|
-
* Returns true if the manager is hidden.
|
668
|
-
* Otherwise returns false.
|
669
|
-
* @return {Boolean} Hidden
|
670
|
-
*/
|
671
|
-
MarkerManager.prototype.isHidden = function () {
|
672
|
-
return !this.show_;
|
673
|
-
};
|
674
|
-
|
675
|
-
|
676
|
-
/**
|
677
|
-
* Shows the manager if it's currently hidden.
|
678
|
-
*/
|
679
|
-
MarkerManager.prototype.show = function () {
|
680
|
-
this.show_ = true;
|
681
|
-
this.refresh();
|
682
|
-
};
|
683
|
-
|
684
|
-
|
685
|
-
/**
|
686
|
-
* Hides the manager if it's currently visible
|
687
|
-
*/
|
688
|
-
MarkerManager.prototype.hide = function () {
|
689
|
-
this.show_ = false;
|
690
|
-
this.refresh();
|
691
|
-
};
|
692
|
-
|
693
|
-
|
694
|
-
/**
|
695
|
-
* Toggles the visibility of the manager.
|
696
|
-
*/
|
697
|
-
MarkerManager.prototype.toggle = function () {
|
698
|
-
this.show_ = !this.show_;
|
699
|
-
this.refresh();
|
700
|
-
};
|
701
|
-
|
702
|
-
|
703
|
-
/**
|
704
|
-
* Refresh forces the marker-manager into a good state.
|
705
|
-
* <ol>
|
706
|
-
* <li>If never before initialized, shows all the markers.</li>
|
707
|
-
* <li>If previously initialized, removes and re-adds all markers.</li>
|
708
|
-
* </ol>
|
709
|
-
*/
|
710
|
-
MarkerManager.prototype.refresh = function () {
|
711
|
-
if (this.shownMarkers_ > 0) {
|
712
|
-
this.processAll_(this.shownBounds_, this.removeOverlay_);
|
713
|
-
}
|
714
|
-
// An extra check on this.show_ to increase performance (no need to processAll_)
|
715
|
-
if (this.show_) {
|
716
|
-
this.processAll_(this.shownBounds_, this.addOverlay_);
|
717
|
-
}
|
718
|
-
this.notifyListeners_();
|
719
|
-
};
|
720
|
-
|
721
|
-
|
722
|
-
/**
|
723
|
-
* After the viewport may have changed, add or remove markers as needed.
|
724
|
-
*/
|
725
|
-
MarkerManager.prototype.updateMarkers_ = function () {
|
726
|
-
this.mapZoom_ = this.map_.getZoom();
|
727
|
-
var newBounds = this.getMapGridBounds_();
|
728
|
-
|
729
|
-
// If the move does not include new grid sections,
|
730
|
-
// we have no work to do:
|
731
|
-
if (newBounds.equals(this.shownBounds_) && newBounds.z === this.shownBounds_.z) {
|
732
|
-
return;
|
733
|
-
}
|
734
|
-
|
735
|
-
if (newBounds.z !== this.shownBounds_.z) {
|
736
|
-
this.processAll_(this.shownBounds_, this.removeOverlay_);
|
737
|
-
if (this.show_) { // performance
|
738
|
-
this.processAll_(newBounds, this.addOverlay_);
|
739
|
-
}
|
740
|
-
} else {
|
741
|
-
// Remove markers:
|
742
|
-
this.rectangleDiff_(this.shownBounds_, newBounds, this.removeCellMarkers_);
|
743
|
-
|
744
|
-
// Add markers:
|
745
|
-
if (this.show_) { // performance
|
746
|
-
this.rectangleDiff_(newBounds, this.shownBounds_, this.addCellMarkers_);
|
747
|
-
}
|
748
|
-
}
|
749
|
-
this.shownBounds_ = newBounds;
|
750
|
-
|
751
|
-
this.notifyListeners_();
|
752
|
-
};
|
753
|
-
|
754
|
-
|
755
|
-
/**
|
756
|
-
* Notify listeners when the state of what is displayed changes.
|
757
|
-
*/
|
758
|
-
MarkerManager.prototype.notifyListeners_ = function () {
|
759
|
-
google.maps.event.trigger(this, 'changed', this.shownBounds_, this.shownMarkers_);
|
760
|
-
};
|
761
|
-
|
762
|
-
|
763
|
-
/**
|
764
|
-
* Process all markers in the bounds provided, using a callback.
|
765
|
-
*
|
766
|
-
* @param {Bounds} bounds The bounds in grid space.
|
767
|
-
* @param {Function} callback The function to call for each marker.
|
768
|
-
*/
|
769
|
-
MarkerManager.prototype.processAll_ = function (bounds, callback) {
|
770
|
-
for (var x = bounds.minX; x <= bounds.maxX; x++) {
|
771
|
-
for (var y = bounds.minY; y <= bounds.maxY; y++) {
|
772
|
-
this.processCellMarkers_(x, y, bounds.z, callback);
|
773
|
-
}
|
774
|
-
}
|
775
|
-
};
|
776
|
-
|
777
|
-
|
778
|
-
/**
|
779
|
-
* Process all markers in the grid cell, using a callback.
|
780
|
-
*
|
781
|
-
* @param {Number} x The x coordinate of the cell.
|
782
|
-
* @param {Number} y The y coordinate of the cell.
|
783
|
-
* @param {Number} z The z coordinate of the cell.
|
784
|
-
* @param {Function} callback The function to call for each marker.
|
785
|
-
*/
|
786
|
-
MarkerManager.prototype.processCellMarkers_ = function (x, y, z, callback) {
|
787
|
-
var cell = this.getGridCellNoCreate_(x, y, z);
|
788
|
-
if (cell) {
|
789
|
-
for (var i = cell.length - 1; i >= 0; i--) {
|
790
|
-
callback(cell[i]);
|
791
|
-
}
|
792
|
-
}
|
793
|
-
};
|
794
|
-
|
795
|
-
|
796
|
-
/**
|
797
|
-
* Remove all markers in a grid cell.
|
798
|
-
*
|
799
|
-
* @param {Number} x The x coordinate of the cell.
|
800
|
-
* @param {Number} y The y coordinate of the cell.
|
801
|
-
* @param {Number} z The z coordinate of the cell.
|
802
|
-
*/
|
803
|
-
MarkerManager.prototype.removeCellMarkers_ = function (x, y, z) {
|
804
|
-
this.processCellMarkers_(x, y, z, this.removeOverlay_);
|
805
|
-
};
|
806
|
-
|
807
|
-
|
808
|
-
/**
|
809
|
-
* Add all markers in a grid cell.
|
810
|
-
*
|
811
|
-
* @param {Number} x The x coordinate of the cell.
|
812
|
-
* @param {Number} y The y coordinate of the cell.
|
813
|
-
* @param {Number} z The z coordinate of the cell.
|
814
|
-
*/
|
815
|
-
MarkerManager.prototype.addCellMarkers_ = function (x, y, z) {
|
816
|
-
this.processCellMarkers_(x, y, z, this.addOverlay_);
|
817
|
-
};
|
818
|
-
|
819
|
-
|
820
|
-
/**
|
821
|
-
* Use the rectangleDiffCoords_ function to process all grid cells
|
822
|
-
* that are in bounds1 but not bounds2, using a callback, and using
|
823
|
-
* the current MarkerManager object as the instance.
|
824
|
-
*
|
825
|
-
* Pass the z parameter to the callback in addition to x and y.
|
826
|
-
*
|
827
|
-
* @param {Bounds} bounds1 The bounds of all points we may process.
|
828
|
-
* @param {Bounds} bounds2 The bounds of points to exclude.
|
829
|
-
* @param {Function} callback The callback function to call
|
830
|
-
* for each grid coordinate (x, y, z).
|
831
|
-
*/
|
832
|
-
MarkerManager.prototype.rectangleDiff_ = function (bounds1, bounds2, callback) {
|
833
|
-
var me = this;
|
834
|
-
me.rectangleDiffCoords_(bounds1, bounds2, function (x, y) {
|
835
|
-
callback.apply(me, [x, y, bounds1.z]);
|
836
|
-
});
|
837
|
-
};
|
838
|
-
|
839
|
-
|
840
|
-
/**
|
841
|
-
* Calls the function for all points in bounds1, not in bounds2
|
842
|
-
*
|
843
|
-
* @param {Bounds} bounds1 The bounds of all points we may process.
|
844
|
-
* @param {Bounds} bounds2 The bounds of points to exclude.
|
845
|
-
* @param {Function} callback The callback function to call
|
846
|
-
* for each grid coordinate.
|
847
|
-
*/
|
848
|
-
MarkerManager.prototype.rectangleDiffCoords_ = function (bounds1, bounds2, callback) {
|
849
|
-
var minX1 = bounds1.minX;
|
850
|
-
var minY1 = bounds1.minY;
|
851
|
-
var maxX1 = bounds1.maxX;
|
852
|
-
var maxY1 = bounds1.maxY;
|
853
|
-
var minX2 = bounds2.minX;
|
854
|
-
var minY2 = bounds2.minY;
|
855
|
-
var maxX2 = bounds2.maxX;
|
856
|
-
var maxY2 = bounds2.maxY;
|
857
|
-
|
858
|
-
var x, y;
|
859
|
-
for (x = minX1; x <= maxX1; x++) { // All x in R1
|
860
|
-
// All above:
|
861
|
-
for (y = minY1; y <= maxY1 && y < minY2; y++) { // y in R1 above R2
|
862
|
-
callback(x, y);
|
863
|
-
}
|
864
|
-
// All below:
|
865
|
-
for (y = Math.max(maxY2 + 1, minY1); // y in R1 below R2
|
866
|
-
y <= maxY1; y++) {
|
867
|
-
callback(x, y);
|
868
|
-
}
|
869
|
-
}
|
870
|
-
|
871
|
-
for (y = Math.max(minY1, minY2);
|
872
|
-
y <= Math.min(maxY1, maxY2); y++) { // All y in R2 and in R1
|
873
|
-
// Strictly left:
|
874
|
-
for (x = Math.min(maxX1 + 1, minX2) - 1;
|
875
|
-
x >= minX1; x--) { // x in R1 left of R2
|
876
|
-
callback(x, y);
|
877
|
-
}
|
878
|
-
// Strictly right:
|
879
|
-
for (x = Math.max(minX1, maxX2 + 1); // x in R1 right of R2
|
880
|
-
x <= maxX1; x++) {
|
881
|
-
callback(x, y);
|
882
|
-
}
|
883
|
-
}
|
884
|
-
};
|
885
|
-
|
886
|
-
|
887
|
-
/**
|
888
|
-
* Removes value from array. O(N).
|
889
|
-
*
|
890
|
-
* @param {Array} array The array to modify.
|
891
|
-
* @param {any} value The value to remove.
|
892
|
-
* @param {Boolean} opt_notype Flag to disable type checking in equality.
|
893
|
-
* @return {Number} The number of instances of value that were removed.
|
894
|
-
*/
|
895
|
-
MarkerManager.prototype.removeFromArray_ = function (array, value, opt_notype) {
|
896
|
-
var shift = 0;
|
897
|
-
for (var i = 0; i < array.length; ++i) {
|
898
|
-
if (array[i] === value || (opt_notype && array[i] === value)) {
|
899
|
-
array.splice(i--, 1);
|
900
|
-
shift++;
|
901
|
-
}
|
902
|
-
}
|
903
|
-
return shift;
|
904
|
-
};
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
/**
|
913
|
-
* Projection overlay helper. Helps in calculating
|
914
|
-
* that markers get into the right grid.
|
915
|
-
* @constructor
|
916
|
-
* @param {Map} map The map to manage.
|
917
|
-
**/
|
918
|
-
function ProjectionHelperOverlay(map) {
|
919
|
-
|
920
|
-
this.setMap(map);
|
921
|
-
|
922
|
-
var TILEFACTOR = 8;
|
923
|
-
var TILESIDE = 1 << TILEFACTOR;
|
924
|
-
var RADIUS = 7;
|
925
|
-
|
926
|
-
this._map = map;
|
927
|
-
this._zoom = -1;
|
928
|
-
this._X0 =
|
929
|
-
this._Y0 =
|
930
|
-
this._X1 =
|
931
|
-
this._Y1 = -1;
|
932
|
-
|
933
|
-
|
934
|
-
}
|
935
|
-
ProjectionHelperOverlay.prototype = new google.maps.OverlayView();
|
936
|
-
|
937
|
-
/**
|
938
|
-
* Helper function to convert Lng to X
|
939
|
-
* @private
|
940
|
-
* @param {float} lng
|
941
|
-
**/
|
942
|
-
ProjectionHelperOverlay.prototype.LngToX_ = function (lng) {
|
943
|
-
return (1 + lng / 180);
|
944
|
-
};
|
945
|
-
|
946
|
-
/**
|
947
|
-
* Helper function to convert Lat to Y
|
948
|
-
* @private
|
949
|
-
* @param {float} lat
|
950
|
-
**/
|
951
|
-
ProjectionHelperOverlay.prototype.LatToY_ = function (lat) {
|
952
|
-
var sinofphi = Math.sin(lat * Math.PI / 180);
|
953
|
-
return (1 - 0.5 / Math.PI * Math.log((1 + sinofphi) / (1 - sinofphi)));
|
954
|
-
};
|
955
|
-
|
956
|
-
/**
|
957
|
-
* Old school LatLngToPixel
|
958
|
-
* @param {LatLng} latlng google.maps.LatLng object
|
959
|
-
* @param {Number} zoom Zoom level
|
960
|
-
* @return {position} {x: pixelPositionX, y: pixelPositionY}
|
961
|
-
**/
|
962
|
-
ProjectionHelperOverlay.prototype.LatLngToPixel = function (latlng, zoom) {
|
963
|
-
var map = this._map;
|
964
|
-
var div = this.getProjection().fromLatLngToDivPixel(latlng);
|
965
|
-
var abs = {x: ~~(0.5 + this.LngToX_(latlng.lng()) * (2 << (zoom + 6))), y: ~~(0.5 + this.LatToY_(latlng.lat()) * (2 << (zoom + 6)))};
|
966
|
-
return abs;
|
967
|
-
};
|
968
|
-
|
969
|
-
|
970
|
-
/**
|
971
|
-
* Draw function only triggers a ready event for
|
972
|
-
* MarkerManager to know projection can proceed to
|
973
|
-
* initialize.
|
974
|
-
*/
|
975
|
-
ProjectionHelperOverlay.prototype.draw = function () {
|
976
|
-
if (!this.ready) {
|
977
|
-
this.ready = true;
|
978
|
-
google.maps.event.trigger(this, 'ready');
|
979
|
-
}
|
980
|
-
};
|
1
|
+
/*** @name MarkerManager v3* @version 1.1*/
|
2
|
+
function MarkerManager(e,t){var n=this;n.map_=e;n.mapZoom_=e.getZoom();n.projectionHelper_=new ProjectionHelperOverlay(e);google.maps.event.addListener(n.projectionHelper_,"ready",function(){n.projection_=this.getProjection();n.initialize(e,t)})}function GridBounds(e){this.minX=Math.min(e[0].x,e[1].x);this.maxX=Math.max(e[0].x,e[1].x);this.minY=Math.min(e[0].y,e[1].y);this.maxY=Math.max(e[0].y,e[1].y)}function ProjectionHelperOverlay(e){this.setMap(e);var t=8;var n=1<<t;var r=7;this._map=e;this._zoom=-1;this._X0=this._Y0=this._X1=this._Y1=-1}MarkerManager.prototype.initialize=function(e,t){var n=this;t=t||{};n.tileSize_=MarkerManager.DEFAULT_TILE_SIZE_;var r=e.mapTypes;var i=1;for(var s in r){if(r.hasOwnProperty(s)&&r.get(s)&&r.get(s).maxZoom==="number"){var o=e.mapTypes.get(s).maxZoom;if(o>i){i=o}}}n.maxZoom_=t.maxZoom||19;n.trackMarkers_=t.trackMarkers;n.show_=t.show||true;var u;if(typeof t.borderPadding==="number"){u=t.borderPadding}else{u=MarkerManager.DEFAULT_BORDER_PADDING_}n.swPadding_=new google.maps.Size(-u,u);n.nePadding_=new google.maps.Size(u,-u);n.borderPadding_=u;n.gridWidth_={};n.grid_={};n.grid_[n.maxZoom_]={};n.numMarkers_={};n.numMarkers_[n.maxZoom_]=0;google.maps.event.addListener(e,"dragend",function(){n.onMapMoveEnd_()});google.maps.event.addListener(e,"idle",function(){n.onMapMoveEnd_()});google.maps.event.addListener(e,"zoom_changed",function(){n.onMapMoveEnd_()});n.removeOverlay_=function(e){e.setMap(null);n.shownMarkers_--};n.addOverlay_=function(e){if(n.show_){e.setMap(n.map_);n.shownMarkers_++}};n.resetManager_();n.shownMarkers_=0;n.shownBounds_=n.getMapGridBounds_();google.maps.event.trigger(n,"loaded")};MarkerManager.DEFAULT_TILE_SIZE_=1024;MarkerManager.DEFAULT_BORDER_PADDING_=100;MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE=256;MarkerManager.prototype.resetManager_=function(){var e=MarkerManager.MERCATOR_ZOOM_LEVEL_ZERO_RANGE;for(var t=0;t<=this.maxZoom_;++t){this.grid_[t]={};this.numMarkers_[t]=0;this.gridWidth_[t]=Math.ceil(e/this.tileSize_);e<<=1}};MarkerManager.prototype.clearMarkers=function(){this.processAll_(this.shownBounds_,this.removeOverlay_);this.resetManager_()};MarkerManager.prototype.getTilePoint_=function(e,t,n){var r=this.projectionHelper_.LatLngToPixel(e,t);var i=new google.maps.Point(Math.floor((r.x+n.width)/this.tileSize_),Math.floor((r.y+n.height)/this.tileSize_));return i};MarkerManager.prototype.addMarkerBatch_=function(e,t,n){var r=this;var i=e.getPosition();e.MarkerManager_minZoom=t;if(this.trackMarkers_){google.maps.event.addListener(e,"changed",function(e,t,n){r.onMarkerMoved_(e,t,n)})}var s=this.getTilePoint_(i,n,new google.maps.Size(0,0,0,0));for(var o=n;o>=t;o--){var u=this.getGridCellCreate_(s.x,s.y,o);u.push(e);s.x=s.x>>1;s.y=s.y>>1}};MarkerManager.prototype.isGridPointVisible_=function(e){var t=this.shownBounds_.minY<=e.y&&e.y<=this.shownBounds_.maxY;var n=this.shownBounds_.minX;var r=n<=e.x&&e.x<=this.shownBounds_.maxX;if(!r&&n<0){var i=this.gridWidth_[this.shownBounds_.z];r=n+i<=e.x&&e.x<=i-1}return t&&r};MarkerManager.prototype.onMarkerMoved_=function(e,t,n){var r=this.maxZoom_;var i=false;var s=this.getTilePoint_(t,r,new google.maps.Size(0,0,0,0));var o=this.getTilePoint_(n,r,new google.maps.Size(0,0,0,0));while(r>=0&&(s.x!==o.x||s.y!==o.y)){var u=this.getGridCellNoCreate_(s.x,s.y,r);if(u){if(this.removeFromArray_(u,e)){this.getGridCellCreate_(o.x,o.y,r).push(e)}}if(r===this.mapZoom_){if(this.isGridPointVisible_(s)){if(!this.isGridPointVisible_(o)){this.removeOverlay_(e);i=true}}else{if(this.isGridPointVisible_(o)){this.addOverlay_(e);i=true}}}s.x=s.x>>1;s.y=s.y>>1;o.x=o.x>>1;o.y=o.y>>1;--r}if(i){this.notifyListeners_()}};MarkerManager.prototype.removeMarker=function(e){var t=this.maxZoom_;var n=false;var r=e.getPosition();var i=this.getTilePoint_(r,t,new google.maps.Size(0,0,0,0));while(t>=0){var s=this.getGridCellNoCreate_(i.x,i.y,t);if(s){this.removeFromArray_(s,e)}if(t===this.mapZoom_){if(this.isGridPointVisible_(i)){this.removeOverlay_(e);n=true}}i.x=i.x>>1;i.y=i.y>>1;--t}if(n){this.notifyListeners_()}this.numMarkers_[e.MarkerManager_minZoom]--};MarkerManager.prototype.addMarkers=function(e,t,n){var r=this.getOptMaxZoom_(n);for(var i=e.length-1;i>=0;i--){this.addMarkerBatch_(e[i],t,r)}this.numMarkers_[t]+=e.length};MarkerManager.prototype.getOptMaxZoom_=function(e){return e||this.maxZoom_};MarkerManager.prototype.getMarkerCount=function(e){var t=0;for(var n=0;n<=e;n++){t+=this.numMarkers_[n]}return t};MarkerManager.prototype.getMarker=function(e,t,n){var r=new google.maps.LatLng(e,t);var i=this.getTilePoint_(r,n,new google.maps.Size(0,0,0,0));var s=new google.maps.Marker({position:r});var o=this.getGridCellNoCreate_(i.x,i.y,n);if(o!==undefined){for(var u=0;u<o.length;u++){if(e===o[u].getPosition().lat()&&t===o[u].getPosition().lng()){s=o[u]}}}return s};MarkerManager.prototype.addMarker=function(e,t,n){var r=this.getOptMaxZoom_(n);this.addMarkerBatch_(e,t,r);var i=this.getTilePoint_(e.getPosition(),this.mapZoom_,new google.maps.Size(0,0,0,0));if(this.isGridPointVisible_(i)&&t<=this.shownBounds_.z&&this.shownBounds_.z<=r){this.addOverlay_(e);this.notifyListeners_()}this.numMarkers_[t]++};GridBounds.prototype.equals=function(e){if(this.maxX===e.maxX&&this.maxY===e.maxY&&this.minX===e.minX&&this.minY===e.minY){return true}else{return false}};GridBounds.prototype.containsPoint=function(e){var t=this;return t.minX<=e.x&&t.maxX>=e.x&&t.minY<=e.y&&t.maxY>=e.y};MarkerManager.prototype.getGridCellCreate_=function(e,t,n){var r=this.grid_[n];if(e<0){e+=this.gridWidth_[n]}var i=r[e];if(!i){i=r[e]=[];return i[t]=[]}var s=i[t];if(!s){return i[t]=[]}return s};MarkerManager.prototype.getGridCellNoCreate_=function(e,t,n){var r=this.grid_[n];if(e<0){e+=this.gridWidth_[n]}var i=r[e];return i?i[t]:undefined};MarkerManager.prototype.getGridBounds_=function(e,t,n,r){t=Math.min(t,this.maxZoom_);var i=e.getSouthWest();var s=e.getNorthEast();var o=this.getTilePoint_(i,t,n);var u=this.getTilePoint_(s,t,r);var a=this.gridWidth_[t];if(s.lng()<i.lng()||u.x<o.x){o.x-=a}if(u.x-o.x+1>=a){o.x=0;u.x=a-1}var f=new GridBounds([o,u]);f.z=t;return f};MarkerManager.prototype.getMapGridBounds_=function(){return this.getGridBounds_(this.map_.getBounds(),this.mapZoom_,this.swPadding_,this.nePadding_)};MarkerManager.prototype.onMapMoveEnd_=function(){this.objectSetTimeout_(this,this.updateMarkers_,0)};MarkerManager.prototype.objectSetTimeout_=function(e,t,n){return window.setTimeout(function(){t.call(e)},n)};MarkerManager.prototype.visible=function(){return this.show_?true:false};MarkerManager.prototype.isHidden=function(){return!this.show_};MarkerManager.prototype.show=function(){this.show_=true;this.refresh()};MarkerManager.prototype.hide=function(){this.show_=false;this.refresh()};MarkerManager.prototype.toggle=function(){this.show_=!this.show_;this.refresh()};MarkerManager.prototype.refresh=function(){if(this.shownMarkers_>0){this.processAll_(this.shownBounds_,this.removeOverlay_)}if(this.show_){this.processAll_(this.shownBounds_,this.addOverlay_)}this.notifyListeners_()};MarkerManager.prototype.updateMarkers_=function(){this.mapZoom_=this.map_.getZoom();var e=this.getMapGridBounds_();if(e.equals(this.shownBounds_)&&e.z===this.shownBounds_.z){return}if(e.z!==this.shownBounds_.z){this.processAll_(this.shownBounds_,this.removeOverlay_);if(this.show_){this.processAll_(e,this.addOverlay_)}}else{this.rectangleDiff_(this.shownBounds_,e,this.removeCellMarkers_);if(this.show_){this.rectangleDiff_(e,this.shownBounds_,this.addCellMarkers_)}}this.shownBounds_=e;this.notifyListeners_()};MarkerManager.prototype.notifyListeners_=function(){google.maps.event.trigger(this,"changed",this.shownBounds_,this.shownMarkers_)};MarkerManager.prototype.processAll_=function(e,t){for(var n=e.minX;n<=e.maxX;n++){for(var r=e.minY;r<=e.maxY;r++){this.processCellMarkers_(n,r,e.z,t)}}};MarkerManager.prototype.processCellMarkers_=function(e,t,n,r){var i=this.getGridCellNoCreate_(e,t,n);if(i){for(var s=i.length-1;s>=0;s--){r(i[s])}}};MarkerManager.prototype.removeCellMarkers_=function(e,t,n){this.processCellMarkers_(e,t,n,this.removeOverlay_)};MarkerManager.prototype.addCellMarkers_=function(e,t,n){this.processCellMarkers_(e,t,n,this.addOverlay_)};MarkerManager.prototype.rectangleDiff_=function(e,t,n){var r=this;r.rectangleDiffCoords_(e,t,function(t,i){n.apply(r,[t,i,e.z])})};MarkerManager.prototype.rectangleDiffCoords_=function(e,t,n){var r=e.minX;var i=e.minY;var s=e.maxX;var o=e.maxY;var u=t.minX;var a=t.minY;var f=t.maxX;var l=t.maxY;var c,h;for(c=r;c<=s;c++){for(h=i;h<=o&&h<a;h++){n(c,h)}for(h=Math.max(l+1,i);h<=o;h++){n(c,h)}}for(h=Math.max(i,a);h<=Math.min(o,l);h++){for(c=Math.min(s+1,u)-1;c>=r;c--){n(c,h)}for(c=Math.max(r,f+1);c<=s;c++){n(c,h)}}};MarkerManager.prototype.removeFromArray_=function(e,t,n){var r=0;for(var i=0;i<e.length;++i){if(e[i]===t||n&&e[i]===t){e.splice(i--,1);r++}}return r};ProjectionHelperOverlay.prototype=new google.maps.OverlayView;ProjectionHelperOverlay.prototype.LngToX_=function(e){return 1+e/180};ProjectionHelperOverlay.prototype.LatToY_=function(e){var t=Math.sin(e*Math.PI/180);return 1-.5/Math.PI*Math.log((1+t)/(1-t))};ProjectionHelperOverlay.prototype.LatLngToPixel=function(e,t){var n=this._map;var r=this.getProjection().fromLatLngToDivPixel(e);var i={x:~~(.5+this.LngToX_(e.lng())*(2<<t+6)),y:~~(.5+this.LatToY_(e.lat())*(2<<t+6))};return i};ProjectionHelperOverlay.prototype.draw=function(){if(!this.ready){this.ready=true;google.maps.event.trigger(this,"ready")}}
|