Клуб API Карт

API Яндекс.Карт искажает тайлы (всё плывёт и становится нечётким)

Пост в архиве.

Перешёл с Leaflet на API Яндекс.Карт. Рисую собственную карту. Беда пришла откуда не ждали - кастомные тайлы на Яндекс.Карте искажаются, по всей видимости из-за масштабирования этих самых тайлов, в результате размер отличается от 256х256 (пусть даже на 1 пиксель) и чёткая картинка размыливается.

 

Сравниваем.

 

Вот Leaflet, всё чётко (и в Google Maps API тоже чётко):

 

 

А вот Яндекс:

 

 

Текст в красном кружке размазан. Наглядно видно на анимации:

 

 

Пример живьём:

- Leaflet: http://cycletrailmap.romanshuvalov.com/leaflet.html

- Яндекс: http://cycletrailmap.romanshuvalov.com/

 

Баг зависит от размеров окна, иногда он есть, иногда нет. Для воспроизведения плавно поизменяйте размер окна браузера. На Leaflet ничего не произойдет, а на Яндексе тайлы "поплывут" примерно как на гифке. Проявляется и в Firefox, и в Chromium. Интересно, что баг проявляется только на собственных тайлах - если выбрать стандартный слой Яндекс.Карт - ничего не плывёт.

 

Такие дела.

 

10 комментариев

Все работает правильно, потому что "работает".

Вы поставили проекцию слою, и он подстраивается под другую проекцию карты. Поставьте проекцию самой карте - и они со слоями заживут дружно и без искажений.

Ошибка была даже не в не туда поставленной проекции, а в том, что проекция неправильно выбрана. Тайлы мои (и OpenCycleMap) WGS84, а выставлена была сферическая. Наверное, из чьего-то чужого примера.

Проблема вроде как решена, спасибо.

А, нет, оказыается проекция действительно долждна быть Spherical, иначе координаты съезжают не туда. И пример взят, собственно, с документации: https://tech.yandex.ru/maps/doc/jsapi/2.0/ref/reference/projection.sphericalMercator-docpage/

 

То есть надо ловить событие смены слоя и для всей карты менять проекцию.

Интересный, кстати, кейс получается. Только не факт что работать будет.

При смене проекции на уровне карты гораздо проще новую карту создать (и/или "передобавить" все обьекты на нее), так как гео и пиксельные координаты теряют связь свою.

Гляньте: http://cycletrailmap.romanshuvalov.com/

 

После выставления правильной проекции слои перестали плыть, но появился еще один баг - при переключении слоёв точка обзора смещается по вертикали (по широте)! Причём, что меня полностью ввело в ступор, координаты отображаются как будто бы верные (их видно в адресной строке). И поиск работает как надо - ищем "Тольятти", получаем метку ровно в центре города. Которая при переключении слоёв смещается вместе с картой.

 

Не понятно, почему смещается карта, и почему при этом координаты центра остаются прежними?

Объектов на карте нет и не будет. Мне не понятно, почему setCenter() с одними теми же координатами (53.4000,49.7000) указывает в разные точки.

 

И почему центр города Тольятти на разных слоях имеет разную широту - 53.6926 на сферической проекции OpenStreetMap и 53.5089 на проекции WGS84 Яндекса. update: 53.5089 правильная, то есть Яндекс как будто некорректно отображает Spherical проекцию, но геопоиск-то работает верно (тайлы грузятся правильные).

 

Я не против, что теряются связь с пикселями, но я оперирую геокоординатами и только ими. Они-то почему разные?

Потому что сами слои существуют в пиксельном мире. Все сложно.

Геокоординаты всегда одинаковые, но карта в глубинах своих оперирует пикселями. В том числе если вы ей установите центр, поменяете проекцию, и спросите центр - он измениться.

Да нет же, я говорю про то, что геокоординаты смещаются относительно карты. Смотрите:

1) OpenCycleMap, проекция Spherical



2) Яндекс, проекция WGS84



В адресной строке видно, что широта (первая координата) сильно отличается. При этом геокодирование работает - г. Тольятти найден и отмечен балуном в правильном месте.

У меня подозрение, что это всё-таки баг JS API: карта не умеет менять проекцию на лету. Работает только с той, что указана при создании. Сейчас указана Spherical, поэтому яндекс-карта врёт координатами. Если по умолчанию указать WGS84 -  то врать будет уже OpenCycleMap.

И это не смотря на то, что я указываю правильную проекцию в слое и меняю ее на карте: map.options.set('projection', ymaps.projection.sphericalMercator).

Получается либо мы работаем с кривыми координатами, либо имеем плывущую картинку (мой первый пост, с которого всё началось).

В данный момент есть "баг" - карта в "динамике" вообще не обрабатывает смену проекции.

В том числе откуда берется "число" в примере? Если из карты, то те координаты которые вы ей задали до смены проекции(setCenter) и те, что получили обратно(getCenter) после смены проекции - будут отличаться. Внутри карта работает в пикселях на текущем зуме. Текущей же проекции.

Все числа берутся из карты через getCenter() и вписываются в hash адресной строки. Через setCenter() ничего не задавалось, я вручную подвинул карту так, чтоб балун оказался в центре, и отскриншотил. Погрешность в десятитысячных есть (по долготе промахнулся на 0.0001), но по сравнению со смещением широты это ничто.

Ок, то есть баг таки обнаружен: в динамике карта не обрабатывает смену проекции. Это всё объясняет. Хотя бы я знаю, что вина не моя.