-
-
Save wazery/25646a488adea230ba82 to your computer and use it in GitHub Desktop.
GoogleMapTUt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Integrate Google maps into your Rails application | |
## Prerequisites | |
- Basic knowledge of Ruby on Rails (RailsBricks) for fast creating Rails apps | |
- Intermediate level of JavaScript | |
- For more jump start understanding to how map works you can read this [article](https://www.mapbox.com/foundations/how-web-maps-work/) | |
## Purpose of the tutorial | |
Giving the required instructions to make Google Maps integration with Rails much easier and funnier. We will be going through the exact steps to integrate Google maps, and we will cover some useful Rails gems and how to use them, also we will show some of the Google maps alternatives like the popular open source libraries *Leaflet.js* and *MapBox*. | |
## Demo application | |
In this tutorial we will go through how to integrate Google maps into your Rails application and adding some features to it, the source code will be available on a [Github repository](https://github.com/NouranMahmoud/GoogleMapTut), each feature will be in a spereate commit, so you can move in history freely. | |
## Initializing the map | |
Google maps provides API key, which Google can contact you with, if there’s a need for it will be exceeding your usage limits, or for informing you about map usage **this API key is no longer mandatory on V3**). | |
### To get Google maps API key, just do the following steps: | |
1- Go to Google APIs Console (you need Google account in order to use it) | |
2- Click the APIs & auth -> APIs | |
3- Activate Google Maps JavaScript API v3 by clicking the Off button | |
4- Click on credentials -> Create new key -> browser key | |
5- Make sure that `ACCEPT REQUESTS FROM THESE HTTP REFERERS (WEB SITES)` is empty or contains your domain, as in the image below. | |
6- Congrats your key has been created! | |
> **NOTE:** | |
> Not every aspect of the map is covered in the material below, it’s just a very significant chunk, so for more detailed information you can visit Google Map JavaScript documentation from [here](https://developers.google.com/maps/documentation/javascript/tutorial). | |
### Initializing the map: | |
Now we need to initialize the map in our home page, so let’s create a div with an id of `map-canvas` in the home view (*/app/views/home.erb*), and wrap this div with another one with an id of `map-container` which will be used to add some border styling and simple box shadow to the map. | |
**First:** Here is the code of the home view: | |
``` | |
<% title("Home Page") %> | |
<h1>Google Maps Tut</h1> | |
<div id="map-container"> | |
<div id="map-canvas"></div> | |
</div> | |
``` | |
Now let’s add some CSS styling. Open up a file named `framework_and_overrides.css.scss` which is generated by RailsBricks boilerplate, and it will be used to add any overriding styles to Bootstrap. | |
**Second:** add the following styles to it: | |
``` | |
#map-container { | |
height: 400px; | |
border-radius: 16px 16px; | |
border-color: #fff; | |
border-style: solid; | |
box-shadow: 2px 2px 10px #B1B1B1; | |
margin-top: 25px; | |
border-width: 7px; | |
} | |
#map-canvas { | |
height: 384px; | |
width: 100%; | |
} | |
``` | |
As you can see in the above CSS, we set the **map-container** to a fixed height of **400 pixels** and added some border styling. The last step to get an initial working map is to create a folder named **“map”** in `app/assets/javascript/map` and add a file named **“gmap.js”** on it. Now the map should look like this: | |
[--screenshot --] | |
> **HINT:** | |
> If the map zoom controller doesn’t show properly, it’s a conflict with Bootstrap styling for images and labels. So, just add the following overrides to your CSS (framework_and_overrides.css.scss) file and all will be fine. | |
``` | |
/* Bootstrap Css Map Fix*/ | |
#map-container #map-canvas img { | |
max-width: none; | |
} | |
/* Bootstrap Css Map Fix*/ | |
#map-container #map-canvas label { | |
width: auto; display:inline; | |
} | |
``` | |
### Drawing on map | |
#### Implementing the basic markers | |
Google maps API contains a marker object which allow you to create a simple marker easily. Marker object contains some attributes which indicate some properties like marker *position*, marker *title*, and the *map* where marker will be located. | |
To avoid repeating the code, we will create a function called `createMarker` which will have the parameters `coords`, `map`, `title`. Apparently it will use this parameters to create the marker object. | |
``` | |
var marker; | |
function createMarker(coords, map, title){ | |
marker = new google.maps.Marker({ | |
position: coords, | |
map: map, | |
title: title | |
}); | |
} | |
``` | |
#### Implementing custom markers | |
Marker object contains **“icon”** attribute which can take a _path_ or _image_ object. We will create two functions one for creating **Image** and the second for _creating custom marker_. To make the marker draggable you just need to add the attribute **draggable** with the value **true**. Adding simple animation to the marker, Google maps API support _two_ types of animation for the marker which are: **“DROP”**, **“BOUNCE”**. | |
So, we have created a function named `createImage` which will return the image object that will be used by our custom marker, and gave it the image url that will be used for the marker. We set it's size to 32x32 pixels, and gave it the origin of (0, 0) to be be placed inside the (32x32) image. | |
Now we will create a function called `createCustomMarker` which will do the actual work of creating the marker object. It will take the coords to place the marker on, the map object, and the title for the marker. We will use the function `createImage` which will return the correct image for our icon. | |
``` | |
function createImage(url){ | |
var image = { | |
url: url, | |
// This marker is 32 pixels wide by 32 pixels tall. | |
size: new google.maps.Size(32, 32), | |
// The origin for this image is 0,0. | |
origin: new google.maps.Point(0,0), | |
// The anchor for this image is the base of the flagpole at 0,32. | |
anchor: new google.maps.Point(0, 32) | |
}; | |
return image; | |
} | |
function createCustomMarker(coords,map,title){ | |
marker = new google.maps.Marker({ | |
position: coords, | |
map: map, | |
title: title, | |
icon: createImage("/assets/icon.png") | |
}); | |
} | |
``` | |
#### Adding infowindow | |
Infowindow is a tooltip for displaying content (text or images). You can add infowindow on a marker or on a specified `longitude` and `latitude` points (_lon_, and _lat_ for short). The InfoWindow object take **InfoWindowOptions** object. | |
``` | |
function createInfoWindow(text){ | |
var infowindow = new google.maps.InfoWindow({ | |
content: text | |
}); | |
return infowindow; | |
} | |
``` | |
Put the following code on the `initialize()` function | |
``` | |
// add infowindow when clicking on the simple marker marker | |
var info = createInfoWindow("Congratulations!"); | |
google.maps.event.addListener(marker, 'click', function() { | |
info.open(map,marker); | |
}); | |
``` | |
This code will create and infowindow named `info` and place a text of "Congratulations!" in it, and handle the click event on the marker then open the infowindow `info` we just created. | |
#### Drawing lines | |
Drawing lines simply needs a series of coordinates to be connected. Google maps API provides an object `Polyline` for drawing lines with some attributes to specify its `stroke_color`, `weight`, `opacity` and adding icons or symbols with or without animation. | |
#### Drawing simple line | |
``` | |
// drawing static polyline | |
var lineCoordinates = [ | |
new google.maps.LatLng(30.055487, 31.279766), | |
new google.maps.LatLng(30.223356, 31.324345), | |
new google.maps.LatLng(30.345656, 31.567677), | |
new google.maps.LatLng(30.565678, 31.676887) | |
]; | |
createPolyline(map, lineCoordinates, lineSymbol); | |
var linePath; | |
function createPolyline(map,lineCoordinates,lineSymbol){ | |
linePath = new google.maps.Polyline({ | |
path: lineCoordinates, | |
geodesic: true, | |
strokeColor: '#FF0000', | |
strokeOpacity: 1.0, | |
strokeWeight: 2 | |
}); | |
linePath.setMap(map); | |
} | |
``` | |
As you can see we defined an array called `lineCoordinates` which will be used to have the exact coords for our polyline, then we defined a function called `createPolyline` where we will actually create the polyline, to create it we need to set its path which we stored its coords in the `lineCoordinates` array and we need to set the `geodesic` attribute to `true`, the polylines need to be declared as geodesic, and Google Maps API takes care of the maths behind. Then we will give it a stroke color of `#FF0000`, and opacity of 1 to make it completly visible, the stroke weight value can be 2 which is enough. After we have our polyline object ready we can add it to the map using the `setMap` function. | |
[-- screenshot --] | |
#### Drawing simple line with dashes. | |
It is easy to draw a simple line with dashes on it. We will create the style in which the line would follow using the `lineSymbol` variable and will use it to be added to the regular polyline we just created. You can see that we gave the `lineSymbol` a path to follow and a scale of 4 and we modified the `createPolyline` function slightly to use that `lineSymbol` as a repeated icon. | |
``` | |
var lineSymbol = { | |
path: 'M 0,-1 0,1', | |
scale: 4, | |
strokeOpacity: 1, | |
strokeColor: '#393' | |
}; | |
// modify the createPolyline function to contain the symbol | |
var linePath; | |
function createPolyline(map, lineCoordinates, lineSymbol){ | |
linePath = new google.maps.Polyline({ | |
path: lineCoordinates, | |
geodesic: true, | |
strokeColor: '#FF0000', | |
strokeOpacity: 1.0, | |
strokeWeight: 2, | |
icons: [{ // this Array is for adding symbols to the line | |
icon: lineSymbol, | |
offset: '100%' | |
}] | |
}); | |
linePath.setMap(map); | |
} | |
``` | |
[-- screenshot --] | |
#### Drawing animated dashes | |
We can even animate the dashes simply by adding a function called `animateCircle` where we move the icons that are repeated along the line by changing its offset and this will produce a feeling of an animation. This function just move the icons offset and no need for using in in the createPolyline function, we just change the offset value to *0* and add a value of *20px* to the repeat attribute. | |
``` | |
function animateCircle() { | |
var count = 0; | |
window.setInterval(function() { | |
count = (count + 1) % 200; | |
var icons = linePath.get('icons'); | |
icons[0].offset = (count / 2) + '%'; | |
linePath.set('icons', icons); | |
}, 20); | |
} | |
//modify the `createPolyline` function to be like the following | |
var linePath; | |
function createPolyline(map, lineCoordinates, lineSymbol){ | |
linePath = new google.maps.Polyline({ | |
path: lineCoordinates, | |
geodesic: true, | |
strokeColor: '#FF0000', | |
strokeOpacity: 1.0, | |
strokeWeight: 2, | |
icons: [{ // this Array is for adding symbols to the line | |
icon: lineSymbol, | |
offset: '0', | |
repeat: '20px' | |
}] | |
}); | |
linePath.setMap(map); | |
} | |
``` | |
Then call the `animateCircle()` function after creating the polyline with `createPolyline` function. | |
[-- screenshot --] | |
#### Drawing dynamic polyline by user | |
In the following code we combined the polyline options/attributes to a variable and used it to create the polyline which is not very diffrenet from what we did in the above code samples. We set the map of the polyline and we added an event handler on click to add the line points after user clicks. | |
``` | |
// drawing dynamic polyline | |
var polyOptions = { | |
strokeColor: '#000000', | |
strokeOpacity: 1.0, | |
strokeWeight: 3 | |
}; | |
poly = new google.maps.Polyline(polyOptions); | |
poly.setMap(map); | |
google.maps.event.addListener(map, 'click', addLatLng); | |
function addLatLng(event){ | |
var path = poly.getPath(); | |
// Because path is an MVCArray, we can simply append a new coordinate | |
// and it will automatically appear. | |
path.push(event.latLng); | |
} | |
``` | |
[-- screenshot --] | |
### Drawing polygons using fixed points | |
Polygons are similar to _polyline_ in that they are drawn by a series of coordinates. Polygon consists of `stroke` and `fill` which can be customized. We will add the coords for the polygon by hand in an array called `polygonCoords` and will pass it to the function we will create which is named `drawingPolygon`. In it we will create the polygon and set its paths to the coords we added in `polygonCoords` array and add some stroke and fill effects, also their is a two useful attributes which are `draggable` and `editable`. | |
#### Simple polygon | |
``` | |
// drawing polygon | |
var polygonCoords = [ | |
new google.maps.LatLng(30.055487, 31.279766), | |
new google.maps.LatLng(30.466465, 31.118292), | |
new google.maps.LatLng(30.321384, 31.75737), | |
new google.maps.LatLng(30.055487, 31.279766) | |
]; | |
// Construct the polygon. | |
drawingPolygon(polygonCoords); | |
function drawingPolygon(polygonCoords) { | |
var polygon = new google.maps.Polygon({ | |
paths: polygonCoords, | |
strokeColor: '#FF00FF', | |
strokeOpacity: 0.8, | |
strokeWeight: 2, | |
fillColor: '#FF0000', | |
fillOpacity: 0.35, | |
draggable:true, | |
editable: true | |
}); | |
polygon.setMap(map); | |
} | |
``` | |
### Drawing on the map by (Drawing library) | |
Google maps API support a drawing library which provides a graphical interface that lets users draw polylines, polygons, circles, markers and triangles on the map. | |
For loading the drawing library on the map, just make the maps API include this part of code (`&libraries=drawing`) and directly start using the DrawingManager object. | |
The API source link should look like this: | |
``` | |
https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=drawing | |
``` | |
Let's start hacking this library by at first initializing the `DrawingManager` object: | |
``` | |
// trying the drawing liberary | |
var drawingManager = new google.maps.drawing.DrawingManager({ | |
drawingMode: null, | |
drawingControl: true, | |
drawingControlOptions: { | |
position: google.maps.ControlPosition.TOP_CENTER, | |
drawingModes: [ | |
google.maps.drawing.OverlayType.MARKER, | |
google.maps.drawing.OverlayType.CIRCLE, | |
google.maps.drawing.OverlayType.POLYGON, | |
google.maps.drawing.OverlayType.POLYLINE, | |
google.maps.drawing.OverlayType.RECTANGLE | |
] | |
}, | |
markerOptions: { | |
icon: "/assets/icon.png" | |
} | |
}); | |
drawingManager.setMap(map); | |
``` | |
The `DrawingManager` constructor allows you to manage the map drawing tools (controls) as specifing which overlay will be rendered, its position on the map and its initial state. `drawingMode` set to null to not be defaulted with specific overlay control, it can be defaulted with polyline overlay by altering `null` with `google.maps.drawing.OverlayType.POLYLINE`. The second argument is `drawingControl` which takes `true` for rendering the control or `false` for hidding it. The third argument is `drawingControlOptions` which specify the control position. | |
Google maps API provides various places to put its controls like `TOP_CENTER`, `TOP_RIGHT`, `BOTTOM_LEFT` an so on. Also this arguments specify the available `drawingModes` which contain an array of available `google.maps.drawing.OverlayType` constants like `CIRCLE`, `POLYLINE`, `POLYGONS`, ` RECTANGLE`, `MARKER`. | |
After that you can give each overlay a specific property as we mentioned in the previous section on drawing on map. | |
After completing the properties then `drawingManager` should be set to the `map` and by this you will see the drawing control on the map. | |
Drawing library can give you more flexible way to manipulate overlays with its events. Moreover its built-in control which give the user easier interface. | |
--- | |
## Adding map services | |
### Generating the address by reverse geocoding | |
The Google maps API provides a class called geocoder for simplifying producing the address via its coordinates (geocoding) and vice versa (reverse geocoding) dynamically. | |
While the service no longer require API key, it does limit geocodes to 2,500 per day and require that the resulting application show data with a Google map. The returned result data is JSON or XML. | |
``` | |
var geocoding = new google.maps.Geocoder(); | |
$("#submit_button_geocoding").click(function(){ | |
codeAddress(geocoding); | |
}); | |
$("#submit_button_reverse").click(function(){ | |
codeLatLng(geocoding); | |
}); | |
``` | |
``` | |
function codeAddress(geocoding){ | |
var address = $("#search_box_geocoding").val(); | |
if(address.length > 0){ | |
geocoding.geocode({'address': address},function(results, status){ | |
if(status == google.maps.GeocoderStatus.OK){ | |
map.setCenter(results[0].geometry.location); | |
var marker = new google.maps.Marker({ | |
map: map, | |
position: results[0].geometry.location | |
}); | |
}else{ | |
alert("Geocode was not successful for the following reason: " + status); | |
} | |
}); | |
}else{ | |
alert("Search field can't be blank"); | |
} | |
} | |
``` | |
### Generating the coordinates by geocoding | |
``` | |
function codeLatLng(geocoding){ | |
var input = $('#search_box_reverse').val(); | |
console.log(input); | |
var latlngbounds = new google.maps.LatLngBounds(); | |
var listener; | |
var regex = /([1-9])+\.([1-9])+\,([1-9])+\.([1-9])+/g; | |
if(regex.test(input)){ | |
var latLngStr = input.split(",",2); | |
var lat = parseFloat(latLngStr[0]); | |
var lng = parseFloat(latLngStr[1]); | |
var latLng = new google.maps.LatLng(lat, lng); | |
geocoding.geocode({'latLng': latLng}, function(results, status) { | |
if (status == google.maps.GeocoderStatus.OK){ | |
if(results.length > 0){ | |
//map.setZoom(11); | |
var marker; | |
map.setCenter(results[1].geometry.location); | |
var i; | |
info = createInfoWindow(""); | |
for(i in results){ | |
latlngbounds.extend(results[i].geometry.location); | |
marker = new google.maps.Marker({ | |
map: map, | |
position: results[i].geometry.location | |
}); | |
google.maps.event.addListener(marker, 'click', (function(marker,i) { | |
return function() { | |
info.setContent(results[i].formatted_address); | |
info.open(map,marker); | |
} | |
})(marker,i)); | |
} | |
map.fitBounds(latlngbounds); | |
listener = google.maps.event.addListener(map, "idle", function() { | |
if (map.getZoom() > 16) map.setZoom(16); | |
google.maps.event.removeListener(listener); | |
}); | |
} | |
} | |
else { | |
alert("Geocoder failed due to: " + status); | |
} | |
}); | |
} else { | |
alert("Wrong lat,lng format!"); | |
} | |
} | |
``` | |
### Generating directions | |
Google map API provides a great direction service for calculating routes between two or more addresses. This service can be enabled by initializing `google.maps.DirectionsService` object which takes no parameters but have one method called `route()` which have the main role to calculate the directions. This method takes two parameters, an object from `google.maps.DirectionsRequest` and a callback function. | |
The basic properties that `DirectionRequest` object takes are `origin`, `destination` and the `travelMode` which define the mode of transportation. | |
For rendering the results generated by the `DirectionsService` there is another object called `DirectionsStatus` which has all the available repsonse status. | |
To expose the resulting routes there is an object called `DirectionsRenderer` which take no parameters and has a method called `setMap` for defining the service on the map and after generating the right result a method called `setDirections` is used which takes the returned response as a parameter. | |
For more details about Google maps direction service read this [tutorial](http://www.sitepoint.com/find-a-route-using-the-geolocation-and-the-google-maps-api/) | |
``` | |
var directionsService = new google.maps.DirectionsService(); | |
var directionsDisplay = new google.maps.DirectionsRenderer(); | |
map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions); | |
directionsDisplay.setMap(map); | |
var request = | |
{ | |
origin: "Mansoura, Daqahlia, Egypt", | |
destination: "Cairo, Egypt", | |
travelMode: google.maps.DirectionsTravelMode.DRIVING | |
}; | |
directionsService.route(request, function(response, status) | |
{ | |
if (status == google.maps.DirectionsStatus.OK) //Check if request is successful. | |
{ | |
console.log(status); | |
directionsDisplay.setDirections(response); //Display the directions result | |
} | |
}); | |
``` | |
### Manipulating controls | |
Google maps API provides controls on the map, for handling and manipulating the map UI. These controls can be disabled or moved or even customized with new functionality. | |
The available controls are (Zoom control, Pan control, Scale control, MapType control, Streetview control, Rotate control, Overview map control). | |
Default UI controls can be disabled just by adding `disableDefaultUI: true`. | |
For removing one of the default controls just add it as an attribute on the `MapOptions`, as `panControl: true`, `zoomControl: false`. | |
Google maps API provides modifying a control UI attribute for each control like “zoomControlOption”. | |
``` | |
var mapOptions = { | |
center: new google.maps.LatLng(30.055487, 31.279766), | |
zoom: 8, | |
mapTypeId: google.maps.MapTypeId.NORMAL, | |
panControl: true, | |
zoomControlOptions: { | |
style: google.maps.ZoomControlStyle.SMALL, | |
position: google.maps.ControlPosition.LEFT_CENTER | |
}, | |
mapTypeControlOptions: { | |
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, | |
mapTypeIds: [google.maps.MapTypeId.ROADMAP, "map_style"] | |
}, | |
scaleControl: false, | |
streetViewControl: true, | |
overviewMapControl: true | |
}; | |
``` | |
### Adding custom map styles | |
This feature give the ability to manipulate the standard base map presentation UI. | |
Map presentation is composed of two characteristics (Map features as roads, park, mountains, …etc) and (Styles which are for the specified map elements). | |
Style array has a limit of number of characters used, if exceeded there are no style will be applied on the map. | |
For creating a new custom map style you need to follow this steps: | |
**First:** We identify style array with two basic properties __MapFeatures__, __stylers__. | |
``` | |
var mapstyle = [ | |
{ | |
"featureType": "administrative.locality", | |
"elementType": "labels.icon", | |
"stylers": [ | |
{ "invert_lightness": true }, | |
{ "color": "#e40952" }, | |
{ "visibility": "on" } | |
] | |
},{ | |
"featureType": "water", | |
"elementType": "geometry.fill", | |
"stylers": [ | |
{ "visibility": "on" }, | |
{ "hue": "#5eff00" }, | |
{ "color": "#282744" }, | |
{ "weight": 0.1 }, | |
{ "saturation": -56 }, | |
{ "lightness": 22 }, | |
{ "gamma": 3.91 } | |
] | |
} | |
] | |
``` | |
**Second:** We set `mapTypeId` to map options, which will be identified in the fifth step. | |
``` | |
var mapOptions = { | |
center: new google.maps.LatLng(30.055487, 31.279766), | |
zoom: 8, | |
mapTypeId: google.maps.MapTypeId.NORMAL, | |
mapTypeControlOptions: { | |
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, | |
mapTypeIds: [google.maps.MapTypeId.ROADMAP, "map_style"] | |
} | |
}; | |
``` | |
**Third:** Here we instantiate the `StyledMapType` which takes pre-defined mapstyle array and its name on the control which will appear on the map as option style. | |
``` | |
var styledMap = new google.maps.StyledMapType(mapstyle, {name: "styled map"}); | |
map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions); | |
``` | |
**Fourth:** We set our customized map style to the object `mapTypes` to be included to the map styles. | |
``` | |
map.mapTypes.set("map_style", styledMap); | |
``` | |
**Fifth:** With this final step we must set the used `mapType` ID to specific chosen id. | |
``` | |
map.setMapTypeId("map_style"); | |
``` | |
As Google maps API know that giving styles to the map and trying every single element and style for reaching the desired style is time-consuming, so it provided a powerful tool for generating JSON for your map style after selecting it by the tool. | |
--- | |
## Useful Rails gems | |
### Geocoder | |
This gem provides geocoding, reverse gecoding and finding nearby locations, determining distances, and map services solution for Ruby. | |
> **HINT:** | |
> Geocoder gem supports using `rails3` and `rails4`, there's another branch for `rails2`. | |
Geocoder gem is installed like any ruby gem by `gem install geocoder` or by adding `gem "geocoder"` to `Gemfile` and then launch `bundle install`. | |
You've to add two float fields (lat, lng) in the model which will be used to store latitude and longitude values after fetching them by street addresses (human readable address) or zip codes (postal codes) by the following Rails command. | |
``` | |
rails generate migration AddLatitudeAndLongitudeToModel lat:float lng:float | |
rake db:migrate | |
``` | |
On the model you have to put two basic lines to spcify which service will be used (geocoder or reverse geocoder): | |
``` | |
geocoded_by :address | |
# auto-fetch coordinates and the condition is for preventing fetching the same address more than once | |
after_validation :geocode, if: :address_changed? | |
``` | |
This `full_street_address` method will be implemented on the model to create the readable address. | |
> **HINT:** | |
> Geocoder supports some of the popular databases like (MySQL, PostgreSQL, MongoDB). | |
Geocoder gem provides you with an easy way to swap between various geocoding providers. | |
### GMaps4rails | |
GMaps4rails is an awesome gem which provides geocoding and map locations. it uses **JS** to generate filters when rendering markers. It has the geocoding feature which calculate simple `lat`, `lng`. | |
It is good to combine between **geocoder gem** features and then rendering the results on map by `GMaps4rails` as `GMaps4rails` tend to work fine with simple `lat` and `lng`. | |
**Installation** | |
First: by Ruby Bundler you must add the following line to your Gemfile file: | |
``` | |
gem 'gmaps4rails | |
``` | |
Then run `bundle install` | |
Second: as we previewed on Google maps API you need to add a div to hold the map as follows: | |
``` | |
<div style='width: 800px;'> | |
<div id="map" style='width: 800px; height: 400px;'></div> | |
</div> | |
``` | |
Third: insert this Google scripts in your `application.html.erb` header part : | |
``` | |
<script src="//maps.google.com/maps/api/js?v=3.13&sensor=false&libraries=geometry" type="text/javascript"></script> | |
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js' type='text/javascript'></script> | |
``` | |
Fourth: require the `underscore.js` library too, because Gmaps4rails uses it. So in the asset pipeline put this code: | |
``` | |
//= require underscore | |
//= require gmaps/google | |
``` | |
Now, you are able to create your map as follows with this JS code: | |
``` | |
handler = Gmaps.build('Google'); | |
handler.buildMap({ | |
provider: { | |
disableDefaultUI: true | |
// here you can pass other Google Maps API options here | |
}, | |
internal: { | |
id: 'map' | |
} | |
}, | |
function(){ | |
markers = handler.addMarkers([ | |
{ | |
"lat": 0, | |
"lng": 0, | |
"picture": { | |
"url": "https://addons.cdn.mozilla.net/img/uploads/addon_icons/13/13028-64.png", | |
"width": 36, | |
"height": 36 | |
}, | |
"infowindow": "hello!" | |
} | |
]); | |
handler.bounds.extendWith(markers); | |
handler.fitMapToBounds(); | |
} | |
); | |
``` | |
The above code is a very simple example to create marker with `inforwindow` on the map. For more details about this gem check this [link](https://github.com/apneadiving/Google-Maps-for-Rails). | |
## Some alternative libraries for creating interactive maps | |
### Leaflet.js, an open source library for interactive maps | |
Leaflet is a modern JS library for embedding maps which gained its popularity from simplicity and ease of implementing markers, overlays and manipulating various map components. Leaflet can be extended with enormous of [plugins](http://leafletjs.com/plugins.html). It uses a permissive BSD open-source license, so it can be involved to any site without legal worries. Also it supports multiple map providers including OpenStreetMap, MapQuestOpen, Stamen, Esri and OpenWeatherMap. | |
__Installation__ | |
First: download it from its official site [leaflet.com](http://leafletjs.com/download.html), it is available as a `.zip` file or get a [fork from githup](https://github.com/Leaflet/Leaflet). | |
A snip of code to illustrate how easy its code is: | |
``` | |
// create a map in the "map" div, set the view to a given place and zoom | |
var map = L.map('map').setView([51.505, -0.09], 13); | |
// add an OpenStreetMap tile layer | |
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { | |
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' | |
}).addTo(map); | |
// add a marker in the given location, attach some popup content to it and open the popup | |
L.marker([51.5, -0.09]).addTo(map) | |
.bindPopup('A pretty CSS3 popup. <br> Easily customizable.') | |
.openPopup(); | |
``` | |
To learn more about [Leaflet](http://leafletjs.com/examples/quick-start.html). | |
### [MapBox](https://www.mapbox.com/) | |
MapBox is a beautiful tool which give flexibility for creating maps. It gives the ability to design custom maps with wonderful layers and a lot of custom features with __TileMill__ (map design studio) a downloadabale application, or you can create MapBox's web applications with custom markers and overlays by using its Javascript API. | |
__installaton__ | |
All you need is creating an account on [MapBox](https://www.mapbox.com) and getting thier unique Map IDs for maps you've had created to integrate it with your web application or sites. | |
This part will give you just a glance about using MapBox with JavaScript. | |
After creating your map on [MapBox](https://www.mapbox.com), and including the Mapbox.js library on your project. | |
**First:** Initialize the map: | |
``` | |
var map = mapbox.map('map'); | |
``` | |
**Second:** Set zoom range and center zoom and point of the map: | |
``` | |
map.setZoomRange(5, 15); | |
map.centerzoom({ | |
lat: 37.871385, | |
lon: -99.228516 | |
}, 5); | |
``` | |
**Third:** Add the custom layer which you have created on the [MapBox](https://www.mapbox.com) tool. | |
``` | |
map.addLayer(mapbox.layer().id('YOUR-MAP-ID-HERE')); | |
``` | |
With this basic lines you can recognize how easy its code is. After that you can embed more features to the map like markers UI features (fullscreen), (zoomer) and so on. | |
> **NOTE:** | |
> This is not an in-depth tutorial on how to use MapBox, but it exposes it as an alternative option to Google maps API . | |
## Summary | |
By this tutorial you got the basic understanding of how to create map and map concepts in general and customizing the map to your needs in specifc details related to which map API you choose to use. You must know that for creating a custom map you don't have to know everything about it, you just need to specify which feature you need and start discovering it. I know it was a quick run through, but I hope if it can give you a jump start, or add some inspiration to your next map project. | |
----- | |
**NEXT POSSIBLE TUTORIAL** | |
Integrate Leaflet.js maps into your Rails application |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment