0

Based on the answer given to Use OpenLayers to display local raster tiles, I have created a prototype implementation using OpenLayers (v7) with an IIIF tile source to display a set of custom tiles.

However, the scaling of the tiles is slightly wrong, as is the extent of the map.

My proof-of-concept code displays a set of tiles which are generated from a 2000x2000px image I captured of an OSM map of London with a GPX route overlay. There are 3 zoom levels of tiles which are hosted in an S3 bucket. I've also loaded in the actual OSM map tiles in a different layer using ol.source.OSM. The custom tiles containing the GPX overlay are too small and do not line up with the OSM layer.

Here's the JS code:

//sample map config
const config = {
    name: 'z_london_test',
    map:{
        width: 2000, // Map image width in pixels
        height: 2000, // Map image height in pixels
        lat_top: 51.449620948774374, // Latitude of North bound of map
        lon_left: -0.11981964111328126, // Longitude of West bound of map
        lat_bottom: 51.42286816395111, // Latitude of South bound of map
        lon_right: -0.07690429687500001, // Longitude of East bound of map
        lat_centre: 51.43624455636274, //map centre
        lon_centre: -0.09836196899414064
    }
}


const _map = 'map',
    projection = 'EPSG:3857',
    minZoom = 14,
    maxZoom = 16,
    initialZoom = 16,
    tileWidth = 256,
    tileHeight = 256,
    tileSize = [tileWidth,tileHeight],
    content_root = 'https://workingedge-public-test-bucket.s3.eu-west-1.amazonaws.com/'+config.name+'/',
    tiles_root = content_root + 'tiles/',
    urlTemplate = tiles_root + '{z}/{y}/{x}.png';

let map, view, tileLayer, geolocation;


initMap = () => {

    const ne_bound = ol.proj.fromLonLat([config.map.lon_right, config.map.lat_top]),
        se_bound = ol.proj.fromLonLat([config.map.lon_left, config.map.lat_bottom]),
        extent = se_bound.concat(ne_bound);

    view = new ol.View({
        projection: projection,
        center: ol.proj.fromLonLat([config.map.lon_centre, config.map.lat_centre]),
        minZoom: minZoom,
        maxZoom: maxZoom,
        zoom: initialZoom,
        extent: extent
    });


    const source = new ol.source.IIIF({
        size: [config.map.width, config.map.height],
        extent: extent,
        projection: projection,
        tileSize: tileSize,
        resolutions: [1, 2, 4],
    });

    source.setTileUrlFunction(function(tileCoord) {
        let z = tileCoord[0],
            x = tileCoord[1],
            y = tileCoord[2];
        const result = urlTemplate
            .replace('{z}', z.toString())
            .replace('{x}', x.toString())
            .replace('{y}', y.toString());
        return result;
    });

    tileLayer = new ol.layer.Tile({
        title: 'Tile Layer',
        type: 'overlay',
        visible: true,
        extent: extent,
        source: source
    });

    const overLayLayers = [
        tileLayer,
    ];

    const overlayGroup = new ol.layer.Group({
        title: 'Tile Map',
        combine: true,
        layers: overLayLayers
    })

    // Base
    const osmLayer = new ol.layer.Tile({
        title: 'OpenStreetMap',
        type: 'base',
        source: new ol.source.OSM()
    })

    const baseLayers = [
        osmLayer,
    ];

    const baseGroup = new ol.layer.Group({
        title: 'OSM',
        combine: true,
        visible: true,
        layers: baseLayers
    })

    map = new ol.Map({
        target: _map,
        layers: [baseGroup, overlayGroup],
        view: view
    });

    const layerSwitcher = new ol.control.LayerSwitcher({
        reverse: true,
        groupSelectStyle: 'group'
    });
    map.addControl(layerSwitcher);
}


init = () => {
    initMap();
}

$(document).ready(init);

How can I fix this so the custom tiles align with the OSM layer and the map bounds are constrained to the extent of the custom tiles?

For ease of demonstration, I've created a CodePen containing the above code to illustrate this: https://codepen.io/dpa99c/pen/jOxogqX

0

1 Answer 1

2

As you only have tiles for a single zoom level I got it to work by setting the resolution for for that, then in the urlFunction added one to the tileCoord[0] as your tiles urls have z set to 1

const source = new ol.source.IIIF({
    size: [config.map.width, config.map.height],
    extent: extent,
    projection: projection,
    tileSize: tileSize,
    resolutions: [(extent[2] - extent[0]) / config.map.width],
});

source.setTileUrlFunction(function(tileCoord) {
    let z = tileCoord[0] + 1,
        x = tileCoord[1],
        y = tileCoord[2];
    const result = urlTemplate
        .replace('{z}', z.toString())
        .replace('{x}', x.toString())
        .replace('{y}', y.toString());
    return result;
});

https://codepen.io/mike-000/pen/KKRjQba

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.