ym4r 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +40 -243
- data/lib/ym4r/google_maps.rb +3 -8
- data/lib/ym4r/google_maps/geocoding.rb +80 -1
- data/lib/ym4r/google_maps/{tiler/image_tiler.rb → image_tiler.rb} +0 -0
- data/lib/ym4r/google_maps/{tiler/wms_tiler.rb → wms_tiler.rb} +0 -0
- data/lib/ym4r/yahoo_maps.rb +0 -1
- data/rakefile.rb +3 -3
- data/test/test_geocoding.rb +4 -4
- data/test/test_gm_geocoding.rb +28 -0
- data/tools/tile_image.rb +2 -1
- data/tools/tile_wms.rb +4 -3
- metadata +9 -28
- data/lib/ym4r/google_maps/control.rb +0 -66
- data/lib/ym4r/google_maps/geocoding/geocoding.rb +0 -80
- data/lib/ym4r/google_maps/helper.rb +0 -22
- data/lib/ym4r/google_maps/javascript/clusterer.js +0 -444
- data/lib/ym4r/google_maps/javascript/geoRssOverlay.js +0 -107
- data/lib/ym4r/google_maps/javascript/markerGroup.js +0 -104
- data/lib/ym4r/google_maps/javascript/wms-gs.js +0 -69
- data/lib/ym4r/google_maps/layer.rb +0 -115
- data/lib/ym4r/google_maps/map.rb +0 -158
- data/lib/ym4r/google_maps/mapping.rb +0 -126
- data/lib/ym4r/google_maps/overlay.rb +0 -187
- data/lib/ym4r/google_maps/point.rb +0 -36
- data/lib/ym4r/yahoo_maps/flash.rb +0 -7
- data/lib/ym4r/yahoo_maps/flash/latlon.rb +0 -18
- data/lib/ym4r/yahoo_maps/flash/map.rb +0 -74
- data/lib/ym4r/yahoo_maps/flash/mapping.rb +0 -71
- data/lib/ym4r/yahoo_maps/flash/marker.rb +0 -43
- data/lib/ym4r/yahoo_maps/flash/overlay.rb +0 -44
- data/lib/ym4r/yahoo_maps/flash/tool.rb +0 -30
- data/lib/ym4r/yahoo_maps/flash/widget.rb +0 -33
- data/test/test_google_maps.rb +0 -75
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
|
3
|
+
require 'ym4r/google_maps/geocoding'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
include Ym4r::GoogleMaps
|
7
|
+
|
8
|
+
class TestGmGeocoding< Test::Unit::TestCase
|
9
|
+
def test_google_maps_geocoding
|
10
|
+
placemarks = Ym4r::GoogleMaps::Geocoding.get("Rue Clovis Paris")
|
11
|
+
assert_equal(Ym4r::GoogleMaps::Geocoding::GEO_SUCCESS,placemarks.status)
|
12
|
+
assert_equal(1,placemarks.length)
|
13
|
+
placemark = placemarks[0]
|
14
|
+
assert_equal("FR",placemark.country_code)
|
15
|
+
assert_equal("Paris",placemark.locality)
|
16
|
+
assert_equal("75005",placemark.postal_code)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_google_maps_pakistan
|
20
|
+
placemarks = Ym4r::GoogleMaps::Geocoding.get("Lahore PK")
|
21
|
+
assert_equal(Ym4r::GoogleMaps::Geocoding::GEO_SUCCESS,placemarks.status)
|
22
|
+
assert_equal(1,placemarks.length)
|
23
|
+
placemark = placemarks[0]
|
24
|
+
assert_equal("PK",placemark.country_code)
|
25
|
+
assert_equal("Lahore",placemark.locality)
|
26
|
+
assert_equal("",placemark.thoroughfare)
|
27
|
+
end
|
28
|
+
end
|
data/tools/tile_image.rb
CHANGED
data/tools/tile_wms.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
-
|
2
|
+
|
3
|
+
require 'ym4r/google_maps/wms_tiler'
|
3
4
|
include Ym4r::GoogleMaps::Tiler
|
4
5
|
|
5
6
|
require 'optparse'
|
@@ -45,10 +46,10 @@ opts = OptionParser.new do |opts|
|
|
45
46
|
opts.on("-g","--gmap-setting SETTING",WmsTiler::FurthestZoom,"Corner coordinates, furthest zoom level, tile width and height") do |fz|
|
46
47
|
options.furthest_zoom = fz
|
47
48
|
end
|
48
|
-
opts.on("-w","--[no-]geographic","Query the WMS server with LatLon coordinates
|
49
|
+
opts.on("-w","--[no-]geographic","Query the WMS server with LatLon coordinates instead of using the Mercator projection") do |g|
|
49
50
|
options.geographic = g
|
50
51
|
end
|
51
|
-
opts.on("-e", "--epsg SRS","SRS to query the WMS server. Should be a the SRS id of a Simple Mercator projection. Can vary between WMS servers. Is 54004 (Simple Mercator for Mapserver) by default") do |srs|
|
52
|
+
opts.on("-e", "--epsg SRS","SRS to query the WMS server. Should be a the SRS id of a Simple Mercator projection. Can vary between WMS servers. Is 54004 (Simple Mercator for Mapserver) by default. For GeoServer use 41001.") do |srs|
|
52
53
|
options.srs = srs
|
53
54
|
|
54
55
|
end
|
metadata
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.
|
2
|
+
rubygems_version: 0.9.0
|
3
3
|
specification_version: 1
|
4
4
|
name: ym4r
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2006-07-
|
8
|
-
summary:
|
6
|
+
version: 0.5.1
|
7
|
+
date: 2006-07-09 00:00:00 +05:00
|
8
|
+
summary: Helping the use of Google Maps and Yahoo! Maps API's from Ruby and Rails
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: guilhem.vellut+ym4r@gmail.com
|
@@ -25,6 +25,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
25
25
|
platform: ruby
|
26
26
|
signing_key:
|
27
27
|
cert_chain:
|
28
|
+
post_install_message:
|
28
29
|
authors:
|
29
30
|
- Guilhem Vellut
|
30
31
|
files:
|
@@ -32,41 +33,21 @@ files:
|
|
32
33
|
- lib/ym4r/google_maps.rb
|
33
34
|
- lib/ym4r/yahoo_maps.rb
|
34
35
|
- lib/ym4r/google_maps/api_key.rb
|
35
|
-
- lib/ym4r/google_maps/control.rb
|
36
36
|
- lib/ym4r/google_maps/geocoding.rb
|
37
|
-
- lib/ym4r/google_maps/
|
38
|
-
- lib/ym4r/google_maps/
|
39
|
-
- lib/ym4r/google_maps/map.rb
|
40
|
-
- lib/ym4r/google_maps/mapping.rb
|
41
|
-
- lib/ym4r/google_maps/overlay.rb
|
42
|
-
- lib/ym4r/google_maps/point.rb
|
43
|
-
- lib/ym4r/google_maps/geocoding/geocoding.rb
|
44
|
-
- lib/ym4r/google_maps/tiler/image_tiler.rb
|
45
|
-
- lib/ym4r/google_maps/tiler/wms_tiler.rb
|
37
|
+
- lib/ym4r/google_maps/image_tiler.rb
|
38
|
+
- lib/ym4r/google_maps/wms_tiler.rb
|
46
39
|
- lib/ym4r/yahoo_maps/app_id.rb
|
47
40
|
- lib/ym4r/yahoo_maps/building_block.rb
|
48
|
-
- lib/ym4r/yahoo_maps/flash.rb
|
49
41
|
- lib/ym4r/yahoo_maps/building_block/exception.rb
|
50
42
|
- lib/ym4r/yahoo_maps/building_block/geocoding.rb
|
51
43
|
- lib/ym4r/yahoo_maps/building_block/local_search.rb
|
52
44
|
- lib/ym4r/yahoo_maps/building_block/map_image.rb
|
53
45
|
- lib/ym4r/yahoo_maps/building_block/traffic.rb
|
54
|
-
- lib/ym4r/yahoo_maps/flash/latlon.rb
|
55
|
-
- lib/ym4r/yahoo_maps/flash/map.rb
|
56
|
-
- lib/ym4r/yahoo_maps/flash/mapping.rb
|
57
|
-
- lib/ym4r/yahoo_maps/flash/marker.rb
|
58
|
-
- lib/ym4r/yahoo_maps/flash/overlay.rb
|
59
|
-
- lib/ym4r/yahoo_maps/flash/tool.rb
|
60
|
-
- lib/ym4r/yahoo_maps/flash/widget.rb
|
61
46
|
- lib/ym4r/google_maps/config/config.yml
|
62
|
-
- lib/ym4r/google_maps/javascript/clusterer.js
|
63
|
-
- lib/ym4r/google_maps/javascript/geoRssOverlay.js
|
64
|
-
- lib/ym4r/google_maps/javascript/markerGroup.js
|
65
|
-
- lib/ym4r/google_maps/javascript/wms-gs.js
|
66
47
|
- tools/tile_image.rb
|
67
48
|
- tools/tile_wms.rb
|
68
49
|
- test/test_geocoding.rb
|
69
|
-
- test/
|
50
|
+
- test/test_gm_geocoding.rb
|
70
51
|
- test/test_local_search.rb
|
71
52
|
- test/test_map_image.rb
|
72
53
|
- test/test_traffic.rb
|
@@ -75,7 +56,7 @@ files:
|
|
75
56
|
- rakefile.rb
|
76
57
|
test_files:
|
77
58
|
- test/test_geocoding.rb
|
78
|
-
- test/
|
59
|
+
- test/test_gm_geocoding.rb
|
79
60
|
- test/test_local_search.rb
|
80
61
|
- test/test_map_image.rb
|
81
62
|
- test/test_traffic.rb
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'ym4r/google_maps/mapping'
|
2
|
-
|
3
|
-
module Ym4r
|
4
|
-
module GoogleMaps
|
5
|
-
#Small map control. Report to the Google Maps API documentation for details.
|
6
|
-
class GSmallMapControl
|
7
|
-
include MappingObject
|
8
|
-
def create
|
9
|
-
"new GSmallMapControl()"
|
10
|
-
end
|
11
|
-
end
|
12
|
-
#Large Map control. Report to the Google Maps API documentation for details.
|
13
|
-
class GLargeMapControl
|
14
|
-
include MappingObject
|
15
|
-
def create
|
16
|
-
"new GLargeMapControl()"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
#Small Zoom control. Report to the Google Maps API documentation for details.
|
20
|
-
class GSmallZoomControl
|
21
|
-
include MappingObject
|
22
|
-
def create
|
23
|
-
"new GSmallZoomControl()"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
#Scale control. Report to the Google Maps API documentation for details.
|
27
|
-
class GScaleControl
|
28
|
-
include MappingObject
|
29
|
-
def create
|
30
|
-
"new GScaleControl()"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
#Map type control. Report to the Google Maps API documentation for details.
|
34
|
-
class GMapTypeControl
|
35
|
-
include MappingObject
|
36
|
-
def create
|
37
|
-
"new GMapTypeControl()"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
#Overview map control. Report to the Google Maps API documentation for details.
|
41
|
-
class GOverviewMapControl
|
42
|
-
include MappingObject
|
43
|
-
def create
|
44
|
-
"new GOverviewMapControl()"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
#An object representing a position of a control.
|
49
|
-
#The first argument of the constructor is one of the following : :top_right, :top_left, :bottom_right, :bottom_left.
|
50
|
-
class GControlPosition < Struct.new(:anchor,:offset)
|
51
|
-
include MappingObject
|
52
|
-
def create
|
53
|
-
js_anchor = if anchor == :top_right
|
54
|
-
"G_ANCHOR_TOP_RIGHT"
|
55
|
-
elsif anchor == :top_left
|
56
|
-
"G_ANCHOR_TOP_LEFT"
|
57
|
-
elsif anchor == :bottom_right
|
58
|
-
"G_ANCHOR_BOTTOM_RIGHT"
|
59
|
-
else
|
60
|
-
"G_ANCHOR_BOTTOM_LEFT"
|
61
|
-
end
|
62
|
-
"new GControlPosition(#{js_anchor},#{offset})"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'ym4r/google_maps/api_key'
|
2
|
-
require 'open-uri'
|
3
|
-
require 'rexml/document'
|
4
|
-
|
5
|
-
module Ym4r
|
6
|
-
module GoogleMaps
|
7
|
-
module Geocoding
|
8
|
-
|
9
|
-
GEO_SUCCESS = 200
|
10
|
-
GEO_MISSING_ADDRESS = 601
|
11
|
-
GEO_UNKNOWN_ADDRESS = 602
|
12
|
-
GEO_UNAVAILABLE_ADDRESS = 603
|
13
|
-
GEO_BAD_KEY = 610
|
14
|
-
GEO_TOO_MANY_QUERIES = 620
|
15
|
-
GEO_SERVER_ERROR = 500
|
16
|
-
|
17
|
-
#Gets placemarks by querying the Google Maps Geocoding service with the +request+ string
|
18
|
-
def self.get(request)
|
19
|
-
|
20
|
-
url = "http://maps.google.com/maps/geo?q=#{request}&key=#{API_KEY}&output=xml"
|
21
|
-
begin
|
22
|
-
xml = open(URI.encode(url)).read
|
23
|
-
rescue
|
24
|
-
raise ConnectionException.new("Unable to connect to Google Maps Geocoding service")
|
25
|
-
end
|
26
|
-
|
27
|
-
doc = REXML::Document.new(xml)
|
28
|
-
|
29
|
-
response = doc.elements['//Response']
|
30
|
-
placemarks = Placemarks.new(response.elements['name'].text,response.elements['Status/code'].text.to_i)
|
31
|
-
response.elements.each("Placemark") do |placemark|
|
32
|
-
data = placemark.elements
|
33
|
-
data_country = data['//CountryNameCode']
|
34
|
-
data_administrative = data['//AdministrativeAreaName']
|
35
|
-
data_sub_administrative = data['//SubAdministrativeAreaName']
|
36
|
-
data_locality = data['//LocalityName']
|
37
|
-
data_dependent_locality = data['//DependentLocalityName']
|
38
|
-
data_thoroughfare = data['//ThoroughfareName']
|
39
|
-
data_postal_code = data['//PostalCodeNumber']
|
40
|
-
placemarks << Geocoding::Placemark.new(data['address'].text,
|
41
|
-
data_country.nil? ? "" : data_country.text,
|
42
|
-
data_administrative.nil? ? "" : data_administrative.text,
|
43
|
-
data_sub_administrative.nil? ? "" : data_sub_administrative.text,
|
44
|
-
data_locality.nil? ? "" : data_locality.text,
|
45
|
-
data_dependent_locality.nil? ? "" : data_dependent_locality.text,
|
46
|
-
data_thoroughfare.nil? ? "" : data_thoroughfare.text,
|
47
|
-
data_postal_code.nil? ? "" : data_postal_code.text,
|
48
|
-
*(data['//coordinates'].text.split(",")[0..1].collect {|l| l.to_f }))
|
49
|
-
end
|
50
|
-
placemarks
|
51
|
-
end
|
52
|
-
|
53
|
-
#Group of placemarks returned by the Geocoding service. If the result is valid the +statius+ attribute should be equal to <tt>Geocoding::GEI_SUCCESS</tt>
|
54
|
-
class Placemarks < Array
|
55
|
-
attr_accessor :name,:status
|
56
|
-
|
57
|
-
def initialize(name,status)
|
58
|
-
super(0)
|
59
|
-
@name = name
|
60
|
-
@status = status
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
#A result from the Geocoding service.
|
65
|
-
class Placemark < Struct.new(:address,:country_code,:administrative_area,:sub_administrative_area,:locality,:dependent_locality,:thoroughfare,:postal_code,:longitude,:latitude)
|
66
|
-
def lonlat
|
67
|
-
[longitude,latitude]
|
68
|
-
end
|
69
|
-
|
70
|
-
def latlon
|
71
|
-
[latitude,longitude]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
#Raised when the connection to the service is not possible
|
76
|
-
class ConnectionException < StandardError
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
|
2
|
-
Ym4r::GoogleMaps::GPolyline.class_eval do
|
3
|
-
#Creates a GPolyline object from a georuby line string. Assumes the points of the line strings are stored in Longitude(x)/Latitude(y) order.
|
4
|
-
def self.from_georuby(line_string,color = nil,weight = nil,opacity = nil)
|
5
|
-
GPolyline.new(line_string.points.collect { |point| GLatLng.new([point.y,point.x])},color,weight,opacity)
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
Ym4r::GoogleMaps::GMarker.class_eval do
|
10
|
-
#Creates a GMarker object from a georuby point. Accepts the same options as the GMarker constructor. Assumes the points of the line strings are stored in Longitude(x)/Latitude(y) order.
|
11
|
-
def self.from_georuby(point,options = {})
|
12
|
-
GMarker.new([point.y,point.x],options)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
Ym4r::GoogleMaps::GLatLng.class_eval do
|
17
|
-
#Creates a GLatLng object from a georuby point. Assumes the points of the line strings are stored in Longitude(x)/Latitude(y) order.
|
18
|
-
def self.from_georuby(point,unbounded = nil)
|
19
|
-
GLatLng.new([point.y,point.x],unbounded)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
@@ -1,444 +0,0 @@
|
|
1
|
-
// Clusterer.js - marker clustering routines for Google Maps apps
|
2
|
-
//
|
3
|
-
// The original version of this code is available at:
|
4
|
-
// http://www.acme.com/javascript/
|
5
|
-
//
|
6
|
-
// Copyright � 2005,2006 by Jef Poskanzer <jef@mail.acme.com>.
|
7
|
-
// All rights reserved.
|
8
|
-
//
|
9
|
-
// Modified for inclusion into the YM4R library in accordance with the
|
10
|
-
// following license:
|
11
|
-
//
|
12
|
-
// Redistribution and use in source and binary forms, with or without
|
13
|
-
// modification, are permitted provided that the following conditions
|
14
|
-
// are met:
|
15
|
-
// 1. Redistributions of source code must retain the above copyright
|
16
|
-
// notice, this list of conditions and the following disclaimer.
|
17
|
-
// 2. Redistributions in binary form must reproduce the above copyright
|
18
|
-
// notice, this list of conditions and the following disclaimer in the
|
19
|
-
// documentation and/or other materials provided with the distribution.
|
20
|
-
//
|
21
|
-
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
22
|
-
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
-
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
24
|
-
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
25
|
-
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
-
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
27
|
-
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
28
|
-
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
29
|
-
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
30
|
-
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
31
|
-
// SUCH DAMAGE.
|
32
|
-
//
|
33
|
-
// For commentary on this license please see http://www.acme.com/license.html
|
34
|
-
|
35
|
-
|
36
|
-
// Constructor.
|
37
|
-
Clusterer = function(markers,icon,maxVisibleMarkers,gridSize,minMarkersPerCluster,maxLinesPerInfoBox) {
|
38
|
-
this.markers = [];
|
39
|
-
if(markers){
|
40
|
-
for(var i =0 ; i< markers.length ; i++){
|
41
|
-
this.addMarker(markers[i]);
|
42
|
-
}
|
43
|
-
}
|
44
|
-
this.clusters = [];
|
45
|
-
this.timeout = null;
|
46
|
-
|
47
|
-
this.maxVisibleMarkers = maxVisibleMarkers || 150;
|
48
|
-
this.gridSize = gridSize || 5;
|
49
|
-
this.minMarkersPerCluster = minMarkersPerCluster || 5;
|
50
|
-
this.maxLinesPerInfoBox = maxLinesPerInfoBox || 10;
|
51
|
-
|
52
|
-
this.icon = icon || G_DEFAULT_ICON;
|
53
|
-
}
|
54
|
-
|
55
|
-
Clusterer.prototype = new GOverlay();
|
56
|
-
|
57
|
-
Clusterer.prototype.initialize = function ( map ){
|
58
|
-
this.map = map;
|
59
|
-
this.currentZoomLevel = map.getZoom();
|
60
|
-
|
61
|
-
GEvent.addListener( map, 'zoomend', Clusterer.makeCaller( Clusterer.display, this ) );
|
62
|
-
GEvent.addListener( map, 'moveend', Clusterer.makeCaller( Clusterer.display, this ) );
|
63
|
-
GEvent.addListener( map, 'infowindowclose', Clusterer.makeCaller( Clusterer.popDown, this ) );
|
64
|
-
//Set map for each marker
|
65
|
-
for(var i = 0,len = this.markers.length ; i < len ; i++){
|
66
|
-
this.markers[i].setMap( map );
|
67
|
-
}
|
68
|
-
this.displayLater();
|
69
|
-
}
|
70
|
-
|
71
|
-
Clusterer.prototype.remove = function(){
|
72
|
-
for ( var i = 0; i < this.markers.length; ++i ){
|
73
|
-
this.removeMarker(this.markers[i]);
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
Clusterer.prototype.copy = function(){
|
78
|
-
return new Clusterer(this.markers,this.icon,this.maxVisibleMarkers,this.gridSize,this.minMarkersPerCluster,this.maxLinesPerInfoBox);
|
79
|
-
}
|
80
|
-
|
81
|
-
Clusterer.prototype.redraw = function(force){
|
82
|
-
this.displayLater();
|
83
|
-
}
|
84
|
-
|
85
|
-
// Call this to change the cluster icon.
|
86
|
-
Clusterer.prototype.setIcon = function ( icon ){
|
87
|
-
this.icon = icon;
|
88
|
-
}
|
89
|
-
|
90
|
-
// Call this to add a marker.
|
91
|
-
Clusterer.prototype.addMarker = function ( marker, description){
|
92
|
-
marker.onMap = false;
|
93
|
-
this.markers.push( marker );
|
94
|
-
marker.description = marker.description || description;
|
95
|
-
if(this.map != null){
|
96
|
-
marker.setMap(this.map);
|
97
|
-
this.displayLater();
|
98
|
-
}
|
99
|
-
};
|
100
|
-
|
101
|
-
|
102
|
-
// Call this to remove a marker.
|
103
|
-
Clusterer.prototype.removeMarker = function ( marker ){
|
104
|
-
for ( var i = 0; i < this.markers.length; ++i )
|
105
|
-
if ( this.markers[i] == marker ){
|
106
|
-
if ( marker.onMap )
|
107
|
-
this.map.removeOverlay( marker );
|
108
|
-
for ( var j = 0; j < this.clusters.length; ++j ){
|
109
|
-
var cluster = this.clusters[j];
|
110
|
-
if ( cluster != null ){
|
111
|
-
for ( var k = 0; k < cluster.markers.length; ++k )
|
112
|
-
if ( cluster.markers[k] == marker ){
|
113
|
-
cluster.markers[k] = null;
|
114
|
-
--cluster.markerCount;
|
115
|
-
break;
|
116
|
-
}
|
117
|
-
if ( cluster.markerCount == 0 ){
|
118
|
-
this.clearCluster( cluster );
|
119
|
-
this.clusters[j] = null;
|
120
|
-
}
|
121
|
-
else if ( cluster == this.poppedUpCluster )
|
122
|
-
Clusterer.rePop( this );
|
123
|
-
}
|
124
|
-
}
|
125
|
-
this.markers[i] = null;
|
126
|
-
break;
|
127
|
-
}
|
128
|
-
this.displayLater();
|
129
|
-
};
|
130
|
-
|
131
|
-
Clusterer.prototype.displayLater = function (){
|
132
|
-
if ( this.timeout != null )
|
133
|
-
clearTimeout( this.timeout );
|
134
|
-
this.timeout = setTimeout( Clusterer.makeCaller( Clusterer.display, this ), 50 );
|
135
|
-
};
|
136
|
-
|
137
|
-
Clusterer.display = function ( clusterer ){
|
138
|
-
var i, j, marker, cluster, len, len2;
|
139
|
-
|
140
|
-
clearTimeout( clusterer.timeout );
|
141
|
-
|
142
|
-
var newZoomLevel = clusterer.map.getZoom();
|
143
|
-
if ( newZoomLevel != clusterer.currentZoomLevel ){
|
144
|
-
// When the zoom level changes, we have to remove all the clusters.
|
145
|
-
for ( i = 0 , len = clusterer.clusters.length; i < len; ++i ){
|
146
|
-
if ( clusterer.clusters[i] != null ){
|
147
|
-
clusterer.clearCluster( clusterer.clusters[i] );
|
148
|
-
clusterer.clusters[i] = null;
|
149
|
-
}
|
150
|
-
}
|
151
|
-
clusterer.clusters.length = 0;
|
152
|
-
clusterer.currentZoomLevel = newZoomLevel;
|
153
|
-
}
|
154
|
-
|
155
|
-
// Get the current bounds of the visible area.
|
156
|
-
var bounds = clusterer.map.getBounds();
|
157
|
-
|
158
|
-
// Expand the bounds a little, so things look smoother when scrolling
|
159
|
-
// by small amounts.
|
160
|
-
var sw = bounds.getSouthWest();
|
161
|
-
var ne = bounds.getNorthEast();
|
162
|
-
var dx = ne.lng() - sw.lng();
|
163
|
-
var dy = ne.lat() - sw.lat();
|
164
|
-
dx *= 0.10;
|
165
|
-
dy *= 0.10;
|
166
|
-
bounds = new GLatLngBounds(
|
167
|
-
new GLatLng( sw.lat() - dy, sw.lng() - dx ),
|
168
|
-
new GLatLng( ne.lat() + dy, ne.lng() + dx )
|
169
|
-
);
|
170
|
-
|
171
|
-
// Partition the markers into visible and non-visible lists.
|
172
|
-
var visibleMarkers = [];
|
173
|
-
var nonvisibleMarkers = [];
|
174
|
-
for ( i = 0, len = clusterer.markers.length ; i < len; ++i ){
|
175
|
-
marker = clusterer.markers[i];
|
176
|
-
if ( marker != null )
|
177
|
-
if ( bounds.contains( marker.getPoint() ) )
|
178
|
-
visibleMarkers.push( marker );
|
179
|
-
else
|
180
|
-
nonvisibleMarkers.push( marker );
|
181
|
-
}
|
182
|
-
|
183
|
-
// Take down the non-visible markers.
|
184
|
-
for ( i = 0, len = nonvisibleMarkers.length ; i < len; ++i ){
|
185
|
-
marker = nonvisibleMarkers[i];
|
186
|
-
if ( marker.onMap ){
|
187
|
-
clusterer.map.removeOverlay( marker );
|
188
|
-
marker.onMap = false;
|
189
|
-
}
|
190
|
-
}
|
191
|
-
|
192
|
-
// Take down the non-visible clusters.
|
193
|
-
for ( i = 0, len = clusterer.clusters.length ; i < len ; ++i ){
|
194
|
-
cluster = clusterer.clusters[i];
|
195
|
-
if ( cluster != null && ! bounds.contains( cluster.marker.getPoint() ) && cluster.onMap ){
|
196
|
-
clusterer.map.removeOverlay( cluster.marker );
|
197
|
-
cluster.onMap = false;
|
198
|
-
}
|
199
|
-
}
|
200
|
-
|
201
|
-
// Clustering! This is some complicated stuff. We have three goals
|
202
|
-
// here. One, limit the number of markers & clusters displayed, so the
|
203
|
-
// maps code doesn't slow to a crawl. Two, when possible keep existing
|
204
|
-
// clusters instead of replacing them with new ones, so that the app pans
|
205
|
-
// better. And three, of course, be CPU and memory efficient.
|
206
|
-
if ( visibleMarkers.length > clusterer.maxVisibleMarkers ){
|
207
|
-
// Add to the list of clusters by splitting up the current bounds
|
208
|
-
// into a grid.
|
209
|
-
var latRange = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();
|
210
|
-
var latInc = latRange / clusterer.gridSize;
|
211
|
-
var lngInc = latInc / Math.cos( ( bounds.getNorthEast().lat() + bounds.getSouthWest().lat() ) / 2.0 * Math.PI / 180.0 );
|
212
|
-
for ( var lat = bounds.getSouthWest().lat(); lat <= bounds.getNorthEast().lat(); lat += latInc )
|
213
|
-
for ( var lng = bounds.getSouthWest().lng(); lng <= bounds.getNorthEast().lng(); lng += lngInc ){
|
214
|
-
cluster = new Object();
|
215
|
-
cluster.clusterer = clusterer;
|
216
|
-
cluster.bounds = new GLatLngBounds( new GLatLng( lat, lng ), new GLatLng( lat + latInc, lng + lngInc ) );
|
217
|
-
cluster.markers = [];
|
218
|
-
cluster.markerCount = 0;
|
219
|
-
cluster.onMap = false;
|
220
|
-
cluster.marker = null;
|
221
|
-
clusterer.clusters.push( cluster );
|
222
|
-
}
|
223
|
-
|
224
|
-
// Put all the unclustered visible markers into a cluster - the first
|
225
|
-
// one it fits in, which favors pre-existing clusters.
|
226
|
-
for ( i = 0, len = visibleMarkers.length ; i < len; ++i ){
|
227
|
-
marker = visibleMarkers[i];
|
228
|
-
if ( marker != null && ! marker.inCluster ){
|
229
|
-
for ( j = 0, len2 = clusterer.clusters.length ; j < len2 ; ++j ){
|
230
|
-
cluster = clusterer.clusters[j];
|
231
|
-
if ( cluster != null && cluster.bounds.contains( marker.getPoint() ) ){
|
232
|
-
cluster.markers.push( marker );
|
233
|
-
++cluster.markerCount;
|
234
|
-
marker.inCluster = true;
|
235
|
-
}
|
236
|
-
}
|
237
|
-
}
|
238
|
-
}
|
239
|
-
|
240
|
-
// Get rid of any clusters containing only a few markers.
|
241
|
-
for ( i = 0, len = clusterer.clusters.length ; i < len ; ++i )
|
242
|
-
if ( clusterer.clusters[i] != null && clusterer.clusters[i].markerCount < clusterer.minMarkersPerCluster ){
|
243
|
-
clusterer.clearCluster( clusterer.clusters[i] );
|
244
|
-
clusterer.clusters[i] = null;
|
245
|
-
}
|
246
|
-
|
247
|
-
// Shrink the clusters list.
|
248
|
-
for ( i = clusterer.clusters.length - 1; i >= 0; --i )
|
249
|
-
if ( clusterer.clusters[i] != null )
|
250
|
-
break;
|
251
|
-
else
|
252
|
-
--clusterer.clusters.length;
|
253
|
-
|
254
|
-
// Ok, we have our clusters. Go through the markers in each
|
255
|
-
// cluster and remove them from the map if they are currently up.
|
256
|
-
for ( i = 0, len = clusterer.clusters.length ; i < len; ++i ){
|
257
|
-
cluster = clusterer.clusters[i];
|
258
|
-
if ( cluster != null ){
|
259
|
-
for ( j = 0 , len2 = cluster.markers.length ; j < len2; ++j ){
|
260
|
-
marker = cluster.markers[j];
|
261
|
-
if ( marker != null && marker.onMap ){
|
262
|
-
clusterer.map.removeOverlay( marker );
|
263
|
-
marker.onMap = false;
|
264
|
-
}
|
265
|
-
}
|
266
|
-
}
|
267
|
-
}
|
268
|
-
|
269
|
-
// Now make cluster-markers for any clusters that need one.
|
270
|
-
for ( i = 0, len = clusterer.clusters.length; i < len; ++i ){
|
271
|
-
cluster = clusterer.clusters[i];
|
272
|
-
if ( cluster != null && cluster.marker == null ){
|
273
|
-
// Figure out the average coordinates of the markers in this
|
274
|
-
// cluster.
|
275
|
-
var xTotal = 0.0, yTotal = 0.0;
|
276
|
-
for ( j = 0, len2 = cluster.markers.length; j < len2 ; ++j ){
|
277
|
-
marker = cluster.markers[j];
|
278
|
-
if ( marker != null ){
|
279
|
-
xTotal += ( + marker.getPoint().lng() );
|
280
|
-
yTotal += ( + marker.getPoint().lat() );
|
281
|
-
}
|
282
|
-
}
|
283
|
-
var location = new GLatLng( yTotal / cluster.markerCount, xTotal / cluster.markerCount );
|
284
|
-
marker = new GMarker( location, { icon: clusterer.icon } );
|
285
|
-
cluster.marker = marker;
|
286
|
-
GEvent.addListener( marker, 'click', Clusterer.makeCaller( Clusterer.popUp, cluster ) );
|
287
|
-
}
|
288
|
-
}
|
289
|
-
}
|
290
|
-
|
291
|
-
// Display the visible markers not already up and not in clusters.
|
292
|
-
for ( i = 0, len = visibleMarkers.length; i < len; ++i ){
|
293
|
-
marker = visibleMarkers[i];
|
294
|
-
if ( marker != null && ! marker.onMap && ! marker.inCluster )
|
295
|
-
{
|
296
|
-
clusterer.map.addOverlay( marker );
|
297
|
-
marker.addedToMap();
|
298
|
-
marker.onMap = true;
|
299
|
-
}
|
300
|
-
}
|
301
|
-
|
302
|
-
// Display the visible clusters not already up.
|
303
|
-
for ( i = 0, len = clusterer.clusters.length ; i < len; ++i ){
|
304
|
-
cluster = clusterer.clusters[i];
|
305
|
-
if ( cluster != null && ! cluster.onMap && bounds.contains( cluster.marker.getPoint() )){
|
306
|
-
clusterer.map.addOverlay( cluster.marker );
|
307
|
-
cluster.onMap = true;
|
308
|
-
}
|
309
|
-
}
|
310
|
-
|
311
|
-
// In case a cluster is currently popped-up, re-pop to get any new
|
312
|
-
// markers into the infobox.
|
313
|
-
Clusterer.rePop( clusterer );
|
314
|
-
};
|
315
|
-
|
316
|
-
|
317
|
-
Clusterer.popUp = function ( cluster ){
|
318
|
-
var clusterer = cluster.clusterer;
|
319
|
-
var html = '<table width="300">';
|
320
|
-
var n = 0;
|
321
|
-
for ( var i = 0 , len = cluster.markers.length; i < len; ++i )
|
322
|
-
{
|
323
|
-
var marker = cluster.markers[i];
|
324
|
-
if ( marker != null )
|
325
|
-
{
|
326
|
-
++n;
|
327
|
-
html += '<tr><td>';
|
328
|
-
if ( marker.getIcon().smallImage != null )
|
329
|
-
html += '<img src="' + marker.getIcon().smallImage + '">';
|
330
|
-
else
|
331
|
-
html += '<img src="' + marker.getIcon().image + '" width="' + ( marker.getIcon().iconSize.width / 2 ) + '" height="' + ( marker.getIcon().iconSize.height / 2 ) + '">';
|
332
|
-
html += '</td><td>' + marker.description + '</td></tr>';
|
333
|
-
if ( n == clusterer.maxLinesPerInfoBox - 1 && cluster.markerCount > clusterer.maxLinesPerInfoBox )
|
334
|
-
{
|
335
|
-
html += '<tr><td colspan="2">...and ' + ( cluster.markerCount - n ) + ' more</td></tr>';
|
336
|
-
break;
|
337
|
-
}
|
338
|
-
}
|
339
|
-
}
|
340
|
-
html += '</table>';
|
341
|
-
clusterer.map.closeInfoWindow();
|
342
|
-
cluster.marker.openInfoWindowHtml( html );
|
343
|
-
clusterer.poppedUpCluster = cluster;
|
344
|
-
};
|
345
|
-
|
346
|
-
Clusterer.rePop = function ( clusterer ){
|
347
|
-
if ( clusterer.poppedUpCluster != null )
|
348
|
-
Clusterer.popUp( poppedUpCluster );
|
349
|
-
};
|
350
|
-
|
351
|
-
Clusterer.popDown = function ( clusterer ){
|
352
|
-
clusterer.poppedUpCluster = null;
|
353
|
-
};
|
354
|
-
|
355
|
-
Clusterer.prototype.clearCluster = function ( cluster ){
|
356
|
-
var i, marker;
|
357
|
-
|
358
|
-
for ( i = 0; i < cluster.markers.length; ++i ){
|
359
|
-
if ( cluster.markers[i] != null ){
|
360
|
-
cluster.markers[i].inCluster = false;
|
361
|
-
cluster.markers[i] = null;
|
362
|
-
}
|
363
|
-
}
|
364
|
-
|
365
|
-
cluster.markers.length = 0;
|
366
|
-
cluster.markerCount = 0;
|
367
|
-
|
368
|
-
if ( cluster == this.poppedUpCluster )
|
369
|
-
this.map.closeInfoWindow();
|
370
|
-
|
371
|
-
if ( cluster.onMap )
|
372
|
-
{
|
373
|
-
this.map.removeOverlay( cluster.marker );
|
374
|
-
cluster.onMap = false;
|
375
|
-
}
|
376
|
-
};
|
377
|
-
|
378
|
-
// This returns a function closure that calls the given routine with the
|
379
|
-
// specified arg.
|
380
|
-
Clusterer.makeCaller = function ( func, arg ){
|
381
|
-
return function () { func( arg ); };
|
382
|
-
};
|
383
|
-
|
384
|
-
|
385
|
-
// Augment GMarker so it handles markers that have been created but
|
386
|
-
// not yet addOverlayed.
|
387
|
-
GMarker.prototype.setMap = function ( map ){
|
388
|
-
this.map = map;
|
389
|
-
};
|
390
|
-
|
391
|
-
GMarker.prototype.getMap = function (){
|
392
|
-
return this.map;
|
393
|
-
}
|
394
|
-
|
395
|
-
GMarker.prototype.addedToMap = function (){
|
396
|
-
this.map = null;
|
397
|
-
};
|
398
|
-
|
399
|
-
|
400
|
-
GMarker.prototype.origOpenInfoWindow = GMarker.prototype.openInfoWindow;
|
401
|
-
GMarker.prototype.openInfoWindow = function ( node, opts ){
|
402
|
-
if ( this.map != null )
|
403
|
-
return this.map.openInfoWindow( this.getPoint(), node, opts );
|
404
|
-
else
|
405
|
-
return this.origOpenInfoWindow( node, opts );
|
406
|
-
};
|
407
|
-
|
408
|
-
GMarker.prototype.origOpenInfoWindowHtml = GMarker.prototype.openInfoWindowHtml;
|
409
|
-
GMarker.prototype.openInfoWindowHtml = function ( html, opts ){
|
410
|
-
if ( this.map != null )
|
411
|
-
return this.map.openInfoWindowHtml( this.getPoint(), html, opts );
|
412
|
-
else
|
413
|
-
return this.origOpenInfoWindowHtml( html, opts );
|
414
|
-
};
|
415
|
-
|
416
|
-
GMarker.prototype.origOpenInfoWindowTabs = GMarker.prototype.openInfoWindowTabs;
|
417
|
-
GMarker.prototype.openInfoWindowTabs = function ( tabNodes, opts ){
|
418
|
-
if ( this.map != null )
|
419
|
-
return this.map.openInfoWindowTabs( this.getPoint(), tabNodes, opts );
|
420
|
-
else
|
421
|
-
return this.origOpenInfoWindowTabs( tabNodes, opts );
|
422
|
-
};
|
423
|
-
|
424
|
-
GMarker.prototype.origOpenInfoWindowTabsHtml = GMarker.prototype.openInfoWindowTabsHtml;
|
425
|
-
GMarker.prototype.openInfoWindowTabsHtml = function ( tabHtmls, opts ){
|
426
|
-
if ( this.map != null )
|
427
|
-
return this.map.openInfoWindowTabsHtml( this.getPoint(), tabHtmls, opts );
|
428
|
-
else
|
429
|
-
return this.origOpenInfoWindowTabsHtml( tabHtmls, opts );
|
430
|
-
};
|
431
|
-
|
432
|
-
GMarker.prototype.origShowMapBlowup = GMarker.prototype.showMapBlowup;
|
433
|
-
GMarker.prototype.showMapBlowup = function ( opts ){
|
434
|
-
if ( this.map != null )
|
435
|
-
return this.map.showMapBlowup( this.getPoint(), opts );
|
436
|
-
else
|
437
|
-
return this.origShowMapBlowup( opts );
|
438
|
-
};
|
439
|
-
|
440
|
-
|
441
|
-
function addDescriptionToMarker(marker, description){
|
442
|
-
marker.description = description;
|
443
|
-
return marker;
|
444
|
-
}
|