Use The Power of Open Source Web GIS #4 Playing with Polygons

Yunus Emre Özkaya
5 min readApr 9, 2023

--

The best part of map-based applications is that their output is visual and this visuality is as limitless as your imagination. You can display the same data in very different shapes, in very different colors and even in different dimensions, thus making the data easier to understand at first glance.

In this article, we will talk about how we can display the same polygon data in many different ways. We will use geojson as data. If you want to get more detailed information about Geojson, you can take a look at the previous story in the series at this link. Use The Power of Open Source Web GIS #3 GeoJSON : Geographic Data Structure Used Everywhere

I will continue on the project that I started in the previous stories of the series. If you have not created a project, you can download it from my GitHub account (https://github.com/utahemre/maplibre-gl-example-project), and please use #2-StyleWithMapTiler Tag.

Since we will add data to the map for the first time in this story, I would like to briefly talk about the source and layer. Sources specify what data the map should show. It can be one of vector, raster, raster-dem, geojson, image, video types. Layers refer to a resource and give it a visual representation.

Before starting, I run “npm install uuid” in terminal. This command will add uuid packages. (I will use this package for generating unique ids for sources and layers.) I also run “npm install axios” in terminal. This command will add axios packages.(This is HTTP client) Then, I run “npm start” to start my server.

In my project, in the /src/components folder, I create 2 folders named sources and layers to put the files that I will manage resources and layers. (see code on github)

I am creating a file named Sources.js inside the sources folder and to manage polygon layers, I add a file named PolygonLayer.js in the layers folder. The final state of the src/components folder is as follows.

I added a simple function for geojson sources to my Sources.js file as seen below. From now on, when I want to add a gejson source, I will use this function to make the code less complicated.

export function geojsonSource(_data) {
return (
{
'type': 'geojson',
'data': _data,
}
);
}

I am adding a function for polygon layers in PolygonLayer.js file. The function takes the resource id to be used and the settings related to the visual properties of the layer as input. For settings that do not come, it uses default values. Finally, if you notice, the id for each layer is created automatically using uuid. The final version of the file looks like this.

import { v4 as uuidv4 } from 'uuid';

export function polygonLayer(_sourceId, _layerProperties) {
let layerId = uuidv4();
return (
{
'id': layerId,
'type': 'fill',
'source': _sourceId,
'paint': {
'fill-color': _layerProperties['fill-color'] ? _layerProperties['fill-color'] : 'red',
'fill-opacity': _layerProperties['fill-opacity'] ? _layerProperties['fill-opacity'] : 0.8,
'fill-outline-color' : _layerProperties['fill-outline-color'] ? _layerProperties['fill-outline-color'] : 'black',
}
}
);
}

Now that my Sources.js and PolygonLayer.js files are ready, let’s add a polygon layer to our map using them from our Map.js file.

First of all, I will make some changes in my Map.js file. I will be using my map object with useRef which is a react hook. The reason I use it this way is that there is no need for re-rendering for changes on our map. For more detailed information, you can check https://react.dev/reference/react/useRef.

To use my map object with useRef, I add the following line to my code and change the inside of the useEffect hook, which is running while our Map component is first rendering, as follows.

const map = useRef(null);

useEffect(() => {
map.current = new maplibregl.Map({
container: "map",
style: "https://api.maptiler.com/maps/basic-v2/style.json?key=" + mapTilerKey, // stylesheet location
center: [34, 40], // starting position [lng, lat]
zoom: 5, // starting zoom
});
}, []);

Now I am adding the following function to add geojson source.

 const addGeojsonSource = (_url, _callback, _callbackParameters) => {
axios
.get(
_url
)
.then((response) => {
const sourceInstance = geojsonSource(response.data);
let sourceId = uuidv4();
map.current.addSource(sourceId,sourceInstance);
if(_callback){
_callback(sourceId, _callbackParameters);
}
return sourceId;
});
};

My function takes the following parameters.

  • _url : address of geojson data
  • _callback : I will use this if I want to add a layer immediately after the geojson data has been downloaded and added as a source to the map.
  • _callbackParameters : Parameters I will use in the _callbak function.

Now I add the following function to add polygon layer

 const addPolygonLayer = (_sourceId, _layerProperties) => {
const polygonLayerInstance = polygonLayer(_sourceId, _layerProperties);
map.current.addLayer(polygonLayerInstance);
};

My function takes the following parameters.

  • _sourceId : the id of the source that the layer will use
  • _layerProperties : properties of the layer

Now that we have all our code ready, let’s see our first polygons on the map. I am adding the following code block inside the UseEffect hook.
The “load” event informs us that all the resources required to use the map have been downloaded and the map is ready, so I am adding sources and layers here. (The address written below is the address of a sample polygon object in my github account. You can also use any geojson address with polygon data.)

map.current.on("load", function () {
addGeojsonSource("https://raw.githubusercontent.com/utahemre/maplibre-gl-example-project/master/public/testdata/population.geojson",
addPolygonLayer, {'fill-color' : 'red', 'fill-opacity' : 0.5, 'fill-outline-color' : 'white'}
);
});

After I made these changes my page looks like this;

Now let’s add a new character to our map by changing the settings in _callbackParameters. I am changing the _callbackParameters as below and let’s see what the result will be.

map.current.on("load", function () {
addGeojsonSource("https://raw.githubusercontent.com/utahemre/maplibre-gl-example-project/master/public/testdata/population.geojson",
addPolygonLayer, {'fill-color':
[
'step',
['get', 'population'],
'#00FF00',
500000,
'#FFFF00',
1000000,
'#FFA500',
3000000,
'#FF0000',
50000000,
'#8B0000'
], 'fill-opacity' : 0.5, 'fill-outline-color' : 'black'}
);

});

It looks really nice doesn’t it? Our map has now become both more beautiful and more meaningful. Here I made a range according to the population data in each polygon and determined a color according to each range.

As you can see, I created 2 different maps from the same data. We can create very different maps by making changes on the settings. We will take this further in future stories. We will generate 3D maps from the same data. We also fixed the color ranges here. We will also produce them automatically.

Always be scout. Leave the code more clean than you found.

--

--

Yunus Emre Özkaya

Developer of related software on gis and stock markets. Runner, trail runner.