From „Hello, World!“ to AR web apps – part 4. – Leaflet detour

As part of a project at EmotionalMaps, a web map needed to be made for a client. Normally Ondra would have done this in no time, but this time I decided to program such a web map myself as part of my attempts to learn how to “code”.

The first idea was to make the maps/layers in QGIS and then use the QGIS2Web plugin to “just export” the web viewer. Cool idea that looked simple, unfortunately I soon found out that QGIS2Web doesn’t export the background OpenStreetMap layer (or I didn’t find out how to set it up). It also can’t turn off/on certain categories within a layer, it can only turn off/on the whole layer. At the same time, I found that the plugin writes pretty frantic code – 4 layers for 332 lines of code, I managed 84 lines and I’m sure it could be done more elegantly (i.e. less lines/code).

QGIS2Web examples (layers preparation, export and final map).

The second attempt was the GISQuick plugin, which also looks promising on the web, but I couldn’t get it to work at all, so I tried to “write” the whole thing myself. This brings us to the magic word Leaflet. I’ll admit without torture, I knew Leaflet was used for web maps, that’s where I ended up – so – it’s an open-source JavaScript library for creating web map applications – see Wikipedia or Leafletjs.com for more.  

I’ll try to describe the process of how I created the map in a very simple way, hopefully it will help beginners like me – some of the steps took me a really long time, I’m sure it could have been done differently, easier, etc.

Preparing the page to insert the Leaflet map – I followed the Leaflet Quick Start Guide, so:

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>

 https://unpkg.com/leaflet@1.7.1/dist/leaflet.js

Leaflet CSS and link to Leaflet JavaScript

http://okresy.js

For this, I had a geojson “districts” that I saved as *.js and used this command to load it. I just opened the geojson in notepad and edited it – see below:

var districts = {INSERT CONTENTS OF GeoJSON HERE}

The whole map script is then like this:

<script>
                var vrstvy = L.layerGroup();
                var okresyLayer = L.geoJSON(okresy, {color: "#000000", fillColor: 'grey', fillOpacity: 0, weight: 3,opacity: 1,}).addTo(vrstvy);
                var mbAttr = 'Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, ' + 'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
mbUrl = 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';
                var grayscale   = L.tileLayer(mbUrl, {id: 'mapbox/light-v9', tileSize: 512, zoomOffset: -1, attribution: mbAttr}), streets  = L.tileLayer(mbUrl, {id: 'mapbox/streets-v11', tileSize: 512, zoomOffset: -1, attribution: mbAttr});
                var map = L.map('map', {
                               center: [49.2468,17.6791],
                               zoom: 10,
                               layers: [grayscale, vrstvy]
                });
                               var baseLayers = {
                               "Grayscale": grayscale,
                               "Streets": streets
                };
                var overlays = {"Okresy": okresyLayer};
                L.control.layers(baseLayers,overlays).addTo(map);
                L.control.scale().addTo(map);
</script>

This describes how I defined the layer symbology, map center and zoom, base map selection, layer on/off panel, and scale.

I spent a few hours on this (my map has a bit more layers and symbology), but in the end I don’t think it was that difficult. Yes, it’s “just a boring map”, but it’s MINE! It’s written using open-source libraries, layers created/edited in open-source QGIS.

Sample of my version of the map

In the next installment, I’ll come back to AR and the markers you need to understand for using AR mobile apps.

Have a great day and thanks for your comments.

Jirka Panek

From „Hello, World!“ to AR web apps – part 3.

I’m starting to realize that maybe I should rename this series and instead of From “Hello, World!” to AR web apps, it should be called Idiot’s guide to coding, or Coding for Dummies, but both of those names are already taken 🙂 Why did I consider renaming it? Because I am a loser! I thought I had at least some basics, but that was a mistake. So I hope my fellow GISers, will still talk to me.

So here we go!

First step/question – where/what/how will I actually write the “code”? (I’m starting to find that I don’t actually know what programming language I’ll be using the most, but more on that later). From my student days (15 years ago) I remember that we just wrote the commands in notepad, then saved the file as somename.html and tried to see if (or why not) it worked. Later I had NotePad++ installed, which I thought was a cool gadget at the time. So when I was wondering what software to use for writing code, I looked up if NotePad++ still existed and wow! the latest version is from March 2021. To avoid diving headfirst into the first SW, I did some quick research and asked my colleagues. My programming Guru Ondra recommended Visual Studio Code and since I didn’t really have any preferences, Visual Studio won. The change from the classic Notepad is amazing, but I guess it’s the standard these days.

Second step – if I want to test something on mobile, or send a sample to someone, I probably need some hosting. Although I’ve been in charge of websites for various projects – GISportal, EmotionalMaps, and the Department of Development and Environmental Studies website – I’ve always been more of a WordPress administrator/user and have no experience with hosting. Anyway, I chose basic web hosting with Wedos, which will be enough for basic testing, plus I renewed a long-expired domain that I used to use – JirkaPanek.cz

Before I start writing my own apps, I need to test how such an AR interface works, how to edit individual parameters, etc. As a pretty nice introduction and at the same time amazingly elegant solution, while doing some research I came across an article by Fauzi Ali – Creating Web-Based Augmented Reality With Just 10 Lines of HTML Code (For Beginners – AR.js), in which he describes a simple use of the AR.js JavaScript library for creating augmented reality on the web. In addition to AR.js, the demo also uses A-Frame, which is an open-source web interface for creating virtual or augmented reality in a web browser environment. The third important component of AR applications is the “marker” – that is, some marker/QR code that triggers an AR visualization when you point a mobile phone camera or webcam at it. In this demo, the so-called Hiro marker is used, which is simply “a marker that triggers a certain reaction on the web”. You can have several such markers, you can create your own, etc. I’ll probably come back to this at some point, but for now Hiro will do for me.

Hiro marker

So, if you run the following code (see below), or open this codepen.io site (copy the source code there – maybe if you don’t have your own hosting), and point at the Hiro marker, you’ll see a semi-transparent cube! Wow, your/my first AR visualization!

<!doctype HTML> 
<html> 
<script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script> 
<script src="https://raw.githack.com/jeromeetienne/AR.js/2.0.5/aframe/build/aframe-ar.js"></script> 
<body style='margin : 0px; overflow: scroll;'> 
 <a-scene embedded arjs>  
  <a-box position='0 0.5 0' material='opacity: 0.5;'></a-box>    
  <a-marker-camera preset='hiro'></a-marker-camera> 
 </a-scene>
</body> 
</html>
Example of a semi-transparent cube above the Hiro marker

I’m not an expert (you’ve probably noticed that already), so just a quick rundown of what the code actually says:

<script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script> 
<script src="https://raw.githack.com/jeromeetienne/AR.js/2.0.5/aframe/build/aframe-ar.js"></script>

This will load two important libraries – AR.js and A-Frame (see above).

<a-scene embedded arjs>

We insert from the A-frame library into the HTML and tell A-frame that we want to initialize AR.js with the embedded arjs in . In other words, we create a scene that we can insert other objects into – in this example, it’s a semi-transparent cube:

<a-box position='0 0.5 0' material='opacity: 0.5;'></a-box>

But feel free to insert other geographic features:

<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>

Or maybe a picture

<a-image rotation="-90 0 0" src="https://i.cdn.nrholding.net/43142277/2000/2000"></a-image>

And finally, let’s say that if the camera sees a Hiro marker, it will display that element (cube, image, model, etc).

<a-marker-camera preset='hiro'></a-marker-camera>

Of course, there’s a lot more you can do with it, adding animations, setting up interactions, etc., but I haven’t gotten to that yet. I did try inserting an image – see below, and learning the “rotation” parameter so that the image “looks” at me and isn’t rotated weirdly, etc.

So my first attempt and sample is this (see below) or here: https://www.jirkapanek.cz/ar/mapa/

<!doctype HTML> 
<html>
<script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script> 
<script src="https://raw.githack.com/jeromeetienne/AR.js/2.0.5/aframe/build/aframe-ar.js"></script> 
<body style='margin : 0px; overflow: hidden;'>
  <a-scene embedded arjs>
    <!-- create your content here. just a box for now -->
   <a-image rotation="-90 0 0" src="https://i.cdn.nrholding.net/43142277/2000/2000"></a-image>
    <!-- define a camera which will move according to the marker position -->
    <a-marker-camera preset='hiro'></a-marker-camera>
  </a-scene>
</body> 
</html>
Sample map (picture on the internet) over Hiro marker

Honestly, I thought it would be harder, but I made it through the first step. Yes, it’s just a simple cube/map in space, but it’s a start!

Jirka Panek