Web Maps from Scratch

Malcolm Meyer

This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.

Web Maps from Scratch

Ohio URISA GIS Education Series 2017 Workshop


"An Introduction to Leaflet, GitHub & Jekyll"


Malcolm Meyer, OVRDC

Jesse Glascock, Pirme 3SG

Jon Woyame, Prime 3SG


Leaflet JS

Publishing with GitHub & Jekyll

What is Leaflet?

JavaScript web mapping API created in 2011 by Vladimir Agafonkin of Cloudmade (now with Mapbox).


Leaflet 1.0.3 was released in January 2017


Open Source

Small & Simple

Hundreds of Plugins

Large Online Community

Prime 3SG Examples

Commerce City plow tracker https://snowtrooper.c3gov.com/

Franklin County election results

Middlesex County demographics

Facebook Live Example

HTML, CSS & JavaScript





Limitations for Rendered Data (GeoJSON, TopoJSON, etc)

Layer Indexing, Layering & Layer Control Limitations


Develop Templates Jekyll/Node JS

Expand Internal Knowledge

Focus Web Apps or use Hosted Data (Esri, Mapbox, CARTO)

Use a Plugin or use a Custom Layer Control


Programming Language for the Web and Beyond

What JavaScript looks like

 { "type": "FeatureCollection",
    "features": [
      { "type": "Feature",
         "geometry": {
           "type": "Polygon",
           "coordinates": [
             [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
               [100.0, 1.0], [100.0, 0.0] ]
         "properties": {
           "prop0": "value0",
           "prop1": {"this": "that"}


Let's Make a MAP!!

    <title>Leaflet Map Intro</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Leaflet -->
    <link rel="stylesheet" href="_leaflet/plugins/leaflet/leaflet.css" />
    <script src="_leaflet/plugins/leaflet/leaflet.js"></script>
    <!-- Plugins -->
    body,html {height:100%;width:100%;margin:0;}
    #map {width:100%;height:100%;background:whitesmoke;}
<div id="map"></div>
/*Our Leaflet Map Here*/

Fullscreen Map

var map = L.map("map");

map.setView([40.3,-96.6], 5);

L.hash(map); //plugin

L.control.scale().addTo(map); //built-in function

//built-in function
var layerControl = L.control.layers().addTo(map);

Basic Leaflet Map


Basic Leaflet Map


/*Easily add basemaps or baselayers with L.tileLayer 
WMS layers can also be added with L.tileLayer.wms */

var tileUrl = 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png';
var attribution = '© OpenStreetMap, Tiles courtesy of Humanitarian OpenStreetMap Team';

var OpenStreetMap_HOT = L.tileLayer(tileUrl, {
  maxZoom: 19,
  attribution: attribution

layerControl.addBaseLayer(OpenStreetMap_HOT, "Streets");

Adding Tile Layers (Basemaps)

Adding Tile Layers (Basemaps)

// Load data with leaflet-omnivore, then add it to 
// our empty counties layer

var url = "tutorial-data/counties.topojson";

var counties = L.geoJson().addTo(map);

layerControl.addOverlay(counties, "Counties");

var cData = omnivore.topojson(url, null, counties);

Add Data Layers

Add Data Layers

var counties = L.geoJson(null, {
    style: function(feature) {
	switch(feature.properties.winner) {
	    case "Trump": return {fillColor: "red"}
	    default	: return {fillColor: "blue"}
    onEachFeature: function(feature, county) {
	var info = county.feature.properties.NAME + 
        "<br>" + county.feature.properties.winner;

Styling & Interaction

Styling & Interaction

var url2= "tutorial-data/airports.geojson"

var aStyle= {
    color: "black",
    radius: 5,
    weight: 0, 
    fillOpacity: 1, 
    pane: "markerPane" };

var airports = L.geoJson(null, {
    pointToLayer: function(feature, latlng) {
	return L.circleMarker(latlng, aStyle)

var aData= omnivore.geojson(url2, null, airports);

Styling Points

Styling Points

Leaflet Plugins

// Once our county data is loaded,
// add search functionality using
// leaflet-search with default settings

cData.on("ready", function() {

    var searchControl = new L.Control.Search({
	layer: counties,
	propertyName: 'NAME'

Searching Layers

Searching Layers

var choropleth;

cData.on("ready", function() {
    choropleth = L.choropleth(cData.toGeoJSON(), {
	valueProperty: "POP_SQMI",
	scale: ["white","#006d2c"],
	steps: 7,
        mode: "q",
	style: {color: "#fff",weight: 1,fillOpacity: 0.9},
        onEachFeature: function(feature, county) {
            var name = feature.properties.NAME;



*legend code not shown in previous page

var airportJson;

aData.on('ready', function() {
    airportJson = aData.toGeoJSON();

var highlightStyle = { 
    color: "goldenrod", 
    fillColor: "goldenrod", 
    opacity: 1, 
    fillOpacity: 1, 
    pane: "markerPane"

var highlight = new L.geoJson(null, {
    pointToLayer: function(feature, latlng) {
	return new L.circleMarker(latlng, highlightStyle)

counties.on("mouseover", function(e) {
    var selLayer = new L.geoJson(e.layer.toGeoJSON());
    var within = turf.within(airportJson, selLayer.toGeoJSON());

Turf GIS Analysis

Turf GIS Analysis

hovering over a county highlights the points inside that county

Part II 

Building a Web Map Publishing Platform with GitHub & Jekyll

GitHub is a code hosting platform for version control and collaboration. It offers free web hosting for small projects and has built-in support for Jekyll and GeoJSON.

Jekyll is a "simple, blog aware, static site generator", based on Ruby, with Markdown support. Jekyll uses the Liquid templating language and yaml for config files.

How and Why use GitHub & Jekyll?

  • Page Templates
  • Code Backup
  • Simple Hosting
  • No Databases to Manage
  • Static Sites are AWESOME!
  • Example

GitHub Web Publishing


Free Hosting!!

Raw HTML, CSS & JavaScript

Jekyll Sites

Built-In Themes

Third-Party Integration

Editable by Multiple Users




Limited Size & Capacity on Free Accounts

Free Repositories are Public 

Choosing & Building the Map Template




Is This the Best We Can Do?

Why Reinvent the Wheel?

Templates from Esri & Google

Material Maps

  • Simple Structure
  • One Map Layout
  • Gallery Layout
  • Maps are a Jekyll 'Collection'
  • Similar template in use at OVRDC

Material Maps Live


Malcolm Meyer



Jesse Glascock



Jon Woyame