С недавних пор начался достаточно оживлённый поток писем с просьбами подготовить изображения для отображения их средствами Яндекс-карт. Немного поразмыслив над причинами этого, удалось выдвинуть вот такую гипотезу.
Яндекс-карты несомненно замечательный сервис. С достаточно развитой инфраструктурой проекта, мощным, порою даже излишне, функционалом и богатой экосистемой, сложившейся вокруг них. Но проект таких габаритов тоже имеет определённые слабости. Например, невозможность равномерного развития, которая и стала спусковым крючком для помянутого потока писем. А истинной, хтонической причиной проблемы стал сделанный некогда инженерами проекта стратегический выбор. Имя этому выбору: WGS84 + non-TMS.
Скачать смотрелкуЕсли смысл аббревиатур от вас ускользнул - не беспокойтесь, это нормально. Сейчас переведу на русский.
А иногда возникает потребность создать свои собственные тайлы для своих карт: схемы зданий, планы участков, гигапиксельную фотографию на зумы разобрать. А то и нарисовать свою собственную планету. Тут потребуются уже весьма специфичные и специальные знания и умения. Яндекс для удобства таких пользователей выпустил утилиту-тайлер (Tiler). Маленькая и надёжная она отлично режет маленькие карты. После небольших шаманств пользовательские карты водружаются поверх базовых карт и все довольны.
Но лишь до тех пор, пока карта не становится сколько-нибудь крупной. Начиная с размера где-то 15к на 15к пикселей, что очень немного, утилита выдаёт ошибку и карт не делает. Обновления утилиты не было. Очевидно Яндекс не признал направление разработки тайлера перспективным. Итоги таковы: описанная грустная история и почти полное отсутствие в экосистеме Яндекс-карт карт пользовательских.
Впрочем, следует сказать что подготовка своих тайлов - дело хлопотное. Но порою без них не обойтись. Для изготовления карт, размещённых на этом сайте, используется техпроцесс, базирующийся на пакете OSGEO (и GDAL, в частности). Этот пакет позволяет сделать топопривзяку растров на местность, используя аэрофотосъёмку, предоставляемую провайдерами сервисов. Затем последовательный запуск ряда утилит командной строки, оформленный в пакетный файл, позволяет сделать нарезку получившихся файлов GeoTIFF в тайлы Яндекс-карт. Или, как альтернативное применение, порезать огромное изображение на тайлы для просмотра с возможностью зума.
Поскольку OSGEO и GDAL проекты международные (а Яндекс - всё же, увы, но местечковый), на самом последнем этапе нарезки используются лучшие международные практики: тайлы подготавливаются для отображения в проекции Sphere Mercator и с Y-ориентацией сетки тайлов в TMS. Таким образом, результат подключения "в лоб", нарезанных при помощи GDAL тайлов, становится немного... э-э-э... обескураживающе обескураживающ.
Выглядит это так:
Это было обстоятельство номер один.
Обстоятельство номер два. В Интернете для решения проблемы подключения своих тайлов к Яндексу распространяется скрипт TilerConverter.js. Как несомненно прогрессивная вещь, он позволяет удобно подключить пользовательские слои, сам инстанциирует карту с надлежащими параметрами и, что очень радует, - действительно показывает пользовательские слои карт.
Но какая же ложка мёда без бочки дёгтя? Вот, например одно из полей объекта конфигурации:
tileUrlTemplate: "http://example.com/%z/%x/%y.png",
вот здесь мы и приплыли - вылезай, сливай керосин.
- Да ладно! - скажут оптимисты, - Всё же работает.
Работает, да. Только платой за эту работу становится утрата целостности среды Яндекс-карт и отрицание того, что: "но, ведь, у всех людей разные лица!".
При этом, надо заметить, что API Яндекс-карт позволяет безо всяких сторонних скриптов отличнейшим образом выводить любые пользовательские тайлы. Далее приведена функция для отображения слоя тайлов на "чистом" API карт Яндекса.
Отсюда начинаются пояснения к коду, находящемуся в ymaps.js.
Ключевым пунктом является функция, обрабатывающая имена тайлов:
ymaps.layer.storage.add('your#map', function () { // (1)
return new ymaps.Layer(function (tile, zoom) {
return zoom + "/" + tile[0] + "/" + (dX[zoom] - tile[1]) + ".png"; // (2)
}, { tileTransparent: 1, zIndex: 1000 });
});
Суть происходящего тут в следующем: в хранилище слоёв помещается функция, возвращающая URL тайла. Вторым параметром передаётся объект свойств этого слоя, он универсален для практически любого случая.
Следует акцентировать внимание на безымянную функцию (1) выше. Она является сердцем механизма для вывода тайлов, подготовленных GDAL (gdal2tiles.py) под управлением Яндекса. В неё передаются собственные координаты тайла и зум.
Возвращает она очень хорошо контролируемую прототипом строку с URL тайла (2), над которым можно производить операции на лету.
Здесь dX[] - хэш коэффициентов, связывающий значение зума и значение поправки для переориентации тайлов из TMS в сетку Яндекса. Задаётся в самом начале функции init() следующим кодом:
var dX = [];
for (var a=0; a < 21; a++){
dX[a] = Math.pow(2, a) - 1;
}
При пересчёте из TMS-ориентации истинный индекс каждого тайла по оси Y находится вычитанием TMS-индекса из (2^zoom - 1). Таким образом, данная реализация позволяет включить поддержку тайлов, сгенерированных в TMS, в Яндекс-картах.
После создания слоя его следует внести в список доступных просмотрщику карт:
ymaps.mapType.storage.add('your#map', new ymaps.MapType('Карта', ['your#map'] ));
а также можно добавить и в пользовательский селектор карт.
Ну и напоследок требуется правильно задать проекцию карты для расчётов:
map = new ymaps.Map("YMapsID",
{center: [-94.6392198798,-40.7223029247], zoom: 6, type: 'your#map', behaviors: ["scrollZoom","drag"]},
{projection: ymaps.projection.sphericalMercator, maxZoom: 7, minZoom: 0, checkZoomRange: false});
Всё остальное можно задавать, сообразуясь со своим вкусом и потребностями приложения.