Usage GeoJSON & indexedDB
Updated: Apr 27, 2021
You will see the demo of the application we will create on the link I will share below. In our article, we will teach you how this work should be coded, and we will also share the final product with github codes
Github Repository: indexeddb-geojson
Topics You Will Learn
Reading GeoJSON File
Adding GeoJSON to the Map with Openlayers
How to Make Vector Drawings with Openlayers
Creating Tables in indexedDB
Adding, Deleting, Editing Saves to IndexedDB Tables
If you’re ready, let’s begin!…
IndexedDB is an HTML5 API that works as a database in web browsers. Although it is confusing for beginners to use, it has become an important feature in terms of GIS software in order to keep a save of the product of the transactions made in the web browser, as it offers a memory up to 50MB to its users.
In the example we will do, we will learn how to add and delete a GeoJSON file on the map on a simple web page, draw different types of drawing and delete this drawing, and while doing these operations, we will learn to keep it in indexedDB. The example we will show is a simple way of use and you can make it more complex in your own work.
In the projects we have developed with the GISLayer team, we save the geometric drawing, editing, deletion and attached spatial files made by our users on their browsers in order to protect them. Now we wanted to share this part with you.
Step 1: Creating a Sample GeoJSON File
Let’s create the GeoJSON file we will use. If you have a file for this action, you can use it. If not, first create a new layer at editor.gislayer.com If you want to learn how to do it, you can quickly create your file by following the order below.
Creating a New Layer
You can download it using Download GeoJSON File or Layer Box
Step 2: Creating the index.html File
We need an HTML page to examine the code we will write. We will use the OpenLayers map library that we can manage in the fastest way to show the actions on the map. Alternatively, you can use Leafletjs, Mapbox or other map libraries. However, it is important to be able to work with GeoJSON. This example we have prepared has been developed for OpenLayers.
First, you have an empty folder to work on and create an index.html page in this folder. In the head tag of this file, we added the CSS and js source codes of OpenLayers directly from the source they provided on their site. We have defined styles for the buttons and their positions we will use. We have added a div element with map id information to publish the map in body tags, and we will add 6 buttons, which constitute the main purpose of this tutorial, and we will use it without any further changes in the index file.
Add GeoJSON: Adds GeoJSON file to the map
Remove GeoJSON: Deletes the added GeoJSON file
Polygon: Draws a polygon on the map
Line: Draws new line on the map
Point: Draws a new point on the map
Clear All: Delete all the drawings.
You can create the map.js and indexedDB.js files in your project folder to be defined at the bottom of the page and hold them for later use. In the following steps, we will learn and add.
Step 3: Preparing map.js Map Functions
Let’s create the first version of the map.js file we created in the project folder. In this file, we will have map functions and we will complete by following a certain order. In this file, we will do the operations listed below. While following this order, you need to add the shared codes to your map.js file respectively.
Adding the basemap
Adding vector layers we will use
Converting GeoJSON data to vector data
Converting vector data to GeoJSON
Adding vector data to a layer
Zoom in on a layer
Creating drawing functions
Reading a GeoJSON file
Deleting the read GeoJSON file
Deleting all geometries
3.1 Adding the Basemap
The base map we will use is described as XYZ tile, and if you have an XYZ tile service of your own, you can publish it by changing the URL address here, you can define the zoom level and center latitude and longitude. If you add the codes below, you can check with your own status by following the screenshot.
3.2 Adding Vector Layers We Will Use
We will use two vector layers within the scope of the project, the first will be for the GeoJSON files added to the map, and the other will keep the drawings we will make on the map. You can determine the appearance of these layers according to the information in the style. After adding these codes, any screen view will not change, you will add two empty layers to your map.
3.3 Converting GeoJSON Data to Vector Data
We cannot directly use the GeoJSON data we want to upload to our map from outside. Therefore, we must make it available for Openlayers, so we have to convert it to vector data. We will use the ol.format.GeoJSON method for this. Assuming that the future GeoJSON data will be in the EPSG: 4326 projection system, we convert it to the EPSG: 3857 projection system that OpenLayers accept in their default settings.
3.4 Converting Vector Data to GeoJSON
Everything is going very well. From this point on, we need to work in a way that indexedDB likes. Because we cannot assign vectors that we will obtain from Openlayers layers directly into indexedDB. We need to make them available to us. This is converting it into GeoJSON for us. For this, we need to use the ol.format.GeoJSON method again. This method can be called a format converter for us.
3.5 Adding Vector Data to a Layer
In the previous functions, we converted GeoJSON data to vector data. Now we need to prepare the function that will add them to the layer. While cleaning the inside of the vector layer to be added to the code below, it also adds the incoming data. So your layer always shows us the GeoJSON file we want cleanly.
3.6 Zoom in on a layer
We may not be able to predict where the GeoJSON data we will add to the map is. Therefore, we have to zoom the BBOX area of the layer for each added layer. The code below is for this.
3.7 Creating Drawing Functions
OpenLayers is a great library. It offers us the opportunity to develop a unique GIS project with its life-saving functions. If you remember, we put buttons to draw polygon, lines and points in the index.html file and the onclick event was directed to a method called draw. The parameter that this method takes was the type of geometry to be drawn. These buttons do their job with this function. At the end of the process, we need to click these buttons again to start a new drawing. The part included in the description line in the code will be activated later. For now, let it quietly wait until we write in indexedDB. Now we can draw on our map. You can remove the description line with the section 4.6.
3.8 Reading a GeoJSON File
We added the Add GeoJSON button in the index.html file. The click event of that button depends on this function and when it runs, it creates a virtual DOM and opens a file dialog for users. When users select and confirm the GeoJSON file they want to upload to the map, we now have the information in the file.
After this point, we need to add this data first indexedDB for the scenario. However, for now, we present this section with the description line. You can remove these description lines after writing the method we need. You can remove the description line after learning sections 4.5 and 4.7
3.9 Deleting the Read GeoJSON File
We had read a GeoJSON file before. The user may want to upload another GeoJSON file. In this case, since the relevant layer must be saved in indexedDB before, we need to delete it from there. The part that needs to be deleted from the map is developed in the map.js file, while the part that needs to be deleted in indexedDB will be explained in the next step.
Now we urgently need to empty the inside of the layer. Here, the name of the function that empties the layer is clearLayer. removeGeoJSON first deletes saves from indexedDB and then uses this function if the action is positive. You can remove the description line after you know the topic number 4.7
3.10 Clearing All Geometries
Step 4: Preparing the Browser Database with the indexedDB.js File
Now we can start developing our indexedDB file. We can say that IndexedDB is already an API that comes with HTML5, which already exists in your browser, but that most people are afraid to use. We are not afraid because we trust ourselves. Trust yourself, it’s not difficult at all.
You have seen the usage of the methods we will write in this step in the map.js file. Now, let’s follow the order below while starting to write the functions defined there.
Creating a global indexedDB variable and creating the IDBGeoJSON class
Version Information Exchange
Creating a Queue Structure
Creating a Database
Adding a Layer
Show Saved Layers in Page Refresh
4.1 Defining in Global and Creating Class
First of all, we need to define our indexedDB in global to work in every browser. After this definition, we can call the variable from anywhere. Let’s create the constructor function of the object we will create, and after this step, let’s define each new function in the class code block and under the constructor function. You can open the section included in the description line for use after creating the section 4.4 in the following titles.
4.2 Version Information Exchange
You need to increase the version information one by one in every transaction that changes the database structure to IndexedDB. Because if there is a change in the database, the database will be upgraded to the next version and you should know the version number. Therefore, we save this information in localStorage. With setVersion, we use it when defining the new version information. We also get the current version information with getVersion.
4.3 Creating the Queue Structure
When running IndexedDB, we need to create the queue structure so that more than one transaction does not overlap with a similar version. In other words, if the database does not pass to the next version, you cannot make changes in the previous system. The inflexibility of the situation makes us sad, but we have to work with such a method instead of wasting time with the low quota of localStorage.
This queue structure to be created will also prevent switching from one process to another before it ends. Then let’s prepare the queue structure we need to do these operations.
In the following methods, “add” triggers the execution while adding a new job to the list, and the “next” method directs all jobs to the correct method until the job is finished. Now we can write the methods that should do the main work and write them in the case blocks in the switch.
The next method takes an object parameter and we define it to write the name of the actual method you will use in the type property information. We define the parameters we will use to the prop property information. If you are waiting for a return after the method is finished, we code it in a way that allows you to get a return in the form of true/false by making an optional callback property definition. The usage examples of this method were demonstrated while creating the map.js file.
4.4 Creating a Database
We have defined the name of the database we will create in the constructor function of the class. Now we can create the database. Below, we wanted to create a ‘layers’ table in indexedDB that only save our layers. While the primary column of this table keeps the name information of the layer, the GeoJSON column is designed to save the GeoJSON information of the relevant layer. The callback function in the parameters of the functions is available to inform you of the result of the operation.
However, creating this method is not enough. First of all, while activating the description line created for createDb in the constructor function, you need to create a new case in the next method. The sample code should be as follows.
When you refresh the page you created, you can see the tables of indexedDB in the Application section of your browser.
4.5 Creating/Adding a Layer
Now there is a table named layers in the database and we need to add save to this table. In this section, we will learn how to add save to indexedDB. We are adding the registration information of our layer to the transaction, which we will define in this method, with the add method.
After adding this method to the class, we can add the required code block to the case part of the next method.
Now, as soon as our page opens, we can add our “layer2” layer, which should be created, to the layers table. Remember that layer2 is a layer that saves the drawings. The code block I mentioned below should be under the class we created. With this code, we add an empty layer2 save to our layers table in indexedDb.
If you refresh your page after typing this code, you can see the save below.
Also, if you use the Add GeoJSON button of your page, it will add and display the file you want to add as layer for once. If you use this feature again, this layer will not take action because it already exists. We will solve this problem as well.
4.6 Layer/Save Editing
Now that we can add our layers to the system, it is necessary to update our non-fixed layer structure in indexedDB with every change. For this process, we create the updateLayer method and define the data we want to edit with put to the transaction in it. Since the Keypath value is the name of the layer, it will only work to change this save.
After this method is ready, we can now define the updateLayer in the case block of our next method.
Now you can remove the description lines in the code block we mentioned in 3.7 and make drawings on the map. Each drawing will also update the layer2 save of the layers table.
You can see that the drawings made below are registered.
4.7 Layer/Save Deletion
Previously, we could only add the GeoJSON file we added to the map for one time. Now we can delete the existing save and add it again. If we wanted to choose easy way, we could do it with layerUpdate, but we developed a project in this way since this topic is about save deletion.
By using the delete method of the transaction that we define in the code block below, we delete the layer whose name we know from the saves.
After adding this method, you will be able to add as many GeoJSON files as you want to your map by adding the following case block to the next method.
Now you can add different GeoJSON files to your map.
4.8 Showing Layers/Reading Save
Now everything is cleaner and the codes we write find a response. Now we need to prove that we do not lose the saves that our users have uploaded even if they refresh the page.
With this method, when we refresh the page, previously saved layers will be automatically loaded on the map and you will be able to please the user. Because Web users don’t like their work to be lost and wasted.
The difference of the code block below from other methods is that the data is taken with the readonly method and it presents this data to us one by one using cursors. Thus, we are able to retrieve the records we obtained from here using callback.
After adding the above code block, we need to add the following code to the case blocks of the next method as a new case.
So, our code is almost ready.
4.9 Show Saved Layers on Page Refresh
Now we have come to the step where we can prove that it leads us to success. In this step, we need to show that even if the user refreshes his page, he does not lose the layers he creates and the geometric data he draws. We will complete it with the code below. This code should be added to the system outside of the class, in the last code block we showed in 4.5 In other words, just add it to the bottom of the indexedDB.js file.
The clear button on the index.html page was explained in 3.10 If you have a forgotten code in the description line, please open it. If you believe something is wrong, please get help from github code.
Step 5: Here We Are!
I hope I was able to do my best. Feel free to write below if you have any questions. If you follow me, I will continue to share decent articles in the times ahead.
If You Want to Get Consultancy Service: You Can Contact Us
Recommended Pages to Follow
Author & Developer : Click Here
GISLayer Linkedin Page: Click and Follow
Our Website: Click and Use Our Products
Our Github Page: Click and Get Code Support