Here is the Part 2 of Integrate PostGIS and Google maps in Rails, in this part we will render the provinces of Gabon on Google map. Unlike Part 1 the GeoJSON data is fetched from a static file, in this part we will see how to fetch data from PostGIS and encode them into GeoJSON directly. The result is like the following figure, the 9 provinces are rendered on the map, and when the user put his mouse over one province, that area will be highlighted, and also on the top right there is a label which shows the name of the province that is highlighted.
Create the Province model
The first thing we need to do is to create a Province model. Like how we created the Country model in part 1, we create a Province model, and then import the data in shape file into our PostGIS database. The main part in the migration is as following,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
The province data is in shape file GAB_adm1.shp, and we fetch the province name and geometry from the shape file and import them into provinces table (In the shape file province name is stored as attribute name_1).
Encode the feature
Now we need to fetch data from database and encode them as GeoJSON. GeoJSON is a JSON format for encoding geographic data structures. The following example is stolen from the GeoJSON website. We can see that in addition to the geometry data, the JSON can also encode additional properties.
1 2 3 4 5 6 7 8 9 10
We will mainly use the rgeo-geojson gem to do the encoding. In rgeo-geojson gem, it converts a geometry type to a feature and then encode the feature to a hash, and then the hash can be rendered as a JSON.
1 2 3 4 5 6
We create a Concern named Featurable, which will add a featurable class method into the class which includes it. So for example in Province class, we include the Featurable like following,
1 2 3 4 5
The featurable accepts two parameters, the first is mandatory, which is the name of the attribute which contains the geometry data, the second parameter is an optional array of attribute names, when encoding it as GeoJSON, those attributes will be encoded as attributes. Here we encode the name attribute as the property of the feature. Now the Province class will have a instance method named to_feature, which returns a RGeo::GeoJSON::Feature.
1 2 3
The result will display as following, it includes the name as its property and also has an id.
1 2 3 4 5 6 7 8 9 10 11 12
Now let’s have a look at how Featurable is implemented.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
In the implementation of featurable class method, when this method is called, the class will call define_method to define an instance method called to_feature and from line 9 to 13 it will generates a hash named properties whose key is the property name and value is the property value. And then on line 14 it calls the RGeo::GeoJSON::EntityFactory#feature method to create the feature and return it.
On line 21 it defines another class method called to_feature_collection, this is to convert a collection of models to a feature collection, for example the following code shows how to encode all 9 provinces as a feature collection.
Now let’s create a ProvincesController to render all 9 provinces as GeoJSON.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
We can see that the index method responds to two formats, in the json format it will call Province.to_feature_collection to create the feature collection, and then calls RGeo::GeoJSON.encode(feature_collection) to encode the feature as a hash, and last calls render to render the hash as a JSON string.
In the views/provinces/index.html.erb, the main part is as following,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
From line 2 to line 4 it creates an info box at the RIGHT TOP to display province name. And from line 6 to line 10 it adds a mouseover event listener, so when the mouse is over the province region, it set the text of the info box to the name property of the feature. And on line 12 it defines a mouseout event listener so the style is reverted when the mouse is out of the province region.
So in this part we showed how to fetch geometry data from PostGIS database and render them on google map. The source code for this part is at github.