OpenLayers & OpenStreetMap Examples

HTML Website jQuery OpenLayers OpenStreetMap OpenLayers & OpenStreetMap Examples

Some examples of how to use OpenStreetMap and OpenLayers to show/add GPX functionalities to a map and other interactions.

See the OpenLayers Documentation for more info and examples.

View source on GitHub

Code Snippets

Add the following snippet code to the html of a page.

<script src="https://cdn.maptiler.com/ol/v6.12.0/ol.js"></script>
<script src="vdwwd-openlayers.js"></script>

<div id="map-container">
    <div class="ol-map-container">
        <div id="map" class="ol-map"></div>
        <div id="map-popup" class="ol-popup"></div>
        <div id="map-popup-click" class="ol-popup"></div>
    </div>
</div> 

And to initialize the map and add functions execute on Document Ready.

initMap();
addGpxFromFileUpload();
addGpxFromPoints(demotrack, 'Demo Track', true);
addClickEvent();

The CSS

.ol-map-container {
    width: 100%;
    height: 600px
}

.ol-map {
    width: 100%;
    height: 100%
}

.ol-popup {
    position: absolute;
    background-color: #fff;
    filter: drop-shadow(0 3px 3px rgba(0,0,0,.4));
    padding: 10px;
    border-radius: 10px;
    border: 1px solid #282c41 !important;
    bottom: 12px;
    left: -50px;
    min-width: 100px;
    white-space: nowrap;
    z-index: 9999;
    color: #000;
    font-size: .9rem
}

    .ol-popup:after, .ol-popup:before {
        top: 100%;
        border: solid transparent;
        content: " ";
        height: 0;
        width: 0;
        position: absolute;
        pointer-events: none
    }

    .ol-popup:after {
        border-top-color: #fff;
        border-width: 10px;
        left: 48px;
        margin-left: -10px
    }

    .ol-popup:before {
        border-top-color: #ccc;
        border-width: 11px;
        left: 48px;
        margin-left: -11px
    }

The code inside vdwwd-openlayers.js

var map;
var overlay;
var interaction;
var featureArr;
var $popup;
var styles = {
    'track-red': new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: '#ff0000',
            width: 3,
        }),
    }),
    'track-black': new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: '#000000',
            width: 3,
        }),
    }),
};


//initialize the map
function initMap() {
    if ($('#map').length === 0)
        return;

    $popup = $('#map-popup');

    //create the map object
    map = new ol.Map({
        target: 'map',
        layers: [
            new ol.layer.Tile({
                source: new ol.source.OSM()
            })
        ],
        view: new ol.View({
            center: ol.proj.fromLonLat([5.6461, 52.1008]),
            zoom: 7,
            maxZoom: 16,
            constrainResolution: true
        }),
        controls: []
    });

    //add a custom layer to the map
    //olms.apply(map, 'https://api.maptiler.com/maps/basic/style.json?key=xxsAuwkPOcpryqPQdtC8');

    //create an overlay to anchor the hover popup to the map
    overlay = new ol.Overlay({
        element: document.getElementById('map-popup'),
        autoPan: {
            animation: {
                duration: 250,
            }
        }
    });

    //add the overlay to the map
    map.addOverlay(overlay);

    //add a mousemove function to the map to detect a marker and if found show popup
    map.on('pointermove', function (e) {
        var feature = map.forEachFeatureAtPixel(e.pixel, function (feat, layer) {
            return feat;
        });

        //get the current position of the mouse in pixels relative to the map div container
        //console.log(e.pixel)

        //show the marker info if there is a name property and it has contents
        if (feature && typeof feature.get('name') != 'undefined' && feature.get('name') != null && feature.get('name') !== '') {
            $popup.html(feature.get('name'));
            overlay.setPosition(e.coordinate);
        } else {
            overlay.setPosition(null);
        }
    });
}


//add a marker to the map
function addMarker(id, name, color, lat, lng, draggable, custom_marker, custom_layer) {
    //create a feature
    var feature = new ol.Feature({
        geometry: new ol.geom.Point(ol.proj.fromLonLat([lng, lat])),
        name: name,
        id: id,
        type: 'marker'
    });

    var markerimg = '/images/marker-' + color + '.png';
    if (custom_marker != null && custom_marker !== '') {
        markerimg = custom_marker;
    }

    //create an icon style with an image as marker
    var style = new ol.style.Style({
        image: new ol.style.Icon(({
            anchor: [0.5, 0.5],
            src: markerimg
        }))
    });

    //or create an icon style with a shape as marker
    //var style = new ol.style.Style({
    //    image: new ol.style.Circle({
    //        radius: 10,
    //        stroke: new ol.style.Stroke({
    //            color: 'black',
    //            width: 3
    //        }),
    //        fill: new ol.style.Fill({
    //            color: 'white'
    //        }),
    //    })
    //});

    //add the style to the feature
    feature.setStyle(style);

    //create a layer and add the feature
    var layer = new ol.layer.Vector({
        source: new ol.source.Vector({
            features: [feature]
        }),
        name: name,
        type: 'marker',
        zIndex: 100
    });

    //is there a custom layer
    if (custom_layer != null) {
        custom_layer.getSource().addFeature(feature);
        layer = custom_layer;
    } else {
        //add the layer to the map
        map.addLayer(layer);
    }

    //no draggable marker
    if (!draggable)
        return;

    //add a modifier
    var modify = new ol.interaction.Modify({
        hitDetection: layer,
        source: layer.getSource()
    });

    //needed variables
    var container = document.getElementById('map-container');
    var overlay = modify.getOverlay().getSource();

    //modify handlers
    modify.on(['modifystart', 'modifyend'], function (e) {
        container.style.cursor = e.type === 'modifystart' ? 'grabbing' : 'pointer';
    });

    overlay.on(['addfeature', 'removefeature'], function (e) {
        container.style.cursor = e.type === 'addfeature' ? 'pointer' : '';
    });

    //get the coordinates during drag
    feature.on('change', function () {
        //console.log(ol.proj.toLonLat(this.getGeometry().getCoordinates()));
    }, feature);

    //add the modifier to the map
    map.addInteraction(modify);
}


//load a gpx file from an url
function addGpxFromUrl(url) {

    //create a layer
    var layer = new ol.layer.Vector({
        source: new ol.source.Vector({
            url: url,
            format: new ol.format.GPX()
        }),
        style: function () {
            return styles['track-red'];
        },
        name: 'GpxFromUrl',
        type: 'track',
        zIndex: 100
    });

    //add the layer to the map
    map.addLayer(layer);

    //bind a listeret to the layer (needed becaue loading the source from an url is async)
    layer.getSource().on('addfeature', function (e) {
        //get the coordinates from the layer
        var coords = e.feature.getGeometry().clone().transform('EPSG:3857', 'EPSG:4326');

        //put the coordinates in a html element (to use elsewhere or post it to the server)
        $('#map-gpx').val(JSON.stringify(coords.getCoordinates()[0]));

        //add a marker to the first coordinate
        addMarker(1, 'Starting Point', 'blue', coords.getFirstCoordinate()[1], coords.getFirstCoordinate()[0], false);

        //zoom and fit bounds
        var geom = ol.geom.Polygon.fromExtent(layer.getSource().getExtent())
        geom.scale(1.1);
        map.getView().fit(geom, { size: map.getSize() });
    });
}


//load a gpx file from a string variable
function addGpxFromString(gpx, name, color) {

    //remove the existing layer
    removeLayer(name);

    //create a layer
    var layer = new ol.layer.Vector({
        source: new ol.source.Vector({}),
        style: function () {
            return styles['track-' + color];
        },
        name: name,
        type: 'track',
        zIndex: 100
    });

    //read the features from the gpx
    var features = new ol.format.GPX().readFeatures(gpx, {
        dataProjection: 'EPSG:4326',
        featureProjection: 'EPSG:3857'
    });

    //add the features to the layer
    layer.getSource().addFeatures(features);

    //add the layer to the map
    map.addLayer(layer);

    //get the coordinates from the layer
    var coords = features[0].getGeometry().clone().transform('EPSG:3857', 'EPSG:4326');

    //put the coordinates in a html element (to use elsewhere or post it to the server)
    var $mapgpx = $('#map-gpx');
    $mapgpx.val(JSON.stringify(coords.getCoordinates()));
    $mapgpx.show();

    //add a marker to the first coordinate
    addMarker(1, 'Starting Point', color, coords.getFirstCoordinate()[1], coords.getFirstCoordinate()[0], false);

    //zoom and fit bounds
    var geom = ol.geom.Polygon.fromExtent(layer.getSource().getExtent())
    geom.scale(1.1);
    map.getView().fit(geom, { size: map.getSize() });
}


//enable dragging and dropping a gpx track on the map
function addGpxFromDragDrop() {

    //if an interaction exists remove it first
    if (interaction) {
        map.removeInteraction(interaction);
    }

    //create the interaction
    interaction = new ol.interaction.DragAndDrop({
        formatConstructors: [
            ol.format.GPX
        ],
    });

    //on drag event
    interaction.on('addfeatures', function (e) {
        //create a layer
        var layer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: e.features,
            }),
            style: function () {
                return styles['track-red'];
            },
            name: 'GpxFromDragDrop',
            type: 'track',
            zIndex: 100
        });

        //add the layer to the map
        map.addLayer(layer);

        //get the coordinates from the layer
        var coords = e.features[0].getGeometry().clone().transform('EPSG:3857', 'EPSG:4326');

        //put the coordinates in a html element (to use elsewhere or post it to the server)
        $('#map-gpx').val(JSON.stringify(coords.getCoordinates()[0]));

        //add a marker to the first coordinate
        addMarker(1, 'Starting Point', 'blue', coords.getFirstCoordinate()[1], coords.getFirstCoordinate()[0], false);

        //zoom and fit bounds
        var geom = ol.geom.Polygon.fromExtent(layer.getSource().getExtent())
        geom.scale(1.1);
        map.getView().fit(geom, { size: map.getSize() });
    });

    //add the interaction to the map
    map.addInteraction(interaction);
}


//add a gpx with a html file upload control
function addGpxFromFileUpload() {

    //bind a change event to the control
    $('#map-upload').bind('change', function () {
        var $this = $(this);
        var gpxfile = document.getElementById($this.prop('id')).files[0];

        //create a reader
        var reader = new FileReader();
        reader.onload = function (e) {
            addGpxFromString(e.target.result, 'GpxFromFileUpload', 'red');
        };

        reader.readAsText(gpxfile);
        $this.val('');
    });
}


//add a gpx track from an array of single points [[52.8058, 6.7958], [52.8056, 6.7957], ... ]
function addGpxFromPoints(gpx, name, animate) {

    //openlayers uses [lon, lat], not [lat, lon]
    if (gpx[0][0] > 20 && gpx[0][1] < 20) {
        gpx.map(function (l) {
            return l.reverse();
        });
    }

    //create a geometry from the coordinates
    var geometry = new ol.geom.LineString(gpx).transform('EPSG:4326', 'EPSG:3857');

    //create a layer
    var layer = new ol.layer.Vector({
        source: new ol.source.Vector({
            features: [
                new ol.Feature({
                    geometry: geometry,
                    name: name
                })
            ]
        }),
        style: function () {
            return styles['track-black'];
        },
        name: name,
        type: 'track',
        zIndex: 100
    });

    //add the layer to the map
    map.addLayer(layer);

    //add a marker to the first coordinate
    addMarker(2, name + ' - Start', 'black', gpx[0][1], gpx[0][0], false);

    //zoom and fit bounds
    var geom = ol.geom.Polygon.fromExtent(layer.getSource().getExtent())
    geom.scale(1.1);
    map.getView().fit(geom, { size: map.getSize() });

    //add a line animation
    if (animate) {
        animateLine(geometry, name + ' - Rijrichting');
    }
}


//add multiple markers from an array
function addMultipleMarkers(markerArr, soort) {
    var markerimg = '/images/site/marker-' + soort + '.png';
    var markerimg_hover = '/images/site/marker-' + soort + '-red.png';
    var url = '/toertochten/';

    if (soort === 'club')
        url = '/clubs/';
    else if (soort == 'track')
        url = '/routes/';

    var normalstyle = new ol.style.Style({
        image: new ol.style.Icon(({
            anchor: [0.5, 0.5],
            src: markerimg
        })),
        zIndex: 100
    });

    var hoverstyle = new ol.style.Style({
        image: new ol.style.Icon(({
            anchor: [0.5, 0.5],
            src: markerimg_hover
        })),
        zIndex: 1000
    });

    //create a new layer
    var layer = new ol.layer.Vector({
        source: new ol.source.Vector(),
        style: normalstyle
    });

    //loop all the markers to add popover
    for (var i = 0; i < markerArr.length; i++) {
        var item = markerArr[i];

        layer.getSource().addFeature(
            new ol.Feature({
                geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(item.lng), parseFloat(item.lat)])),
                id: item.id,
                soort: 'icon',
                name: '' + item.naam + '
' + item.regel2 }) ); } featureArr = layer.getSource().getFeatures(); //maak de marker rood on hover var hover = null; map.on('pointermove', function (evt) { map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : ''; if (hover != null) { hover.setStyle(normalstyle); hover = null; } map.forEachFeatureAtPixel(evt.pixel, function (f) { if (f.get('soort') === 'icon') { hover = f; return true; } else { return false; } }); if (hover) { hover.setStyle(hoverstyle); } }); //voeg de laag toe aan de map map.addLayer(layer); //maak de marker clickable map.on('click', (e) => { map.forEachFeatureAtPixel(e.pixel, function (f) { if (f.get('soort') === 'icon') { location.href = url + hover.get('id'); return true; } else { return false; } }); }); //zoom and fit bounds //var geom = ol.geom.Polygon.fromExtent(layer.getSource().getExtent()) //geom.scale(1.1); //map.getView().fit(geom, { size: map.getSize() }); } //add a click event to the map to get the clicked coordinate function addClickEvent() { //create an overlay to anchor the hover popup to the map var clickOverlay = new ol.Overlay({ element: document.getElementById('map-popup-click'), autoPan: { animation: { duration: 250, } } }); //add the overlay to the map map.addOverlay(clickOverlay); //add the click event and show the popup var $popupclick = $('#map-popup-click'); map.on('singleclick', function (e) { //if a popup is open then close it on map click if (clickOverlay.getPosition()) { clickOverlay.setPosition(null); } else { $popupclick.html('

You clicked here:

' + ol.proj.toLonLat(e.coordinate) + ''); clickOverlay.setPosition(e.coordinate); } }); } //add a moving marker to a route function animateLine(route, name) { var speed = 30; var distance = 0; var lasttime; var position = new ol.geom.Point(route.clone().getFirstCoordinate()); var feature = new ol.Feature({ geometry: position, }); var startMarker = new ol.Feature({ geometry: position, }); var endMarker = new ol.Feature({ geometry: position }); //create an icon style with a shape as marker var style = new ol.style.Style({ image: new ol.style.Circle({ radius: 10, stroke: new ol.style.Stroke({ color: 'black', width: 2 }), fill: new ol.style.Fill({ color: 'red' }) }) }); //create a layer with the marker that will move var layer = new ol.layer.Vector({ source: new ol.source.Vector({ features: [feature, startMarker, endMarker], }), name: name, zIndex: 200 }); //add the layer to the map map.addLayer(layer); //function to move the marker function moveFeature(e) { var time = e.frameState.time; distance = (distance + (speed * (time - lasttime)) / 1e6) % 2; lasttime = time; //if the distance > 1 then the end has been reached so restart if (distance > 1) { stopAnimation(); startAnimation(); } //set the new coordinate for the marker position.setCoordinates(route.getCoordinateAt(distance)); //draw it on the map var context = ol.render.getVectorContext(e); context.setStyle(style); context.drawGeometry(position); map.render(); } //start the animation function startAnimation() { distance = 0; lasttime = Date.now(); layer.on('postrender', moveFeature); feature.setGeometry(null); } //stop the animation function stopAnimation() { feature.setGeometry(position); layer.un('postrender', moveFeature); } //start startAnimation(); } //remove a layer from the map function removeLayer(name) { map.getLayers().forEach(layer => { if (layer && layer.get('name') === name) { map.removeLayer(layer); } }); } //add multiple markers from an array and make them clustered function addMultipleMarkersClustered(markerArr, soort) { var markerimg = '/images/site/marker-' + soort + '.png'; var markerimg_hover = '/images/site/marker-' + soort + '-red.png'; var url = ''; //sort the array markerArr.sort((a, b) => a.lat - b.lat) //create the features featureArr = new Array(markerArr.length); var prevmarker; var offsetdefault = 0.0009; var offsettotal = offsetdefault; for (let i = 0; i < markerArr.length; ++i) { var item = markerArr[i]; var point = new ol.geom.Point(ol.proj.fromLonLat([parseFloat(item.lng), parseFloat(item.lat)])); //if the features have the same coordinates move them slightly so they appear next to each other if (item.lng.toFixed(3) + '_' + item.lat.toFixed(3) === prevmarker) { point = new ol.geom.Point(ol.proj.fromLonLat([parseFloat(item.lng) + offsettotal, parseFloat(item.lat)])); offsettotal += offsetdefault; } else { offsettotal = offsetdefault; } featureArr[i] = new ol.Feature({ geometry: point, id: item.id, soort: 'icon', name: '' + item.naam + '
' + item.regel2 }); prevmarker = item.lng.toFixed(3) + '_' + item.lat.toFixed(3); } //create the source var clusterSource = new ol.source.Cluster({ distance: 40, minDistance: 10, source: new ol.source.Vector({ features: featureArr, }) }); //clustered style var zindex = 100; var clusters = new ol.layer.Vector({ zIndex: 1, source: clusterSource, style: function (feature) { const size = feature.get('features').length; //if there are no more clusters you can return a different icon if (size === 1) { //var style = new ol.style.Style(); //return style; } var radius = 12; var textsize = 1; var text = size.toString(); //dynamic cluster marker size calculations if (size > 100) { radius = (size * 0.2); textsize = size / 60; } else if (size > 50) { radius = (size * 0.4); textsize = size / 25; } else if (size > 25) { radius = (size * 0.6); textsize = size / 20; } else if (size > 1) { radius = 15; textsize = 1.3; } //max markercluster size if (radius > 75) { radius = 75; textsize = 5; } var style = new ol.style.Style({ image: new ol.style.Circle({ radius: radius, fill: new ol.style.Fill({ color: 'black' }), stroke: new ol.style.Stroke({ color: 'white', width: 1 }), }), text: new ol.style.Text({ text: text, fill: new ol.style.Fill({ color: '#fff', }), scale: textsize, offsetY: size > 50 ? 2 : 1 }), zIndex: zindex }); zindex++; return style; }, }); //create a tile layer var raster = new ol.layer.Tile({ source: new ol.source.OSM() }); //add the layers to the map map.addLayer(raster); map.addLayer(clusters); //make the marker clickable map.on('click', (e) => { clusters.getFeatures(e.pixel).then((clickedFeatures) => { if (clickedFeatures.length) { //get the clustered coordinates const features = clickedFeatures[0].get('features'); //when there are multiple features do a zoom otherwise handle the click if (features.length > 1) { const extent = ol.extent.boundingExtent( features.map((r) => r.getGeometry().getCoordinates()) ); map.getView().fit(extent, { duration: 1000, padding: [50, 50, 50, 50] }); } else { location.href = url + features[0].get('id'); } } }); }); //show a mouse pointer and popup on hover map.on('pointermove', function (e) { map.getTargetElement().style.cursor = map.hasFeatureAtPixel(e.pixel) ? 'pointer' : ''; clusters.getFeatures(e.pixel).then((hoveredFeatures) => { if (hoveredFeatures.length) { //get the clustered coordinates const features = hoveredFeatures[0].get('features'); //when there is a single features show the popup if (features.length === 1) { if (features[0] && typeof features[0].get('name') != 'undefined' && features[0].get('name') != null && features[0].get('name') !== '') { $popup.html(features[0].get('name')); overlay.setPosition(e.coordinate); } else { overlay.setPosition(null); } } } }); }); }