Plugin details

Its aim is to facilitate the use of Google Maps from Rails application. It includes and enhances all the web application-related functionalities found in the YM4R gem as of version 0.4.1.

Websitehttp://github.com/bitbckt/ym4r-gm/tree/master Repositorygit://github.com/bitbckt/ym4r-gm.git Author Guilhem Vellut Tags Maps LicenseMIT

Documentation

Install the plugin:
ruby script/plugin install git://github.com/bitbckt/ym4r-gm.git

==Getting Started
I present here the most common operations you would want to do with YM4R/GM. Read the rest of the documents if you want more details.

In your controller, here is a typical initialization sequence in action +index+:
	def index
	  @map = GMap.new("map_div")
	  @map.control_init(:large_map => true,:map_type => true)
	  @map.center_zoom_init([75.5,-42.56],4)
	  @map.overlay_init(GMarker.new([75.6,-42.467],:title => "Hello", :info_window => "Info! Info!"))
	end



Here I create a GMap (which will be placed inside a DIV of id +map_div+), add controls (large zoom slider and pan cross + map type selector), set the center and the zoom and add a marker. Of these 4 steps only the creation of the map and the setting of the center and the zoom are absolutely necessary.

In your view, here is what you would have:

#head of html
	<%= GMap.header %>
	<%= @map.to_html %>
	#body html
	<%= @map.div(:width => 600, :height => 400) %>



First you must output the header, used by all the maps of the page: It includes the Google Maps API JS code and the JS helper functions of YM4R/GM. Then we initialize the map by calling @map.to_html. In the body, we need a DIV whose +id+ is the same as the one passed to the GMap constructor in the controller. The call to @map.div outputs such a DIV. We pass to it options to set the width and height of the map in the style attribute of the DIV.

Note that you need to set a size for the map DIV element at some point or the map will not be displayed. You have a few ways to do this:
- You define it yourself, wherever you want. Usually as part of the layout definition in an external CSS.
- In the head of the document, through a CSS instruction output by @map.header_width_height, to which you pass 2 arguments (width and height).
- When outputting the DIV with @map.div, you can also pass an option hash, with keys :width and :height and a style attribute for the DIV element will be output.

You can update the map trough RJS. Here is an action you can call from a link_remote_tag which would do this:

	def update
	  @map = Variable.new("map")
	  @marker = GMarker.new([75.89,-42.767],:title => "Update", :info_window => "I have been placed through RJS")
	end



Here, I first bind the Ruby @map variable to the JS variable map, which already exists in the client browser. +map+ is by default the name given to a map created from YM4R/GM (this could be overriden by passing a second argument to the GMap constructor). Then I create a marker.

And you would have inside the RJS template for the action:

	page << @map.clear_overlays
	page << @map.add_overlay(@marker)



Here I first clear the map of all overlays. Then I add the marker. Note that the +overlay_init+ is not used anymore since, as its name indicates, this method is only for the initialization of the map.

==Relation between the YM4R gem and the YM4R/GM plugin
They are completely independent from each other.

With the plugin, you don't need the YM4R gem anymore, unless you want to use the tilers or the Ruby helpers for the Yahoo! Maps Building Block API's and the Google Maps geocoding API. Please refer to the documentation of the YM4R gem to know more about the functionalities in it.

Conversely, the YM4R gem does not need the plugin to work.

As part of the installation procedure, the JavaScript files found in the PLUGIN_ROOT/javascript directory will be copied to the RAILS_ROOT/public/javascripts/ directory.

Moreover a gmaps_api_key.yml file will also be created in the RAILS_ROOT/config/ folder. If this file already exists (installed for example by a previous version of the plugin), nothing will be done to it, so you can keep your configuration data even after updating the plugin. This file is a YAML representation of a hash, similar to the database.yml file in that the primary keys in the file are the different environments (development, test, production), since you will probably need to have different Google Maps API keys depending on that criteria (for example: a key for localhost for development and test; a key for your host for production). If you don't have any special need, there will be only one key associated with each environment. If however, you need to have multiple keys (for example if your app will be accessible from multiple URLs, for which you need different keys), you can also associate a hash to the environment, whose keys will be the different hosts. In this case, you will need to pass a value to the :host key when calling the method GMap.header (usually @request.host).

==Migration from the YM4R gem versions <= 0.4.1
Apart from the installation of the plugin detailed above, you will also need to delete the instructions to require the file and include the Ym4r::GoogleMaps module in your controllers:

	require 'ym4r'
	include Ym4r::GoogleMaps


This lines are now not needed since the plugin is loaded as part of the normal Rails loading procedure and the module is included when the plugin is loaded.

===Naming conventions
The names of the Ruby class follow the ones in the JavaScript Google Maps API v2, except for GMap2, which in Ruby code is called simply GMap. To know what is possible to do with each class, you should refer to the documentation available on Google website.

On top of that, you have some convenience methods for initializing the map (in the GMap class). Also, the constructors of some classes accept different types of arguments to be converted later in the correct JavaScript format. For example, the +GMarker+ aclass accepts an array of 2 floats as parameter, in addition of a GLatLng object, to indicate its position. It also facilitates the attribution of an HTML info window, displayed when the user clicks on it, since you can pass to the constructor an options hash with the :info_window key and the text to display as the value, instead of having to wire the response to a click event yourself.

===Binding JavaScript and Ruby
Since the Google Maps API uses JavaScript to create and manipulate a map, most of what the library does is outputting JavaScript, although some convenience methods are provided to simplify some common operations at initialization time. When you create a YM4R mapping object (a Ruby object which includes the MappingObject module) and call methods on it, these calls are converted by the library into JavaScript code. At initialization time, you can pass arbitrary JavaScript code to the GMap#record_init and GMap#record_global_init.Then, at update time, if you use Ruby-on-Rails as your web framework, you can update your map through RJS by passing the result of the method calls to the page << method to have it then interpreted by the browser.

For example, here is a typical initialization sequence for a map

	@map = GMap.new("map_div")
	@map.control_init(:large_map => true,:map_type => true)
	@map.center_zoom_init([35.12313,-110.567],12)
	@map.overlay_init GMarker.new([35.12878, -110.578],:title => "Hello!")
	@map.record_init @map.add_overlay(GMarker.new([35.12878, -110.578],:title => "Hello!"))



While +center_zoom_init+, +control_init+ or +overlay_init+ (and generally all the GMap methods which end in +init+) are one of the rare convenience methods that do not output JavaScript, the +add_overlay+ does. Actually, if you look at the code of the GMap class, you won't find any +add_overlay+ method, although in the documentation of the GMap2 class from the Google Maps API documentation, you will find something about the +addOverlay+ JavaScript method. In fact, when you call on a mapping object an unknow method, it is converted to a javascriptified version of it, along with its arguments, and a string of JavaScript code is output. So the @map.add_overlay... above is converted to "map.addOverlay(new GMarker(GLatLng.new(35.12878, -110.578),{title:\"Hello!\"}))", which is then passed to the +record_init+ method of a Ruby GMap object to be later output along with the rest of the initialization code. Any arbitrary JavaScript code can be passed to the +record_init+ method. Note that 2 last lines of the previous code sample are strictly equivalent and since the +overlay_init+ version is a bit simpler, it should be preferred.

===Initialization of the map
The map is represented by a GMap object. You need to pass to the constructor the id of a DIV that will contain the map. You have to place this DIV yourself in your HTML template. You can also optionnally pass to the constructor the JavaScript name of the variable that will reference the map, which by default will be global in JavaScript. You have convenience methods to setup the controls, the center, the zoom, overlays, the interface configuration (continuous zoom, double click zoom, dragging), map types and the icons (which are also global). You can also pass arbitrary JavaScript to +record_init+ and +record_global_init+. Since, by default, the initialization of the map is performed in a callback function, if you want to have a globally accessible variable, you need to use the +global+ version.

You can also have multiple maps. Just make sure you give them different DIV id's, as well as different global variable names, when constructing them:

	@map1 = GMap("map1_div","map1")
	@map2 = GMap("map2_div","map2")



The other absolutely necessary initialization step in the controller is the setting of center and zoom:
@map1.center_zoom_init([49.12,-56.453],3)
Withouth this code the map will display an empty grey rectangle with Google's logo.

Then in your template, you have 2 necessary calls:
- The static GMap.header: Outputs the inclusion of the JavaScript file from Google to make use of the Google Maps API and by default a style declaration for VML objects, necessary to display polylines under IE. This default can be overriddent by passing :with_vml => false as option to the +header+ method. You can also pass to this method a :host option in order to select the correct key for the location where your app is currently deployed, in case the current environment has multiple possible keys. Usually, in this case, you should pass it @request.host. Finally you can override all the key settings in the configuration by passing a value to the :key key.
- GMap#to_html: Outputs the initialization code of the map. By default, it outputs the +script+ tags and initializes the map in response to the onload event of the JavaScript window object. You can call +to_html+ on each one of your maps to have them all initialized. You can pass the option :full=>true to the method to setup a fullscreen map, which will also be resized when the window size changes.

You can also use GMap#div to output the div element with the correct +id+. You can pass it options :height and :width to set the size of the div (although, as indicated below, you have other ways to do that).

So you should have something like the following:

	#head html
	<%= GMap.header %>
	<%= @map.to_html %>
	#body html
	<%= @map.div(:width => 600,:height => 400) %>



Note that you need to set a size for the map DIV element at some point or the map will not be displayed. You have a few ways to do this:
- You define it yourself, wherever you want. Usually as part of the layout definition in an external CSS.
- In the head of the document, through a CSS instruction output by @map.header_width_height, to which you pass 2 arguments (width and height).
- When outputting the DIV with @map.div, you can also pass an option hash, with keys :width and :height and a style attribute for the DIV element will be output.

===GMarkers
GMarkers are point of interests on a map. You can give a position to a GMarker constructor either by passing it a 2D-array of coordinates, a GLatLng object, an object of type Variable (which evaluates to a GLatLng when interpreted in the browser) or an address, which will be geocoded when the marker is initialized by the map.

You can pass options to the GMarker to customize the info window (:info_window or :info_window_tabs options), the tooltip (:title option) or the icon used (:icon option).

For example:

	GMarker.new([12.4,65.6],:info_window => "I'm a Popup window",:title => "Tooltip")
	GMarker.new(GLatLng.new([12.3,45.6]))
	GMarker.new("Rue Clovis Paris France", :title => "geocoded")




===Update of the map
You are able to update the map through Ajax. In Ruby-on-Rails, you have something called RJS, which sends JavaScript created on the server as a response to an action, which is later interpreted by the browser. It is usually used for visual effects and replacing or adding elements. It can also accept arbitrary JavaScript and this is what YM4R uses.

For example, if you want to add a marker to the map, you need to do a few things. First, you have to bind a Ruby mapping object to the global JavaScript map variable. By default its name is +map+, but you could have overriden that at initialization time. You need to do something like this:

	@map = Variable.new("map")


+map+ in the Variable constructor is the name of the global JavaScript map variable. Then any method you call on @map will be converted in JavaScript to a method called on +map+. In your RJS code, you would do something like this to add a marker:

	page << @map.add_overlay(GMarker.new([12.1,12.76],:title => "Hello again!"))


What is sent to the browser will be the fllowing JavaScript code:

	map.addOverlay(new GMarker(new GLatLng(123123.1,12313.76),{title:\"Hello again!\"}))




===GPolyline
GPolylines are colored lines on the map. The constructor takes as argument a list of GLatLng or a list of 2-element arrays, which will be transformed into GLatLng for you. It can also take the color (in the #rrggbb form), the weight (an integer) and the opacity. These arguments are optional though.

For example:

	GPolyline.new([[12.4,65.6],[4.5,61.2]],"#ff0000",3,1.0)



Then you add it like any other overlay:

	@map.overlay_init(polyline)



===GPolygon
GPolygons are colored areas on the map. As of 29/12, this feature is not documented in the official GMaps API, but thanks to Steven Talcott Smith (http://www.talcottsystems.com), it is possible to use it now in ym4r.

The constructor takes as argument a list of GLatLng or a list of 2-element arrays, which will be transformed into GLatLng for you. Note that for polygons, the last point must be equal to the first, in order to have a closed loop. It can also take the color (in the #rrggbb form) of the stroke, the weight of the stroke, the opacity of the stroke, as well as the color of the fill and the opacity. These arguments are optional though.

For example:

	GPolygon.new([[12.4,6.6],[4.5,1.2],[-5.6,-12.4],[12.4,6.6]],"#ff0000",3,1.0,"#00ff00",1.0)



Then you add it like any other overlay:

	@map.overlay_init(polygon)



===GMarkerGroup
A new type of GOverlay is available, called GMarkerGroup.

To use it you would have to include in your HTML template the JavaScript file markerGroup.js after the call to GMap.header (because it extends the GOverlay class). You should have something like that in your template:

	<%= javascript_include_tag("markerGroup") %>



It is useful in 2 situations:
- Display and undisplay a group of markers without referencing all of them. You just declare your marker group globally and call +activate+ and +deactivate+ on this group in response, for example, to clicks on links on your page.
- Keeping an index of markers, for example, in order to show one of these markers in reponse to a click on a link (the way Google Local does with the results of the search).

Here is how you would use it from your Ruby code:

	@map = GMap.new("map_div")
	marker1 = GMarker.new([123.55,123.988],:info_window => "Hello from 1!")
	marker2 = GMarker.new([87.123,18.9],:info_window =>"Hello from 2!")
	@map.overlay_global_init(GMarkerGroup.new(true,
					1 => marker1,
					2 => marker2),"myGroup")


Here I have created an active (ie which is going to be displayed when the map is created) marker group called +myGroup+ with 2 markers, which I want to reference later. If I did not want to reference them later (I just want to be able to display and undisplay the marker group), I could have passed an array instead of the hash.

Then in your template, you could have that:

	Click here to display marker1
	Click here to display marker2
	<%= @map.div %>


When you click on one of the links, the corresponding marker has its info window displayed.

You can call +activate+ and +deactivate+ to display or undisplay a group of markers. You can add new markers with addMarker(marker,id). Again if you don't care about referencing the marker, you don't need to pass an id. If the marker group is active, the newly added marker will be displayed immediately. Otherwise it will be displayed the next time the group is activated. Finally, since it is an overlay, the group will be removed when calling clearOverlays on the GMap object.

You can center and zoom on all the markers in the group by calling GMarkerGroup#centerAndZoomOnMarkers() after the group has been added to a map. So for example, if you would want to do that at initalization time, you would do the following (assuming your marker group has been declared as +group+):

	@map.record_init group.center_and_zoom_on_markers



===GMarkerManager
It is a recent (v2.67) GMaps API class that manages the efficient display of potentially thousands of markers. It is similar to the Clusterer (see below) since markers start appearing at specified zoom levels. The clustering behaviour has to be managed explicitly though by specifying the cluster for smaller zoom levels and specify the expanded cluster for larger zoom levels and so on. Note that it is not an overlay and is not added to the map through an overlay_init call.

Here is an example of use:

    @map = GMap.new("map_div")
    @map.control_init(:large_map => true, :map_type => true)
    @map.center_zoom_init([59.91106, 10.72223],3)
    srand 1234
    markers1 = []
    1.upto(20) do  |i|
      markers1 << GMarker.new([59.91106 + 6 * rand - 3, 10.72223 + 6 * rand - 3],:title => "OY-20-#{i}")
    end
    managed_markers1 = ManagedMarker.new(markers1,0,7)

    markers2 = []
    1.upto(200) do  |i|
      markers2 << GMarker.new([59.91106 + 6 * rand - 3, 10.72223 + 6 * rand - 3],:title => "OY-200-#{i}")
    end
    managed_markers2 = ManagedMarker.new(markers2,8,9)

    markers3 = []
    1.upto(1000) do  |i|
      markers3 << GMarker.new([59.91106 +  6 * rand - 3, 10.72223 + 6 * rand - 3],:title => "OY-300-#{i}")
    end
    managed_markers3= ManagedMarker.new(markers3,10)

    mm = GMarkerManager.new(@map,:managed_markers => [managed_markers1,managed_markers2,managed_markers3])
    @map.declare_init(mm,"mgr")

Further Documentation

There is currently no advanced documentation for this plugin.

New documentation

Edit plugin | Back in time (2 older versions) | Last edited by: scott, over 2 years ago