gmaps4rails 0.8.8 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,7 @@
1
1
  class Array
2
+ #Scopes on models generate Arrays
3
+ #this method enables short call to the json creation for all elements in the array
4
+
2
5
  def to_gmaps4rails
3
6
  json = "["
4
7
  each do |object|
@@ -1,4 +1,8 @@
1
1
  class Hash
2
+
3
+ # this method extracts all info from the hash to create javascript
4
+ # this javascript is then rendered raw to the view so it can be interpreted and executed
5
+
2
6
  def to_gmaps4rails(init = false)
3
7
  #the variable 'options' must have the following structure
4
8
  #{
@@ -62,7 +66,7 @@ class Hash
62
66
  result << "Gmaps4Rails.create_#{category}();"
63
67
  end
64
68
  end
65
- result << "if(typeof gmaps4rails_callback == 'function') { gmaps4rails_callback(); }"
69
+ result << "Gmaps4Rails.callback();"
66
70
  result * ('
67
71
  ')
68
72
  end
data/lib/gmaps4rails.rb CHANGED
@@ -1,18 +1,17 @@
1
1
  if defined?(Rails) && Rails::VERSION::MAJOR == 3
2
2
  module Gmaps4rails
3
- require "rails"
4
- #require "action_controller"
5
- require 'array'
6
- require 'hash'
7
- #require 'application_helper'
8
- require 'acts_as_gmappable/base'
3
+ require 'rails'
4
+ require 'extensions/array'
5
+ require 'extensions/hash'
6
+ require 'gmaps4rails/base'
7
+ require 'gmaps4rails/acts_as_gmappable'
8
+ require 'helper/gmaps4rails_helper'
9
9
 
10
10
  class Engine < Rails::Engine
11
11
  initializer "static assets" do |app|
12
12
  app.middleware.use ::ActionDispatch::Static, "#{root}/public"
13
13
  end
14
14
  initializer "gmaps4rails view helpers" do |app|
15
- require 'gmaps4rails_helper'
16
15
  ActionView::Base.send :include, Gmaps4railsHelper
17
16
  end
18
17
  end
@@ -0,0 +1,85 @@
1
+ module Gmaps4rails
2
+ module ActsAsGmappable
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ module InstanceMethods
7
+
8
+ # This is a before_filter to trigger the geocoding and save its results
9
+
10
+ def process_geocoding
11
+ #to prevent geocoding each time a save is made
12
+ return true if gmaps4rails_options[:check_process] == true && self.send(gmaps4rails_options[:checker]) == true
13
+ #try to geocode
14
+ begin
15
+ coordinates = Gmaps4rails.geocode(self.send(gmaps4rails_options[:address]), gmaps4rails_options[:language])
16
+ rescue GeocodeStatus, GeocodeInvalidQuery #address was invalid, add error to base.
17
+ errors[gmaps4rails_options[:address]] << gmaps4rails_options[:msg] if gmaps4rails_options[:validation]
18
+ rescue GeocodeNetStatus => e #connection error, No need to prevent save.
19
+ logger.warn(e)
20
+ #TODO add customization here?
21
+ else #if no exception, save the values
22
+ self.send(gmaps4rails_options[:lng_column]+"=", coordinates.first[:lng]) if self.respond_to?(gmaps4rails_options[:lng_column]+"=")
23
+ self.send(gmaps4rails_options[:lat_column]+"=", coordinates.first[:lat]) if self.respond_to?(gmaps4rails_options[:lat_column]+"=")
24
+ unless gmaps4rails_options[:normalized_address].nil?
25
+ self.send(gmaps4rails_options[:normalized_address].to_s+"=", coordinates.first[:matched_address])
26
+ end
27
+ # Call the callback method to let the user do what he wants with the data
28
+ self.send(gmaps4rails_options[:callback], coordinates.first[:full_data]) unless gmaps4rails_options[:callback].nil?
29
+ if gmaps4rails_options[:check_process] == true
30
+ self[gmaps4rails_options[:checker]] = true
31
+ end
32
+ end
33
+ end
34
+
35
+ def to_gmaps4rails
36
+ json = "["
37
+ json += Gmaps4rails.create_json(self).to_s.chop.chop #removes the extra comma
38
+ json += "]"
39
+ end
40
+
41
+ end
42
+
43
+ module ClassMethods
44
+
45
+ def acts_as_gmappable args = {}
46
+
47
+ # disable before_filter if explicitly set
48
+
49
+ unless args[:process_geocoding] == false
50
+ validate :process_geocoding
51
+ end
52
+
53
+ #instance method containing all the options to configure the behaviour of the gem regarding the current Model
54
+
55
+ define_method "gmaps4rails_options" do
56
+ {
57
+ :lat_column => args[:lat] || "latitude",
58
+ :lng_column => args[:lng] || "longitude",
59
+ :check_process => args[:check_process].nil? ? true : args[:check_process],
60
+ :checker => args[:checker] || "gmaps",
61
+ :msg => args[:msg] || "Address invalid",
62
+ :validation => args[:validation].nil? ? true : args[:validation],
63
+ :normalized_address => args[:normalized_address],
64
+ :address => args[:address] || "gmaps4rails_address",
65
+ :callback => args[:callback],
66
+ :language => args[:language] || "en"
67
+ }
68
+ end
69
+
70
+ include InstanceMethods
71
+
72
+ end
73
+ end
74
+
75
+ end #ActsAsGmappable
76
+ end
77
+
78
+ ActiveSupport.on_load(:active_record) do
79
+ ActiveRecord::Base.send(:include, Gmaps4rails::ActsAsGmappable)
80
+ end
81
+
82
+ #::ActiveRecord::Base.send :include, Gmaps4rails::ActsAsGmappable
83
+ # Mongoid::Document::ClassMethods.class_eval do
84
+ # include Gmaps4rails::ActsAsGmappable::Base
85
+ # end
@@ -0,0 +1,170 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'crack'
4
+
5
+ module Gmaps4rails
6
+
7
+ class GeocodeStatus < StandardError; end
8
+ class GeocodeNetStatus < StandardError; end
9
+ class GeocodeInvalidQuery < StandardError; end
10
+ class DirectionStatus < StandardError; end
11
+ class DirectionNetStatus < StandardError; end
12
+ class DirectionInvalidQuery < StandardError; end
13
+
14
+ # Creates the json related to one Object (only tried ActiveRecord objects)
15
+ # This json will contian the marker's attributes of the object
16
+
17
+ def Gmaps4rails.create_json(object)
18
+ unless object.send(object.gmaps4rails_options[:lat_column]).blank? && object.send(object.gmaps4rails_options[:lng_column]).blank?
19
+ "{#{Gmaps4rails.description(object)}#{Gmaps4rails.title(object)}#{Gmaps4rails.sidebar(object)}\"longitude\": \"#{object.send(object.gmaps4rails_options[:lng_column])}\", \"latitude\": \"#{object.send(object.gmaps4rails_options[:lat_column])}\"#{Gmaps4rails.picture(object)}},\n"
20
+ end
21
+ end
22
+
23
+ # Returns description if gmaps4rails_infowindow is defined in the model
24
+
25
+ def Gmaps4rails.description(object)
26
+ return "\"description\": \"#{object.gmaps4rails_infowindow}\", " if object.respond_to?("gmaps4rails_infowindow")
27
+ end
28
+
29
+ # Returns title if gmaps4rails_title is defined in the model
30
+
31
+ def Gmaps4rails.title(object)
32
+ return "\"title\": \"#{object.gmaps4rails_title}\", " if object.respond_to?("gmaps4rails_title")
33
+ end
34
+
35
+ # Returns sidebar content if gmaps4rails_sidebar is defined in the model
36
+
37
+ def Gmaps4rails.sidebar(object)
38
+ return "\"sidebar\": \"#{object.gmaps4rails_sidebar}\"," if object.respond_to?("gmaps4rails_sidebar")
39
+ end
40
+
41
+ # Returns picture options if gmaps4rails_marker_picture is defined in the model
42
+ def Gmaps4rails.picture(object)
43
+ if object.respond_to?("gmaps4rails_marker_picture")
44
+ ", " + object.gmaps4rails_marker_picture.map do |k,v|
45
+ #specific case, anchors are array and should be interpreted this way
46
+ if k.include? "_anchor"
47
+ "\"#{k}\": [#{v[0]}, #{v[1]}]"
48
+ else
49
+ "\"#{k}\": \"#{v}\""
50
+ end
51
+ end.join(", ")
52
+ end
53
+ end
54
+
55
+ # This method geocodes an address using the GoogleMaps webservice
56
+ # options are:
57
+ # * address: string, mandatory
58
+ # * lang: to set the language one wants the result to be translated (default is english)
59
+ # * raw: to get the raw response from google, default is false
60
+
61
+ def Gmaps4rails.geocode(address, lang="en", raw = false)
62
+ if address.nil? || address.empty?
63
+ raise Gmaps4rails::GeocodeInvalidQuery, "You must provide an address"
64
+ else #coordinates are valid
65
+ geocoder = "http://maps.googleapis.com/maps/api/geocode/json?language=#{lang}&address="
66
+ output = "&sensor=false"
67
+ #send request to the google api to get the lat/lng
68
+ request = geocoder + address + output
69
+ url = URI.escape(request)
70
+ Gmaps4rails.handle_geocoding_response(request, Net::HTTP.get_response(URI.parse(url)), raw)
71
+ end # end address valid
72
+ end
73
+
74
+ # This method retrieves destination results provided by GoogleMaps webservice
75
+ # options are:
76
+ # * start_end: Hash { "from" => string, "to" => string}, mandatory
77
+ # * options: details given in the github's wiki
78
+ # * output: could be "pretty", "raw" or "clean"; filters the output from google
79
+
80
+ #output could be raw, pretty or clean
81
+ def Gmaps4rails.destination(start_end, options={}, output="pretty")
82
+ if start_end["from"].nil? || start_end["to"].empty?
83
+ raise Gmaps4rails::DirectionInvalidQuery, "Origin and destination must be provided in a hash as first argument"
84
+ else #great, we have stuff to work with
85
+ geocoder = "http://maps.googleapis.com/maps/api/directions/json?origin=#{start_end["from"]}&destination=#{start_end["to"]}"
86
+ #if value is an Array, it means it contains the waypoints, otherwise it's chained normally
87
+ dest_options = options.empty? ? "" : "&" + options.map {|k,v| v.is_a?(Array) ? k + "=" + v * ("|") : k + "=" + v }*("&")
88
+ #send request to the google api to get the directions
89
+ request = geocoder + dest_options + "&sensor=false"
90
+ url = URI.escape(request)
91
+ Gmaps4rails.handle_destination_response(request, Net::HTTP.get_response(URI.parse(url)), output)
92
+ end # end origin + destination exist
93
+ end #end destination
94
+
95
+ # To create valid js, this method escapes everything but Numeric, true or false
96
+
97
+ def Gmaps4rails.filter(data)
98
+ return data if data.is_a?(Numeric) || data.is_a?(TrueClass) || data.is_a?(FalseClass)
99
+ "'#{data}'"
100
+ end
101
+
102
+ private
103
+
104
+ def Gmaps4rails.handle_geocoding_response(request, response, raw)
105
+ #parse result if result received properly
106
+ if response.is_a?(Net::HTTPSuccess)
107
+ #parse the json
108
+ parse = Crack::JSON.parse(response.body)
109
+ #check if google went well
110
+ if parse["status"] == "OK"
111
+ return parse if raw == true
112
+ array = []
113
+ parse["results"].each do |result|
114
+ array << {
115
+ :lat => result["geometry"]["location"]["lat"],
116
+ :lng => result["geometry"]["location"]["lng"],
117
+ :matched_address => result["formatted_address"],
118
+ :bounds => result["geometry"]["bounds"],
119
+ :full_data => result
120
+ }
121
+ end
122
+ return array
123
+ else #status != OK
124
+ raise Gmaps4rails::GeocodeStatus, "The address you passed seems invalid, status was: #{parse["status"]}.
125
+ Request was: #{request}"
126
+ end #end parse status
127
+
128
+ else #if not http success
129
+ raise Gmaps4rails::GeocodeNetStatus, "The request sent to google was invalid (not http success): #{request}.
130
+ Response was: #{response}"
131
+ end #end resp test
132
+ end
133
+
134
+ def Gmaps4rails.handle_destination_response(request, response, output)
135
+ if response.is_a?(Net::HTTPSuccess)
136
+ #parse the json
137
+ parse = Crack::JSON.parse(response.body)
138
+ #check if google went well
139
+ if parse["status"] == "OK"
140
+ legs = []
141
+ #Each element in the legs array specifies a single leg of the journey from the origin to the destination in the calculated route
142
+ parse["routes"].first["legs"].each do |leg|
143
+ #delete coded polyline elements from legs and store it in polylines to make output cleaner
144
+ polylines = leg["steps"].map {|step| step.delete("polyline")} if output == "pretty" || output == "clean"
145
+ legs << {
146
+ "duration" => { "text" => leg["duration"]["text"], "value" => leg["duration"]["value"].to_f },
147
+ "distance" => { "text" => leg["distance"]["text"], "value" => leg["distance"]["value"].to_f },
148
+ "steps" => leg["steps"]
149
+ }
150
+ if output == "pretty"
151
+ #polylines contain levels data, which are not that useful.
152
+ polylines.map{|poly| poly.delete("levels")}
153
+ #create valid json from all polylines, this could be directly passed to javascript for display
154
+ json = polylines.map { |poly| {"coded_array" => poly["points"]} }.to_json
155
+ #merge results in legs
156
+ legs.last.merge!({ "polylines" => json })
157
+ end
158
+ end
159
+ return legs
160
+ else #status != OK
161
+ raise Gmaps4rails::DirectionStatus, "The query you passed seems invalid, status was: #{parse["status"]}.
162
+ Request was: #{request}"
163
+ end #end parse status
164
+ else #if not http success
165
+ raise Gmaps4rails::DirectionNetStatus, "The request sent to google was invalid (not http success): #{request}.
166
+ Response was: #{response}"
167
+ end #end resp test
168
+ end
169
+
170
+ end
@@ -1,5 +1,7 @@
1
1
  module Gmaps4railsHelper
2
2
 
3
+ # shortcut helper for basic marker display
4
+
3
5
  def gmaps4rails(builder, enable_css = true, enable_js = true )
4
6
  options = {
5
7
  "map_options" => { "auto_adjust" => true},
@@ -8,6 +10,8 @@ module Gmaps4railsHelper
8
10
  render :partial => 'gmaps4rails/gmaps4rails', :locals => { :options => options, :enable_css => enable_css, :enable_js => enable_js }
9
11
  end
10
12
 
13
+ # complete helper to pass all variables alongside their options
14
+
11
15
  def gmaps(options, enable_css = true, enable_js = true )
12
16
  render :partial => 'gmaps4rails/gmaps4rails', :locals => { :options => options, :enable_css => enable_css, :enable_js => enable_js }
13
17
  end
@@ -4,6 +4,12 @@ var Gmaps4Rails = {
4
4
  visibleInfoWindow: null, //contains the current opened infowindow
5
5
  userLocation: null, //contains user's location if geolocalization was performed and successful
6
6
 
7
+ //empty slots
8
+ geolocationFailure: function() { return false;}, //triggered when geolocation fails. If customized, must be like: function(navigator_handles_geolocation){} where 'navigator_handles_geolocation' is a boolean
9
+ callback: function() { return false;}, //to let user set a custom callback function
10
+ customClusterer: function() { return null;}, //to let user set custom clusterer pictures
11
+ infobox: function() { return null;}, //to let user use custom infoboxes
12
+
7
13
  //Map settings
8
14
  map_options: {
9
15
  id: 'gmaps4rails_map',
@@ -32,7 +38,6 @@ var Gmaps4Rails = {
32
38
  width: 22,
33
39
  length: 32,
34
40
  draggable: false, // how to modify: <%= gmaps( "markers" => { "data" => @object.to_gmaps4rails, "options" => { "draggable" => true }}) %>
35
- anchor: null, // centeranchor position of the marker image. Default is null <=> center, you can set options: top_left, top_center, top_right, center_left, center, center_right, bottom_right, bottom_center, bottom_left
36
41
  //clustering config
37
42
  do_clustering: true, // do clustering if set to true
38
43
  clusterer_gridSize: 50, // the more the quicker but the less precise
@@ -42,17 +47,18 @@ var Gmaps4Rails = {
42
47
  list_container: null, // id of the ul that will host links to all markers
43
48
  custom_cluster_pictures: null,
44
49
  custom_infowindow_class: null,
45
- offset: 0 //used when adding_markers to an existing map. Because new markers are concated with previous one, offset is here to avoid the existing are re-created.
50
+ offset: 0 //used when adding_markers to an existing map. Because new markers are concated with previous one, offset is here to prevent the existing from being re-created.
46
51
  },
47
52
 
48
53
  //Stored variables
49
- markers: [], // contains all markers. A marker contains the following: {"description": , "longitude": , "title":, "latitude":, "picture": "", "width": "", "length": "", "sidebar": "", "google_object": google_marker}
54
+ markers: [], // contains all markers. A marker contains the following: {"description": , "longitude": , "title":, "latitude":, "picture": "", "width": "", "length": "", "sidebar": "", "serviceObject": google_marker}
50
55
  bounds_object: null, // contains current bounds from markers, polylines etc...
51
56
  polygons: [], // contains raw data, array of arrays (first element could be a hash containing options)
52
57
  polylines: [], // contains raw data, array of arrays (first element could be a hash containing options)
53
58
  circles: [], // contains raw data, array of hash
54
59
  markerClusterer: null, // contains all marker clusterers
55
-
60
+ markerImages: [],
61
+
56
62
  //Polygon Styling
57
63
  polygons_conf: { // default style for polygons
58
64
  strokeColor: "#FFAA00",
@@ -98,23 +104,13 @@ var Gmaps4Rails = {
98
104
  //initializes the map
99
105
  initialize: function() {
100
106
 
101
- this.map = new google.maps.Map(document.getElementById(this.map_options.id), {
102
- maxZoom: this.map_options.maxZoom,
103
- minZoom: this.map_options.minZoom,
104
- zoom: this.map_options.zoom,
105
- center: new google.maps.LatLng(this.map_options.center_latitude, this.map_options.center_longitude),
106
- mapTypeId: google.maps.MapTypeId[this.map_options.type],
107
- mapTypeControl: this.map_options.mapTypeControl,
108
- disableDefaultUI: this.map_options.disableDefaultUI,
109
- disableDoubleClickZoom: this.map_options.disableDoubleClickZoom,
110
- draggable: this.map_options.draggable
111
- });
107
+ this.map = Gmaps4Rails.createMap();
112
108
 
113
109
  if (this.map_options.detect_location === true || this.map_options.center_on_user === true) {
114
110
  this.findUserLocation();
115
111
  }
116
112
  //resets sidebar if needed
117
- this.reset_sidebar_content();
113
+ this.resetSidebarContent();
118
114
  },
119
115
 
120
116
  findUserLocation: function() {
@@ -122,20 +118,20 @@ var Gmaps4Rails = {
122
118
  //try to retrieve user's position
123
119
  navigator.geolocation.getCurrentPosition(function(position) {
124
120
  //saves the position in the userLocation variable
125
- Gmaps4Rails.userLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
121
+ Gmaps4Rails.userLocation = Gmaps4Rails.createLatLng(position.coords.latitude, position.coords.longitude);
126
122
  //change map's center to focus on user's geoloc if asked
127
123
  if(Gmaps4Rails.map_options.center_on_user === true) {
128
124
  Gmaps4Rails.map.setCenter(Gmaps4Rails.userLocation);
129
125
  }
130
126
  },
131
127
  function() {
132
- //if failure, triggers the function if defined
133
- if(this.fnSet("gmaps4rails_geolocation_failure")) { gmaps4rails_geolocation_failure(true); }
128
+ //failure, but the navigator handles geolocation
129
+ this.geolocationFailure(true);
134
130
  });
135
131
  }
136
132
  else {
137
- //if failure, triggers the function if defined
138
- if(this.fnSet("gmaps4rails_geolocation_failure")) { gmaps4rails_geolocation_failure(false); }
133
+ //failure but the navigator doesn't handle geolocation
134
+ this.geolocationFailure(false);
139
135
  }
140
136
  },
141
137
 
@@ -199,7 +195,7 @@ var Gmaps4Rails = {
199
195
  // always check if a config is given, if not, use defaults
200
196
  // NOTE: is there a cleaner way to do this? Maybe a hash merge of some sort?
201
197
  var newCircle = new google.maps.Circle({
202
- center: new google.maps.LatLng(circle.latitude, circle.longitude),
198
+ center: Gmaps4Rails.createLatLng(circle.latitude, circle.longitude),
203
199
  strokeColor: circle.strokeColor || this.circles_conf.strokeColor,
204
200
  strokeOpacity: circle.strokeOpacity || this.circles_conf.strokeOpacity,
205
201
  strokeWeight: circle.strokeWeight || this.circles_conf.strokeWeight,
@@ -209,7 +205,7 @@ var Gmaps4Rails = {
209
205
  zIndex: circle.zIndex || this.circles_conf.zIndex,
210
206
  radius: circle.radius
211
207
  });
212
- circle.google_object = newCircle;
208
+ circle.serviceObject = newCircle;
213
209
  newCircle.setMap(this.map);
214
210
  }
215
211
  },
@@ -222,7 +218,7 @@ var Gmaps4Rails = {
222
218
  },
223
219
 
224
220
  clear_circle: function(circle) {
225
- circle.google_object.setMap(null);
221
+ circle.serviceObject.setMap(null);
226
222
  },
227
223
 
228
224
  hide_circles: function() {
@@ -232,7 +228,7 @@ var Gmaps4Rails = {
232
228
  },
233
229
 
234
230
  hide_circle: function(circle) {
235
- circle.google_object.setMap(null);
231
+ circle.serviceObject.setMap(null);
236
232
  },
237
233
 
238
234
  show_circles: function() {
@@ -242,7 +238,7 @@ var Gmaps4Rails = {
242
238
  },
243
239
 
244
240
  show_circle: function(circle) {
245
- circle.google_object.setMap(this.map);
241
+ circle.serviceObject.setMap(this.map);
246
242
  },
247
243
 
248
244
  ////////////////////////////////////////////////////
@@ -266,7 +262,7 @@ var Gmaps4Rails = {
266
262
  var fillOpacity;
267
263
  //Polygon points are in an Array, that's why looping is necessary
268
264
  for (var j = 0; j < this.polygons[i].length; ++j) {
269
- var latlng = new google.maps.LatLng(this.polygons[i][j].latitude, this.polygons[i][j].longitude);
265
+ var latlng = Gmaps4Rails.createLatLng(this.polygons[i][j].latitude, this.polygons[i][j].longitude);
270
266
  polygon_coordinates.push(latlng);
271
267
  //first element of an Array could contain specific configuration for this particular polygon. If no config given, use default
272
268
  if (j===0) {
@@ -289,7 +285,7 @@ var Gmaps4Rails = {
289
285
  clickable: false
290
286
  });
291
287
  //save polygon in list
292
- this.polygons[i].google_object = new_poly;
288
+ this.polygons[i].serviceObject = new_poly;
293
289
  new_poly.setMap(this.map);
294
290
  },
295
291
 
@@ -332,7 +328,7 @@ var Gmaps4Rails = {
332
328
  }
333
329
  //add latlng if positions provided
334
330
  if (this.exists(this.polylines[i][j].latitude) && this.exists(this.polylines[i][j].longitude)) {
335
- var latlng = new google.maps.LatLng(this.polylines[i][j].latitude, this.polylines[i][j].longitude);
331
+ var latlng = Gmaps4Rails.createLatLng(this.polylines[i][j].latitude, this.polylines[i][j].longitude);
336
332
  polyline_coordinates.push(latlng);
337
333
  }
338
334
  }
@@ -346,167 +342,140 @@ var Gmaps4Rails = {
346
342
  clickable: false
347
343
  });
348
344
  //save polyline
349
- this.polylines[i].google_object = new_poly;
345
+ this.polylines[i].serviceObject = new_poly;
350
346
  new_poly.setMap(this.map);
351
347
  },
352
348
 
353
349
  ////////////////////////////////////////////////////
354
350
  ///////////////////// MARKERS //////////////////////
355
- ////////////////////////////////////////////////////
351
+ //////////////////tests coded///////////////////////
356
352
 
357
353
  //creates, clusterizes and adjusts map
358
354
  create_markers: function() {
359
- this.create_google_markers_from_markers();
355
+ this.markers_conf.offset = 0;
356
+ this.createServiceMarkersFromMarkers();
360
357
  this.clusterize();
361
- this.adjust_map_to_bounds();
358
+ this.adjustMapToBounds();
362
359
  },
363
360
 
364
361
  //create google.maps Markers from data provided by user
365
- create_google_markers_from_markers: function() {
362
+ createServiceMarkersFromMarkers: function() {
366
363
  for (var i = this.markers_conf.offset; i < this.markers.length; ++i) {
367
364
  //check if the marker has not already been created
368
- if (!this.exists(this.markers[i].google_object)) {
369
- //test if value passed or use default
365
+ if (!this.exists(this.markers[i].serviceObject)) {
366
+ //extract options, test if value passed or use default
370
367
  var marker_picture = this.exists(this.markers[i].picture) ? this.markers[i].picture : this.markers_conf.picture;
371
368
  var marker_width = this.exists(this.markers[i].width) ? this.markers[i].width : this.markers_conf.width;
372
369
  var marker_height = this.exists(this.markers[i].height) ? this.markers[i].height : this.markers_conf.length;
373
- var marker_anchor = this.exists(this.markers[i].anchor) ? this.markers[i].anchor : this.markers_conf.anchor;
374
370
  var marker_title = this.exists(this.markers[i].title) ? this.markers[i].title : null;
375
- var marker_draggable = this.exists(this.markers[i].draggable) ? this.markers[i].draggable : this.markers_conf.draggable;
376
- var Lat = this.markers[i].latitude;
371
+ var marker_anchor = this.exists(this.markers[i].marker_anchor) ? this.markers[i].marker_anchor : null;
372
+ var shadow_anchor = this.exists(this.markers[i].shadow_anchor) ? this.markers[i].shadow_anchor : null;
373
+ var shadow_picture = this.exists(this.markers[i].shadow_picture) ? this.markers[i].shadow_picture : null;
374
+ var shadow_width = this.exists(this.markers[i].shadow_width) ? this.markers[i].shadow_width : null;
375
+ var shadow_height = this.exists(this.markers[i].shadow_height) ? this.markers[i].shadow_height : null;
376
+ var marker_draggable = this.exists(this.markers[i].draggable) ? this.markers[i].draggable : this.markers_conf.draggable;
377
+ var Lat = this.markers[i].latitude;
377
378
  var Lng = this.markers[i].longitude;
378
- var imageAnchorPosition = null;
379
- // calculate MarkerImage anchor location
380
- if (this.exists(this.markers[i].width) && this.exists(this.markers[i].height) && marker_anchor !== null) {
381
- imageAnchorPosition = this.getImageAnchorPosition(marker_width, marker_height, marker_anchor);
382
- }
383
-
379
+
384
380
  //alter coordinates if randomize is true
385
381
  if ( this.markers_conf.randomize) {
386
- var LatLng = this.randomize(Lat, Lng);
382
+ var LatLng = Gmaps4Rails.randomize(Lat, Lng);
387
383
  //retrieve coordinates from the array
388
384
  Lat = LatLng[0]; Lng = LatLng[1];
389
385
  }
390
386
 
391
- var markerLatLng = new google.maps.LatLng(Lat, Lng);
387
+ var markerLatLng = Gmaps4Rails.createLatLng(Lat, Lng);
392
388
  var thisMarker;
389
+
393
390
  // Marker sizes are expressed as a Size of X,Y
394
- if (marker_picture === "") {
395
- thisMarker = new google.maps.Marker({position: markerLatLng, map: this.map, title: marker_title, draggable: marker_draggable});
391
+ if (marker_picture === "" ) {
392
+ thisMarker = Gmaps4Rails.createMarker({position: markerLatLng, map: this.map, title: marker_title, draggable: marker_draggable});
396
393
  } else {
397
- var image = new google.maps.MarkerImage(marker_picture, new google.maps.Size(marker_width, marker_height), null, imageAnchorPosition, null );
398
- thisMarker = new google.maps.Marker({position: markerLatLng, map: this.map, icon: image, title: marker_title, draggable: marker_draggable});
394
+ // calculate MarkerImage anchor location
395
+ var imageAnchorPosition = this.createImageAnchorPosition(marker_anchor);
396
+ var shadowAnchorPosition = this.createImageAnchorPosition(shadow_anchor);
397
+
398
+ //create or retrieve existing MarkerImages
399
+ var markerImage = this.createOrRetrieveImage(marker_picture, marker_width, marker_height, imageAnchorPosition);
400
+ var shadowImage = this.createOrRetrieveImage(shadow_picture, shadow_width, shadow_height, shadowAnchorPosition);
401
+
402
+ thisMarker = Gmaps4Rails.createMarker({position: markerLatLng, map: this.map, icon: markerImage, title: marker_title, draggable: marker_draggable, shadow: shadowImage});
399
403
  }
404
+
400
405
  //save object
401
- this.markers[i].google_object = thisMarker;
406
+ this.markers[i].serviceObject = thisMarker;
402
407
  //add infowindowstuff if enabled
403
- this.create_info_window(this.markers[i]);
408
+ this.createInfoWindow(this.markers[i]);
404
409
  //create sidebar if enabled
405
- this.create_sidebar(this.markers[i]);
406
- }
410
+ this.createSidebar(this.markers[i]);
411
+ }
407
412
  }
408
413
  this.markers_conf.offset = this.markers.length;
409
- },
414
+ },
415
+
416
+ // checks if MarkerImage exists before creating a new one
417
+ // returns a MarkerImage or false if ever something wrong is passed as argument
418
+ createOrRetrieveImage: function(currentMarkerPicture, markerWidth, markerHeight, imageAnchorPosition){
419
+ if (currentMarkerPicture === "" || currentMarkerPicture === null )
420
+ { return null;}
421
+
422
+ var test_image_index = this.includeMarkerImage(this.markerImages, currentMarkerPicture);
423
+ switch (test_image_index)
424
+ {
425
+ case false:
426
+ var markerImage = Gmaps4Rails.createMarkerImage(currentMarkerPicture, Gmaps4Rails.createSize(markerWidth, markerHeight), null, imageAnchorPosition, null );
427
+ this.markerImages.push(markerImage);
428
+ return markerImage;
429
+ break;
430
+ default:
431
+ if (typeof test_image_index == 'number') { return this.markerImages[test_image_index]; }
432
+ else { return false; }
433
+ break;
434
+ }
435
+ },
410
436
 
411
- // calculate anchor point for MarkerImage
412
- getImageAnchorPosition: function(markerWidth, markerHeight, anchorLocation) {
413
- var x;
414
- var y;
415
- switch (anchorLocation) {
416
- case "top_left":
417
- x = 0;
418
- y = 0;
419
- break;
420
- case "top_center":
421
- x = markerWidth / 2;
422
- y = 0;
423
- break;
424
- case "top_right":
425
- x = markerWidth;
426
- y = 0;
427
- break;
428
- case "center_left":
429
- x = 0;
430
- y = markerHeight / 2;
431
- break;
432
- case "center":
433
- x = markerWidth / 2;
434
- y = markerHeight / 2;
435
- break;
436
- case "center_right":
437
- x = markerWidth;
438
- y = markerHeight / 2;
439
- break;
440
- case "bottom_left":
441
- x = 0;
442
- y = markerHeight;
443
- break;
444
- case "bottom_center":
445
- x = markerWidth / 2;
446
- y = markerHeight;
447
- break;
448
- case "bottom_right":
449
- x = markerWidth;
450
- y = markerHeight;
451
- break;
452
- }
453
- return new google.maps.Point(x,y);
437
+ // creates Image Anchor Position or return null if nothing passed
438
+ createImageAnchorPosition: function(anchorLocation) {
439
+ if (anchorLocation === null)
440
+ { return null; }
441
+ else
442
+ { return Gmaps4Rails.createPoint(anchorLocation[0], anchorLocation[1]); }
454
443
  },
455
444
 
456
445
  // clear markers
457
- clear_markers: function() {
458
- // //clear clusterer first
459
- // if (this.markerClusterer !== null){
460
- // this.markerClusterer.clearMarkers();
461
- // }
446
+ clearMarkers: function() {
462
447
  for (var i = 0; i < this.markers.length; ++i) {
463
- this.clear_marker(this.markers[i]);
448
+ this.clearMarker(this.markers[i]);
464
449
  }
465
450
  },
466
451
 
467
- clear_marker: function(marker) {
468
- marker.google_object.setMap(null);
469
- },
470
-
471
452
  // show and hide markers
472
- show_markers: function() {
453
+ showMarkers: function() {
473
454
  for (var i = 0; i < this.markers.length; ++i) {
474
- this.show_marker(this.markers[i]);
455
+ this.showMarker(this.markers[i]);
475
456
  }
476
457
  },
477
458
 
478
- show_marker: function(marker) {
479
- marker.google_object.setVisible(true);
480
- },
481
-
482
- hide_markers: function() {
459
+ hideMarkers: function() {
483
460
  for (var i = 0; i < this.markers.length; ++i) {
484
- this.hide_marker(this.markers[i]);
461
+ this.hideMarker(this.markers[i]);
485
462
  }
486
463
  },
487
464
 
488
- hide_marker: function(marker) {
489
- marker.google_object.setVisible(false);
490
- },
491
-
492
465
  // replace old markers with new markers on an existing map
493
- replace_markers: function(new_markers){
494
- //reset the offset
495
- this.markers_conf.offset = 0;
466
+ replaceMarkers: function(new_markers){
496
467
  //reset previous markers
497
468
  this.markers = new Array;
498
469
  //reset current bounds
499
- this.google_bounds = new google.maps.LatLngBounds();
470
+ this.serviceBounds = Gmaps4Rails.createLatLngBounds();
500
471
  //reset sidebar content if exists
501
- this.reset_sidebar_content();
472
+ this.resetSidebarContent();
502
473
  //add new markers
503
- this.add_markers(new_markers);
474
+ this.addMarkers(new_markers);
504
475
  },
505
476
 
506
477
  //add new markers to on an existing map
507
- add_markers: function(new_markers){
508
- //clear the whole map
509
- //this.clear_markers();
478
+ addMarkers: function(new_markers){
510
479
  //update the list of markers to take into account
511
480
  this.markers = this.markers.concat(new_markers);
512
481
  //put markers on the map
@@ -520,21 +489,15 @@ var Gmaps4Rails = {
520
489
  {
521
490
  //first clear the existing clusterer if any
522
491
  if (this.markerClusterer !== null) {
523
- this.markerClusterer.clearMarkers();
492
+ this.clearClusterer();
524
493
  }
525
494
 
526
- var gmarkers_array = new Array;
495
+ var markers_array = new Array;
527
496
  for (var i = 0; i < this.markers.length; ++i) {
528
- gmarkers_array.push(this.markers[i].google_object);
497
+ markers_array.push(this.markers[i].serviceObject);
529
498
  }
530
- var clustererStyle = null;
531
- if(this.fnSet("gmaps_custom_clusterer_pic")) {
532
- clustererStyle = gmaps_custom_clusterer_pic();
533
- }
534
- this.markerClusterer = new MarkerClusterer( this.map,
535
- gmarkers_array,
536
- { maxZoom: this.markers_conf.clusterer_maxZoom, gridSize: this.markers_conf.clusterer_gridSize, styles: clustererStyle }
537
- );
499
+
500
+ this.markerClusterer = Gmaps4Rails.createClusterer(markers_array);
538
501
  }
539
502
  },
540
503
 
@@ -543,21 +506,21 @@ var Gmaps4Rails = {
543
506
  ////////////////////////////////////////////////////
544
507
 
545
508
  // creates infowindows
546
- create_info_window: function(marker_container){
509
+ createInfoWindow: function(marker_container){
547
510
  var info_window;
548
511
  if (this.markers_conf.custom_infowindow_class === null) {
549
512
  //create the infowindow
550
513
  info_window = new google.maps.InfoWindow({content: marker_container.description });
551
514
  //add the listener associated
552
- google.maps.event.addListener(marker_container.google_object, 'click', this.openInfoWindow(info_window, marker_container.google_object));
515
+ google.maps.event.addListener(marker_container.serviceObject, 'click', this.openInfoWindow(info_window, marker_container.serviceObject));
553
516
  }
554
517
  else { //creating custom infowindow
555
518
  if (this.exists(marker_container.description)) {
556
519
  var boxText = document.createElement("div");
557
520
  boxText.setAttribute("class", this.markers_conf.custom_infowindow_class); //to customize
558
521
  boxText.innerHTML = marker_container.description;
559
- info_window = new InfoBox(gmaps4rails_infobox(boxText));
560
- google.maps.event.addListener(marker_container.google_object, 'click', this.openInfoWindow(info_window, marker_container.google_object));
522
+ info_window = new InfoBox(Gmaps4Rails.infobox(boxText));
523
+ google.maps.event.addListener(marker_container.serviceObject, 'click', this.openInfoWindow(info_window, marker_container.serviceObject));
561
524
  }
562
525
  }
563
526
  },
@@ -579,7 +542,7 @@ var Gmaps4Rails = {
579
542
  ////////////////////////////////////////////////////
580
543
 
581
544
  //creates sidebar
582
- create_sidebar: function(marker_container){
545
+ createSidebar: function(marker_container){
583
546
  if (this.markers_conf.list_container)
584
547
  {
585
548
  var ul = document.getElementById(this.markers_conf.list_container);
@@ -588,7 +551,7 @@ var Gmaps4Rails = {
588
551
  aSel.href = 'javascript:void(0);';
589
552
  var html = this.exists(marker_container.sidebar) ? marker_container.sidebar : "Marker";
590
553
  aSel.innerHTML = html;
591
- aSel.onclick = this.sidebar_element_handler(marker_container.google_object, 'click');
554
+ aSel.onclick = this.sidebar_element_handler(marker_container.serviceObject, 'click');
592
555
  li.appendChild(aSel);
593
556
  ul.appendChild(li);
594
557
  }
@@ -602,7 +565,7 @@ var Gmaps4Rails = {
602
565
  };
603
566
  },
604
567
 
605
- reset_sidebar_content: function(){
568
+ resetSidebarContent: function(){
606
569
  if (this.markers_conf.list_container !== null ){
607
570
  var ul = document.getElementById(this.markers_conf.list_container);
608
571
  ul.innerHTML = "";
@@ -614,39 +577,39 @@ var Gmaps4Rails = {
614
577
  ////////////////////////////////////////////////////
615
578
 
616
579
  //to make the map fit the different LatLng points
617
- adjust_map_to_bounds: function(latlng) {
580
+ adjustMapToBounds: function(latlng) {
618
581
 
619
582
  //FIRST_STEP: retrieve all bounds
620
583
  //create the bounds object only if necessary
621
584
  if (this.map_options.auto_adjust || this.map_options.bounds !== null) {
622
- this.google_bounds = new google.maps.LatLngBounds();
585
+ this.serviceBounds = Gmaps4Rails.createLatLngBounds();
623
586
  }
624
587
 
625
588
  //if autodjust is true, must get bounds from markers polylines etc...
626
589
  if (this.map_options.auto_adjust) {
627
590
  //from markers
628
591
  for (var i = 0; i < this.markers.length; ++i) {
629
- this.google_bounds.extend(this.markers[i].google_object.position);
592
+ this.serviceBounds.extend(this.markers[i].serviceObject.position);
630
593
  }
631
594
  //from polygons:
632
595
  for (var i = 0; i < this.polylines.length; ++i) {
633
- this.polylines[i].google_object.latLngs.forEach(function(obj1){ obj1.forEach(function(obj2){ Gmaps4Rails.google_bounds.extend(obj2);} );});
596
+ this.polylines[i].serviceObject.latLngs.forEach(function(obj1){ obj1.forEach(function(obj2){ Gmaps4Rails.serviceBounds.extend(obj2);} );});
634
597
  }
635
598
  //from polylines:
636
599
  for (var i = 0; i < this.polygons.length; ++i) {
637
- this.polygons[i].google_object.latLngs.forEach(function(obj1){ obj1.forEach(function(obj2){ Gmaps4Rails.google_bounds.extend(obj2);} );});
600
+ this.polygons[i].serviceObject.latLngs.forEach(function(obj1){ obj1.forEach(function(obj2){ Gmaps4Rails.serviceBounds.extend(obj2);} );});
638
601
  }
639
602
  //from circles
640
603
  for (var i = 0; i < this.circles.length; ++i) {
641
- this.google_bounds.extend(this.circles[i].google_object.getBounds().getNorthEast());
642
- this.google_bounds.extend(this.circles[i].google_object.getBounds().getSouthWest());
604
+ this.serviceBounds.extend(this.circles[i].serviceObject.getBounds().getNorthEast());
605
+ this.serviceBounds.extend(this.circles[i].serviceObject.getBounds().getSouthWest());
643
606
  }
644
607
  }
645
608
  //in every case, I've to take into account the bounds set up by the user
646
609
  for (var i = 0; i < this.map_options.bounds.length; ++i) {
647
610
  //create points from bounds provided
648
- var bound = new google.maps.LatLng(this.map_options.bounds[i].lat, this.map_options.bounds[i].lng);
649
- this.google_bounds.extend(bound);
611
+ var bound = Gmaps4Rails.createLatLng(this.map_options.bounds[i].lat, this.map_options.bounds[i].lng);
612
+ this.serviceBounds.extend(bound);
650
613
  }
651
614
 
652
615
  //SECOND_STEP: ajust the map to the bounds
@@ -654,25 +617,99 @@ var Gmaps4Rails = {
654
617
 
655
618
  //if autozoom is false, take user info into account
656
619
  if(!this.map_options.auto_zoom) {
657
- var map_center = this.google_bounds.getCenter();
620
+ var map_center = this.serviceBounds.getCenter();
658
621
  this.map_options.center_longitude = map_center.lat();
659
622
  this.map_options.center_latitude = map_center.lng();
660
623
  this.map.setCenter(map_center);
661
624
  }
662
625
  else {
663
- this.map.fitBounds(this.google_bounds);
626
+ this.map.fitBounds(this.serviceBounds);
664
627
  }
665
628
  }
666
629
  },
630
+
631
+ ////////////////////////////////////////////////////
632
+ /////////////// Abstracting API calls //////////////
633
+ //(for maybe an extension to another map provider)//
634
+ //////////////////mocks created/////////////////////
635
+
636
+ clearMarker: function(marker) {
637
+ marker.serviceObject.setMap(null);
638
+ },
639
+
640
+ showMarker: function(marker) {
641
+ marker.serviceObject.setVisible(true);
642
+ },
643
+
644
+ hideMarker: function(marker) {
645
+ marker.serviceObject.setVisible(false);
646
+ },
647
+
648
+ createPoint: function(lat, lng){
649
+ return new google.maps.Point(lat, lng);
650
+ },
651
+
652
+ createLatLng: function(lat, lng){
653
+ return new google.maps.LatLng(lat, lng);
654
+ },
655
+
656
+ createLatLngBounds: function(){
657
+ return new google.maps.LatLngBounds();
658
+ },
659
+
660
+ createMap: function(){
661
+ return new google.maps.Map(document.getElementById(Gmaps4Rails.map_options.id), {
662
+ maxZoom: Gmaps4Rails.map_options.maxZoom,
663
+ minZoom: Gmaps4Rails.map_options.minZoom,
664
+ zoom: Gmaps4Rails.map_options.zoom,
665
+ center: Gmaps4Rails.createLatLng(this.map_options.center_latitude, this.map_options.center_longitude),
666
+ mapTypeId: google.maps.MapTypeId[this.map_options.type],
667
+ mapTypeControl: Gmaps4Rails.map_options.mapTypeControl,
668
+ disableDefaultUI: Gmaps4Rails.map_options.disableDefaultUI,
669
+ disableDoubleClickZoom: Gmaps4Rails.map_options.disableDoubleClickZoom,
670
+ draggable: Gmaps4Rails.map_options.draggable
671
+ });
672
+ },
673
+
674
+ createMarkerImage: function(markerPicture, markerSize, origin, anchor, scaledSize) {
675
+ return new google.maps.MarkerImage(markerPicture, markerSize, origin, anchor, scaledSize);
676
+ },
677
+
678
+ createMarker: function(args){
679
+ return new google.maps.Marker(args);
680
+ },
681
+
682
+ createSize: function(width, height){
683
+ return new google.maps.Size(width, height);
684
+ },
685
+
686
+ createClusterer: function(markers_array){
687
+ return new MarkerClusterer( Gmaps4Rails.map,
688
+ markers_array,
689
+ { maxZoom: this.markers_conf.clusterer_maxZoom, gridSize: this.markers_conf.clusterer_gridSize, styles: Gmaps4Rails.customClusterer() }
690
+ );
691
+ },
692
+
693
+ clearClusterer: function() {
694
+ this.markerClusterer.clearMarkers();
695
+ },
696
+
697
+ //checks if obj is included in arr Array and returns the position or false
698
+ includeMarkerImage: function(arr, obj) {
699
+ for(var i=0; i<arr.length; i++) {
700
+ if (arr[i].url == obj) {return i;}
701
+ }
702
+ return false;
703
+ },
704
+
705
+ ////////////////////////////////////////////////////
706
+ ///////////////// Basic functions //////////////////
707
+ ///////////////////tests coded//////////////////////
667
708
 
668
709
  //basic function to check existence of a variable
669
710
  exists: function(var_name) {
670
711
  return (var_name !== "" && typeof var_name !== "undefined");
671
712
  },
672
- //check existence of function
673
- fnSet: function(fn_name){
674
- return(typeof fn_name == 'function');
675
- },
676
713
 
677
714
  //randomize
678
715
  randomize: function(Lat0, Lng0) {
@@ -685,6 +722,6 @@ var Gmaps4Rails = {
685
722
  },
686
723
 
687
724
  //gives a value between -1 and 1
688
- random: function() { return ( Math.random() * 2 -1); }
725
+ random: function() { return(Math.random() * 2 -1); }
689
726
 
690
727
  };