Клуб API Карт

Событие перетаскивания карты пользователем, api 2.0

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

Добрый день. Как отловить событие перетаскивания карты пользователем?  

Через boundschange не получается, т.к. моя карта может двигаться и программным способом

22 комментария

Я бы попробовал выкрутиться так:

отключить flight во всех panTo

и присвоить событиям actionend и wheel вашу ф-цию.

 

а что это даёт?

после panTo([x, y], {flying: false}) все равно срабатывает actionend, а хотелось бы чтоб не срабатывал

печально на самом деле, ведь  документации написанно:


Началось новое плавное движение карты

а если flying: false, то оно по идее не должно быть плавным =\


 

оно при setCenter() не плавное, однако actionend опять же срабатывает

В общем вышел из ситуации использованием трёх событий mousedown, mousemove, mouseup

Sergey Konstantinov
28 января 2016, 02:54
Если вам нужно отличать действия пользователя от остальных способов изменить положение карты - в логике работы вашего приложения, скорее всего, ошибка.
Мы сознательно не открываем событий перетаскивания карты именно по этой причине.

раз уже вы прочитали, то расшифруйте, пожалуйста, что имелось ввиду под "плавным" движением карты?

Sergey Konstantinov
28 января 2016, 02:54
Немоментальные перемещения - инерция драга, масштабирование по колесу и т.п.

Возможно ошибка и есть, я всё ж не гуру. Однако вот у Placemark есть событие drag, т.е. испольльзование этого события логику приложения не нарушает?

Sergey Konstantinov
28 января 2016, 02:54
Нет, не нарушает. Геообъект - это сущность, привязанная к некоторой точке на карте. Его геокоординаты не могут измениться в результате работы каких-то внешних компонент АПИ, а только с явного указания разработчика - посредством выставления draggable или явного перезадания координат.

Область просмотра карты же является просто состоянием и может произвольно меняться любым объектом в АПИ. Например, если пользователь что-то ищет, то контрол поиска будет менять bounds для того, чтобы показать найденный объект.

Соответственно, попытки разделить "программное" и "пользовательское" изменение положения карты некорректны. Если пользователь вбил "Москва" в поиск - это программное изменение центра карты? Клик по кластеру? Изменение размеров окна браузера?

Расскажите, какую задачу вы пытаетесь решить, а я попробую вам дать совет.

У меня есть Placemark на карте. С течением времени его геокоординаты могут изменяться. По-умолчанию карта должна центрироваться на этом Placemark'е, однако, если пользователь захотел посмотретьна карте другое место, и решил карту "потаскать", центрирование на Placemark нужно отключить. Вот поэтому у меня и возник такой вопрос

Sergey Konstantinov
28 января 2016, 02:54
А в каких ситуациях карта двигается программно?

Как только координаты Placemark'а поменялись, вызываю panTo() либо setCenter() чтобы отцентрировать (если нужно) на нём карту (это я и имел ввиду программно).

Sergey Konstantinov
28 января 2016, 02:54
Тогда как-то так:
// pm - ваш placemark
map.events.add('boundschange', function (e) {
   var newCenter = e.get('newCenter'),
         pmPosition = pm.geometry.getCoordinates();
   if (Math.abs(pmPosition[0] - newCenter[0]) > 1e-6 || Math.abs(pmPosition[1] - newCenter[1]) > 1e-6) {
      // Снимаем слежение за координатами метки
  }
});
Иными словами, если в результате чего-то центр карты стал отличаться от позиции метки - считать это "действием пользователя".

Спасибо!

А имеет ли право на жизнь такой вариант?

function onMoveMouse(){

//снимаем слежение за координатами метки

map.events.remove('mousemove', onMoveMouse);

}

map.events.add('mousedown', function(){

map.events.add('mousemove', onMoveMouse);

}) ;

map.events.add('mouseup', function(){

map.events.remove('mousemove', onMoveMouse);

}) ;

Sergey Konstantinov
28 января 2016, 02:54
Смотря чего вы хотите добиться.
Таким образом, например, зум колесом не будет отключать автоцентрирование. Вы точно этого хотите?

Да. Я хочу отключать автоцентрирование только по "тасканию" карты мышкой

Sergey Konstantinov
28 января 2016, 02:54
Тогда ваш код правильный. Я бы только посоветовал ещё пользоваться методом once.

Прошу вас помочь и мне с решением проблемы.

Логика приложения такова:
есть функция загрузки объектов на карту (ajax запрос на сервер).После загрузки объектов вызываем ymaps.util.bounds.getCenterAndZoom() чтобы все объекты попали в область карты.

Эта функция вызывается в двух случаях:
1. при инициализации карты ymap
2. по событию actionend. 


Проблема в том, что после первичной загрузки объектов на карту чаще всего срабатывает зумирование, поэтому выстреливает событие actionend из-за чего функция загрузки объектов на карту вызывается повторно.

Как исключить повторный вызов? Все работает асинхронно, конечно же. Если включать синхронность появляются дикие тормоза и очереди.

Sergey Konstantinov
28 января 2016, 02:54
Проще всего воспользоваться готовым инструментом.
http://habrahabr.ru/company/yandex/blog/243665/

Решений можно много придумать. Например, сначала зуммировать, потом грузить. Или настроить правильное кэширование, чтобы повторный запрос из кэша брался.

Определить сначала координаты с зумом сложно да и не нужно - это задача клиента (ymaps). Сервер всего-нишь возвращает набор меток с координатами.
Попробуем разобраться с ObjectManager, но решение, прямо скажем, не из коробки.
А задача-то тривиальная. 

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