gmaps4rails 0.8.8 → 0.9.0

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.
@@ -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
  };