This page provides you with shippets of generic code that is ready to just copy and paste for your own use. I will add to this as the course progresses.
- Library Links
- A Blank Leaflet Map
- A Blank Leaflet Map Using Events
- AJAX
- Comments
- Conditional Statements
- Coordinate Transformation (
Proj4js
) - Firebase
- Functions
- GeoJSON
if
statements- Objects
- Operators
- Thousands Separators
- Variables
XMLHTTP
Objects
Library Links
Here is how to add the libraries that we use in this course
<!-- Leaflet -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"></script>
<!-- Proj4js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
<!-- Turf.js -->
<script src="https://npmcdn.com/@turf/turf/turf.min.js"></script>
<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-database.js"></script>
<!-- Chart.js -->
<script src="https://www.chartjs.org/dist/2.9.3/Chart.min.js"></script>
A Blank Leaflet Map
This is the basic template with which you can start weeks 1 and 2 - Do not use from week 3 onwards
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>GIS and the Web</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"></script>
<style>
/* set the web page to full size */
html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
/* set the map to full page */
#map {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<!-- A division to hold the map -->
<div id='map'></div>
<script>
// this is a variable that holds the map
const map = L.map('map');
// this is a variable that holds the coordinates of the map centre
const mapCentre = L.latLng(53.466502, -2.235387);
// set the map to use the above coordinates, and to zoom level 16
map.setView(mapCentre, 16);
// this is a variable that holds a reference the tiles that will be used for the basemap
const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'});
//add the tiles to the map
tiles.addTo(map);
</script>
</body>
</html>
A Blank Leaflet Map Using Events
This is a better basic template with which you can start weeks 3-12
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>GIS and the Web</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"></script>
<style>
/* set the web page to full size */
html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
/* set the map to full page */
#map {
width: 100%;
height: 100%;
}
</style>
</head>
<body onload="initMap();">
<!-- a division to hold the map -->
<div id='map'></div>
<script>
// global variable for map
let map;
/**
* Initialise the map (called when the body has loaded)
*/
function initMap() {
// this is a variable that holds the map
map = L.map('map');
// set the map to use the above coordinates, and to zoom level 16
map.setView(L.latLng(53.466502, -2.235387), 16);
// this is a variable that holds a reference the tiles that will be used for the basemap
const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'}).addTo(map);
}
</script>
</body>
</html>
AJAX (XMLHttpRequest
Object)
For accessing JSON data asynchoronously via HTTP…
/**
* Make a request for JSON over HTTP, pass resulting text to callback when ready
*/
function makeRequest(url, callback) {
//initialise the XMLHttpRequest object
var httpRequest = new XMLHttpRequest();
//set an event listener for when the HTTP state changes
httpRequest.onreadystatechange = function () {
//a successful HTTP request returns a state of DONE and a status of 200
if (httpRequest.readyState === XMLHttpRequest.DONE && httpRequest.status === 200) {
callback(JSON.parse(httpRequest.responseText));
}
};
//prepare and send the request
httpRequest.open('GET', url);
httpRequest.send();
}
You then call that function, passing the URL where the JSON data is located, and a callback function to which the data will be passed when the data is ready:
/**
* This is a normal function that will be used as the callback
*/
function myCallback(jsonData){
// jsonData contains the parsed data in JSON format
// do something with it here
}
//get the journey data and add to the map when ready
makeRequest(url, myCallback);
Comments
As a rule of thumb, well-written code should be roughly one-third code, one-third comments, and one third whitespace. Programmers call this the Rule of Thirds.
Doc comment (should be used at the top of each function):
/**
* Everything here is a comment.
*/
Multiline comment (should be used for sections of code):
/*
Everything in here is a comment.
*/
/* Also works like this */
Single line comment (should be used for every individual line):
// This is a comment
Conditional Statements
Conditional statements allow your code to make decisions about whether or not to run, or what to do based upon different conditions.
if
Statements
if
statements are the most common variant of conditional statement, and take this form:
if (condition1) {
// statement 1;
} else if (condition2) {
// statement 2
} else if (condition3) {
// statement 3
} else {
// statement 4
}
else if
allows unlimited extra conditions to be tested, whereas else
simply allows for a default action in case all of the conditions evaluate to false
. Similarly condition2
will only be tested if condition1
evaluates to false
, as soon as one evaluates to true
the rest of the if
statement will be ignored.
Here is a slightly more realiistic example:
// greet the visitor with an alert box
if (language === "German") {
alert("Guten Tag");
} else if (language === "English") {
alert("Hello");
} else if (language === French) {
alert("Bonjour")
} else {
alert("Sorry, I don't speak" + language);
}
This will open an alert saying “Hello”.
Coordinate Transformation using Proj4js
To use proj4js
to transform coordinates, you need to get the proj4 strings for the CRSs that you want to use. You can get them by searching online, from websites like this or this.
// store the proj4 string for the CRS that you are transforming FROM
// this one is WGS84 (what Leaflet is using)
const p_wgs84 = "+proj=longlat +datum=WGS84 +no_defs";
// store the proj4 string for the CRS that you are transforming TO
// this one is British National Grid
const p_osgb = "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 +units=m +no_defs";
// use those proj4 strings to create a proj4 object
const transformer = proj4(p_wgs84, p_osgb);
Now we have our object, it’s time to use it! proj4
objects contain two functions:
.forward() |
transform between the first coordinate reference system and the second (wgs84 to osgb in our case) |
.inverse() |
transform between the second coordinate reference system and the first (osgb to wgs84 in our case) |
You pass coordinates to the functions as an array in the form [ longitude, latitude ]
.
The transformation itself is as simple as:
// transform coordinates to OSGB
let xy = transformer.forward([-2.345, 53.456]);
//xy[0] = longitude;
//xy[1] = latitude;
Events
To add an event to an HTML element, you just need to use the relevant attribute in the opening tag:
<!-- Set the listener for the load event -->
<body onload='initMap();'>
<!-- Set the listener for the click event -->
<button onclick="alert('You clicked my button!');">Go on, give me a click...</button>
To add listeners to a Leaflet Map, simply use the map.on()
function:
// add listener for click event on the map
map.on('click', onMapClick);
Then you just need a listener, which is a function that takes a single argument (the event object):
/**
* Event handler for map click
*/
function onMapClick(e) {
// add a popup to the marker and open it
console.log( "you clicked at " + e.latlng );
}
You can also add events to other map elements, such as GeoJSON layers (click for example).
Firebase
Firebase is an online nosql database service offered by Google.
Anonymously sign in to Firebase
// sign in anonymously - this helps stop your database being abused
firebase.auth().signInAnonymously().catch(function(error) {
console.log(error.code);
console.log(error.message);
});
Get a reference to a particular collection in Firebase
This gets a reference to a collection called "clicks"
// create a global reference to the 'clicks' collection in your database
myDb = firebase.database().ref().child('clicks');
Adding some GeoJson to Firebase
// push the data into the database, set inline callback
myDb.push(data, function(error) {
//if no error is returned to the callback, then it was loaded successfully
if (!error) {
console.log("successfully added to firebase!");
// otherwise pass the error to the console
} else {
console.error(error);
}
});
Deleting some data from Firebase
In this example we are updating a marker location based upon a click
event
// prepare the data to update in the database (deleting is done by updating to null)
let updates = {};
updates['/clicks/' + snapshot.key] = null; //snapshot is the database snapshot
// update the point location in the database and callback to console
firebase.database().ref().update(updates, function(error) {
if (!error) {
console.log("successfully deleted point!");
} else {
console.error(error);
}
});
Updating some data in Firebase
In this example we are updating some data in firebase
// prepare the data to update in the database
let updates = {};
updates['/clicks/' + snapshot.key] = data; //snapshot is the database snapshot
// update the point location in the database and callback to console
firebase.database().ref().update(updates, function(error) {
if (!error) {
console.log("successfully updated firebase!");
} else {
console.error(error);
}
});
Getting all of the data from Firebase at once
//get a snapshot containing everything in the database
myDb.once("value").then(function (snapshot) {
//extract the result
var dataset = snapshot.val();
console.log(dataset);
//get an array containing the keys
var keys = Object.keys(dataset);
console.log(keys);
//loop through everything in the array by key
for (var j = 0; j < keys.length; j++){
console.log( dataset[keys[j]] );
}
/* --ALTERNATIVELY-- */
//get an array containing all of the the values in the dataset
var values = Object.values(dataset);
});
Functions
Functions must first be declared, this tells the browser what they do and what arguments they require, but does not actually do anything else:
/**
* Add two numbers together
*/
function addUp(arg1, arg2) {
return arg1 + arg2;
}
To make the function actually run, you must then call it:
//get my name from the function and store it in a variable called result
var result = addup(2, 4);
//result = 6
GeoJSON
GeoJSON is a spatial data format commonly used for web applications.
You can add it to a map like this:
// load the geojson data, style it, set events and add to map
geojson = L.geoJson(countries, { }).addTo(map);
You can add it with a global style like this:
// load the geojson data and style it
geojson = L.geoJson(countries, {
style: {
weight: 0.5,
color: 'white',
fillOpacity: 1,
fillColor: 'lightgrey',
}
}).addTo(map);
You can add it with a dynamic style (based upon property values) like this:
geojson = L.geoJson(countries, {
style: style, //set the style using a function
}).addTo(map);
/**
* This function styles the data (a single country)
*/
function style(feature) {
//return a style
return {
weight: 0.5,
color: 'white',
fillOpacity: 1,
fillColor: getColour(feature.properties.POP_EST) //the colour is set using a function
};
}
GeoJSON and Events
Events can be added to each individual feature in a GeoJSON layer using thre onEachFeature
option, which calls a specified function once for each feature in the GeoJSON dataset:
// load the geojson data, style it, set events and add to map
geojson = L.geoJson(countries, {
style: style, //set the style using your function
onEachFeature: setEvents, //set the hover events using your function
}).addTo(map);
You then add events to a GeoJSON layer just as you would the map or anything else in leaflet: using the .on()
function.
/**
* Create a function to tie the mouseover and mouseout events to re-styling the layer
*/
function setEvents(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
});
}
Objects
Objects in JavaScript are created using constructors. For example, coordinates are stored in Leaflet using a LatLng
object, which can be made using a constructor like this:
const latlng = L.latLng(50.5, 30.5);
Operators
An operator is a mathematical symbol that produces a result based upon two values (which are normally stored in variables). In the following table you can see some of the simplest operators, along with some examples:
Operator | Explanation | Symbol(s) | Example |
---|---|---|---|
add/concatenate | Used to add two numbers together, or concatenate two strings together. | + |
6 + 9; "Hello " + "world!" ; |
subtract, multiply, divide | These do what you’d expect them to do in basic maths. | - , * , / |
9 - 3; 8 * 2; 9 / 3; |
assignment operator | You’ve seen this already, it assigns a value to a variable. | = |
myVariable = "Bob"; |
identity operator | Does a test to see if two values are equal to one another, and returns a true/false (Boolean) result. | === |
myVariable = 3; myVariable === 4; (false ) |
negation, not equal | Returns the logically opposite value of what it preceeds; it turns a true into a false, etc. When it is used alongside the equality operator, the negation operator tests whether two values are not equal. |
!, !== |
myVariable = 3; !(myVariable === 3); (false ) myVariable = 3; myVariable !== 3; (false ) |
greater than, less than | these operators compare the operands and determine whether the one to the left is greater than (> ) or less than (< ) the one on the right. When combined with an equals ( >= , <= ), the meaning changes to greater than or equal to or less than or equal to respectively. |
> , >= , < , <= |
var2 > var1 var1 <= var2 |
increment, decrement | ++ , -- |
Adds one to and subtracts one from its operand respectively. If used as a prefix operator (++x ), returns the value of its operand after adding one; if used as a postfix operator (x++ ), returns the value of its operand before adding one. |
If x is 3, then ++x sets x to 4 and returns 4, whereas x++ returns 3 and, only then, sets x to 4. |
Thousands Separators
Covert numbers like 1234567
to more easily readable formats like 1,234,567
with this simple toLocaleString()
function.
// add thousands separators to a string representing a number
parseFloat(numberAsString).toLocaleString('en-GB');
// add thousand separators to a number (results in a string)
number.toLocaleString('en-GB');
Variables
// if you DON'T want to edit the value
const myVariable = "Jonny";
// if you DO want to edit the value
let myVariable = "Jonny";
Basic Variable Types:
Variable | Explanation | Example |
---|---|---|
String | A string of text. To signify that the variable is a string, you should enclose it in quote marks. | let myVariable = "Bob"; |
Number | A number. Numbers don’t have quotes around them. | let myVariable = 10; |
Boolean | A True/False value. The words true and false are special keywords in JavaScript, and don’t need quotes. |
let myVariable = true; |
Variables can also hold functions, objects and arrays.