MapServer UTFGrid + OpenLayers 3

Решенные задачи, первая запись - описание решения.
Ответить
Аватара пользователя
Denis Rykov
Гуру
Сообщения: 3323
Зарегистрирован: 11 апр 2008, 21:09
Статьи: 33
Проекты: 9
Репутация: 494
Ваше звание: Author
Контактная информация:

MapServer UTFGrid + OpenLayers 3

Сообщение Denis Rykov » 01 ноя 2016, 10:10

MapServer начиная с 7 версии умеет отдавать данные в формате UTFGrid, подробнее. Так вот, очень часто возникает вопрос о том, как этим вообще пользоваться, например, в связке с OpenLayers 3. И хотя на сайте OpenLayers есть пример подключения UTFGrid, всё равно остаётся ряд моментов, которые требуется прояснить дополнительно.

1. TileJSON. Согласно документации за поддержку UTFGrid со стороны OpenLayers отвечает класс ol.source.TileUTFGrid (Layer source for UTFGrid interaction data loaded from TileJSON format). Мы видим, что тут возникает упоминание некоего TileJSON формата, с которым большинству до этого сталкиваться не приходилось. Что же это за формат? А это очередное изобретение Mapbox, представляющее собой формат описания тайловых наборов, репозиторий. Всё что нам пока нужно знать - это то, что в этом формате можно описать URL-ы до обычных тайлов и до тайлов UTFGrid, например:

Код: Выделить всё

{
    "version": "1.0.0",
    "tiles": [
        "https://a.tiles.mapbox.com/v4/mapbox.geography-class/{z}/{x}/{y}.png",
        "https://b.tiles.mapbox.com/v4/mapbox.geography-class/{z}/{x}/{y}.png"
    ],
    "grids": [
        "https://a.tiles.mapbox.com/v4/mapbox.geography-class/{z}/{x}/{y}.grid.json",
        "https://b.tiles.mapbox.com/v4/mapbox.geography-class/{z}/{x}/{y}.grid.json"
    ]
}
2. MapServer Tile Mode. Как видно из предыдущего пункта нам каким-то образом нужно научить отдавать MapServer UTFGrid по переданным значениям xyz. MapServer умеет это делать с помощью режима Tile Mode о чём я писал тут. Единственная проблема - если один и тот же mapfile используется у нас и для обычных (растровых) и для UTFGrid тайлов, то как указать нужный формат в запросе? На помощь приходит возможность MapServer передавать значения переменных через URL. Предположим, что у нас есть mapfile utfgrid.map следующего содержания (кстати, вполне рабочий):

Код: Выделить всё

MAP
    IMAGETYPE UTFGRID
    SIZE      2000 2000
    EXTENT    75.0819396972656 49.0830841064453 89.8699798583984 57.2502746582031
    NAME      geosample

    PROJECTION
        "init=epsg:4326"
    END

    OUTPUTFORMAT
        NAME         "png"
        EXTENSION    "png"
        MIMETYPE     "image/png"
        DRIVER        AGG/PNG
        IMAGEMODE     RGBA
        FORMATOPTION "INTERLACE=OFF"
    END

    OUTPUTFORMAT
        NAME         "utfgrid"
        MIMETYPE     "application/json"
        DRIVER        UTFGRID
        EXTENSION    "json"
        FORMATOPTION "UTFRESOLUTION=4"
        FORMATOPTION "DUPLICATES=false"
    END

    LAYER
        CONNECTIONTYPE postgis 
        NAME           admin
        CONNECTION    "host=gis-lab.info dbname=geosample user=guest password=guest"
        DATA          "the_geom from admin using srid=4326"
        TYPE           POLYGON
        UTFITEM        gid
        UTFDATA       "{\"gid\":\"[id]\",\"name\":\"[name]\"}"

        CLASS
            NAME admin
            STYLE
                COLOR 100 100 100
            END
        END

    END
END
Тогда TileJSON описание (поместим его, например, в файл tile.json, а сам файл разместим на веб сервере) будет иметь вид:

Код: Выделить всё

{
    "version": "2.1.0",
    "tiles": [
        "http://localhost:8001/cgi-bin/mapserv?map=utfgrid.map&layers=admin&mode=tile&tile={x}+{y}+{z}&tilemode=gmap&map.imagetype=png"
    ],
    "grids": [
        "http://localhost:8001/cgi-bin/mapserv?map=utfgrid.map&layers=admin&mode=tile&tile={x}+{y}+{z}&tilemode=gmap&map.imagetype=utfgrid"
    ]
}
3. OpenLayers. Пример подключения в OpenLayers:

Код: Выделить всё

var mapLayer = new ol.layer.Tile({
    source: new ol.source.TileJSON({
        url: 'http://localhost:8001/tile.json'
    })
});

var gridSource = new ol.source.TileUTFGrid({
    url: "http://localhost:8001/tile.json"
});

var gridLayer = new ol.layer.Tile({source: gridSource});

var map = new ol.Map({
    layers: [mapLayer, gridLayer],
    target: 'map',
    view: new ol.View({
        center: [9449777.3, 6914882.51],
        zoom: 7
    })
});

map.on('click', function(evt) {
    var viewRes = map.getView().getResolution();
    gridSource.forDataAtCoordinateAndResolution(evt.coordinate, viewRes, function (data) {
        console.log(data);
    });
});
В данном случае при подключении слоя gridLayer на карту - для каждого растрового тайла автоматически загрузятся UTFGrid описания, которые для примера мы выводим в консоль по клику на карте.

Важно. Растровые тайлы и UTFGrid не связаны между собой ничем, кроме как адресацией xyz. То есть в данном примере наш TileJSON файл мог не содержать секцию "tiles", в этом случае мы бы просто подключали растровые тайлы не через ol.source.TileJSON, а, например, через ol.source.XYZ.

UPD.: как мне тут подсказывают - в случае с ol.source.TileUTFGrid можно не создавать отдельный файл tile.json, а передать его параметры непосредственно при инициализации хранилища:

Код: Выделить всё

var gridSource = new ol.source.TileUTFGrid({
    tileJSON: {
        "version": "2.1.0",
        "tiles": ["http://localhost:8001/cgi-bin/mapserv?map=utfgrid.map&layers=admin&mode=tile&tile={x}+{y}+{z}&tilemode=gmap&map.imagetype=png"],
        "grids": ["http://localhost:8001/cgi-bin/mapserv?map=utfgrid.map&layers=admin&mode=tile&tile={x}+{y}+{z}&tilemode=gmap&map.imagetype=utfgrid"]
    }
});
Spatial is now, more than ever, just another column- The Geometry Column.

Ответить

Вернуться в «Рецепты»