Клуб API Карт

Как отличить в обработчике программное изменение масштаба/границ карты от пользовательского?

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

День добрый.

Помогите, пожалуйста разобраться.

 

Ситуация

Область просмотра карты может меняться:

1) как программным способом через API (конкретно методами map.setCenter; map.setZoom; map.container.fitToViewport;)

2) так и в результате действий пользователя (скролл над картой, кнопки "+", "-", перетаскиванием карты с помощью мыши и т.д.)

 

Все эти действия можно обработать, с помощью события boundschange.

 

Вопрос

Как в обработчике события boundschange отличить событие, программно вызванное через API, от события, инициированного непосредственными действиями пользователя?

* Это важно для построения нашего UI.

 

Попытки решения

1) В методах (setCenter и setZoom) есть callback. С его помощью можно, конечно, отловить часть именно программных действий. Но как тогда обработать fitToViewport? И отдельный колбэк для пользовательких действий всё равно не получится назначить.

2) Хотелось бы, конечно, увидеть способ (не смог найти) передать некий флаг в эти методы, который потом можно прочитать из объекта инциированных событий в обработчике. Т.е. увидеть что-то вроде jQuery-подобного подхода:

 

$('.link').trigger('click', [true]);

//...

$('.link').on('click', function(event, isProgramClickEmulation){

    if(isProgramClickEmulation){

        console.log('Это программная эмуляция клика');

    }

});
5 комментариев

Никогда не нужно отличать кто инициировал действие. Это плохое архитектурное решение. Уверен на 100% что задача решается без подобных костылей

В большинстве случаев, да, не стоит так делать. Однако, я бы не был так категоричен.

Но раз такое дело, прошу поделиться вашей уверенностью и мыслями в решении моей задачи:

Наша карта интерактивно обновляется. Метки добавляются и убираются по AJAX.

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

Если пользователь хоть раз руками изменил масштаб на карте/сместил ее, то автоматический режим отключается (это надобие автослежения в играх типа стратегий).

Хотелось бы сделать в обработчике boundschange, но можно и пораньше, наверное, непосредственно на элементах ввода, которые использует пользователь:

https://tech.yandex.ru/maps/doc/jsapi/2.1/ref/reference/behavior.Drag-docpage/

https://tech.yandex.ru/maps/doc/jsapi/2.1/ref/reference/behavior.ScrollZoom-docpage/

https://tech.yandex.ru/maps/doc/jsapi/2.1/ref/reference/control.ZoomControl-docpage/#param-parameters.options

Этот вариант, в принципе, более правильный, только пока не понятно, как там навесить обработчик.

 

 

при смене области видимости в автоматическом режиме запоминайте выставленное значение (bounds). Если при следующей загрузке данных область видимости карты не совпадает с той что вы запомнили - не меняйте её

Да, это пока единственный рабочий вариант. Спасибо.

Не нравится только то, что посреди кучи асинхронных колбэков (реальная задача куда сложнее описанной) придется с какой-то степенью глобальности хранить эти координаты. А это архитуктурно довольно шаткое решение.

 

А в поведениях/контролах, упомянутых выше, не знаете как обработать нажатие пользователя? Это было бы надежнее.

Не надо их хранить посреди кучи колбэков. Создайте отдельный класс который будет это хранить и проверять состояние:

Глобальность тоже не нужна. Вы же весь код не в одном файле пишете. Используйте модульную систему

 

class MapState {

  constructor(map) {

    this._map = map;

    this._state = this.getMapState()

  }

  getMapState() {

    const map = this._map;

    return {

      center: map.getCenter(),

      zoom: map.getZoom()

    }

  }

  checkState() {

    const mapState = this.getMapState()

    return this._state.center === mapState.center &&

      this._state.zoom === mapState.zoom

  }

  setState(state) {

    this._state = state

  }

}

export default MapState 

 

и подключайте его везде где нужно.

import MapState from './lib/MapState'