pyk 0.2.3 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZjRjZjIzYWZmMzExNWIxMTEzZTU0ZjljNTE1ZDJlNTJmYzBlODE3ZA==
4
+ Mzg5NTc1MmI3MDY0ZWU4MjRlYjNjOGRiZDM5YjBkNTBjYWI2MmExOQ==
5
5
  data.tar.gz: !binary |-
6
- ZjhmOGY0YTJkMDBiMDQ1ZGQ4NTlhOTQ1ZDU3MmEyNWY3Y2EzMjg3YQ==
6
+ Y2M2NjdlMDhkZjYzMWFmM2IxYjFmMzA2ZDViYjk0Nzc1ZGRhNGU2YQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NDc5OWY5MDk1ZTI5M2U3YjU4ZTFkMDY3YTUxNTljY2Q3ZDFhM2QwNjJhZTM4
10
- YTY0YTI0MGI3ZTRjNmQyMmRkNTE4MDAyZjBkODk5NzE1ZjQzMjg2MzJkNTFk
11
- Zjc4YTBmOGVmZDZkNmMzMjg3MWYwNmE5ZmZjNjlkY2I2NWQ4NDk=
9
+ M2QwM2IyZmQyZTA2OTA0NTFhNmRkODU2NzA3OWYxOGM1YjQyMDU4Yjk0M2E4
10
+ NzZlYjU0MDgwMGJkY2NlNTFhOTM0ZDc4MTY0NzYxZTQxZWYyYjc1MDkyM2Fm
11
+ YWU5MWViMmQ4MzcwNWZmNTI5YWQzNmZkYTc3MDE1NzUxMDk1Nzk=
12
12
  data.tar.gz: !binary |-
13
- OTFlMWFmYTllOGI3Mjg4M2M2N2RiNzExMTc2MWYzZmRkZmE4MGM1NWRjZmI1
14
- ZmRiMDEwMTUyZWE0MDlkMDdjMDUzZGY4MjRmYmQ4ODNiMzgwNjNhYzMwYTAy
15
- ZTVmMTYyMjE2NmU4MWQ3OTE2OTFjMGVhMzZlZTM0NTVkZGNiY2M=
13
+ Zjg3MTkyMTI0MmQ5MTIxZDEzNzA0NTkyYmVjODdkYjYyZWVhOTdmMDA2NWJm
14
+ YTE4ZTVjYWJiMzM2ZTFkZTk3ZWYzMWE1ZGE2ZWRhYjBmNmI3ZjBkYzA0MWRh
15
+ NjU3MDVkOWE5MjE4OTJiZDEwNmJmYmFhZWMxYWE0YjBkZDBmMzA=
File without changes
File without changes
@@ -0,0 +1,980 @@
1
+ /**
2
+ * @name MarkerManager v3
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
+ };