GMapsTable: Usage

0
72

Introduction

Have you ever needed to place some sort of geographic data on a map? For example, in my job, I develop analytical web services and I had to display orders grouped by latitude and longitude. And not a static table, but dynamic one, which changes its detailization with the map zoom!

Unfortunately, I found no existing solution for this task. Google Maps allow to add markers and shapes to the map, but this is not appropriate, too little information is shown. However, Google Maps allow to create custom overlays. Thus, I created GMapsTable for encapsulating this stuff. A live example is here.

Solving the Problem

So, what do we have? A server with a database, that processes and sends data in JSON; and a client with JavaScript, that sends queries and handles the results putting the data on Google Maps.

The data has accumulative nature (in my case, each region may have: orders count, clients count, and mean sum of orders). The data can and must be presented with different detailization for different map scales. And this is done on server-side only, client does not change the data.

Here is the main content of an HTML page for GMapsTable:

 ..in <head>:
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY"></script>
<script src="http://www.aivanf.com/static/gmt/gmapstable.js"></script>

 ..in <body>:
<div id="map"></div>

GMapsTable allows you to abstract from direct interaction with GoogleMaps API. All you need is to provide an appropriate data object. Time to dive into JavaScript! To use GMapsTable, you need to obtain a DataContainer object for your map’s div element:




var container = new DataContainer("map", {
 zoom: 9,
 center: {lat: 55.7558, lng: 37.6173},
 mapTypeId: 'roadmap'
});

Then you have to specify two functions:

container.dataLoader = function (scale, borders) {
 ... call container.processData(some_data)
}

container.scaler = function getScale(zoom) {
 ... return some number
}

But what to write inside?… Let’s begin with how GMapsTable works.

Data for DataContainer

DataContainer handles your data visualisation process and worries if it must be updated. At the start and when zoom or bounds are changed significantly, it calls dataLoader function. There you should generate a data object and pass it to DataContainer.processData function. Its structure is as follows:

data: {
 minLat: float,
 difLat: float,
 minLon: float,
 difLon: float,
 scale: int,
 table: [
 [value, value, ...],
 [value, value, ...],
 ...
 ],
 tocache: boolean
}

A value can be a number, a string or other object if you specify custom cell formatter. Scale is a number of parts in each lat/lon unit. The “tocache” property says if the values for this scale should be saved and no longer requested. To clarify, have a look at an example:

data: {
 minLat: 55.0,
 difLat: 2.0,
 minLon: 37.0,
 difLon: 1.0,
 scale: 2,
 table: [
 [1, 3, 0, 1],
 [0, 1, 2, 0]
 ],
 tocache: true
}

Here, the data covers region from 55.0, 37.0 to 57.0, 38.0 and splits every lat/lon into two parts. Also the values will be saved for this scale value.

Zoom to Scale

The zoom is the variable of Google Maps API, ranged between 1 (world map) and 22 (street view). It’s expensive and helpless to request and store values for every zoom value, so, GMapsTable translates it to scale value — number of parts to divide latitude and longitude units.

Caching the Data

To provide flexible and immediate table display, GMapsTable can store datasets for some scales. For example, I had a table on my database with coordinates from all of Russia — about 42 thousand cells for scale 10 (500 KB, can be easily stored and processed on a desktop browser) and 17 million for scale 200 (several MB, causes significant freezing). Hereby, the server estimates cells count and to a certain extent, starts cutting the data. The algorithm:

The bounds argument is a JavaScript object with properties minlat, maxlat, minlon, maxlon — current bounds of Google Maps view with big padding on each side.

In your dataLoader realisation, you can ignore arguments if you don’t need scaling the detailization or if your data does not cover huge region — just indicate preferred min/max/lat/lon and scale in your data response. But I suggest the full behaviour of dataLoader:

List of Properties

You may specify the following properties of DataContainer:

  1. scaler(zoom) — translates GoogleMaps zoom to GMapsTable scale. Both are integer numbers.
     
  2. dataLoader(scale, borders) — is called when DataContainer needs new data. Must call DataContainer.processData(data).

    borders is a JavaScript object with properties minlat, maxlat, minlon, maxlon — current bounds of Google Maps view with big padding on each side.
     

  3. tableBeforeInit(map, table, data) — is called when table element was created but not filled with rows and cells. map is a Google Maps object, table is an HTML element, and data is your data object for current scale.
     
  4. cellFormatter(td, val) — is called when table is filling with rows and cells. td is an HTML element, a cell of the table. val is a value from provided data object.
     
  5. boundsChangedListener(zoom) — is called when Google Maps bounds are changed.
     
  6. minZoomLevel, maxZoomLevel — minimal and maximal zoom of Google Maps. Integer numbers ranged between 1 (world map) and 22 (street view).

Only the 1st and 2nd are necessary for DataContainer successful operation.

Example and Sources

You can find full and well-commented example of GMapsTable usage here:

SaveSaveSave

SaveSave

LEAVE A REPLY