Storing and Editing GeoJSON Data Within IndexedDB

By Ali Kilic
Picture of the author
Published on
Usage GeoJSON & indexedDB

Article Number : 1

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

Demo: GeoJSON and IndexedDB Usage

Github Repository: GeoJSON and IndexedDB GitHub

Topics You Will Learn

  1. Reading GeoJSON File
  2. Adding GeoJSON to the Map with Openlayers
  3. How to Make Vector Drawings with Openlayers
  4. indexedDB Creation
  5. Creating Tables in indexedDB
  6. Adding, Deleting, Editing Saves to IndexedDB Tables

If you’re ready, let’s begin!…

GeoJSON is a JSON structure that contains geometry and attribute information. This file structure is readable and editable with a simple text editor. The JSON data structure can be comfortably used with JavaScript, making it highly popular today. It shares similarities with the use of object-oriented software. It shares similarities with the use of object-oriented software.

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. It allows keeping a save of the product of the transactions made in the web browser. Additionally, it offers a memory of 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.

  1. Creating a New Layer
  2. Drawing
  3. 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.

  1. Add GeoJSON: Adds GeoJSON file to the map
  2. Remove GeoJSON: Deletes the added GeoJSON file
  3. Polygon: Draws a polygon on the map
  4. Line: Draws new line on the map
  5. Point: Draws a new point on the map
  6. 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.

GIST : file-03-indexed-geojson-html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GeoJSON and indexedDB Usage</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css"
    type="text/css">
  <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
  <style>
    #map {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
    }

    .topRight {
      position: fixed;
      top: 10px;
      right: 10px;
      z-index: 2;
    }

    button {
      padding: 10px;
      color: #fff;
      border: none;
      border-radius: 5px;
    }
  </style>
</head>

<body>
  <div id="map"></div>
  <div class="topRight">
    <button onclick="readGeoJSON()" style="background-color: #8BC34A;">Add GeoJSON</button>
    <button onclick="removeGeoJSON()" style="background-color: #F44336; display: none;" id="removeButton">Remove GeoJSON</button>
    <button onclick="draw('Polygon')" style="background-color: #ffc107; color: #545454;">Polygon</button>
    <button onclick="draw('LineString')" style="background-color: #00bcd4;">Line</button>
    <button onclick="draw('Point')" style="background-color: #9c27b0;">Point</button>
    <button onclick="clearAll()" style="background-color: #fff; color: #545454;">Clear All</button>
  </div>
</body>

</html>
<script src="map.js"></script>
<script src="indexedDB.js"></script>

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.

  1. Adding the basemap
  2. Adding vector layers we will use
  3. Converting GeoJSON data to vector data
  4. Converting vector data to GeoJSON
  5. Adding vector data to a layer
  6. Zoom in on a layer
  7. Creating drawing functions
  8. Reading a GeoJSON file
  9. Deleting the read GeoJSON file
  10. 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.

GIST : 05-indexed-geojson.js

var map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'http://{a-d}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
        crossOrigin: 'anonymous'
      })
    })
  ],
  view: new ol.View({
    center: ol.proj.fromLonLat([-0.09, 51.505]),
    zoom: 13
  })
});
Polygon, Line and Point add To IndexedDB
Polygon, Line and Point add To IndexedDB

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.

GIST : file-06-indexed-geojson-js

var layer1 = new ol.layer.Vector({
  source: new ol.source.Vector(),
  style: new ol.style.Style({
    fill: new ol.style.Fill({
      color: 'rgba(139, 195, 74, 0.5)'
    }),
    stroke: new ol.style.Stroke({
      color: '#8BC34A',
      width: 3
    }),
    image: new ol.style.Circle({
      radius: 5,
      fill: new ol.style.Fill({
        color: '#8BC34A'
      })
    })
  })
});
map.addLayer(layer1);

var layer2 = new ol.layer.Vector({
  source: new ol.source.Vector(),
  style: new ol.style.Style({
    fill: new ol.style.Fill({
      color: 'rgba(255, 193, 7, 0.7)'
    }),
    stroke: new ol.style.Stroke({
      color: '#00bcd4',
      width: 4
    }),
    image: new ol.style.Circle({
      radius: 7,
      fill: new ol.style.Fill({
        color: '#9c27b0'
      })
    })
  })
});
map.addLayer(layer2);

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.

GIST : file-08-indexed-geojson-js

function GeoJSONToFeature(geojson) {
  var reader = new ol.format.GeoJSON();
  var features = reader.readFeatures(geojson, {
    featureProjection: 'EPSG:3857',
    dataProjection: 'EPSG:4326'
  });
  return features;
}

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.

GIST : file-07-indexed-geojson-js

function featuresToGeoJSON(features) {
  var reader = new ol.format.GeoJSON();
  var geojson = reader.writeFeatures(features, {
    featureProjection: 'EPSG:3857',
    dataProjection: 'EPSG:4326'
  });
  return JSON.parse(geojson);
}

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.

GIST : file-09-indexed-geojson-js

function addFeaturesToLayer(layer, features) {
  var src = layer.getSource();
  src.clear();
  src.addFeatures(features);
}

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.

GIST : file-10-indexed-geojson-js

function zoomToLayer(layer) {
  var features = layer.getSource().getFeatures();
  if (features.length > 0) {
    var extend = layer.getSource().getExtent();
    map.getView().fit(extend, map.getSize());
    var zoomlevel = map.getView().getZoom();
    if (zoomlevel > 18) {
      zoomlevel = 18;
    }
    map.getView().setZoom(zoomlevel);
  }
}

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.

GIST : file-11-indexed-geojson-js

function draw(type) {
    var draw = new ol.interaction.Draw({
      source: layer2.getSource(),
      type: type
    });
    map.addInteraction(draw);
    draw.on('drawend', function (e) {
      setTimeout(function () {
      var features = layer2.getSource().getFeatures();
      var geojson = featuresToGeoJSON(features);
      database_1.add({
        type: 'updateLayer',
        param: {
          layerId: 'layer2',
          geojson: geojson
        }
      });
    }, 100)
      map.removeInteraction(draw);
    });
  }
Sample Stored Data
Sample Stored Data

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

GIST : file-12-indexed-geojson-js

function readGeoJSON() {
  var input = document.createElement('input');
  input.type = 'file';
  input.accept = '.json, .geojson';
  input.addEventListener('input', function (e) {
    var file = e.target.files[0];
    var reader = new FileReader();
    reader.addEventListener("load", function (e2) {
      var geojson = JSON.parse(reader.result);
      database_1.add({
        type: 'addLayer',
        param: {
          layerId: 'layer1',
          geojson: geojson
        },
        callback: function (status1) {
          if (status1) {
            var features = GeoJSONToFeature(geojson);
            addFeaturesToLayer(layer1, features);
            zoomToLayer(layer1);
            document.getElementById('removeButton').style.display = 'inline-block';
          } else {
            database_1.add({
              type: 'deleteLayer',
              param: {
                layerId: 'layer1'
              },
              callback: function (status2) {
                //debugger;
                if (status2) {
                  document.getElementById('removeButton').style.display = 'none';
                  database_1.add({
                    type: 'addLayer',
                    param: {
                      layerId: 'layer1',
                      geojson: geojson
                    },
                    callback: function (status3) {
                      if (status3) {
                        var features = GeoJSONToFeature(geojson);
                        addFeaturesToLayer(layer1, features);
                        zoomToLayer(layer1);
                        document.getElementById('removeButton').style.display = 'inline-block';
                      }
                    }
                  });
                }
              }
            });
          }
        }
      });
    });
    reader.readAsText(file);
  });
  input.click();
}

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 GIST : file-13-indexed-geojson-js

function clearLayer(layer) {
  layer.getSource().clear();
}

function removeGeoJSON() {
  database_1.add({
    type: 'deleteLayer',
    param: {
      layerId: 'layer1'
    },
    callback: function (status) {
      if (status) {
        document.getElementById('removeButton').style.display = 'none';
        clearLayer(layer1);
      }
    }
  });
}

3.10 Clearing All Geometries

The only difference from the previous topic is that it also covers the drawn layer. So, for this project it means all the layers that exist in our map. Please look at the section in Step 4 to learn the indexedDB updateLayer method without following the step order. With this step, we pass the 3rd step. If you have come this far, you are also in love with GIS like us. After this step, you need to be a Javascript lover.

GIST : file-14-indexed-geojson-js

function clearAll() {
  database_1.add({
    type: 'updateLayer',
    param: {
      layerId: 'layer1',
      geojson: {
        "type": "FeatureCollection",
        "features": []
      }
    },
    callback: function (status) {
      if (status) {
        clearLayer(layer1);
      }
    }
  })
  database_1.add({
    type: 'updateLayer',
    param: {
      layerId: 'layer2',
      geojson: {
        "type": "FeatureCollection",
        "features": []
      }
    },
    callback: function (status) {
      if (status) {
        clearLayer(layer2);
      }
    }
  })
}

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.

  1. Creating a global indexedDB variable and creating the IDBGeoJSON class
  2. Version Information Exchange
  3. Creating a Queue Structure
  4. Creating a Database
  5. Adding a Layer
  6. Layer Editing
  7. Layer Deletion
  8. Show Layers
  9. 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.

GIST : file-02-indexed-geojson-js

window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;

class IDBGeoJSON {
  constructor(params){
    this.db_name = params.db_name;
    this.localStorageName = this.db_name+'-indexedDB-version';
    this.jobs=[];
    this.add({
      type:'createDB',
      prop:{
        db_name:this.db_name
      }
    });
  }
}

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.

GIST : file-01-indexed-geojson-js

 setVersion(version){
    localStorage.setItem(this.localStorageName, version);
 }

  getVersion(){
    var version = localStorage.getItem(this.localStorageName);
    if (version == null || version == '') {
      localStorage.setItem(this.localStorageName, 1);
    }
    version = localStorage.getItem(this.localStorageName);
    return parseInt(version,10);
  }

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.

GIST : file-15-indexed-geojson-js

add(job){
    this.jobs.push(job);
    if(this.jobs.length==1){
      this.next();
    }
  }

 next(){
   var self = this;
   if(this.jobs.length>0){
     const job = this.jobs[0];
     switch(job.type){
        /* cases */
     }
   }
 }

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

GIST : file-16-indexed-geojson-js

createDB(callback){
    var self = this;
    var request = indexedDB.open(this.db_name);
    request.onerror = function(event) {
      console.log('indexedDB Error Code:'+event.target.errorCode);
      callback(false)
    };
    request.onsuccess = function(sender) {
      var db = sender.target.result;
      var newVersion = db.version+1;
      self.setVersion(newVersion);
      var tableNames = db.objectStoreNames;
      db.close();
      if(tableNames.length==0){
        var request = indexedDB.open('gislayer', newVersion);
        request.onupgradeneeded = function (event) {
          var layerTable = event.target.result.createObjectStore('layers', {
            keyPath: "layerid"
          });
          layerTable.createIndex('layerid', 'layerid', {
            unique: true
          });
          layerTable.createIndex('geojson', 'geojson', {
            unique: false
          });
          event.target.result.close();
          callback(true);
        }
      }else{
        callback(true);
      }      
    };
}

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.

GIST : file-17-indexed-geojson-js

next(){
      switch(job.type){
        case 'createDB':{
          this.createDB((status)=>{
            if(job.callback!==undefined){
              job.callback(status);
            }
            self.jobs.splice(0,1);
            self.next();
          })
          break;
        }
      }
}

When you refresh the page you created, you can see the tables of indexedDB in the Application section of your browser

Browser IndexedDB Checks
Browser IndexedDB Checks

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.

GIST : file-18-indexed-geojson-js

addLayer(layerId,GeoJSON,callback){
    var self = this;
    var version = self.getVersion();
    var request = indexedDB.open(this.db_name, version);
    request.onsuccess = function(event){
      var db = event.target.result;
      var data = {
        layerid:layerId,
        geojson:GeoJSON
      };
      var insert = db.transaction(['layers'], "readwrite").objectStore('layers').add(data);
      insert.onsuccess = function (e1) {
        event.target.result.close();
        callback(true);
      }
      insert.onerror = function (e1) {
        event.target.result.close();
        console.log(e1.target.error.message);
        callback(false);
      }
      db.close();
    }
  }

After adding this method to the class, we can add the required code block to the case part of the next method.

GIST : file-19-indexed-geojson-js

next(){
  switch(job.type){
    case 'addLayer':{
      this.addLayer(job.param.layerId,job.param.geojson,(status)=>{
        if(job.callback!==undefined){
          job.callback(status);
        }
        self.jobs.splice(0,1);
        self.next();
      });
      break;
    }
  }
}

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.

GIST : file-20-indexed-geojson-js

var database_1 = new IDBGeoJSON({
  db_name:'gislayer'
});

database_1.add({
  type:'addLayer',
  param:{
    layerId:'layer2',
    geojson:{ "type": "FeatureCollection", "features": [] }
  }
});

If you refresh your page after typing this code, you can see the save below.

Browser IndexedDB Checks
Browser IndexedDB Checks

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.

Sample Geo Data
Sample Geo Data

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.

GIST : file-21-indexed-geojson-js

updateLayer(layerId,GeoJSON,callback){
    var newVersion = this.getVersion() + 1;
    this.setVersion(newVersion);
    var request = window.indexedDB.open('gislayer', newVersion);
    request.onsuccess = function (event) {
      var db = event.target.result;
      var store = db.transaction(['layers'], "readwrite").objectStore('layers');
      var data = {
        layerid: layerId,
        geojson: GeoJSON,
      };
      store.put(data);
      db.close();
      callback(true);
    }
    request.onerror = function (e1) {
      var db = e1.target.result;
      db.close();
      console.log(e1.target.error.message);
      callback(false);
    }
}

After this method is ready, we can now define the updateLayer in the case block of our next method.

GIST : file-22-indexed-geojson-js

next(){
  switch(job.type){
    case 'updateLayer':{
      self.updateLayer(job.param.layerId,job.param.geojson,function(status){
        if(job.callback!==undefined){
          job.callback(status);
        }
        self.jobs.splice(0,1);
        self.next();
      });
      break;
    }
  }
}

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.

Sample Geo Data
Sample Geo Data

You can see that the drawings made below are registered

Browser IndexedDB Checkings
Browser IndexedDB Checkings

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.

GIST : file-23-indexed-geojson-js

deleteLayer(layerId,callback){
    var self = this;
    var version = this.getVersion();
    var request = window.indexedDB.open('gislayer', version);
    request.onsuccess = function (event) {
      var db = event.target.result;
      var request2 = db.transaction(['layers'], "readwrite").objectStore('layers').delete(layerId);
      request2.onsuccess = function (event) {
        var db = event.target.transaction.db;
        var currentVersion = db.version;
        db.close();
        self.setVersion(currentVersion);
        callback(true);
      }
      request.onerror = function(event) {
        console.log('indexedDB Error Code:'+event.target.errorCode);
        callback(false)
      };
    }
  }

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.

GIST : file-24-indexed-geojson-js

next(){
  switch(job.type){
    case 'deleteLayer':{
      self.deleteLayer(job.param.layerId,function(status){
        if(job.callback!==undefined){
          job.callback(status);
        }
        self.jobs.splice(0,1);
        self.next();
      });
      break;
    }
  }
}
Sample Geo Data
Sample Geo Data

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.

GIST : file-25-indexed-geojson-js

showLayer(callback){
    var newVersion = this.getVersion() + 1;
    this.setVersion(newVersion);
    var request = window.indexedDB.open('gislayer', newVersion);
    request.onsuccess = function (event) {
      var db = event.target.result;
      var store = db.transaction(['layers'], "readonly").objectStore('layers');
      var result = [];
      store.openCursor().onsuccess = function (e) {
        var cursor = e.target.result;
        if (cursor) {
          result.push(cursor.value);
          cursor.continue();
        }else{
          callback(result);
        }
      }
      db.close();
    }
    request.onerror = function (e1) {
      var db = e1.target.result;
      db.close();
      console.log(e1.target.error.message);
      callback(false);
    }
  }

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.

GIST : file-26-indexed-geojson-js

next(){
  switch(job.type){
    case 'showLayer':{
      self.showLayer(function(data){
        if(job.callback!==undefined){
          job.callback(data);
        }
        self.jobs.splice(0,1);
        self.next();
      });
      break;
    }
  }
}

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.

GIST : file-27-indexed-geojson-js

database_1.add({
  type:'showLayer',
  callback:(layers)=>{
    layers.map((layer)=>{
      var features = GeoJSONToFeature(layer.geojson);
      addFeaturesToLayer(window[layer.layerid],features);
      zoomToLayer(window[layer.layerid]);
    });
  }
});

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.

Sample Geo Data
Sample Geo Data

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

Demo: GeoJSON and IndexedDB Usage

Github Repository: GeoJSON and IndexedDB GitHub

Follow My Updates

Would you like to stay informed about my new projects and blog posts?
If you'd like to stay informed about new projects and articles, please fill out and submit the form below