PageSourceSearch

https://511pa.com/bundles/googleMapsOldMarkers?v=8YJeuxjGFwdZnTa6S3Cha-sb1tdXaivyal6u4CLYEJw1

js 511pa.com collected 2026-10-02 03:20:27 UTC 64,251 bytes, 2,002 lines download raw bytes

1gMarkers.buildMarker = ({ position, mapIconItem }) => {
2    //create and add associate with map
3    let marker = new google.maps.Marker({
4        clickable: mapIconItem.icon.isClickable,
5        position: position,
6        title: mapIconItem.title,
7        zIndex: mapIconItem.zindex,
8        preventClustering: mapIconItem.icon.preventClustering
9    });
10
11    return marker;
12}
13
14gMarkers.setIcon = (marker, icon) => {
15    marker.setIcon(icon);
16}
17
18gMarkers.getMapId = () => {
19    //a placeholder function.  It is needed for new_gMarkers.js
20    return  undefined;
21}
22
23gMarkers.getPosition = (marker) => {
24    return marker.getPosition();
25}
26
27gMarkers.setMarker = (options) => {
28    let marker = new google.maps.Marker(options);
29    return marker;
30}
31
32gMarkers.getHeight = (marker) => {
33    return marker.get('anchorSize').height;
34}
35/**
36 * @name MarkerClusterer for Google Maps v3
37 * @version version 1.0
38 * @author Luke Mahe
39 * @fileoverview
40 * The library creates and manages per-zoom-level clusters for large amounts of
41 * markers.
42 * <br/>
43 * This is a v3 implementation of the
44 * <a href="http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/"
45 * >v2 MarkerClusterer</a>.
46 */
47
48/**
49 * Licensed under the Apache License, Version 2.0 (the "License");
50 * you may not use this file except in compliance with the License.
51 * You may obtain a copy of the License at
52 *
53 *     http://www.apache.org/licenses/LICENSE-2.0
54 *
55 * Unless required by applicable law or agreed to in writing, software
56 * distributed under the License is distributed on an "AS IS" BASIS,
57 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
58 * See the License for the specific language governing permissions and
59 * limitations under the License.
60 */
61
62
63/******* See line 171 and 990 for our code modification, plus line 1105 to stop click propagation *******/
64
65
66/**
67 * A Marker Clusterer that clusters markers.
68 *
69 * @param {google.maps.Map} map The Google map to attach to.
70 * @param {Array.<google.maps.Marker>=} opt_markers Optional markers to add to
71 *   the cluster.
72 * @param {Object=} opt_options support the following options:
73 *     'gridSize': (number) The grid size of a cluster in pixels.
74 *     'maxZoom': (number) The maximum zoom level that a marker can be part of a
75 *                cluster.
76 *     'zoomOnClick': (boolean) Whether the default behaviour of clicking on a
77 *                    cluster is to zoom into it.
78 *     'averageCenter': (boolean) Wether the center of each cluster should be
79 *                      the average of all markers in the cluster.
80 *     'minimumClusterSize': (number) The minimum number of markers to be in a
81 *                           cluster before the markers are hidden and a count
82 *                           is shown.
83 *     'styles': (object) An object that has style properties:
84 *       'url': (string) The image url.
85 *       'height': (number) The image height.
86 *       'width': (number) The image width.
87 *       'anchor': (Array) The anchor position of the label text.
88 *       'textColor': (string) The text color.
89 *       'textSize': (number) The text size.
90 *       'backgroundPosition': (string) The position of the backgound x, y.
91 *       'iconAnchor': (Array) The anchor position of the icon x, y.
92 * @constructor
93 * @extends google.maps.OverlayView
94 */
95function MarkerClusterer(map, opt_markers, opt_options, oms) {
96    // MarkerClusterer implements google.maps.OverlayView interface. We use the
97    // extend function to extend MarkerClusterer with google.maps.OverlayView
98    // because it might not always be available when the code is defined so we
99    // look for it at the last possible moment. If it doesn't exist now then
100    // there is no point going ahead :)
101    this.extend(MarkerClusterer, google.maps.OverlayView);
102    this.map_ = map;
103    this.oms_ = oms;
104
105    /**
106     * @type {Array.<google.maps.Marker>}
107     * @private
108     */
109    this.markers_ = [];
110
111    /**
112     *  @type {Array.<Cluster>}
113     */
114    this.clusters_ = [];
115
116    this.sizes = [53, 56, 66, 78, 90];
117
118    /**
119     * @private
120     */
121    this.styles_ = [];
122
123    /**
124     * @type {boolean}
125     * @private
126     */
127    this.ready_ = false;
128
129    var options = opt_options || {};
130
131    /**
132     * @type {number}
133     * @private
134     */
135    this.gridSize_ = options['gridSize'] || 60;
136
137    /**
138     * @private
139     */
140    this.minClusterSize_ = options['minimumClusterSize'] || 2;
141
142
143    /**
144     * @type {?number}
145     * @private
146     */
147    this.maxZoom_ = options['maxZoom'] || null;
148
149    this.styles_ = options['styles'] || [];
150
151    /**
152     * @type {string}
153     * @private
154     */
155    this.imagePath_ = options['imagePath'] ||
156        this.MARKER_CLUSTER_IMAGE_PATH_;
157
158    /**
159     * @type {string}
160     * @private
161     */
162    this.imageExtension_ = options['imageExtension'] ||
163        this.MARKER_CLUSTER_IMAGE_EXTENSION_;
164
165    /**
166     * @type {boolean}
167     * @private
168     */
169    this.zoomOnClick_ = true;
170
171    if (options['zoomOnClick'] != undefined) {
172        this.zoomOnClick_ = options['zoomOnClick'];
173    }
174
175    /**
176     * @type {boolean}
177     * @private
178     */
179    this.averageCenter_ = false;
180
181    if (options['averageCenter'] != undefined) {
182        this.averageCenter_ = options['averageCenter'];
183    }
184
185    this.setupStyles_();
186
187    this.setMap(map);
188
189    /**
190     * @type {number}
191     * @private
192     */
193    this.prevZoom_ = this.map_.getZoom();
194
195    // Add the map event listeners
196    var that = this;
197
198    // MODIFIED: Track zoom changes for reference but don't update clusters during gesture
199    // Application layer (iconManager/appHelper) handles all cluster updates via idle event
200    // This prevents zoom reset issues during rapid pinch-zoom on mobile
201    google.maps.event.addListener(this.map_, 'zoom_changed', function () {
202        that.prevZoom_ = that.map_.getZoom();
203    });
204
205    // NOTE: idle listener removed - redundant with application layer handling
206    // iconManager.Redraw() in appHelper.js calls markerClusterer.repaint() at appropriate times
207    //google.maps.event.addListener(this.map_, 'idle', function () {
208    //    that.redraw();
209    //});
210
211    // Finally, add the markers
212    if (opt_markers && opt_markers.length) {
213        this.addMarkers(opt_markers, false);
214    }
215}
216
217
218/**
219 * The marker cluster image path.
220 *
221 * @type {string}
222 * @private
223 */
224MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_PATH_ =
225    'https://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/' +
226    'images/m';
227
228
229/**
230 * The marker cluster image path.
231 *
232 * @type {string}
233 * @private
234 */
235MarkerClusterer.prototype.MARKER_CLUSTER_IMAGE_EXTENSION_ = 'png';
236
237
238/**
239 * Extends a objects prototype by anothers.
240 *
241 * @param {Object} obj1 The object to be extended.
242 * @param {Object} obj2 The object to extend with.
243 * @return {Object} The new extended object.
244 * @ignore
245 */
246MarkerClusterer.prototype.extend = function (obj1, obj2) {
247    return (function (object) {
248        for (var property in object.prototype) {
249            this.prototype[property] = object.prototype[property];
250        }
251        return this;
252    }).apply(obj1, [obj2]);
253};
254
255
256/**
257 * Implementaion of the interface method.
258 * @ignore
259 */
260MarkerClusterer.prototype.onAdd = function () {
261    this.setReady_(true);
262};
263
264/**
265 * Implementaion of the interface method.
266 * @ignore
267 */
268MarkerClusterer.prototype.draw = function () { };
269
270/**
271 * Sets up the styles object.
272 *
273 * @private
274 */
275MarkerClusterer.prototype.setupStyles_ = function () {
276    if (this.styles_.length) {
277        return;
278    }
279
280    for (var i = 0, size; size = this.sizes[i]; i++) {
281        this.styles_.push({
282            url: this.imagePath_ + (i + 1) + '.' + this.imageExtension_,
283            height: size,
284            width: size
285        });
286    }
287};
288
289/**
290 *  Fit the map to the bounds of the markers in the clusterer.
291 */
292MarkerClusterer.prototype.fitMapToMarkers = function () {
293    var markers = this.getMarkers();
294    var bounds = new google.maps.LatLngBounds();
295    for (var i = 0, marker; marker = markers[i]; i++) {
296        bounds.extend(marker.getPosition());
297    }
298
299    this.map_.fitBounds(bounds);
300    this.map_.panBy(0, 0);
301};
302
303
304/**
305 *  Sets the styles.
306 *
307 *  @param {Object} styles The style to set.
308 */
309MarkerClusterer.prototype.setStyles = function (styles) {
310    this.styles_ = styles;
311};
312
313
314/**
315 *  Gets the styles.
316 *
317 *  @return {Object} The styles object.
318 */
319MarkerClusterer.prototype.getStyles = function () {
320    return this.styles_;
321};
322
323
324/**
325 * Whether zoom on click is set.
326 *
327 * @return {boolean} True if zoomOnClick_ is set.
328 */
329MarkerClusterer.prototype.isZoomOnClick = function () {
330    return this.zoomOnClick_;
331};
332
333/**
334 * Whether average center is set.
335 *
336 * @return {boolean} True if averageCenter_ is set.
337 */
338MarkerClusterer.prototype.isAverageCenter = function () {
339    return this.averageCenter_;
340};
341
342
343/**
344 *  Returns the array of markers in the clusterer.
345 *
346 *  @return {Array.<google.maps.Marker>} The markers.
347 */
348MarkerClusterer.prototype.getMarkers = function () {
349    return this.markers_;
350};
351
352
353/**
354 *  Returns the number of markers in the clusterer
355 *
356 *  @return {Number} The number of markers.
357 */
358MarkerClusterer.prototype.getTotalMarkers = function () {
359    return this.markers_.length;
360};
361
362
363/**
364 *  Sets the max zoom for the clusterer.
365 *
366 *  @param {number} maxZoom The max zoom level.
367 */
368MarkerClusterer.prototype.setMaxZoom = function (maxZoom) {
369    this.maxZoom_ = maxZoom;
370};
371
372
373/**
374 *  Gets the max zoom for the clusterer.
375 *
376 *  @return {number} The max zoom level.
377 */
378MarkerClusterer.prototype.getMaxZoom = function () {
379    return this.maxZoom_;
380};
381
382
383/**
384 *  The function for calculating the cluster icon image.
385 *
386 *  @param {Array.<google.maps.Marker>} markers The markers in the clusterer.
387 *  @param {number} numStyles The number of styles available.
388 *  @return {Object} A object properties: 'text' (string) and 'index' (number).
389 *  @private
390 */
391MarkerClusterer.prototype.calculator_ = function (markers, numStyles) {
392    var index = 0;
393    var count = markers.length;
394    var dv = count;
395    while (dv !== 0) {
396        dv = parseInt(dv / 10, 10);
397        index++;
398    }
399
400    index = Math.min(index, numStyles);
401    return {
402        text: count,
403        index: index
404    };
405};
406
407
408/**
409 * Set the calculator function.
410 *
411 * @param {function(Array, number)} calculator The function to set as the
412 *     calculator. The function should return a object properties:
413 *     'text' (string) and 'index' (number).
414 *
415 */
416MarkerClusterer.prototype.setCalculator = function (calculator) {
417    this.calculator_ = calculator;
418};
419
420
421/**
422 * Get the calculator function.
423 *
424 * @return {function(Array, number)} the calculator function.
425 */
426MarkerClusterer.prototype.getCalculator = function () {
427    return this.calculator_;
428};
429
430
431/**
432 * Add an array of markers to the clusterer.
433 *
434 * @param {Array.<google.maps.Marker>} markers The markers to add.
435 * @param {boolean=} opt_nodraw Whether to redraw the clusters.
436 */
437MarkerClusterer.prototype.addMarkers = function (markers, opt_nodraw) {
438    for (var i = 0, marker; marker = markers[i]; i++) {
439        if (!marker.preventClustering) {
440          //ToDo: get oms to work with new Google markers
441            this.oms_.addMarker(marker);
442        }
443        this.pushMarkerTo_(marker);
444    }
445    if (!opt_nodraw) {
446        this.redraw();
447    }
448};
449
450
451/**
452 * Pushes a marker to the clusterer.
453 *
454 * @param {google.maps.Marker} marker The marker to add.
455 * @private
456 */
457MarkerClusterer.prototype.pushMarkerTo_ = function (marker) {
458    marker.isAdded = false;
459    if (marker['draggable']) {
460        // If the marker is draggable add a listener so we update the clusters on
461        // the drag end.
462        var that = this;
463        google.maps.event.addListener(marker, 'dragend', function () {
464            marker.isAdded = false;
465            that.repaint();
466        });
467    }
468    this.markers_.push(marker);
469};
470
471
472/**
473 * Adds a marker to the clusterer and redraws if needed.
474 *
475 * @param {google.maps.Marker} marker The marker to add.
476 * @param {boolean=} opt_nodraw Whether to redraw the clusters.
477 */
478MarkerClusterer.prototype.addMarker = function (marker, opt_nodraw) {
479    if (!marker.preventClustering) {
480        this.oms_.addMarker(marker);
481    }
482    this.pushMarkerTo_(marker);
483    if (!opt_nodraw) {
484        this.redraw();
485    }
486};
487
488
489/**
490 * Removes a marker and returns true if removed, false if not
491 *
492 * @param {google.maps.Marker} marker The marker to remove
493 * @return {boolean} Whether the marker was removed or not
494 * @private
495 */
496MarkerClusterer.prototype.removeMarker_ = function (marker) {
497    var index = -1;
498    if (this.markers_.indexOf) {
499        index = this.markers_.indexOf(marker);
500    } else {
501        for (var i = 0, m; m = this.markers_[i]; i++) {
502            if (m == marker) {
503                index = i;
504                break;
505            }
506        }
507    }
508
509    if (index == -1) {
510        // Marker is not in our list of markers.
511        return false;
512    }
513
514    marker.setMap(null);
515    marker.clustered = true;
516    google.maps.event.trigger(marker, 'marker-clustered', true);
517    this.markers_.splice(index, 1);
518
519    return true;
520};
521
522
523/**
524 * Remove a marker from the cluster.
525 *
526 * @param {google.maps.Marker} marker The marker to remove.
527 * @param {boolean=} opt_nodraw Optional boolean to force no redraw.
528 * @return {boolean} True if the marker was removed.
529 */
530MarkerClusterer.prototype.removeMarker = function (marker, opt_nodraw) {
531    this.oms_.removeMarker(marker);
532    var removed = this.removeMarker_(marker);
533
534    if (!opt_nodraw && removed) {
535        this.resetViewport();
536        this.redraw();
537        return true;
538    } else {
539        return false;
540    }
541};
542
543
544/**
545 * Removes an array of markers from the cluster.
546 *
547 * @param {Array.<google.maps.Marker>} markers The markers to remove.
548 * @param {boolean=} opt_nodraw Optional boolean to force no redraw.
549 */
550MarkerClusterer.prototype.removeMarkers = function (markers, opt_nodraw) {
551    var removed = false;
552
553    for (var i = 0, marker; marker = markers[i]; i++) {
554        this.oms_.removeMarker(marker);
555        var r = this.removeMarker_(marker);
556        removed = removed || r;
557    }
558
559    if (!opt_nodraw && removed) {
560        this.resetViewport();
561        this.redraw();
562        return true;
563    }
564};
565
566
567/**
568 * Sets the clusterer's ready state.
569 *
570 * @param {boolean} ready The state.
571 * @private
572 */
573MarkerClusterer.prototype.setReady_ = function (ready) {
574    if (!this.ready_) {
575        this.ready_ = ready;
576        this.createClusters_();
577    }
578};
579
580
581/**
582 * Returns the number of clusters in the clusterer.
583 *
584 * @return {number} The number of clusters.
585 */
586MarkerClusterer.prototype.getTotalClusters = function () {
587    return this.clusters_.length;
588};
589
590
591/**
592 * Returns the google map that the clusterer is associated with.
593 *
594 * @return {google.maps.Map} The map.
595 */
596MarkerClusterer.prototype.getMap = function () {
597    return this.map_;
598};
599
600
601/**
602 * Sets the google map that the clusterer is associated with.
603 *
604 * @param {google.maps.Map} map The map.
605 */
606MarkerClusterer.prototype.setMap = function (map) {
607    this.map_ = map;
608};
609
610
611/**
612 * Returns the size of the grid.
613 *
614 * @return {number} The grid size.
615 */
616MarkerClusterer.prototype.getGridSize = function () {
617    return this.gridSize_;
618};
619
620
621/**
622 * Sets the size of the grid.
623 *
624 * @param {number} size The grid size.
625 */
626MarkerClusterer.prototype.setGridSize = function (size) {
627    this.gridSize_ = size;
628};
629
630
631/**
632 * Returns the min cluster size.
633 *
634 * @return {number} The grid size.
635 */
636MarkerClusterer.prototype.getMinClusterSize = function () {
637    return this.minClusterSize_;
638};
639
640/**
641 * Sets the min cluster size.
642 *
643 * @param {number} size The grid size.
644 */
645MarkerClusterer.prototype.setMinClusterSize = function (size) {
646    this.minClusterSize_ = size;
647};
648
649
650/**
651 * Extends a bounds object by the grid size.
652 *
653 * @param {google.maps.LatLngBounds} bounds The bounds to extend.
654 * @return {google.maps.LatLngBounds}
654 The extended bounds.
655 */
656MarkerClusterer.prototype.getExtendedBounds = function (bounds) {
657    var projection = this.getProjection();
658
659    // Turn the bounds into latlng.
660    var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),
661        bounds.getNorthEast().lng());
662    var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),
663        bounds.getSouthWest().lng());
664
665    // Convert the points to pixels and the extend out by the grid size.
666    var trPix = projection.fromLatLngToDivPixel(tr);
667    trPix.x += this.gridSize_;
668    trPix.y -= this.gridSize_;
669
670    var blPix = projection.fromLatLngToDivPixel(bl);
671    blPix.x -= this.gridSize_;
672    blPix.y += this.gridSize_;
673
674    // Convert the pixel points back to LatLng
675    var ne = projection.fromDivPixelToLatLng(trPix);
676    var sw = projection.fromDivPixelToLatLng(blPix);
677
678    // Extend the bounds to contain the new bounds.
679    bounds.extend(ne);
680    bounds.extend(sw);
681
682    return bounds;
683};
684
685
686/**
687 * Determins if a marker is contained in a bounds.
688 *
689 * @param {google.maps.Marker} marker The marker to check.
690 * @param {google.maps.LatLngBounds} bounds The bounds to check against.
691 * @return {boolean} True if the marker is in the bounds.
692 * @private
693 */
694MarkerClusterer.prototype.isMarkerInBounds_ = function (marker, bounds) {
695    if (marker.getPosition) return bounds.contains(marker.getPosition());
696    else return false;
697};
698
699
700/**
701 * Clears all clusters and markers from the clusterer.
702 */
703MarkerClusterer.prototype.clearMarkers = function () {
704    this.resetViewport(true);
705
706    // Set the markers a empty array.
707    this.markers_ = [];
708};
709
710
711/**
712 * Clears all existing clusters and recreates them.
713 * @param {boolean} opt_hide To also hide the marker.
714 */
715MarkerClusterer.prototype.resetViewport = function (opt_hide) {
716    // Remove all the clusters
717    for (var i = 0, cluster; cluster = this.clusters_[i]; i++) {
718        cluster.removeCluster();
719    }
720
721    // Reset the markers to not be added and to be invisible.
722    for (var i = 0, marker; marker = this.markers_[i]; i++) {
723        marker.isAdded = false;
724        if (opt_hide) {
725            marker.setMap(null);
726        }
727    }
728
729    this.clusters_ = [];
730};
731
732/**
733 *
734 */
735MarkerClusterer.prototype.repaint = function () {
736    var oldClusters = this.clusters_.slice();
737    this.clusters_.length = 0;
738    this.resetViewport();
739    this.redraw();
740
741    // Remove the old clusters.
742    // Do it in a timeout so the other clusters have been drawn first.
743    window.setTimeout(function () {
744        for (var i = 0, cluster; cluster = oldClusters[i]; i++) {
745            cluster.removeCluster();
746        }
747    }, 0);
748};
749
750
751/**
752 * Redraws the clusters.
753 */
754MarkerClusterer.prototype.redraw = function () {
755    this.createClusters_();
756};
757
758
759/**
760 * Calculates the distance between two latlng locations in km.
761 * @see http://www.movable-type.co.uk/scripts/latlong.html
762 *
763 * @param {google.maps.LatLng} p1 The first lat lng point.
764 * @param {google.maps.LatLng} p2 The second lat lng point.
765 * @return {number} The distance between the two points in km.
766 * @private
767*/
768MarkerClusterer.prototype.distanceBetweenPoints_ = function (p1, p2) {
769    if (!p1 || !p2) {
770        return 0;
771    }
772
773    var R = 6371; // Radius of the Earth in km
774    var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
775    var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
776    var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
777        Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) *
778        Math.sin(dLon / 2) * Math.sin(dLon / 2);
779    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
780    var d = R * c;
781    return d;
782};
783
784
785/**
786 * Add a marker to a cluster, or creates a new cluster.
787 *
788 * @param {google.maps.Marker} marker The marker to add.
789 * @private
790 */
791MarkerClusterer.prototype.addToClosestCluster_ = function (marker) {
792    var distance = 40000; // Some large number
793    var clusterToAddTo = null;
794    var pos = marker.getPosition();
795    for (var i = 0, cluster;
795 cluster = this.clusters_[i]; i++) {
796        var center = cluster.getCenter();
797        if (center) {
798            var d = this.distanceBetweenPoints_(center, marker.getPosition());
799            if (d < distance) {
800                distance = d;
801                clusterToAddTo = cluster;
802            }
803        }
804    }
805
806    if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {
807        clusterToAddTo.addMarker(marker);
808    } else {
809        var cluster = new Cluster(this);
810        cluster.addMarker(marker);
811        this.clusters_.push(cluster);
812    }
813};
814
815
816/**
817 * Creates the clusters.
818 *
819 * @private
820 */
821MarkerClusterer.prototype.createClusters_ = function () {
822    if (!this.ready_) {
823        return;
824    }
825
826    // Get our current map view bounds.
827    // Create a new bounds object so we don't affect the map.
828    var mapBounds = new google.maps.LatLngBounds(this.map_.getBounds().getSouthWest(),
829        this.map_.getBounds().getNorthEast());
830    var bounds = this.getExtendedBounds(mapBounds);
831
832    for (var i = 0, marker; marker = this.markers_[i]; i++) {
833        if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {
834            this.addToClosestCluster_(marker);
835        }
836    }
837};
838
839
840/**
841 * A cluster that contains markers.
842 *
843 * @param {MarkerClusterer} markerClusterer The markerclusterer that this
844 *     cluster is associated with.
845 * @constructor
846 * @ignore
847 */
848function Cluster(markerClusterer) {
849    this.markerClusterer_ = markerClusterer;
850    this.map_ = markerClusterer.getMap();
851    this.gridSize_ = markerClusterer.getGridSize();
852    this.minClusterSize_ = markerClusterer.getMinClusterSize();
853    this.averageCenter_ = markerClusterer.isAverageCenter();
854    this.center_ = null;
855    this.markers_ = [];
856    this.bounds_ = null;
857    this.clusterIcon_ = new ClusterIcon(this, markerClusterer.getStyles(),
858        markerClusterer.getGridSize());
859}
860
861/**
862 * Determins if a marker is already added to the cluster.
863 *
864 * @param {google.maps.Marker} marker The marker to check.
865 * @return {boolean} True if the marker is already added.
866 */
867Cluster.prototype.isMarkerAlreadyAdded = function (marker) {
868    if (this.markers_.indexOf) {
869        return this.markers_.indexOf(marker) != -1;
870    } else {
871        for (var i = 0, m; m = this.markers_[i]; i++) {
872            if (m == marker) {
873                return true;
874            }
875        }
876    }
877    return false;
878};
879
880
881/**
882 * Add a marker the cluster.
883 *
884 * @param {google.maps.Marker} marker The marker to add.
885 * @return {boolean} True if the marker was added.
886 */
887Cluster.prototype.addMarker = function (marker) {
888    if (this.isMarkerAlreadyAdded(marker)) {
889        return false;
890    }
891
892    if (!this.center_) {
893        this.center_ = marker.getPosition();
894        this.calculateBounds_();
895    } else {
896        if (this.averageCenter_) {
897            var l = this.markers_.length + 1;
898            var lat = (this.center_.lat() * (l - 1) + marker.getPosition().lat()) / l;
899            var lng = (this.center_.lng() * (l - 1) + marker.getPosition().lng()) / l;
900            this.center_ = new google.maps.LatLng(lat, lng);
901            this.calculateBounds_();
902        }
903    }
904
905    marker.isAdded = true;
906    if (!marker.preventClustering) {
907        this.markers_.push(marker);
908    }
909    
910    var len = this.markers_.length;
911    if (len < this.minClusterSize_ || marker.preventClustering) {
912        // Min cluster size not reached so show the marker.
913        if (marker.getMap() != this.map_) {
914            marker.setMap(this.map_);
915        }
916        marker.clustered = false;
917        google.maps.event.trigger(marker, 'marker-clustered', false);
918    }
919
920    if (len == this.minClusterSize_) {
921        // Hide the markers that were showing.
922        for (var i = 0; i < len; i++) {
923            this.markers_[i].setMap(null);
924            this.markers_[i].clustered = true;
925            google.maps.event.trigger(this.markers_[i], 'marker-clustered', true);
926        }
927    }
928
929    if (len >= this.minClusterSize_ && !marker.preventClustering) {
930        marker.setMap(null);
931        marker.clustered = true;
932        google.maps.event.trigger(marker, 'marker-clustered', true);
933    }
934
935    this.updateIcon();
936    return true;
937};
938
939
940/**
941 * Returns the marker clusterer that the cluster is associated with.
942 *
943 * @return {MarkerClusterer} The associated marker clusterer.
944 */
945Cluster.prototype.getMarkerClusterer = function () {
946    return this.markerClusterer_;
947};
948
949
950/**
951 * Returns the bounds of the cluster.
952 *
953 * @return {google.maps.LatLngBounds} the cluster bounds.
954 */
955Cluster.prototype.getBounds = function () {
956    var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
957    var markers = this.getMarkers();
958    for (var i = 0, marker; marker = markers[i]; i++) {
959        bounds.extend(marker.getPosition());
960    }
961    return bounds;
962};
963
964
965/**
966 * Removes the cluster
967 */
968Cluster.prototype.removeCluster = function () {
969    this.clusterIcon_.removeClusterIcon();
970    this.markers_.length = 0;
971    delete this.markers_;
972};
973
974
975/**
976 * Returns the center of the cluster.
977 *
978 * @return {number} The cluster center.
979 */
980Cluster.prototype.getSize = function () {
981    return this.markers_.length;
982};
983
984
985/**
986 * Returns the center of the cluster.
987 *
988 * @return {Array.<google.maps.Marker>} The cluster center.
989 */
990Cluster.prototype.getMarkers = function () {
991    return this.markers_;
992};
993
994
995/**
996 * Returns the center of the cluster.
997 *
998 * @return {google.maps.LatLng} The cluster center.
999 */
1000Cluster.prototype.getCenter = function () {
1001    return this.center_;
1002};
1003
1004
1005/**
1006 * Calculated the extended bounds of the cluster with the grid.
1007 *
1008 * @private
1009 */
1010Cluster.prototype.calculateBounds_ = function () {
1011    var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
1012    this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds);
1013};
1014
1015
1016/**
1017 * Determines if a marker lies in the clusters bounds.
1018 *
1019 * @param {google.maps.Marker} marker The marker to check.
1020 * @return {boolean} True if the marker lies in the bounds.
1021 */
1022Cluster.prototype.isMarkerInClusterBounds = function (marker) {
1023    return this.bounds_.contains(marker.getPosition());
1024};
1025
1026
1027/**
1028 * Returns the map that the cluster is associated with.
1029 *
1030 * @return {google.maps.Map} The map.
1031 */
1032Cluster.prototype.getMap = function () {
1033    return this.map_;
1034};
1035
1036
1037/**
1038 * Updates the cluster icon
1039 */
1040Cluster.prototype.updateIcon = function () {
1041    var zoom = this.map_.getZoom();
1042    var mz = this.markerClusterer_.getMaxZoom();
1043
1044    if (mz && zoom > mz) {
1045        // The zoom is greater than our max zoom so show all the markers in cluster.
1046        for (var i = 0, marker; marker = this.markers_[i]; i++) {
1047            //check to see if the map is already set so we don't flicker the icon
1048            if (marker.map !== this.map_) {
1049                marker.setMap(this.map_);
1050                marker.clustered = false;
1051                google.maps.event.trigger(marker, 'marker-clustered', false);
1052            }
1053        }
1054        return;
1055    }
1056
1057    if (this.markers_.length < this.minClusterSize_) {
1058        // Min cluster size not yet reached.
1059        this.clusterIcon_.hide();
1060        return;
1061    }
1062
1063    var numStyles = this.markerClusterer_.getStyles().length;
1064    var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles);
1065    this.clusterIcon_.setCenter(this.center_);
1066    this.clusterIcon_.setSums(sums);
1067    this.clusterIcon_.show();
1068};
1069
1070
1071/**
1072 * A cluster icon
1073 *
1074 * @param {Cluster} cluster The cluster to be associated with.
1075 * @param {Object} styles An object that has style properties:
1076 *     'url': (string) The image url.
1077 *     'height': (number) The image height.
1078 *     'width': (number) The image width.
1079 *     'anchor': (Array) The anchor position of the label text.
1080 *     'textColor': (string) The text color.
1081 *     'textSize': (number) The text size.
1082 *     'backgroundPosition: (string) The background postition x, y.
1083 * @param {number=} opt_padding Optional padding to apply to the cluster icon.
1084 * @constructor
1085 * @extends google.maps.OverlayView
1086 * @ignore
1087 */
1088function ClusterIcon(cluster, styles, opt_padding) {
1089    cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView);
1090
1091    this.styles_ = styles;
1092    this.padding_ = opt_padding || 0;
1093    this.cluster_ = cluster;
1094    this.center_ = null;
1095    this.map_ = cluster.getMap();
1096    this.div_ = null;
1097    this.sums_ = null;
1098    this.visible_ = false;
1099
1100    this.setMap(this.map_);
1101}
1102
1103
1104/**
1105 * Triggers the clusterclick event and zoom's if the option is set.
1106 *
1107 * @param {google.maps.MouseEvent} event The event to propagate
1108 */
1109ClusterIcon.prototype.triggerClusterClick = function (event) {
1110    var markerClusterer = this.cluster_.getMarkerClusterer();
1111
1112    // Trigger the clusterclick event.
1113    google.maps.event.trigger(markerClusterer, 'clusterclick', this.cluster_, event);
1114
1115    if (markerClusterer.isZoomOnClick()) {
1116        // Zoom into the cluster.
1117        this.map_.fitBounds(this.cluster_.getBounds());
1118        this.map_.panBy(0, 0);
1119    }
1120};
1121
1122
1123/**
1124 * Adding the cluster icon to the dom.
1125 * @ignore
1126 */
1127ClusterIcon.prototype.onAdd = function () {
1128    this.div_ = document.createElement('DIV');
1129    if (this.visible_) {
1130        var pos = this.getPosFromLatLng_(this.center_);
1131        this.div_.style.cssText = this.createCss(pos);
1132        this.div_.innerHTML = this.sums_.text;
1133    }
1134
1135    var panes = this.getPanes();
1136    panes.overlayMouseTarget.appendChild(this.div_);
1137
1138    var that = this;
1139    this.div_.addEventListener('click', function (event) {
1140        event.stopPropagation();  //to avoid click conflict with KML layer (County Boundary)
1141        that.triggerClusterClick(event);
1142    });
1143};
1144
1145
1146/**
1147 * Returns the position to place the div dending on the latlng.
1148 *
1149 * @param {google.maps.LatLng} latlng The position in latlng.
1150 * @return {google.maps.Point} The position in pixels.
1151 * @private
1152 */
1153ClusterIcon.prototype.getPosFromLatLng_ = function (latlng) {
1154    var pos = this.getProjection().fromLatLngToDivPixel(latlng);
1155
1156    if (typeof this.iconAnchor_ === 'object' && this.iconAnchor_.length === 2) {
1157        pos.x -= this.iconAnchor_[0];
1158        pos.y -= this.iconAnchor_[1];
1159    } else {
1160        pos.x -= parseInt(this.width_ / 2, 10);
1161        pos.y -= parseInt(this.height_ / 2, 10);
1162    }
1163    return pos;
1164};
1165
1166
1167/**
1168 * Draw the icon.
1169 * @ignore
1170 */
1171ClusterIcon.prototype.draw = function () {
1172    if (this.visible_) {
1173        var pos = this.getPosFromLatLng_(this.center_);
1174        this.div_.style.top = pos.y + 'px';
1175        this.div_.style.left = pos.x + 'px';
1176    }
1177};
1178
1179
1180/**
1181 * Hide the icon.
1182 */
1183ClusterIcon.prototype.hide = function () {
1184    if (this.div_) {
1185        this.div_.style.display = 'none';
1186    }
1187    this.visible_ = false;
1188};
1189
1190
1191/**
1192 * Position and show the icon.
1193 */
1194ClusterIcon.prototype.show = function () {
1195    if (this.div_) {
1196        var pos = this.getPosFromLatLng_(this.center_);
1197        this.div_.style.cssText = this.createCss(pos);
1198        this.div_.style.display = '';
1199    }
1200    this.visible_ = true;
1201};
1202
1203
1204/**
1205 * Remove the icon from the map
1206 */
1207ClusterIcon.prototype.removeClusterIcon = function () {
1208    this.setMap(null);
1209};
1210
1211
1212/**
1213 * Implementation of the onRemove interface.
1214 * @ignore
1215 */
1216ClusterIcon.prototype.onRemove = function () {
1217    if (this.div_ && this.div_.parentNode) {
1218        this.hide();
1219        this.div_.parentNode.removeChild(this.div_);
1220        this.div_ = null;
1221    }
1222};
1223
1224
1225/**
1226 * Set the sums of the icon.
1227 *
1228 * @param {Object} sums The sums containing:
1229 *   'text': (string) The text to display in the icon.
1230 *   'index': (number) The style index of the icon.
1231 */
1232ClusterIcon.prototype.setSums = function (sums) {
1233    this.sums_ = sums;
1234    this.text_ = sums.text;
1235    this.index_ = sums.index;
1236    if (this.div_) {
1237        this.div_.innerHTML = sums.text;
1238    }
1239
1240    this.useStyle();
1241};
1242
1243
1244/**
1245 * Sets the icon to the the styles.
1246 */
1247ClusterIcon.prototype.useStyle = function () {
1248    var index = Math.max(0, this.sums_.index - 1);
1249    index = Math.min(this.styles_.length - 1, index);
1250    var style = this.styles_[index];
1251    this.url_ = style['url'];
1252    this.height_ = style['height'];
1253    this.width_ = style['width'];
1254    this.textColor_ = style['textColor'];
1255    this.anchor_ = style['anchor'];
1256    this.textSize_ = style['textSize'];
1257    this.backgroundPosition_ = style['backgroundPosition'];
1258    this.iconAnchor_ = style['iconAnchor'];
1259};
1260
1261
1262/**
1263 * Sets the center of the icon.
1264 *
1265 * @param {google.maps.LatLng} center The latlng to set as the center.
1266 */
1267ClusterIcon.prototype.setCenter = function (center) {
1268    this.center_ = center;
1269};
1270
1271
1272/**
1273 * Create the css text based on the position of the icon.
1274 *
1275 * @param {google.maps.Point} pos The position.
1276 * @return {string} The css style text.
1277 */
1278ClusterIcon.prototype.createCss = function (pos) {
1279    var style = [];
1280    style.push('background-image:url(' + this.url_ + ');');
1281    var backgroundPosition = this.backgroundPosition_ ? this.backgroundPosition_ : '0 0';
1282    style.push('background-position:' + backgroundPosition + ';');
1283
1284    if (typeof this.anchor_ === 'object') {
1285        if (typeof this.anchor_[0] === 'number' && this.anchor_[0] > 0 &&
1286            this.anchor_[0] < this.height_) {
1287            style.push('height:' + (this.height_ - this.anchor_[0]) +
1288                'px; padding-top:' + this.anchor_[0] + 'px;');
1289        } else if (typeof this.anchor_[0] === 'number' && this.anchor_[0] < 0 &&
1290            -this.anchor_[0] < this.height_) {
1291            style.push('height:' + this.height_ + 'px; line-height:' + (this.height_ + this.anchor_[0]) +
1292                'px;');
1293        } else {
1294            style.push('height:' + this.height_ + 'px; line-height:' + this.height_ +
1295                'px;');
1296        }
1297        if (typeof this.anchor_[1] === 'number' && this.anchor_[1] > 0 &&
1298            this.anchor_[1] < this.width_) {
1299            style.push('width:' + (this.width_ - this.anchor_[1]) +
1300                'px; padding-left:' + this.anchor_[1] + 'px;');
1301        } else {
1302            style.push('width:' + this.width_ + 'px; text-align:center;');
1303        }
1304    } else {
1305        style.push('height:' + this.height_ + 'px; line-height:' +
1306            this.height_ + 'px; width:' + this.width_ + 'px; text-align:center;');
1307    }
1308
1309    var txtColor = this.textColor_ ? this.textColor_ : 'black';
1310    var txtSize = this.textSize_ ? this.textSize_ : 11;
1311
1312    style.push('cursor:pointer; top:' + pos.y + 'px; left:' +
1313        pos.x + 'px; color:' + txtColor + '; position:absolute; font-size:' +
1314        txtSize + 'px; font-family:Arial,sans-serif; font-weight:bold');
1315    return style.join('');
1316};
vendor: 28,321 bytes, lines 1317-2002
1317/*
1318 OverlappingMarkerSpiderfier
1319https://github.com/jawj/OverlappingMarkerSpiderfier
1320Copyright (c) 2011 - 2017 George MacKerron
1321Released under the MIT licence: http://opensource.org/licenses/mit-license
1322Note: The Google Maps API v3 must be included *before* this code
1323*/
1324
1325(function () {
1326    var callbackName, callbackRegEx, ref, ref1, scriptTag, tag,
1327        hasProp = {}.hasOwnProperty,
1328        slice = [].slice;
1329
1330    this['OverlappingMarkerSpiderfier'] = (function () {
1331        var ge, gm, j, len, mt, p, ref, twoPi, x;
1332
1333        p = _Class.prototype;
1334
1335        ref = [_Class, p];
1336        for (j = 0, len = ref.length; j < len; j++) {
1337            x = ref[j];
1338            x['VERSION'] = '1.0.3';
1339        }
1340
1341        twoPi = Math.PI * 2;
1342
1343        gm = ge = mt = null;
1344
1345        _Class['markerStatus'] = {
1346            'SPIDERFIED': 'SPIDERFIED',
1347            'SPIDERFIABLE': 'SPIDERFIABLE',
1348            'UNSPIDERFIABLE': 'UNSPIDERFIABLE',
1349            'UNSPIDERFIED': 'UNSPIDERFIED'
1350        };
1351
1352        function _Class(map1, opts) {
1353            var k, lcH, lcU, v;
1354            this.map = map1;
1355            if (opts == null) {
1356                opts = {};
1357            }
1358            if (this.constructor.hasInitialized == null) {
1359                this.constructor.hasInitialized = true;
1360                gm = google.maps;
1361                ge = gm.event;
1362                mt = gm.MapTypeId;
1363                p['keepSpiderfied'] = false;
1364                p['ignoreMapClick'] = false;
1365                p['markersWontHide'] = false;
1366                p['markersWontMove'] = false;
1367                p['basicFormatEvents'] = false;
1368                p['nearbyDistance'] = 20;
1369                p['circleSpiralSwitchover'] = 9;
1370                p['circleFootSeparation'] = 23;
1371                p['circleStartAngle'] = twoPi / 12;
1372                p['spiralFootSeparation'] = 26;
1373                p['spiralLengthStart'] = 11;
1374                p['spiralLengthFactor'] = 4;
1375                p['spiderfiedZIndex'] = gm.Marker.MAX_ZINDEX + 20000;
1376                p['highlightedLegZIndex'] = gm.Marker.MAX_ZINDEX + 10000;
1377                p['usualLegZIndex'] = gm.Marker.MAX_ZINDEX + 1;
1378                p['legWeight'] = 1.5;
1379                p['legColors'] = {
1380                    'usual': {},
1381                    'highlighted': {}
1382                };
1383                lcU = p['legColors']['usual'];
1384                lcH = p['legColors']['highlighted'];
1385                lcU[mt.HYBRID] = lcU[mt.SATELLITE] = '#fff';
1386                lcH[mt.HYBRID] = lcH[mt.SATELLITE] = '#f00';
1387                lcU[mt.TERRAIN] = lcU[mt.ROADMAP] = '#444';
1388                lcH[mt.TERRAIN] = lcH[mt.ROADMAP] = '#f00';
1389                this.constructor.ProjHelper = function (map) {
1390                    return this.setMap(map);
1391                };
1392                this.constructor.ProjHelper.prototype = new gm.OverlayView();
1393                this.constructor.ProjHelper.prototype['draw'] = function () { };
1394            }
1395            for (k in opts) {
1396                if (!hasProp.call(opts, k)) continue;
1397                v = opts[k];
1398                this[k] = v;
1399            }
1400            this.projHelper = new this.constructor.ProjHelper(this.map);
1401            this.initMarkerArrays();
1402            this.listeners = {};
1403            this.formatIdleListener = this.formatTimeoutId = null;
1404            this.addListener('click', function (marker, e) {
1405                return ge.trigger(marker, 'spider_click', e);
1406            });
1407            this.addListener('format', function (marker, status) {
1408                return ge.trigger(marker, 'spider_format', status);
1409            });
1410            if (!this['ignoreMapClick']) {
1411                ge.addListener(this.map, 'click', (function (_this) {
1412                    return function () {
1413                        return _this['unspiderfy']();
1414                    };
1415                })(this));
1416            }
1417            ge.addListener(this.map, 'maptypeid_changed', (function (_this) {
1418                return function () {
1419                    return _this['unspiderfy']();
1420                };
1421            })(this));
1422            ge.addListener(this.map, 'zoom_changed', (function (_this) {
1423                return function () {
1424                    _this['unspiderfy']();
1425                    if (!_this['basicFormatEvents']) {
1426                        return _this.formatMarkers();
1427                    }
1428                };
1429            })(this));
1430        }
1431
1432        p.initMarkerArrays = function () {
1433            this.markers = [];
1434            return this.markerListenerRefs = [];
1435        };
1436
1437        p['addMarker'] = function (marker, spiderClickHandler) {
1438            marker.setMap(this.map);
1439            return this['trackMarker'](marker, spiderClickHandler);
1440        };
1441
1442        p['trackMarker'] = function (marker, spiderClickHandler) {
1443            var listenerRefs;
1444            if (marker['_oms'] != null) {
1445                return this;
1446            }
1447            marker['_oms'] = true;
1448            listenerRefs = [
1449                ge.addListener(marker, 'click', (function (_this) {
1450                    return function (e) {
1451                        return _this.spiderListener(marker, e);
1452                    };
1453                })(this))
1454            ];
1455            if (!this['markersWontHide']) {
1456                listenerRefs.push(ge.addListener(marker, 'visible_changed', (function (_this) {
1457                    return function () {
1458                        return _this.markerChangeListener(marker, false);
1459                    };
1460                })(this)));
1461            }
1462            if (!this['markersWontMove']) {
1463                listenerRefs.push(ge.addListener(marker, 'position_changed', (function (_this) {
1464                    return function () {
1465                        return _this.markerChangeListener(marker, true);
1466                    };
1467                })(this)));
1468            }
1469            if (spiderClickHandler != null) {
1470                listenerRefs.push(ge.addListener(marker, 'spider_click', spiderClickHandler));
1471            }
1472            this.markerListenerRefs.push(listenerRefs);
1473            this.markers.push(marker);
1474            if (this['basicFormatEvents']) {
1475                this.trigger('format', marker, this.constructor['markerStatus']['UNSPIDERFIED']);
1476            } else {
1477                this.trigger('format', marker, this.constructor['markerStatus']['UNSPIDERFIABLE']);
1478                this.formatMarkers();
1479            }
1480            return this;
1481        };
1482
1483        p.markerChangeListener = function (marker, positionChanged) {
1484            if (this.spiderfying || this.unspiderfying) {
1485                return;
1486            }
1487            if ((marker['_omsData'] != null) && (positionChanged || !marker.getVisible())) {
1488                this['unspiderfy'](positionChanged ? marker : null);
1489            }
1490            return this.formatMarkers();
1491        };
1492
1493        p['getMarkers'] = function () {
1494            return this.markers.slice(0);
1495        };
1496
1497        p['removeMarker'] = function (marker) {
1498            this['forgetMarker'](marker);
1499            return marker.setMap(null);
1500        };
1501
1502        p['forgetMarker'] = function (marker) {
1503            var i, l, len1, listenerRef, listenerRefs;
1504            if (marker['_omsData'] != null) {
1505                this['unspiderfy']();
1506            }
1507            i = this.arrIndexOf(this.markers, marker);
1508            if (i < 0) {
1509                return this;
1510            }
1511            listenerRefs = this.markerListenerRefs.splice(i, 1)[0];
1512            for (l = 0, len1 = listenerRefs.length; l < len1; l++) {
1513                listenerRef = listenerRefs[l];
1514                ge.removeListener(listenerRef);
1515            }
1516            delete marker['_oms'];
1517            this.markers.splice(i, 1);
1518            this.formatMarkers();
1519            return this;
1520        };
1521
1522        p['removeAllMarkers'] = p['clearMarkers'] = function () {
1523            var l, len1, marker, markers;
1524            markers = this['getMarkers']();
1525            this['forgetAllMarkers']();
1526            for (l = 0, len1 = markers.length; l < len1; l++) {
1527                marker = markers[l];
1528                marker.setMap(null);
1529            }
1530            return this;
1531        };
1532
1533        p['forgetAllMarkers'] = function () {
1534            var i, l, len1, len2, listenerRef, listenerRefs, marker, n, ref1;
1535            this['unspiderfy']();
1536            ref1 = this.markers;
1537            for (i = l = 0, len1 = ref1.length; l < len1; i = ++l) {
1538                marker = ref1[i];
1539                listenerRefs = this.markerListenerRefs[i];
1540                for (n = 0, len2 = listenerRefs.length; n < len2; n++) {
1541                    listenerRef = listenerRefs[n];
1542                    ge.removeListener(listenerRef);
1543                }
1544                delete marker['_oms'];
1545            }
1546            this.initMarkerArrays();
1547            return this;
1548        };
1549
1550        p['addListener'] = function (eventName, func) {
1551            var base;
1552            ((base = this.listeners)[eventName] != null ? base[eventName] : base[eventName] = []).push(func);
1553            return this;
1554        };
1555
1556        p['removeListener'] = function (eventName, func) {
1557            var i;
1558            i = this.arrIndexOf(this.listeners[eventName], func);
1559            if (!(i < 0)) {
1560                this.listeners[eventName].splice(i, 1);
1561            }
1562            return this;
1563        };
1564
1565        p['clearListeners'] = function (eventName) {
1566            this.listeners[eventName] = [];
1567            return this;
1568        };
1569
1570        p.trigger = function () {
1571            var args, eventName, func, l, len1, ref1, ref2, results;
1572            eventName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
1573            ref2 = (ref1 = this.listeners[eventName]) != null ? ref1 : [];
1574            results = [];
1575            for (l = 0, len1 = ref2.length; l < len1; l++) {
1576                func = ref2[l];
1577                results.push(func.apply(null, args));
1578            }
1579            return results;
1580        };
1581
1582        p.generatePtsCircle = function (count, centerPt) {
1583            var angle, angleStep, circumference, i, l, legLength, ref1, results;
1584            circumference = this['circleFootSeparation'] * (2 + count);
1585            legLength = circumference / twoPi;
1586            angleStep = twoPi / count;
1587            results = [];
1588            for (i = l = 0, ref1 = count; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
1589                angle = this['circleStartAngle'] + i * angleStep;
1590                results.push(new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle)));
1591            }
1592            return results;
1593        };
1594
1595        p.generatePtsSpiral = function (count, centerPt) {
1596            var angle, i, l, legLength, pt, ref1, results;
1597            legLength = this['spiralLengthStart'];
1598            angle = 0;
1599            results = [];
1600            for (i = l = 0, ref1 = count; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {
1601                angle += this['spiralFootSeparation'] / legLength + i * 0.0005;
1602                pt = new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle));
1603                legLength += twoPi * this['spiralLengthFactor'] / angle;
1604                results.push(pt);
1605            }
1606            return results;
1607        };
1608
1609        p.spiderListener = function (marker, e) {
1610            var l, len1, m, mPt, markerPt, markerSpiderfied, nDist, nearbyMarkerData, nonNearbyMarkers, pxSq, ref1;
1611            markerSpiderfied = marker['_omsData'] != null;
1612            if (!(markerSpiderfied && this['keepSpiderfied'])) {
1613                this['unspiderfy']();
1614            }
1615            if (markerSpiderfied || this.map.getStreetView().getVisible() || this.map.getMapTypeId() === 'GoogleEarthAPI') {
1616                return this.trigger('click', marker, e);
1617            } else {
1618                nearbyMarkerData = [];
1619                nonNearbyMarkers = [];
1620                nDist = this['nearbyDistance'];
1621                pxSq = nDist * nDist;
1622                markerPt = this.llToPt(marker.position);
1623                ref1 = this.markers;
1624                for (l = 0, len1 = ref1.length; l < len1; l++) {
1625                    m = ref1[l];
1626                    if (!((m.map != null) && m.getVisible())) {
1627                        continue;
1628                    }
1629                    mPt = this.llToPt(m.position);
1630                    if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
1631                        nearbyMarkerData.push({
1632                            marker: m,
1633                            markerPt: mPt
1634                        });
1635                    } else {
1636                        nonNearbyMarkers.push(m);
1637                    }
1638                }
1639                if (nearbyMarkerData.length === 1) {
1640                    return this.trigger('click', marker, e);
1641                } else {
1642                    return this.spiderfy(nearbyMarkerData, nonNearbyMarkers);
1643                }
1644            }
1645        };
1646
1647        p['markersNearMarker'] = function (marker, firstOnly) {
1648            var l, len1, m, mPt, markerPt, markers, nDist, pxSq, ref1, ref2, ref3;
1649            if (firstOnly == null) {
1650                firstOnly = false;
1651            }
1652            if (this.projHelper.getProjection() == null) {
1653                throw "Must wait for 'idle' event on map before calling markersNearMarker";
1654            }
1655            nDist = this['nearbyDistance'];
1656            pxSq = nDist * nDist;
1657            markerPt = this.llToPt(marker.position);
1658            markers = [];
1659            ref1 = this.markers;
1660            for (l = 0, len1 = ref1.length; l < len1; l++) {
1661                m = ref1[l];
1662                if (m === marker || (m.map == null) || !m.getVisible()) {
1663                    continue;
1664                }
1665                mPt = this.llToPt((ref2 = (ref3 = m['_omsData']) != null ? ref3.usualPosition : void 0) != null ? ref2 : m.position);
1666                if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
1667                    markers.push(m);
1668                    if (firstOnly) {
1669                        break;
1670                    }
1671                }
1672            }
1673            return markers;
1674        };
1675
1676        p.markerProximityData = function () {
1677            var i1, i2, l, len1, len2, m, m1, m1Data, m2, m2Data, mData, n, nDist, pxSq, ref1, ref2;
1678            if (this.projHelper.getProjection() == null) {
1679                throw "Must wait for 'idle' event on map before calling markersNearAnyOtherMarker";
1680            }
1681            nDist = this['nearbyDistance'];
1682            pxSq = nDist * nDist;
1683            mData = (function () {
1684                var l, len1, ref1, ref2, ref3, results;
1685                ref1 = this.markers;
1686                results = [];
1687                for (l = 0, len1 = ref1.length; l < len1; l++) {
1688                    m = ref1[l];
1689                    results.push({
1690                        pt: this.llToPt((ref2 = (ref3 = m['_omsData']) != null ? ref3.usualPosition : void 0) != null ? ref2 : m.position),
1691                        willSpiderfy: false
1692                    });
1693                }
1694                return results;
1695            }).call(this);
1696            ref1 = this.markers;
1697            for (i1 = l = 0, len1 = ref1.length; l < len1; i1 = ++l) {
1698                m1 = ref1[i1];
1699                if (!((m1.getMap() != null) && m1.getVisible())) {
1700                    continue;
1701                }
1702                m1Data = mData[i1];
1703                if (m1Data.willSpiderfy) {
1704                    continue;
1705                }
1706                ref2 = this.markers;
1707                for (i2 = n = 0, len2 = ref2.length; n < len2; i2 = ++n) {
1708                    m2 = ref2[i2];
1709                    if (i2 === i1) {
1710                        continue;
1711                    }
1712                    if (!((m2.getMap() != null) && m2.getVisible())) {
1713                        continue;
1714                    }
1715                    m2Data = mData[i2];
1716                    if (i2 < i1 && !m2Data.willSpiderfy) {
1717                        continue;
1718                    }
1719                    if (this.ptDistanceSq(m1Data.pt, m2Data.pt) < pxSq) {
1720                        m1Data.willSpiderfy = m2Data.willSpiderfy = true;
1721                        break;
1722                    }
1723                }
1724            }
1725            return mData;
1726        };
1727
1728        p['markersNearAnyOtherMarker'] = function () {
1729            var i, l, len1, m, mData, ref1, results;
1730            mData = this.markerProximityData();
1731            ref1 = this.markers;
1732            results = [];
1733            for (i = l = 0, len1 = ref1.length; l < len1; i = ++l) {
1734                m = ref1[i];
1735                if (mData[i].willSpiderfy) {
1736                    results.push(m);
1737                }
1738            }
1739            return results;
1740        };
1741
1742        p.setImmediate = function (func) {
1743            return window.setTimeout(func, 0);
1744        };
1745
1746        p.formatMarkers = function () {
1747            if (this['basicFormatEvents']) {
1748                return;
1749            }
1750            if (this.formatTimeoutId != null) {
1751                return;
1752            }
1753            return this.formatTimeoutId = this.setImmediate((function (_this) {
1754                return function () {
1755                    _this.formatTimeoutId = null;
1756                    if (_this.projHelper.getProjection() != null) {
1757                        return _this._formatMarkers();
1758                    } else {
1759                        if (_this.formatIdleListener != null) {
1760                            return;
1761                        }
1762                        return _this.formatIdleListener = ge.addListenerOnce(_this.map, 'idle', function () {
1763                            return _this._formatMarkers();
1764                        });
1765                    }
1766                };
1767            })(this));
1768        };
1769
1770        p._formatMarkers = function () {
1771            var i, l, len1, len2, marker, n, proximities, ref1, results, results1, status;
1772            if (this['basicFormatEvents']) {
1773                results = [];
1774                for (l = 0, len1 = markers.length; l < len1; l++) {
1775                    marker = markers[l];
1776                    status = marker['_omsData'] != null ? 'SPIDERFIED' : 'UNSPIDERFIED';
1777                    results.push(this.trigger('format', marker, this.constructor['markerStatus'][status]));
1778                }
1779                return results;
1780            } else {
1781                proximities = this.markerProximityData();
1782                ref1 = this.markers;
1783                results1 = [];
1784                for (i = n = 0, len2 = ref1.length; n < len2; i = ++n) {
1785                    marker = ref1[i];
1786                    status = marker['_omsData'] != null ? 'SPIDERFIED' : proximities[i].willSpiderfy ? 'SPIDERFIABLE' : 'UNSPIDERFIABLE';
1787                    results1.push(this.trigger('format', marker, this.constructor['markerStatus'][status]));
1788                }
1789                return results1;
1790            }
1791        };
1792
1793        p.makeHighlightListenerFuncs = function (marker) {
1794            return {
1795                highlight: (function (_this) {
1796                    return function () {
1797                        return marker['_omsData'].leg.setOptions({
1798                            strokeColor: _this['legColors']['highlighted'][_this.map.mapTypeId],
1799                            zIndex: _this['highlightedLegZIndex']
1800                        });
1801                    };
1802                })(this),
1803                unhighlight: (function (_this) {
1804                    return function () {
1805                        return marker['_omsData'].leg.setOptions({
1806                            strokeColor: _this['legColors']['usual'][_this.map.mapTypeId],
1807                            zIndex: _this['usualLegZIndex']
1808                        });
1809                    };
1810                })(this)
1811            };
1812        };
1813
1814        p.spiderfy = function (markerData, nonNearbyMarkers) {
1815            var bodyPt, footLl, footPt, footPts, highlightListenerFuncs, leg, marker, md, nearestMarkerDatum, numFeet, spiderfiedMarkers;
1816            this.spiderfying = true;
1817            numFeet = markerData.length;
1818            bodyPt = this.ptAverage((function () {
1819                var l, len1, results;
1820                results = [];
1821                for (l = 0, len1 = markerData.length; l < len1; l++) {
1822                    md = markerData[l];
1823                    results.push(md.markerPt);
1824                }
1825                return results;
1826            })());
1827            footPts = numFeet >= this['circleSpiralSwitchover'] ? this.generatePtsSpiral(numFeet, bodyPt).reverse() : this.generatePtsCircle(numFeet, bodyPt);
1828            spiderfiedMarkers = (function () {
1829                var l, len1, results;
1830                results = [];
1831                for (l = 0, len1 = footPts.length; l < len1; l++) {
1832                    footPt = footPts[l];
1833                    footLl = this.ptToLl(footPt);
1834                    nearestMarkerDatum = this.minExtract(markerData, (function (_this) {
1835                        return function (md) {
1836                            return _this.ptDistanceSq(md.markerPt, footPt);
1837                        };
1838                    })(this));
1839                    marker = nearestMarkerDatum.marker;
1840                    leg = new gm.Polyline({
1841                        map: this.map,
1842                        path: [marker.position, footLl],
1843                        strokeColor: this['legColors']['usual'][this.map.mapTypeId],
1844                        strokeWeight: this['legWeight'],
1845                        zIndex: this['usualLegZIndex']
1846                    });
1847                    marker['_omsData'] = {
1848                        usualPosition: marker.getPosition(),
1849                        usualZIndex: marker.getZIndex(),
1850                        leg: leg
1851                    };
1852                    if (this['legColors']['highlighted'][this.map.mapTypeId] !== this['legColors']['usual'][this.map.mapTypeId]) {
1853                        highlightListenerFuncs = this.makeHighlightListenerFuncs(marker);
1854                        marker['_omsData'].hightlightListeners = {
1855                            highlight: ge.addListener(marker, 'mouseover', highlightListenerFuncs.highlight),
1856                            unhighlight: ge.addListener(marker, 'mouseout', highlightListenerFuncs.unhighlight)
1857                        };
1858                    }
1859                    this.trigger('format', marker, this.constructor['markerStatus']['SPIDERFIED']);
1860                    marker.setPosition(footLl);
1861                    marker.setZIndex(Math.round(this['spiderfiedZIndex'] + footPt.y));
1862                    results.push(marker);
1863                }
1864                return results;
1865            }).call(this);
1866            delete this.spiderfying;
1867            this.spiderfied = true;
1868            return this.trigger('spiderfy', spiderfiedMarkers, nonNearbyMarkers);
1869        };
1870
1871        p['unspiderfy'] = function (markerNotToMove) {
1872            var l, len1, listeners, marker, nonNearbyMarkers, ref1, status, unspiderfiedMarkers;
1873            if (markerNotToMove == null) {
1874                markerNotToMove = null;
1875            }
1876            if (this.spiderfied == null) {
1877                return this;
1878            }
1879            this.unspiderfying = true;
1880            unspiderfiedMarkers = [];
1881            nonNearbyMarkers = [];
1882            ref1 = this.markers;
1883            for (l = 0, len1 = ref1.length; l < len1; l++) {
1884                marker = ref1[l];
1885                if (marker['_omsData'] != null) {
1886                    marker['_omsData'].leg.setMap(null);
1887                    if (marker !== markerNotToMove) {
1888                        marker.setPosition(marker['_omsData'].usualPosition);
1889                    }
1890                    marker.setZIndex(marker['_omsData'].usualZIndex);
1891                    listeners = marker['_omsData'].hightlightListeners;
1892                    if (listeners != null) {
1893                        ge.removeListener(listeners.highlight);
1894                        ge.removeListener(listeners.unhighlight);
1895                    }
1896                    delete marker['_omsData'];
1897                    if (marker !== markerNotToMove) {
1898                        status = this['basicFormatEvents'] ? 'UNSPIDERFIED' : 'SPIDERFIABLE';
1899                        this.trigger('format', marker, this.constructor['markerStatus'][status]);
1900                    }
1901                    unspiderfiedMarkers.push(marker);
1902                } else {
1903                    nonNearbyMarkers.push(marker);
1904                }
1905            }
1906            delete this.unspiderfying;
1907            delete this.spiderfied;
1908            this.trigger('unspiderfy', unspiderfiedMarkers, nonNearbyMarkers);
1909            return this;
1910        };
1911
1912        p.ptDistanceSq = function (pt1, pt2) {
1913            var dx, dy;
1914            dx = pt1.x - pt2.x;
1915            dy = pt1.y - pt2.y;
1916            return dx * dx + dy * dy;
1917        };
1918
1919        p.ptAverage = function (pts) {
1920            var l, len1, numPts, pt, sumX, sumY;
1921            sumX = sumY = 0;
1922            for (l = 0, len1 = pts.length; l < len1; l++) {
1923                pt = pts[l];
1924                sumX += pt.x;
1925                sumY += pt.y;
1926            }
1927            numPts = pts.length;
1928            return new gm.Point(sumX / numPts, sumY / numPts);
1929        };
1930
1931        p.llToPt = function (ll) {
1932            return this.projHelper.getProjection().fromLatLngToDivPixel(ll);
1933        };
1934
1935        p.ptToLl = function (pt) {
1936            return this.projHelper.getProjection().fromDivPixelToLatLng(pt);
1937        };
1938
1939        p.minExtract = function (set, func) {
1940            var bestIndex, bestVal, index, item, l, len1, val;
1941            for (index = l = 0, len1 = set.length; l < len1; index = ++l) {
1942                item = set[index];
1943                val = func(item);
1944                if ((typeof bestIndex === "undefined" || bestIndex === null) || val < bestVal) {
1945                    bestVal = val;
1946                    bestIndex = index;
1947                }
1948            }
1949            return set.splice(bestIndex, 1)[0];
1950        };
1951
1952        p.arrIndexOf = function (arr, obj) {
1953            var i, l, len1, o;
1954            if (arr.indexOf != null) {
1955                return arr.indexOf(obj);
1956            }
1957            for (i = l = 0, len1 = arr.length; l < len1; i = ++l) {
1958                o = arr[i];
1959                if (o === obj) {
1960                    return i;
1961                }
1962            }
1963            return -1;
1964        };
1965
1966        return _Class;
1967
1968    })();
1969
1970    callbackRegEx = /(\?.*(&|&amp;)|\?)spiderfier_callback=(\w+)/;
1971
1972    scriptTag = document.currentScript;
1973
1974    if (scriptTag == null) {
1975        scriptTag = ((function () {
1976            var j, len, ref, ref1, results;
1977            ref = document.getElementsByTagName('script');
1978            results = [];
1979            for (j = 0, len = ref.length; j < len; j++) {
1980                tag = ref[j];
1981                if ((ref1 = tag.getAttribute('src')) != null ? ref1.match(callbackRegEx) : void 0) {
1982                    results.push(tag);
1983                }
1984            }
1985            return results;
1986        })())[0];
1987    }
1988
1989    if (scriptTag != null) {
1990        callbackName = (ref = scriptTag.getAttribute('src')) != null ? (ref1 = ref.match(callbackRegEx)) != null ? ref1[3] : void 0 : void 0;
1991        if (callbackName) {
1992            if (typeof window[callbackName] === "function") {
1993                window[callbackName]();
1994            }
1995        }
1996    }
1997
1998    if (typeof window['spiderfier_callback'] === "function") {
1999        window['spiderfier_callback']();
2000    }
2001
2002}).call(this);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.