In my previous blog Basic map with geojson2svg we have seen that how easily we can create svg world map using geojson2svg. The previous map was a basic map without any information of any country. Now we are going to create world population map showing low, medium and high population countries with different colors.
First I am showing the output, countries population thematic map color-coded as low, medium and high.
- Low
- Medium
- High
Now the approach for the map creation is assemble the data (geojson and population) then convert to svg and render on maps with styles required.
Please clone the project blog2-thematic-map so that while going through this blog you can execute also.
Code below shows the HTML component from map1.html for the above map.
<ul id="legend">
<li> <span class="box l"></span><span class="label">Low</span>
<li> <span class="box m"></span><span class="label">Medium</span>
<li> <span class="box h"></span><span class="label">High</span>
</ul>
<div id="mapArea" style="width: 100%;height:50%;border: 1px solid #c0c0c0;">
<svg id="map" xmlns="http://www.w3.org/2000/svg" x="0" y="0" >
</svg>
</div>
<script type="text/javascript" src="./js/build.js"></script>
We’ll discuss each step of the JavaScript code main.js in detail, the first is the data i.e. geographic boundaries of countries and population of each country. As discussed in the last blog, geojson is well suited for countries’ boundaries. Though geojson has a structure to store the attributes of the feature like population, I prefer to store the feature information in a separate json file. Advantage is that we have to maintain just one geojson file and any information can be linked at run time. To join geojson with json I am using module extend-geojson-properties. Let’s see the code now:
1 var $ = require('jquery'),
2 geojson2svg = require('geojson2svg'),
3 parseSVG = require('parse-svg'),
4 extendGeoJSON = require('extend-geojson-properties');
5
6 // get countires geojson data and population data
7 $.when(
8 $.getJSON('./data/countries.geo.json'),
9 $.getJSON('./data/population.json')
10 ).then(drawGeoJSON, function() {
11 console.log('data not found');
12 })
In first four lines we just include the modules that we require. Then with ajax’ promise approach I fetch geojson and population json data. The response from the both request are passed in drawGeoJSON function. Next in drawGeoJSON function we’ll see how to join the geojson and json data.
14 function drawGeoJSON(respGeojson,respPopulation) {
15 var geojson = respGeojson[0],
16 population = respPopulation[0];
17 // extend geojson properties with country's population
18 var joinMap = {
19 geoKey: 'properties.name',
20 dataKey: 'countryName'
21 };
22 extendGeoJSON(geojson,population.countries,joinMap);
In jQuery’s ajax response objects respGeojson and respPopulation, zeroth value is data. Now we need to join the geojson and population data. extend-geojson-properties is very simple module for this purpose, we have to just specify the joining keys for each in joinMap. This module is function that accepts parameters, first - geojson (geojson), second - json data set (population) and third - object of join keys (joinMap). The function extends all the json fields of json data set to geojson properties object. You can read more about extend-geojson-properties module here.
Now we need to convert geojson to svg:
24 // get the width and height of svg element.
25 // as the width of the map container is 100%, we have to set the width and
26 // height of the svgElement as per the current width/height of the container.
27 var container = document.getElementById('mapArea'),
28 width = container.offsetWidth,
29 svgMap = document.getElementById('map');
30 svgMap.setAttribute('width', width);
31 svgMap.setAttribute('height', width * 0.5);
32 // initiate geojson2svg
33 var convertor = geojson2svg(
34 {width: width, height: width * 0.5},
35 {
36 mapExtent: {
37 left: -180,
38 right: 180,
39 bottom: -90,
40 top: 90
41 }
42 }
43 );
In the above code we initialize the geojson2svg instance as explained in the last blog Basic map with geojson2svg.
Next we categorize every feature according to the population and convert to svg by assigning css class accordingly.
44 // process every feature
45 geojson.features.forEach(function(f) {
46 var popCat, svgString, svg;
47 if (f.properties.population <= 30000000) {
48 popCat = 'low';
49 } else if ( f.properties.population > 30000000
50 && f.properties.population <= 60000000) {
51 popCat = 'medium';
52 } else {
53 popCat = 'high';
54 }
55 svgString = convertor.convert(
56 f,
57 {attributes: {'class': popCat}});
58 svg = parseSVG(svgString);
59 svgMap.appendChild(svg);
60 });
61 }
For each feature we first check to which category the feature belongs. Once we get the category (popCat) feature is converted to svg string (svgString) by convert function. Two parameters are passed to this function first - feature (f) and second options. In options here we are passing the svg class name that will apply the style to svg according to population category (line no 57). Here attributes are the attributes of svg DOM element, we can pass any attribute while converting the geojson as per our requirement. Next (line 58) with parse-svg module svg string is converted to svg DOM element and then appended to main svg element (svgMap). And we are done, our thematic map is ready.
The map included in this blog is svg map generated from the above code.
Note: Each article in this blog is an individual project. Here is the source code for this article. In the source repository there are maps[n].html files that are used to show maps in the blog.