ym4r-mapstraction 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,105 @@
1
+ function addCodeToFunction(func,code){
2
+ if(func == undefined)
3
+ return code;
4
+ else{
5
+ return function(){
6
+ func();
7
+ code();
8
+ }
9
+ }
10
+ }
11
+
12
+ function addDataToMarker(marker,options){
13
+ if(options.label)
14
+ marker.setLabel(options.label);
15
+ if(options.infoBubble)
16
+ marker.setInfoBubble(options.infoBubble);
17
+ if(options.icon)
18
+ marker.setIcon(options.icon);
19
+ if(options.infoDiv)
20
+ marker.setInfoDiv(options.infoDiv[0],options.infoDiv[1]);
21
+ return marker;
22
+ }
23
+
24
+ function addDataToPolyline(polyline,options){
25
+ if(options.color)
26
+ polyline.setColor(options.color);
27
+ if(options.width)
28
+ polyline.setWidth(options.width);
29
+ if(options.opacity)
30
+ polyline.setOpacity(options.opacity);
31
+ return polyline;
32
+ }
33
+
34
+
35
+
36
+ //For full screen mode
37
+ function setWindowDims(elem,mapstraction) {
38
+ if (window.innerWidth){
39
+ mapstraction.resizeTo(window.innerWidth,window.innerHeight);
40
+ }else if (document.body.clientWidth){
41
+ mapstraction.resizeTo(document.body.clientWidth,document.body.clientHeight);
42
+ }
43
+ }
44
+
45
+ Mapstraction.prototype.addMarkerAndOpen = function(marker){
46
+ this.addMarker(marker);
47
+ marker.openBubble();
48
+ }
49
+
50
+ //MarkerGroup
51
+ //Method to add and remove marker group to a Mapstraction map
52
+
53
+ Mapstraction.prototype.addMarkerGroup = function(markerGroup){
54
+ markerGroup.initalize(this);
55
+ }
56
+
57
+ Mapstraction.prototype.removeMarkerGroup = function(markerGroup){
58
+ markerGroup.hide();
59
+ }
60
+
61
+ function MarkerGroup(markers,visible){
62
+ this.visible = visible == undefined ? true : visible;
63
+ this.markers = markers;
64
+ }
65
+
66
+ MarkerGroup.prototype.initalize = function(map){
67
+ this.map = map;
68
+ if(this.visible){
69
+ for(var i = 0 , len = this.markers.length; i < len; i++){
70
+ this.map.addMarker(this.markers[i]);
71
+ }
72
+ }
73
+ }
74
+
75
+ MarkerGroup.prototype.show = function(){
76
+ if(!this.visible){
77
+ if(this.map != undefined){
78
+ for(var i = 0 , len = this.markers.length; i < len; i++){
79
+ this.map.addMarker(this.markers[i]);
80
+ }
81
+ }
82
+ this.visible = true;
83
+ }
84
+ }
85
+
86
+ MarkerGroup.prototype.hide = function(){
87
+ if(this.visible){
88
+ if(this.map != undefined){
89
+ for(var i = 0 , len = this.markers.length; i < len; i++){
90
+ this.map.removeMarker(this.markers[i])
91
+ }
92
+ }
93
+ this.visible = false;
94
+ }
95
+ }
96
+
97
+ MarkerGroup.prototype.toggle = function(){
98
+ if(this.visible){
99
+ this.hide();
100
+ }else{
101
+ this.show();
102
+ }
103
+ }
104
+
105
+
@@ -0,0 +1,14 @@
1
+ Ym4r::MapstractionPlugin::Marker.class_eval do
2
+ #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.
3
+ def self.from_georuby(point,options = {})
4
+ Marker.new([point.y,point.x],options)
5
+ end
6
+ end
7
+
8
+ Ym4r::MapstractionPlugin::LatLonPoint.class_eval do
9
+ #Creates a GLatLng object from a georuby point. Assumes the points of the line strings are stored in Longitude(x)/Latitude(y) order.
10
+ def self.from_georuby(point)
11
+ LatLonPoint.new([point.y,point.x])
12
+ end
13
+ end
14
+
@@ -0,0 +1,120 @@
1
+ module Ym4r
2
+ module MapstractionPlugin
3
+ #The module where all the Ruby-to-JavaScript conversion takes place. It is included by all the classes in the YM4R library.
4
+ module MappingObject
5
+ #The name of the variable in JavaScript space.
6
+ attr_reader :variable
7
+
8
+ #Creates javascript code for missing methods + takes care of listeners
9
+ def method_missing(name,*args)
10
+ str_name = name.to_s
11
+ args.collect! do |arg|
12
+ MappingObject.javascriptify_variable(arg)
13
+ end
14
+ Variable.new("#{to_javascript}.#{MappingObject.javascriptify_method(str_name)}(#{args.join(",")})")
15
+ end
16
+
17
+ #Creates javascript code for array or hash indexing
18
+ def [](index) #index could be an integer or string
19
+ return Variable.new("#{to_javascript}[#{MappingObject.javascriptify_variable(index)}]")
20
+ end
21
+
22
+ #Transforms a Ruby object into a JavaScript string : MAppingObject, String, Array, Hash and general case (using to_s)
23
+ def self.javascriptify_variable(arg)
24
+ if arg.is_a?(MappingObject)
25
+ arg.to_javascript
26
+ elsif arg.is_a?(String)
27
+ "\"#{MappingObject.escape_javascript(arg)}\""
28
+ elsif arg.is_a?(Array)
29
+ "[" + arg.collect{ |a| MappingObject.javascriptify_variable(a)}.join(",") + "]"
30
+ elsif arg.is_a?(Hash)
31
+ "{" + arg.to_a.collect do |v|
32
+ "#{MappingObject.javascriptify_method(v[0].to_s)} : #{MappingObject.javascriptify_variable(v[1])}"
33
+ end.join(",") + "}"
34
+ elsif arg.nil?
35
+ "undefined"
36
+ else
37
+ arg.to_s
38
+ end
39
+ end
40
+
41
+ #Escape string to be used in JavaScript. Lifted from rails.
42
+ def self.escape_javascript(javascript)
43
+ javascript.gsub(/\r\n|\n|\r/, "\\n").gsub("\"","\\\"")
44
+ end
45
+
46
+ #Transform a ruby-type method name (like add_overlay) to a JavaScript-style one (like addOverlay).
47
+ def self.javascriptify_method(method_name)
48
+ method_name.gsub(/_(\w)/){|s| $1.upcase}
49
+ end
50
+
51
+ #Declares a Mapping Object bound to a JavaScript variable of name +variable+.
52
+ def declare(variable)
53
+ @variable = variable
54
+ "var #{@variable} = #{create};"
55
+ end
56
+
57
+ #declare with a random variable name
58
+ def declare_random(init,size = 8)
59
+ s = init.clone
60
+ 6.times { s << (i = Kernel.rand(62); i += ((i < 10) ? 48 : ((i < 36) ? 55 : 61 ))).chr }
61
+ declare(s)
62
+ end
63
+
64
+ #Checks if the MappinObject has been declared
65
+ def declared?
66
+ !@variable.nil?
67
+ end
68
+
69
+ #Binds a Mapping object to a previously declared JavaScript variable of name +variable+.
70
+ def assign_to(variable)
71
+ @variable = variable
72
+ "#{@variable} = #{create};"
73
+ end
74
+
75
+ #Assign the +value+ to the +property+ of the MappingObject
76
+ def set_property(property, value)
77
+ "#{to_javascript}.#{MappingObject.javascriptify_method(property.to_s)} = #{MappingObject.javascriptify_variable(value)}"
78
+ end
79
+
80
+ #Returns the code to get a +property+ from the MappingObject
81
+ def get_property(property)
82
+ Variable.new("#{to_javascript}.#{MappingObject.javascriptify_method(property.to_s)}")
83
+ end
84
+
85
+ #Returns a Javascript code representing the object
86
+ def to_javascript
87
+ unless @variable.nil?
88
+ @variable
89
+ else
90
+ create
91
+ end
92
+ end
93
+
94
+ #Creates a Mapping Object in JavaScript.
95
+ #To be implemented by subclasses if needed
96
+ def create
97
+ end
98
+ end
99
+
100
+ #Used to bind a ruby variable to an already existing JavaScript one. It doesn't have to be a variable in the sense "var variable" but it can be any valid JavaScript expression that has a value.
101
+ class Variable
102
+ include MappingObject
103
+
104
+ def initialize(variable)
105
+ @variable = variable
106
+ end
107
+ #Returns the javascript expression contained in the object.
108
+ def create
109
+ @variable
110
+ end
111
+ #Returns the expression inside the Variable followed by a ";"
112
+ def to_s
113
+ @variable + ";"
114
+ end
115
+
116
+ UNDEFINED = Variable.new("undefined")
117
+ end
118
+ end
119
+ end
120
+
@@ -0,0 +1,309 @@
1
+ module Ym4r
2
+ module MapstractionPlugin
3
+
4
+ #Map types of the map
5
+ class MapType
6
+ ROAD = Variable.new("Mapstraction.ROAD")
7
+ SATELLITE = Variable.new("Mapstraction.SATELLITE")
8
+ HYBRID = Variable.new("Mapstraction.HYBRID")
9
+ end
10
+
11
+ #Represents a Mapstracted map.
12
+ class Mapstraction
13
+ include MappingObject
14
+
15
+ #The id of the DIV that will contain the map in the HTML page.
16
+ attr_reader :container, :map_type
17
+
18
+ #A constant containing the declaration of the VML namespace, necessary to display polylines in google maps under IE.
19
+ VML_NAMESPACE = "xmlns:v=\"urn:schemas-microsoft-com:vml\""
20
+
21
+ #By default the map in the HTML page will be globally accessible with the name +map+. +map_type+ is one of three choices: <tt>:google</tt>, <tt>:yahoo</tt> or <tt>microsoft</tt>.
22
+ def initialize(container, map_type, variable = "map")
23
+ @container = container
24
+ @map_type = map_type
25
+ @variable = variable
26
+ @init = []
27
+ @init_begin = []
28
+ @init_end = []
29
+ @global_init = []
30
+ end
31
+
32
+ def self.header(types,options = {})
33
+ a = ""
34
+ Array(types).each do |type|
35
+ if type == :google || type == :openstreetmap
36
+ options[:with_vml] = true unless options.has_key?(:with_vml)
37
+ if options.has_key?(:key)
38
+ api_key = options[:key]
39
+ elsif GMAPS_API_KEY.is_a?(Hash)
40
+ #For this environment, multiple hosts are possible.
41
+ #:host must have been passed as option
42
+ if options.has_key?(:host)
43
+ api_key = GMAPS_API_KEY[options[:host]]
44
+ else
45
+ raise AmbiguousGMapsAPIKeyException.new(GMAPS_API_KEY.keys.join(","))
46
+ end
47
+ else
48
+ #Only one possible key: take it
49
+ api_key = GMAPS_API_KEY
50
+ end
51
+ a << "<script src=\"http://maps.google.com/maps?file=api&amp;v=2&amp;key=#{api_key}\" type=\"text/javascript\"></script>\n"
52
+ a << "<style type=\"text/css\">\n v\:* { behavior:url(#default#VML);}\n</style>" if options[:with_vml]
53
+ elsif type == :yahoo
54
+ a << "<script type=\"text/javascript\" src=\"http://api.maps.yahoo.com/ajaxymap?v=3.4&amp;appid=YellowMasp4R\"></script>\n"
55
+ elsif type == :microsoft
56
+ a << "<script src=\"http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2\"></script>\n"
57
+ elsif type == :map24
58
+ if options.has_key?(:key)
59
+ api_key = options[:key]
60
+ elsif MAP24_API_KEY.is_a?(Hash)
61
+ #For this environment, multiple hosts are possible.
62
+ #:host must have been passed as option
63
+ if options.has_key?(:host)
64
+ api_key = MAP24_API_KEY[options[:host]]
65
+ else
66
+ raise AmbiguousMap24APIKeyException.new(MAP24_API_KEY.keys.join(","))
67
+ end
68
+ else
69
+ #Only one possible key: take it
70
+ api_key = MAP24_API_KEY
71
+ end
72
+ a << "<script type=\"text/javascript\" language=\"javascript\" src=\"http://api.maptp.map24.com/ajax?appkey=#{api_key}\"></script>\n"
73
+ elsif type == :multimap
74
+ if options.has_key?(:key)
75
+ api_key = options[:key]
76
+ elsif MULTIMAP_API_KEY.is_a?(Hash)
77
+ #For this environment, multiple hosts are possible.
78
+ #:host must have been passed as option
79
+ if options.has_key?(:host)
80
+ api_key = MULTIMAP_API_KEY[options[:host]]
81
+ else
82
+ raise AmbiguousMultimapAPIKeyException.new(MULTIMAP_API_KEY.keys.join(","))
83
+ end
84
+ else
85
+ #Only one possible key: take it
86
+ api_key = MULTIMAP_API_KEY
87
+ end
88
+ a << "<script type=\"text/javascript\" src=\"http://developer.multimap.com/API/maps/1.2/#{api_key}\"></script>\n"
89
+ elsif type == :mapquest
90
+ if options.has_key?(:key)
91
+ api_key = options[:key]
92
+ elsif MAPQUEST_API_KEY.is_a?(Hash)
93
+ #For this environment, multiple hosts are possible.
94
+ #:host must have been passed as option
95
+ if options.has_key?(:host)
96
+ api_key = MAPQUEST_API_KEY[options[:host]]
97
+ else
98
+ raise AmbiguousMapquestAPIKeyException.new(MAPQUEST_API_KEY.keys.join(","))
99
+ end
100
+ else
101
+ #Only one possible key: take it
102
+ api_key = MAPQUEST_API_KEY
103
+ end
104
+ a << "<script src=\"http://btilelog.access.mapquest.com/tilelog/transaction?transaction=script&amp;key=#{api_key}&amp;ipr=true&amp;itk=true&amp;v=5.2.0\" type=\"text/javascript\"></script>\n"
105
+ a << "<!-- The JSAPI Source files (only needed for geocoding & routing with MapQuest) -->\n"
106
+ a << "<script src=\"/javascripts/mapquest-js/mqcommon.js\" type=\"text/javascript\"></script>\n"
107
+ a << "<script src=\"/javascripts/mapquest-js/mqutils.js\" type=\"text/javascript\"></script>\n"
108
+ a << "<script src=\"/javascripts/mapquest-js/mqobjects.js\" type=\"text/javascript\"></script>\n"
109
+ a << "<script src=\"/javascripts/mapquest-js/mqexec.js\" type=\"text/javascript\"></script>\n"
110
+ elsif type == :freeearth
111
+ a << "<script type=\"text/javascript\" src=\"http://freeearth.poly9.com/api.js\"></script>\n"
112
+ elsif type == :openlayers
113
+ a << "<script src=\"http://openlayers.org/api/OpenLayers.js\"></script>\n"
114
+ end
115
+ end
116
+ a << "<script src=\"/javascripts/mapstraction.js\" type=\"text/javascript\"></script>\n"
117
+ a << "<script src=\"/javascripts/mapstraction-route.js\" type=\"text/javascript\"></script>\n"
118
+ a << "<script src=\"/javascripts/ym4r-mapstraction.js\" type=\"text/javascript\"></script>\n"
119
+ a
120
+ end
121
+
122
+ #Outputs the <div id=...></div> which has been configured to contain the map. You can pass <tt>:width</tt> and <tt>:height</tt> as options to output this in the style attribute of the DIV element (you could also achieve the same effect by putting the dimension info into a CSS or using the instance method Mapstraction#header_width_height)
123
+ def div(options = {})
124
+ attributes = "id=\"#{@container}\" "
125
+ if options.has_key?(:height) && options.has_key?(:width)
126
+ attributes += "style=\"width:#{options[:width]}px;height:#{options[:height]}px\""
127
+ end
128
+ "<div #{attributes}></div>"
129
+ end
130
+
131
+ #Outputs a style declaration setting the dimensions of the DIV container of the map. This info can also be set manually in a CSS.
132
+ def header_width_height(width,height)
133
+ "<style type=\"text/css\">\n##{@container} { height: #{height}px;\n width: #{width}px;\n}\n</style>"
134
+ end
135
+
136
+ #Records arbitrary JavaScript code and outputs it during initialization inside the +load+ function.
137
+ def record_init(code)
138
+ @init << code
139
+ end
140
+
141
+ #Initializes the controls: you can pass a hash with key <tt>:small</tt> (only one for now) and a boolean value as the value (usually true, since the control is not displayed by default). Also in later version, you can be a bit more precise, with the following keys: pan (boolean), zoom (:large or :small), overview (boolean), scale (boolean), map_type (boolean)
142
+ def control_init(controls = {})
143
+ if controls[:small]
144
+ @init << add_small_controls()
145
+ elsif controls[:large]
146
+ @init << add_large_controls()
147
+ else
148
+ @init << add_controls(controls)
149
+ end
150
+ end
151
+
152
+ #Initializes the initial center and zoom of the map. +center+ can be both a GLatLng object or a 2-float array.
153
+ def center_zoom_init(center, zoom)
154
+ if center.is_a?(LatLonPoint)
155
+ @init_begin << set_center_and_zoom(center,zoom)
156
+ else
157
+ @init_begin << set_center_and_zoom(LatLonPoint.new(center),zoom)
158
+ end
159
+ end
160
+
161
+ #Center and zoom based on the bbox corners. Pass a GLatLngBounds object, an array of 2D coordinates (sw and ne) or an array of GLatLng objects (sw and ne).
162
+ def center_zoom_on_bounds_init(bounds)
163
+ if bounds.is_a?(Array)
164
+ if bounds[0].is_a?(Array)
165
+ bounds = BoundingBox.new(bounds[0][0],bounds[0][1],bounds[1][0],bounds[1][1])
166
+ elsif bounds[0].is_a?(LatLonPoint)
167
+ bounds = BoundingBox.new(bounds[0].lat,bounds[0].lon,bounds[1].lat,bounds[1].lon)
168
+ end
169
+ end
170
+ #else it is already a latlngbounds object
171
+
172
+ @init_begin << set_bounds(bounds)
173
+ end
174
+
175
+ #Initializes the map by adding a marker
176
+ def marker_init(marker, options = {})
177
+ if options[:open_bubble]
178
+ @init << add_marker_and_open(marker)
179
+ else
180
+ @init << add_marker(marker)
181
+ end
182
+ end
183
+
184
+ def marker_group_init(marker_group)
185
+ @init << add_marker_group(marker_group)
186
+ end
187
+
188
+ def clusterer_init(clusterer)
189
+ @init << add_clusterer(clusterer)
190
+ end
191
+
192
+ def polyline_init(polyline)
193
+ @init << add_polyline(polyline)
194
+ end
195
+
196
+ #Sets the map type displayed by default after the map is loaded.
197
+ def set_map_type_init(map_type)
198
+ @init << set_map_type(map_type)
199
+ end
200
+
201
+ #Locally declare a MappingObject with variable name "name"
202
+ def declare_init(variable, name)
203
+ @init << variable.declare(name)
204
+ end
205
+
206
+ #Records arbitrary JavaScript code and outputs it during initialization outside the +load+ function (ie globally).
207
+ def record_global_init(code)
208
+ @global_init << code
209
+ end
210
+
211
+ #Registers an event
212
+ def event_init(object,event,callback)
213
+ @init << "#{object.to_javascript}.addEventListener(\"#{MappingObject.javascriptify_method(event.to_s)}\",#{callback})"
214
+ end
215
+
216
+ #Registers an event globally
217
+ def event_global_init(object,event,callback)
218
+ @global_init << "#{object.to_javascript}.addEventListener(\"#{MappingObject.javascriptify_method(event.to_s)}\",#{callback})"
219
+ end
220
+
221
+ #Declares the marker globally with name +name+
222
+ def marker_global_init(marker,name, options = {})
223
+ declare_global_init(marker,name)
224
+ marker_init(marker,options)
225
+ end
226
+
227
+ #Declares the marker group globally with name +name+
228
+ def marker_group_global_init(marker_group,name)
229
+ declare_global_init(marker_group,name)
230
+ marker_group_init(marker_group)
231
+ end
232
+
233
+ def clusterer_global_init(clusterer,name)
234
+ declare_global_init(clusterer,name)
235
+ clusterer_init(clusterer)
236
+ end
237
+
238
+ def polyline_global_init(polyline, name)
239
+ declare_global_init(polyline,name)
240
+ polyline_init(clusterer)
241
+ end
242
+
243
+ #Globally declare a MappingObject with variable name "name"
244
+ def declare_global_init(variable,name)
245
+ @global_init << variable.declare(name)
246
+ end
247
+
248
+ #Outputs the initialization code for the map. By default, it outputs the script tags, performs the initialization in response to the onload event of the window and makes the map globally available. You can pass the <tt>:full => true</tt> option to setup fullscreen for the map.
249
+ def to_html(options = {})
250
+ no_load = options[:no_load]
251
+ no_script_tag = options[:no_script_tag]
252
+ no_declare = options[:no_declare]
253
+ no_global = options[:no_global]
254
+ fullscreen = options[:full]
255
+
256
+ html = ""
257
+ html << "<script type=\"text/javascript\">\n" if !no_script_tag
258
+ #put the functions in a separate javascript file to be included in the page
259
+ html << @global_init * "\n"
260
+ html << "var #{@variable};\n" if !no_declare and !no_global
261
+ html << "window.onload = addCodeToFunction(window.onload,function() {\n" if !no_load
262
+
263
+ if fullscreen
264
+ #Adding the initial resizing and setting up the event handler for
265
+ #future resizes
266
+ html << "setWindowDims($('#{@container}'));\n"
267
+ html << "if (window.attachEvent) { window.attachEvent(\"onresize\", function() {setWindowDims($('#{@container}'));})} else {window.addEventListener(\"resize\", function() {setWindowDims($('#{@container}')); } , false);}\n"
268
+ end
269
+
270
+ if !no_declare and no_global
271
+ html << "#{declare(@variable)}\n"
272
+ else
273
+ html << "#{assign_to(@variable)}\n"
274
+ end
275
+
276
+ html << @init_begin * "\n"
277
+ html << @init * "\n"
278
+ html << @init_end * "\n"
279
+ html << "\n});\n" if !no_load
280
+ html << "</script>" if !no_script_tag
281
+
282
+ if fullscreen
283
+ #setting up the style in case of full screen
284
+ html << "<style>html, body {width: 100%; height: 100%} body {margin:0} ##{@container} {margin:0} </style>"
285
+ end
286
+
287
+ html
288
+ end
289
+
290
+ #Outputs in JavaScript the creation of a Mapstraction object
291
+ def create
292
+ "new Mapstraction(\"#{@container}\",\"#{@map_type.to_s}\")"
293
+ end
294
+ end
295
+
296
+ class AmbiguousGMapsAPIKeyException < StandardError
297
+ end
298
+
299
+ class AmbiguousMap24APIKeyException < StandardError
300
+ end
301
+
302
+ class AmbiguousMapquestAPIKeyException < StandardError
303
+ end
304
+
305
+ class AmbiguousMultimapAPIKeyException < StandardError
306
+ end
307
+ end
308
+ end
309
+