Использование API Яндекс.Карт для работы с произвольными подложками

в 12:45, , рубрики: api, yandex map api, тайлы, яндекс.карты, метки: , ,

Использование API Яндекс.Карт для работы с произвольными подложками

Что общего у трех картинок сверху? На левой — часть Санкт-Петербурга из OpenStreetMap. На центральной — карта из Lineage 2. На правой — автомобильные пробки Москвы на подложке от Google. А объединяет эти изображения новое API Яндекс.Карт, вышедшее совсем недавно.

Одной из особенностей API 2.0 является очень простая в использовании поддержка произвольных подложек. Вам не обязательно использовать карты Яндекса для своего ресурса. Никто не мешает скрестить подложку от OpenStreetMap и мощное API от Яндекса для реализации функционала карты.

Хотите показать на OpenStreetMap область доставки вашей пиццерии? Расположить на карте очередной MMORPG монстров? Отобразить Яндекс.Пробки на карте от Google? Нет ничего проще!

Пример 1. Яндекс.Пробки + Google.Карты

живой пример

    var map = new ym.Map('map', {
        center: [55.744, 37.587],
        zoom: 12,
        type: null // что-бы не загружался слой "Схема" Яндекс.Карт
    }, {});

    var googleLayer = new ym.Layer('http://mt0.google.com/vt/lyrs=m@176000000&hl=ru&%c', {
        projection: ym.projection.sphericalMercator,
        // указываем проекцию слоя Google.Карт
        tileTransparent: true
    });
    map.layers.add(googleLayer);

    map.controls.add(new ym.control.TrafficControl({
        shown: true
    }), {
        left: 5,
        top: 5
    });

Разберем, что же мы понаписали. В первую очередь стоит обратить внимание на класс Layer, именно с помощью него создаются новые слои карты. Входными параметрами являются шаблон url'а тайлов и опции. Описание формата шаблона есть в документации. В данном же примере интерес представляет опция projection, которая говорит API о проекции слоя. Дело в том, что API Яндекс.Карт использует проекцию WGS 84, которая немного отличается от Spherical Mercator, используемой в OSM и Google. Поэтому при добавлении слоя нужно указать его проекцию, в противном случае, если вы добавите точку по координатам вашего дома, то визуально она может оказаться на стороннем слое не там, где вы ее ожидали увидеть.

Пример 2. OpenStreetMap + Графика API Яндекс.Карт

живой пример

    var map = new ym.Map('map', {
        center: [59.947, 30.325],
        zoom: 13,
        type: null // что-бы не загружался слой "Схема" Яндекс.Карт
    }, {});

    var osmLayer = new ym.Layer('http://otile%d.mqcdn.com/tiles/1.0.0/osm/%z/%x/%y.png', {
        projection: ym.projection.sphericalMercator,
        // указываем проекцию слоя OSM
        tileTransparent: true
    });
    map.layers.add(osmLayer);

    var train = new ym.Placemark([59.928815, 30.362311], {
        hintContent: "Московский вокзал"
    }, {
        preset: "twirl#trainIcon"
    })
    map.geoObjects.add(train);

    var pizza = new ym.Placemark([59.954327, 30.30698], {
        balloonContent: "Пиццерия"
    }, {
        preset: "twirl#cafeIcon"
    })
    map.geoObjects.add(pizza);

    var area = new ym.Circle([[59.954327, 30.30698], 1400], {
        hintContent: "Область доставки"
    }, {
        strokeColor: "#7C444399",
        strokeWidth: 2,
        fillColor: "#FFFFFF66",
        hintHideTimeout: 100
    });

    area.events.add("mouseenter", function(e) {
        this.options.set({
            strokeColor: "#7C4443BB",
            strokeWidth: 4,
            fillColor: "#FFFFFF99"
        })
    }, area);

    area.events.add("mouseleave", function(e) {
        this.options.set({
            strokeColor: "#7C444399",
            strokeWidth: 2,
            fillColor: "#FFFFFF66"
        })
    }, area);

    var geometry = ym.geometry.LineString.fromEncodedCoordinates("-nCSA99KzwFdBwAA0v3__2kBAABk-___" + "SgYAAKHO__8bEQAAQHX__y0BAAB_____8gIAAFcBAAAREAAAXej__-EEAAAo_v__mwIAANH8__9zAwAAdfj__" + "wAJAACBAAAAbgEAAK0BAAAaAgAA2wMAAKAEAAB_____VgAAAAoHAAACAQAArAAAAHcFAAAl_P__" + "3gMAAAAAAAAyAwAA1wAAAMYCAACtAQAAcAIAAFkCAAA="); // закодированая геометрия линии
    var line = new ym.Polyline(geometry, {}, {
        strokeWidth: 2,
        strokeStyle: "longdash"
    });
    map.geoObjects.add(line);

    map.geoObjects.add(area);

    map.copyrights.add({}, [{
        text: '<a href="http://www.mapquest.com/">MapQuest</a>'}]);

    pizza.balloon.open();

Касательно добавления слоя, данный пример мало отличается от предыдущего. Разве что только в шаблоне используются параметры %d, %z, x и %y, а не %c как в первом примере.
Описание параметров есть в документации.

Пример 3. Создание своих карт

живой пример

    // декартова система координат, зацикленая по осям
    var projection = new ym.projection.Cartesian([[0, 0], [100, 100]], [true, true]);

    var layerConstructor = function() {
        var layer = new ym.Layer();
        layer.getTileUrl = function(tile, zoom) {
            var tile = this.restrict(tile, zoom);
            return tile ? "http://mt.gmapuploader.com/tiles/bneaLXS8B7/tile-" + zoom + "-" + (tile[1] * Math.pow(2, zoom) + tile[0]) + ".jpg" : null;
        }
        return layer;
    };
    var lineageMap = new ym.MapType('LineageMap', [layerConstructor]);
    ym.mapType.storage.add('lineage#map', lineageMap);

    var map = new ym.Map('map', {
        center: [45, 54],
        zoom: 1,
        type: "lineage#map"
    }, {
        maxZoom: 6,
        minZoom: 1,
        projection: projection
    });

    var miniMap = new ym.control.MiniMap();
    miniMap.options.set("zoomOffset", 2); // отличие в зуме минкарты от большой карты
    miniMap.setType('lineage#map');

    map.controls.add(miniMap);

    map.controls.add(new ym.control.MapTools(['drag', 'magnifier']));

    var zoom = new ym.control.ZoomControl({
        customTips: [{
            index: 2,
            value: 'мир'},
        {
            index: 5,
            value: 'земли'}]
    });
    map.controls.add(zoom);

    var points = [];
    for (var i = 0; i < 100; i++) {
        var coordinates = [Math.floor(Math.random() * 60) + 20, Math.floor(Math.random() * 60) + 20];
        points[i] = new ym.Placemark(coordinates, {
            hintContent: "point " + i
        }, {
            iconImageHref: "http://wowimg.zamimg.com/images/Mapper/pin-yellow.png",
            iconImageSize: [11, 11]
        });
    }
    var clusterer = new ym.Clusterer();
    clusterer.add(points);
    map.geoObjects.add(clusterer);

Данный пример в корне отличается от двух предыдущих. Начнем с того, что тут мы добавляем слой не через менеджер слоев карты, а через хранилище типов карты. Как видно из названия, нам надо создать тип карты, содержащий в себе наш слой. Который в последствии можно будет задать при инициализации карты type: «lineage#map» и применить к миникарте miniMap.setType('lineage#map').

Слой мы создаем как и в предыдущих примерах, но при этом переопределяем метод getTileUrl, принимающий на вход номер тайла и уровень масштабирования, а возвращающий url до нужного тайла. Дело в том, что возможностей шаблонизатора, задаваемого через параметр tileUrlTemplate, не хватает для работы с Gmap Uploader.

В случае с MMORPG и планами зданий нам нет смысла работать со сферическими координатами, поэтому мы используем Декартову систему координат, которую применяем к карте через опцию projection. Теперь точки добавляются не через долготу и широту, а через простые x и y.

P.S. Чем нарезать тайлы?

Автор: d0lfin

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js