﻿var MapIconMaker = {}; MapIconMaker.createMarkerIcon = function(b) { var a = b.width || 32; var c = b.height || 32; var d = b.primaryColor || "#ff0000"; var g = b.strokeColor || "#000000"; var f = b.cornerColor || "#ffffff"; var e = "http://chart.apis.google.com/chart?cht=mm"; var h = e + "&chs=" + a + "x" + c + "&chco=" + f.replace("#", "") + "," + d.replace("#", "") + "," + g.replace("#", "") + "&ext=.png"; var k = new GIcon(G_DEFAULT_ICON); k.image = h; k.iconSize = new GSize(a, c); k.shadowSize = new GSize(Math.floor(a * 1.6), c); k.iconAnchor = new GPoint(a / 2, c); k.infoWindowAnchor = new GPoint(a / 2, Math.floor(c / 12)); k.printImage = h + "&chof=gif"; k.mozPrintImage = h + "&chf=bg,s,ECECD8&chof=gif"; h = e + "&chs=" + a + "x" + c + "&chco=" + f.replace("#", "") + "," + d.replace("#", "") + "," + g.replace("#", ""); k.transparent = h + "&chf=a,s,ffffff11&ext=.png"; k.imageMap = [a / 2, c, (7 / 16) * a, (5 / 8) * c, (5 / 16) * a, (7 / 16) * c, (7 / 32) * a, (5 / 16) * c, (5 / 16) * a, (1 / 8) * c, (1 / 2) * a, 0, (11 / 16) * a, (1 / 8) * c, (25 / 32) * a, (5 / 16) * c, (11 / 16) * a, (7 / 16) * c, (9 / 16) * a, (5 / 8) * c]; for (var l = 0; l < k.imageMap.length; l++) { k.imageMap[l] = parseInt(k.imageMap[l]) } return k }; MapIconMaker.createFlatIcon = function(b) { var a = b.width || 32; var c = b.height || 32; var d = b.primaryColor || "#ff0000"; var g = b.shadowColor || "#000000"; var f = MapIconMaker.escapeUserText_(b.label) || ""; var e = b.labelColor || "#000000"; var h = b.labelSize || 0; var k = b.shape || "circle"; var l = (k === "circle") ? "it" : "itr"; var m = "http://chart.apis.google.com/chart?cht=" + l; var i = m + "&chs=" + a + "x" + c + "&chco=" + d.replace("#", "") + "," + g.replace("#", "") + "ff,ffffff01&chl=" + f + "&chx=" + e.replace("#", "") + "," + h; var j = new GIcon(G_DEFAULT_ICON); j.image = i + "&chf=bg,s,00000000&ext=.png"; j.iconSize = new GSize(a, c); j.shadowSize = new GSize(0, 0); j.iconAnchor = new GPoint(a / 2, c / 2); j.infoWindowAnchor = new GPoint(a / 2, c / 2); j.printImage = i + "&chof=gif"; j.mozPrintImage = i + "&chf=bg,s,ECECD8&chof=gif"; j.transparent = i + "&chf=a,s,ffffff01&ext=.png"; j.imageMap = []; if (l === "itr") { j.imageMap = [0, 0, a, 0, a, c, 0, c] } else { var n = 8; var o = 360 / n; var p = Math.min(a, c) / 2; for (var q = 0; q < (n + 1); q++) { var r = o * q * (Math.PI / 180); var s = p + p * Math.cos(r); var t = p + p * Math.sin(r); j.imageMap.push(parseInt(s), parseInt(t)) } } return j }; MapIconMaker.createLabeledMarkerIcon = function(b) { var a = b.primaryColor || "#DA7187"; var c = b.strokeColor || "#000000"; var d = b.starPrimaryColor || "#FFFF00"; var g = b.starStrokeColor || "#0000FF"; var f = MapIconMaker.escapeUserText_(b.label) || ""; var e = b.labelColor || "#000000"; var h = b.addStar || false; var k = (h) ? "pin_star" : "pin"; var l = "http://chart.apis.google.com/chart?cht=d&chdp=mapsapi&chl="; var m = l + k + "'i\\'[" + f + "'-2'f\\hv'a\\]h\\]o\\" + a.replace("#", "") + "'fC\\" + e.replace("#", "") + "'tC\\" + c.replace("#", "") + "'eC\\"; if (h) { m += d.replace("#", "") + "'1C\\" + g.replace("#", "") + "'0C\\" } m += "Lauto'f\\"; var i = new GIcon(G_DEFAULT_ICON); i.image = m + "&ext=.png"; i.iconSize = (h) ? new GSize(23, 39) : new GSize(21, 34); return i }; MapIconMaker.escapeUserText_ = function(b) { if (b === undefined) { return null } return encodeURIComponent(b) }; function ClusterMarker(a, b) { this._map = a; this._mapMarkers = []; this._iconBounds = []; this._clusterMarkers = []; this._eventListeners = []; if (typeof (b) === 'undefined') { b = {} } this.borderPadding = (b.borderPadding) ? b.borderPadding : 256; this.clusteringEnabled = (b.clusteringEnabled === false) ? false : true; if (b.clusterMarkerClick) { this.clusterMarkerClick = b.clusterMarkerClick } if (b.clusterMarkerIcon) { this.clusterMarkerIcon = b.clusterMarkerIcon } else { this.clusterMarkerIcon = new GIcon(); this.clusterMarkerIcon.image = 'http://maps.google.com/mapfiles/arrow.png'; this.clusterMarkerIcon.iconSize = new GSize(39, 34); this.clusterMarkerIcon.iconAnchor = new GPoint(9, 31); this.clusterMarkerIcon.infoWindowAnchor = new GPoint(9, 31); this.clusterMarkerIcon.shadow = 'http://www.google.com/intl/en_us/mapfiles/arrowshadow.png'; this.clusterMarkerIcon.shadowSize = new GSize(39, 34) } this.clusterMarkerTitle = (b.clusterMarkerTitle) ? b.clusterMarkerTitle : 'Click to zoom in and see %count houses'; if (b.fitMapMaxZoom) { this.fitMapMaxZoom = b.fitMapMaxZoom } this.intersectPadding = (b.intersectPadding) ? b.intersectPadding : 0; if (b.markers) { this.addMarkers(b.markers) } GEvent.bind(this._map, 'moveend', this, this._moveEnd); GEvent.bind(this._map, 'zoomend', this, this._zoomEnd); GEvent.bind(this._map, 'maptypechanged', this, this._mapTypeChanged) } ClusterMarker.prototype.addMarkers = function(a) { var i; if (!a[0]) { var b = []; for (i in a) { b.push(a[i]) } a = b } for (i = a.length - 1; i >= 0; i--) { a[i]._isVisible = false; a[i]._isActive = false; a[i]._makeVisible = false } this._mapMarkers = this._mapMarkers.concat(a) }; ClusterMarker.prototype._clusterMarker = function(d) { function $newClusterMarker(a, b, c) { return new GMarker(a, { icon: b, title: c }) } var e = new GLatLngBounds(), i, $clusterMarker, $clusteredMarkers = [], $marker, $this = this, $mapMarkers = this._mapMarkers; for (i = d.length - 1; i >= 0; i--) { $marker = $mapMarkers[d[i]]; $marker.index = d[i]; e.extend($marker.getLatLng()); $clusteredMarkers.push($marker) } var f = {}; var g = Math.log(d.length); f.width = Math.floor(10 * g) + 21; f.height = Math.floor(10 * g) + 21; f.primaryColor = "#00a3e1"; f.label = d.length; f.labelSize = Math.floor(f.height * .5); f.labelColor = "#FFFFFF"; f.shape = "circle"; var h = MapIconMaker.createFlatIcon(f); $clusterMarker = $newClusterMarker(e.getCenter(), h, this.clusterMarkerTitle.replace(/%count/gi, d.length)); $clusterMarker.clusterGroupBounds = e; this._eventListeners.push(GEvent.addListener($clusterMarker, 'click', function() { $this.clusterMarkerClick({ clusterMarker: $clusterMarker, clusteredMarkers: $clusteredMarkers }) })); $clusterMarker._childIndexes = d; for (i = d.length - 1; i >= 0; i--) { $mapMarkers[d[i]]._parentCluster = $clusterMarker } return $clusterMarker }; ClusterMarker.prototype.clusterMarkerClick = function(a) { this._map.setCenter(a.clusterMarker.getLatLng(), this._map.getBoundsZoomLevel(a.clusterMarker.clusterGroupBounds)) }; ClusterMarker.prototype._filterActiveMapMarkers = function() { var a = this.borderPadding, $mapZoomLevel = this._map.getZoom(), $mapProjection = this._map.getCurrentMapType().getProjection(), $mapPointSw, $activeAreaPointSw, $activeAreaLatLngSw, $mapPointNe, $activeAreaPointNe, $activeAreaLatLngNe, $activeAreaBounds = this._map.getBounds(), i, $marker, $uncachedIconBoundsIndexes = [], $oldState, $mapMarkers = this._mapMarkers, $iconBounds = this._iconBounds; if (a) { $mapPointSw = $mapProjection.fromLatLngToPixel($activeAreaBounds.getSouthWest(), $mapZoomLevel); $activeAreaPointSw = new GPoint($mapPointSw.x - a, $mapPointSw.y + a); $activeAreaLatLngSw = $mapProjection.fromPixelToLatLng($activeAreaPointSw, $mapZoomLevel); $mapPointNe = $mapProjection.fromLatLngToPixel($activeAreaBounds.getNorthEast(), $mapZoomLevel); $activeAreaPointNe = new GPoint($mapPointNe.x + a, $mapPointNe.y - a); $activeAreaLatLngNe = $mapProjection.fromPixelToLatLng($activeAreaPointNe, $mapZoomLevel); $activeAreaBounds.extend($activeAreaLatLngSw); $activeAreaBounds.extend($activeAreaLatLngNe) } this._activeMarkersChanged = false; if (typeof ($iconBounds[$mapZoomLevel]) === 'undefined') { this._iconBounds[$mapZoomLevel] = []; this._activeMarkersChanged = true; for (i = $mapMarkers.length - 1; i >= 0; i--) { $marker = $mapMarkers[i]; $marker._isActive = $activeAreaBounds.containsLatLng($marker.getLatLng()) ? true : false; $marker._makeVisible = $marker._isActive; if ($marker._isActive) { $uncachedIconBoundsIndexes.push(i) } } } else { for (i = $mapMarkers.length - 1; i >= 0; i--) { $marker = $mapMarkers[i]; $oldState = $marker._isActive; $marker._isActive = $activeAreaBounds.containsLatLng($marker.getLatLng()) ? true : false; $marker._makeVisible = $marker._isActive; if (!this._activeMarkersChanged && $oldState !== $marker._isActive) { this._activeMarkersChanged = true } if ($marker._isActive && typeof ($iconBounds[$mapZoomLevel][i]) === 'undefined') { $uncachedIconBoundsIndexes.push(i) } } } return $uncachedIconBoundsIndexes }; ClusterMarker.prototype._filterIntersectingMapMarkers = function() { var a, i, j, $mapZoomLevel = this._map.getZoom(), $mapMarkers = this._mapMarkers, $iconBounds = this._iconBounds; for (i = $mapMarkers.length - 1; i > 0; i--) { if ($mapMarkers[i]._makeVisible) { a = []; for (j = i - 1; j >= 0; j--) { if ($mapMarkers[j]._makeVisible && $iconBounds[$mapZoomLevel][i].intersects($iconBounds[$mapZoomLevel][j])) { a.push(j) } } if (a.length !== 0) { a.push(i); for (j = a.length - 1; j >= 0; j--) { $mapMarkers[a[j]]._makeVisible = false } this._clusterMarkers.push(this._clusterMarker(a)) } } } }; ClusterMarker.prototype.fitMapToMarkers = function(a) { var b = this._mapMarkers, $markersBounds = new GLatLngBounds(), i; var c = this._map.getBounds(); for (i = b.length - 1; i >= 0; i--) { $markersBounds.extend(b[i].getLatLng()) } if (!c.containsBounds($markersBounds) || a) { var d = this._map.getBoundsZoomLevel($markersBounds); if (this.fitMapMaxZoom && d > this.fitMapMaxZoom) { d = this.fitMapMaxZoom } this._map.setCenter($markersBounds.getCenter(), d); this.refresh() } }; ClusterMarker.prototype.OLDfitMapToMarkers = function() { var a = this._mapMarkers, $markersBounds = new GLatLngBounds(), i; for (i = a.length - 1; i >= 0; i--) { $markersBounds.extend(a[i].getLatLng()) } var b = this._map.getBoundsZoomLevel($markersBounds); if (this.fitMapMaxZoom && b > this.fitMapMaxZoom) { b = this.fitMapMaxZoom } this._map.setCenter($markersBounds.getCenter(), b); this.refresh() }; ClusterMarker.prototype._mapTypeChanged = function() { this.refresh(true) }; ClusterMarker.prototype._moveEnd = function() { if (!this._cancelMoveEnd) { this.refresh() } else { this._cancelMoveEnd = false } }; ClusterMarker.prototype._preCacheIconBounds = function(a, b) { var c = this._map.getCurrentMapType().getProjection(), i, $marker, $iconSize, $iconAnchorPoint, $iconAnchorPointOffset, $iconBoundsPointSw, $iconBoundsPointNe, $iconBoundsLatLngSw, $iconBoundsLatLngNe, $intersectPadding = this.intersectPadding, $mapMarkers = this._mapMarkers; for (i = a.length - 1; i >= 0; i--) { $marker = $mapMarkers[a[i]]; $iconSize = $marker.getIcon().iconSize; $iconAnchorPoint = c.fromLatLngToPixel($marker.getLatLng(), b); $iconAnchorPointOffset = $marker.getIcon().iconAnchor; $iconBoundsPointSw = new GPoint($iconAnchorPoint.x - $iconAnchorPointOffset.x - $intersectPadding, $iconAnchorPoint.y - $iconAnchorPointOffset.y + $iconSize.height + $intersectPadding); $iconBoundsPointNe = new GPoint($iconAnchorPoint.x - $iconAnchorPointOffset.x + $iconSize.width + $intersectPadding, $iconAnchorPoint.y - $iconAnchorPointOffset.y - $intersectPadding); $iconBoundsLatLngSw = c.fromPixelToLatLng($iconBoundsPointSw, b); $iconBoundsLatLngNe = c.fromPixelToLatLng($iconBoundsPointNe, b); this._iconBounds[b][a[i]] = new GLatLngBounds($iconBoundsLatLngSw, $iconBoundsLatLngNe) } }; ClusterMarker.prototype.refresh = function(a) { var i, $marker, $zoomLevel = this._map.getZoom(), $uncachedIconBoundsIndexes = this._filterActiveMapMarkers(); if (this._activeMarkersChanged || a) { this._removeClusterMarkers(); if (this.clusteringEnabled && $zoomLevel < 20) { if ($uncachedIconBoundsIndexes.length > 0) { this._preCacheIconBounds($uncachedIconBoundsIndexes, $zoomLevel) } this._filterIntersectingMapMarkers() } for (i = this._clusterMarkers.length - 1; i >= 0; i--) { this._map.addOverlay(this._clusterMarkers[i]) } for (i = this._mapMarkers.length - 1; i >= 0; i--) { $marker = this._mapMarkers[i]; if (!$marker._isVisible && $marker._makeVisible) { this._map.addOverlay($marker); try { $marker.setImage(Sawbuck.Renderer.getMap().getIcon(Sawbuck.Page.getRatingByListingID($marker.listing_id)).image); } catch (err) { } $marker._isVisible = true } if ($marker._isVisible && !$marker._makeVisible) { this._map.removeOverlay($marker); $marker._isVisible = false } } } }; ClusterMarker.prototype._removeClusterMarkers = function() { var i, j, $map = this._map, $eventListeners = this._eventListeners, $clusterMarkers = this._clusterMarkers, $childIndexes, $mapMarkers = this._mapMarkers; for (i = $clusterMarkers.length - 1; i >= 0; i--) { $childIndexes = $clusterMarkers[i]._childIndexes; for (j = $childIndexes.length - 1; j >= 0; j--) { delete $mapMarkers[$childIndexes[j]]._parentCluster } $map.removeOverlay($clusterMarkers[i]) } for (i = $eventListeners.length - 1; i >= 0; i--) { GEvent.removeListener($eventListeners[i]) } this._clusterMarkers = []; this._eventListeners = [] }; ClusterMarker.prototype.removeMarkers = function() { var i, $mapMarkers = this._mapMarkers, $map = this._map; for (i = $mapMarkers.length - 1; i >= 0; i--) { if ($mapMarkers[i]._isVisible) { $map.removeOverlay($mapMarkers[i]) } delete $mapMarkers[i]._isVisible; delete $mapMarkers[i]._isActive; delete $mapMarkers[i]._makeVisible } this._removeClusterMarkers(); this._mapMarkers = []; this._iconBounds = [] }; ClusterMarker.prototype.triggerClick = function(a) { var b = this._mapMarkers[a]; if (b._isVisible) { GEvent.trigger(b, 'click') } else if (b._isActive) { var c = b._parentCluster._childIndexes, $intersectDetected = true, $uncachedIconBoundsIndexes, i, $mapZoomLevel = this._map.getZoom(), $clusteredMarkerIndex, $iconBounds = this._iconBounds, $mapMaxZoomLevel = this._map.getCurrentMapType().getMaximumResolution(); while ($intersectDetected && $mapZoomLevel < 23) { if (this._map.getZoom() > $mapMaxZoomLevel) { return false } if ($mapZoomLevel > $mapMaxZoomLevel) { this._map.setCenter(b.getLatLng(), $mapZoomLevel); GEvent.trigger(b._parentCluster, "click"); return false } $intersectDetected = false; $mapZoomLevel++; if (typeof ($iconBounds[$mapZoomLevel]) === 'undefined') { $iconBounds[$mapZoomLevel] = []; this._preCacheIconBounds(c, $mapZoomLevel) } else { $uncachedIconBoundsIndexes = []; for (i = c.length - 1; i >= 0; i--) { if (typeof ($iconBounds[$mapZoomLevel][c[i]]) === 'undefined') { $uncachedIconBoundsIndexes.push(c[i]) } } if ($uncachedIconBoundsIndexes.length >= 1) { this._preCacheIconBounds($uncachedIconBoundsIndexes, $mapZoomLevel) } } for (i = c.length - 1; i >= 0; i--) { $clusteredMarkerIndex = c[i]; if ($clusteredMarkerIndex !== a && $iconBounds[$mapZoomLevel][$clusteredMarkerIndex].intersects($iconBounds[$mapZoomLevel][a])) { $intersectDetected = true; break } } }; this._map.setCenter(b.getLatLng(), $mapZoomLevel); this.triggerClick(a) } else { this._map.setCenter(b.getLatLng()); this.triggerClick(a) } }; ClusterMarker.prototype._zoomEnd = function() { this._cancelMoveEnd = true; this.refresh(true) };