Skip to content

Обработка событий карты

Совет

В консоли разработчика отображается вся информация по сработавшим событиям!

html
<yandex-map
    class="events"
    :class="[`theme--${ theme }`]"
    :height="resizeHeight ? `calc(${ height } + 100px)` : height"
    :settings="{
        location: {
            center,
            zoom,
        },
        behaviors: BEHAVIOR,
        theme,
        showScaleInCopyrights: true,
    }"
    :width="width"
>
    <yandex-map-default-scheme-layer/>
    <yandex-map-controls :settings="{ position: 'top left' }">
        <yandex-map-entity class="events-container">
            <div class="events-block">
                <div class="events-block_title">
                    DOM Events
                </div>
                <div
                    v-for="(value, key) in events.dom"
                    :key="key"
                    class="events-block_item"
                    :class="{ 'events-block_item--active': value }"
                >
                    {{ key }}
                </div>
            </div>
        </yandex-map-entity>
        <yandex-map-entity class="events-container">
            <div class="events-block">
                <div class="events-block_title">
                    Map Events
                </div>
                <div
                    v-for="(value, key) in events.map"
                    :key="key"
                    class="events-block_item"
                    :class="{ 'events-block_item--active': value }"
                >
                    {{ key }}
                </div>
            </div>
            <div class="events-block">
                <div class="events-block_title">
                    Behavior Events
                </div>
                <div
                    v-for="(value, key) in events.behavior"
                    :key="key"
                    class="events-block_item"
                    :class="{ 'events-block_item--active': value }"
                >
                    {{ key }}
                </div>
            </div>
        </yandex-map-entity>
    </yandex-map-controls>
    <yandex-map-controls :settings="{ position: 'top right' }">
        <yandex-map-control-button :settings="{ onClick: () => resizeHeight = !resizeHeight }">
            Изменить высоту карты
        </yandex-map-control-button>
    </yandex-map-controls>
    <yandex-map-listener
        :settings="{
            onUpdate: createEvent('map', 'update'),
            onResize: createEvent('map', 'resize'),

            onClick: createEvent('dom', 'click'),
            onFastClick: createEvent('dom', 'fastClick'),
            onDblClick: createEvent('dom', 'dblClick'),
            onContextMenu: createEvent('dom', 'contextMenu'),
            onRightDblClick: createEvent('dom', 'rightDblClick'),
            onMouseMove: createEvent('dom', 'mouseMove'),
            onMouseEnter: createEvent('dom', 'mouseEnter'),
            onMouseLeave: createEvent('dom', 'mouseLeave'),
            onMouseDown: createEvent('dom', 'mouseDown'),
            onMouseUp: createEvent('dom', 'mouseUp'),

            onActionStart: createEvent('behavior', true),
            onActionEnd: createEvent('behavior', false),
        }"
    />
</yandex-map>
ts
import {
    YandexMap,
    YandexMapControlButton,
    YandexMapControls,
    YandexMapDefaultSchemeLayer,
    YandexMapEntity,
    YandexMapListener,
} from 'vue-yandex-maps';
import { reactive, ref } from 'vue';
import type { BehaviorMapEventHandler, BehaviorType, DomEvent } from '@yandex/ymaps3-types';

const resizeHeight = ref(false);
const BEHAVIOR: BehaviorType[] = ['drag', 'scrollZoom', 'dblClick', 'mouseRotate', 'mouseTilt'];

const events = reactive({
    map: {
        update: false,
        resize: false,
    },
    dom: {
        click: false,
        fastClick: false,
        dblClick: false,
        contextMenu: false,
        rightDblClick: false,
        mouseMove: false,
        mouseEnter: false,
        mouseLeave: false,
        mouseUp: false,
        mouseDown: false,
    },
    behavior: {
        scrollZoom: false,
        drag: false,
        mouseRotate: false,
        mouseTilt: false,
    },
});

function debounce<T extends Function>(func: T, delay: number): (...args: any[]) => void {
    let timeoutId: ReturnType<typeof setTimeout>;

    return function _(this: any, ...args: any[]): void {
        clearTimeout(timeoutId);

        timeoutId = setTimeout(() => {
            func.apply(this, args);
        }, delay);
    };
}

const createEvent = <T extends keyof typeof events, E = keyof typeof events[T]>(category: T, type: E | boolean): any => {
    const eventState = events[category] as any;

    if (typeof type !== 'boolean') {
        const endEvent = debounce(() => {
            eventState[type] = false;
        }, 250);

        return (object: Record<string, any>, event?: DomEvent) => {
            console.log(`${ type } Object: `, object, `\n`, `${ type } Event: `, event);

            eventState[type] = true;
            endEvent();
        };
    }
    return (object: Parameters<BehaviorMapEventHandler>[0]) => {
        console.log(`${ type ? 'actionStart' : 'actionEnd' } Object:`, object);
        if (!(object.type in events.behavior)) return;

        eventState[object.type] = type;
    };
};
css
<style scoped>
.events {
  --bg: #fff;
  --color: #111;
  color: var(--color);
}

.events.theme--dark {
  --bg: #111;
  --color: #eee;
}

.events-container, .events-block {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.events-container {
  pointer-events: all;

  + .events-container {
    margin-left: 10px;
  }
}

.events-block {
  background: var(--bg);
  padding: 10px;
  border-radius: 5px;
  text-align: center;
}

.events-block_title {
  font-weight: 600;
  border-bottom: 2px solid rgba(150, 150, 150, 0.5);
  padding-bottom: 5px;
  margin-bottom: 5px;
}

.events-block_item {
  background: rgba(150, 150, 150, 0.15);
  padding: 5px;
  border-radius: 5px;
  transition: 0.3s ease-out;
}

.events-block_item--active {
  background: rgba(150, 150, 150, 0.8);
}
</style>

Сделано с ♥ под лицензией MIT.