Ionic 4 Leaflet Plug-ins (OpenStreetMap) App

Using Appery.io Leaflet Map and Leaflet Route plug-ins for creating an application with OpenStreetMap

Introduction

If you're looking for a free alternative to the Google Maps service, take a look at OpenStreetMap, a free editable world map.

In this sample app, we will use Leaflet, an open-source JavaScript library for embedding maps, and the OpenStreetMap service to integrate a map in the Appery.io Ionic 4 app.

👍

Appery.io Leaflet Plugins

Also, you can easily integrate the map into your app with the use of Appery.io Leaflet plugins.

Downloads and Resources

You can also try it yourself by creating from the backup:

  1. Download the app backup file.
  2. Click Create new app.
  3. Click From backup and select the project backup file on your drive.
  4. Type in the app name.
  5. Click Create.

🚧

Defining DB credentials

Note, that if you decide to create from backup but would like to use your database like described in the Displaying List of Markers section, you will need to modify the default travelDB service in your app.

To do it, in the Project view, unfold the Services > travelDB > travelDB_settings folder and replace the default database_id value with your database ID (can be found in the browser search field or in YOUR DATABASE > Settings > API keys.

But if you are interested in the detailed tutorial, please follow the step-by-step instructions below.

Creating New App

  1. Navigate to the Appery.io dashboard. Here, from the Apps tab, click Create new app.

  2. Select the Ionic 4 application for its type and Blank as a template. Name it, for example openstreetmapApp and confirm by clicking Create.

Adding Dependencies

  1. Go to Project > App settings > Npm modules. Here, add a new Dependency, leaflet of ^1.6.0 version:
  1. Then, switch to the Cordova plugins tab and enable the Geolocation plug-in:
  1. Switch to the General tab and in the Custom tags section, add a new link tag with the following Attributes value: rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"

Displaying Map

Then, let's start building the app UI. First, we will simply display a map on the screen.

  1. Go to Pages > Screen1 > CODE. Here, in the Custom includes section, add a new include, * as L with leaflet path:
  1. Scroll down to the Variables section. Here, create a new map variable of Any type:
  1. Switch to the DESIGN tab. Set the page's Footer property to False. In the header, set text of Toolbar Title to Map:
  1. To create a container for a map, drag & drop an Html component to the screen. In the PROPERTIES panel, set its Class property to map-container. Also, add a new attribute with id name and map value. Save the changes:
  1. Let's apply some simple styles for the map. Switch to the SCSS tab, add the following styles and save the changes:
.map-container {
    height: 100%;
}
  1. Go back to the DESIGN tab and expand the EVENTS panel from the bottom. Here, select Page as the Component and After page showing as the Event. For the Action, select Run Typescript and type in the code below. It creates a new map in the div element with id="map" and adds OpenStreetMap tiles — square bitmap images displayed in a grid arrangement to show a map:
this.map = new L.Map('map').setView([40.647491, -73.787827], 15);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(this.map);

📘

Setting Map View

Let's take a look at this line of code:

this.map = new L.Map('map').setView([40.647491, -73.787827], 15);

Here, we create a new map and set its view. You can set any initial map center coordinates (first function parameter) and zoom level (second function parameter). More information can be found in Leaflet documentation

Save all the changes. You can click the TEST button in the top panel to test the app in the browser. You will see a fullscreen map that can be dragged around and zoomed in and out:

Getting Current Location

Then let's get our current location and display a marker on the map.

  1. In the page header, drag & drop a Button component into ToolbarButtons1. Clear the button's Text property, change Icon > Style to locate, set Icon > Color to primary and Icon > Slot to Icon Only:
  1. Select ToolbarButtons1 (you can use the breadcrumbs) and change the Slot property to End:
  1. Go to the CODE tab. Here, in the Variables section, create a new locationMarker variable of Any type:
  1. Then, let's create an auxiliary method for clearing the map. In the Functions section, create a new function, clearMap, with adding the following code. It removes all layers that are not tile layers:
this.map.eachLayer((layer) => {
    if (!(layer instanceof L.TileLayer)) {
        this.map.removeLayer(layer);
    }
});
  1. Then, go back to the DESIGN tab to add a button click event handler. In the EVENTS panel, select the Button1 component Click event with the Action as Run Typescript . In the code editor, type in the code below. Click on the button will detect your current location and place a marker with a popup on the map. We made a marker draggable, so you can change its position:
this.map.locate({ setView: true }).on("locationfound", (event: any) => {
    this.clearMap();
    
    this.locationMarker = L.marker([event.latitude, event.longitude], {
        draggable: true
    }).addTo(this.map);

    this.locationMarker.bindPopup("You are here!").openPopup();
});

Now you can test the app. After the page is loaded, the map should be shown. Click the button in the header and the view will move to your current location. Note that you should allow the app to use your location:

🚧

Troubleshooting

If nothing happens when you click the button, please make sure geolocation is enabled on your device.

Displaying List of Markers

Let's modify our app a bit to display a list of locations stored in the Appery.io database.

  1. First, we need to create a new database. Go to the Databases tab and click Create new database. Enter travelDB as a new database name and confirm creating.

  2. In the new database, create a new custom collection. Click Create new collection, enter TravelList as its name and click Add.

  3. In the new collection, add 3 columns by clicking + Col:

  • title column of String type,
  • lat column of Number type,
  • lng column of Number type:
  1. Fill the collection with some sample data by adding rows (click +Row). For example, you can add a couple of places to visit in New York with geographical coordinates:

title

lat

lng

Statue of Liberty

40.689247

-74.044502

Empire State Building

40.748440

-73.985664

Central Park

40.782864

-73.965355

  1. The database is ready, let's return to our app. Click Create new > Database service, select the created travelDB database, unfold the TravelList collection's services list, mark the List service as checked, and confirm importing:
  1. Then, let's create a model to hold the locations. Go to Project > Model and Storage and click the Model tab. Add a new Location model. Then, for the Location model, add 3 parameters:
  • title of String type,
  • lat of Number type,
  • lng of Number type.
  1. Create one more model for the list of locations, LocationsList of Array type. Then, change the type of LocationList[i] to Location:
  1. Then, go to the Screen1 > CODE tab. Here, create two variables:
  • travelList variable of LocationsList type. It will be used to store the list of locations.
  • travelMarkersGroup variable of Any type. It will be used for grouping an array of markers:
  1. Go to Screen1 > DATA and add the travelDB_TravelList_list_service as a new datasource. Click Add and rename the datasource to getTravelList:
  1. Edit the service's Success mapping. Map the service response to locationsList variable and click Save & Replace:
  1. Then, click the Add button next to the datasource's Success event. Select the Run Typescript action and type in the following code. After that, save the changes:
this.clearMap();
this.travelMarkersGroup = L.featureGroup();

this.travelList.forEach(item => {
    const newMarker = L.marker([item.lat, item.lng]);
    newMarker.bindPopup(item.title);
    
    this.travelMarkersGroup.addLayer(newMarker);
    this.map.addLayer(this.travelMarkersGroup);
});

this.map.fitBounds(this.travelMarkersGroup.getBounds());
  1. Go back to the DESIGN tab and place two more buttons in the app header, inside ToolbarButtons1. For the first created button, clear its Text, change Icon > Style to map, set Icon > Color to primary and Icon > Slot to Icon Only:
  1. For the second created button, clear its Text, change Icon > Style to trash, set Icon > Color to danger and Icon > Slot to Icon Only. Also, set its (click) property to clearMap():
  1. Unfold the EVENTS panel from the bottom, select the Button2 component. For the event, select Click, and for the action, select Invoke service. Set getTravelList service as the datasource and click Save:

Save all the changes and test the app. Click on the second button will add markers from the database to the map. You can click the markers to see a popup:

Clicking the last button will clear the map.

Adding Markers

Let's also add the possibility to place new markers by clicking on the map.

  1. On the Screen1 CODE tab, add a new userMarkers variable to store a list of markers. Set its type to LocationsList.

  2. Go to the DESIGN tab and modify the code of page's After page showing event by adding the this.map.on('click', (event) => this.addMarker(event)); line so that the code looks like the following:

this.map = new L.Map('map').setView([40.647491, -73.787827], 15);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(this.map);

this.map.on('click', (event) => this.addMarker(event));

📘

Map Providers

You can use any map provider instead of OpenStreetMap. Some of them can be found in this demo.

Note that some of them require API key and may charge a fee for additional requests.

  1. Now, in the CODE tab, create a new Async method, name it addMarker, add the event parameter, and provide the below code. It shows a popup that lets users enter a marker title, then a marker is placed on the map as a separate layer:
const { lat, lng } = event.latlng;

const alert = await this.Apperyio.getController("AlertController").create({
    header: 'Add Location',
    inputs: [{
        name: 'name',
        type: 'text',
        placeholder: 'Location title'
    }],
    buttons: [{
        text: 'Cancel',
        role: 'cancel',
        cssClass: 'secondary',
        handler: () => {
            console.log('Creation cancelled');
        }
    }, {
        text: 'Add',
        handler: (res) => {
          const title = res.name;
          const newMarker = new L.marker({ lat, lng })
            .bindPopup(title)
            .addTo(this.map);
          
          this.userMarkers.push({ title, lat, lng });
        }
    }]
});

await alert.present();

Save the changes and test the app. Click on the random place on the map, enter a title for a marker and confirm creating. You will see that a marker has appeared on the map:

Using Appery.io Leaflet Plug-ins

You can also easily import the map into your app, using one of the Appery.io Leaflet plug-ins. Let's take a closer look at them.

Leaflet Map Plug-in

This plug-in integrates Leaflet map into your app, adds OpenStreetMap layer on it. Clicking the buttons in the app toolbar can locate you on the map, add a new OpenRailwayMap overlay layer or clear all the markers.

To add the plug-in into your app, do the following:

  1. In the app builder, click Create new > From Plugin. Here, in the Utilities section, select the Leaflet Map plug-in and click Import selected plugins:
  1. Go to Project > Routing and change the default route to LeafletMap:

After that the app can be tested. You can find your location, place markers on the map and clear the map:

Also, an additional overlay layer showing the railway routes can be switched on and off:

🚧

Enabling Geolocation

Please make sure the geolocation is enabled on your device before testing the app. If you're testing the app in the browser, please allow the app to access the location.

Leaflet Routes Plug-in

This plug-in uses openrouteservice to build routes on the Leaflet map. To use it in your app, please follow the steps:

  1. In the app builder, click Create new > From Plugin. Here, in the Utilities section, select the Leaflet Routes plug-in and click Import selected plugins:
  1. Go to Project > Routing and change the default route to LeafletRoutes:
  1. Sign up to openrouteservice. In the Dev dashboard navigate to the TOKENS tab. Select Free for the token type, enter some token name and click CREATE TOKEN:
  1. You will see the generated token. Double-click it and the key will be copied to the clipboard:
  1. In the Appery.io app builder, go to Services > openrouteserviceSettings and paste the copied key as the api_key parameter's value:

That's it, you're ready to test the app. Add several markers (at least 2) by clicking on the map. The app will build the route between the markers automatically. Also, you can see the approximate route distance, duration and instructions about your maneuvers at the bottom of the screen: