Слушатели событий карты
vanilla.html
react.html
vue.html
common.css
common.ts
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
<script crossorigin src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<!-- To make the map appear, you must add your apikey -->
<script src="https://api-maps.yandex.ru/v3/?apikey=<YOUR_APIKEY>&lang=en_US" type="text/javascript"></script>
<script
data-plugins="transform-modules-umd"
data-presets="typescript"
type="text/babel"
src="./common.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
import type {
MapEventUpdateHandler,
MapEventResizeHandler,
DomEventHandler,
BehaviorMapEventHandler
} from '@yandex/ymaps3-types';
import {LOCATION, BEHAVIOR, EventListener, InfoMessage} from './common';
window.map = null;
main();
async function main() {
// Waiting for all api elements to be loaded
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer, YMapListener, YMapControls, YMapControl} = ymaps3;
// Initialize the map
map = new YMap(
// Pass the link to the HTMLElement of the container
document.getElementById('app'),
// Pass the map initialization parameters
{location: LOCATION, showScaleInCopyrights: true, behaviors: BEHAVIOR},
// Add a map scheme layer
[new YMapDefaultSchemeLayer({})]
);
// Status of map events
const mapEvents = {
update: false,
resize: false
};
// Status of dom events
const domEvents = {
click: false,
fastClick: false,
dblClick: false,
rightClick: false,
rightDblClick: false,
mouseMove: false,
mouseEnter: false,
mouseLeave: false,
mouseDown: false
};
// Status of behavior events
const behaviorEvents = {
scrollZoom: false,
drag: false,
mouseRotate: false,
mouseTilt: false
};
// Create an EventListener control to display the status of map events
const mapEventsControl = new EventListener({
title: 'Map Events',
events: {...mapEvents}
});
// Create an EventListener control to display the status of dom events
const domEventsControl = new EventListener({
title: 'Dom Events',
events: {...domEvents}
});
// Create an EventListener control to display the status of behavior events
const behaviorEventsControl = new EventListener({
title: 'Behavior Events',
events: {...behaviorEvents}
});
/* Create and add a shared container for controls to the map.
Using YMapControls you can change the position of the control */
const topLeftControls = new YMapControls({position: 'top left', orientation: 'horizontal'});
map.addChild(topLeftControls);
// Add controls to the map
topLeftControls
.addChild(new YMapControl().addChild(domEventsControl))
.addChild(new YMapControl().addChild(mapEventsControl).addChild(behaviorEventsControl));
// Handler function for changing the status of the onUpdate event
const updateHandler: MapEventUpdateHandler = (object) => {
console.log('Update object: ', object);
object.mapInAction ? (mapEvents.update = true) : (mapEvents.update = false);
mapEventsControl.update({events: {...mapEvents}});
};
// Function that creates a handler function to change the status of the onResize event
const createResizeHandler = (): MapEventResizeHandler => {
const disableResizeEvent = _.debounce(() => {
mapEvents.resize = false;
mapEventsControl.update({events: {...mapEvents}});
}, 250);
return function (object) {
console.log('Resize object: ', object);
mapEvents.resize = true;
mapEventsControl.update({events: {...mapEvents}});
disableResizeEvent();
};
};
// Function that creates a handler function to change the status of dom events
const createDomEventHandler = (eventType: keyof typeof domEvents): DomEventHandler => {
const disableEvent = _.debounce(() => {
domEvents[eventType] = false;
domEventsControl.update({
events: {
...domEvents
}
});
}, 250);
return function (object, event) {
console.log(`${eventType} object: `, object, `\n${eventType} event: `, event);
domEvents[eventType] = true;
domEventsControl.update({
events: {
...domEvents
}
});
disableEvent();
};
};
// Function that creates a handler function to change the status of behavior event
const createBehaviorEventHandler = (isStart: boolean): BehaviorMapEventHandler => {
return function (object) {
if (object.type === 'dblClick') return;
if (isStart) {
console.log('actionStart object: ', object);
} else {
console.log('actionEnd object: ', object);
}
behaviorEvents[object.type] = isStart;
behaviorEventsControl.update({events: {...behaviorEvents}});
};
};
/* Add a listener to the map and pass the handlers functions for the events you want to process
These are just some of the events, you can see them all in the documentation */
map.addChild(
new YMapListener({
onUpdate: updateHandler,
onResize: createResizeHandler(),
onClick: createDomEventHandler('click'),
onFastClick: createDomEventHandler('fastClick'),
onDblClick: createDomEventHandler('dblClick'),
onContextMenu: createDomEventHandler('rightClick'),
onRightDblClick: createDomEventHandler('rightDblClick'),
onMouseMove: createDomEventHandler('mouseMove'),
onMouseEnter: createDomEventHandler('mouseEnter'),
onMouseLeave: createDomEventHandler('mouseLeave'),
onMouseDown: createDomEventHandler('mouseDown'),
onActionStart: createBehaviorEventHandler(true),
onActionEnd: createBehaviorEventHandler(false)
})
);
/* Create and add a shared container for controls to the map.
Using YMapControls you can change the position of the control */
const topRightControls1 = new YMapControls({position: 'top right'});
map.addChild(topRightControls1);
// Add a custom information message control to the map
topRightControls1.addChild(
new InfoMessage({text: 'Open the console to see the parameters of the executed event.'})
);
}
</script>
<!-- prettier-ignore -->
<style> html, body, #app { width: 100%; height: 100%; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .toolbar { position: absolute; z-index: 1000; top: 0; left: 0; display: flex; align-items: center; padding: 16px; } .toolbar a { padding: 16px; } </style>
<link rel="stylesheet" href="./common.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<script crossorigin src="https://cdn.jsdelivr.net/npm/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.production.min.js"></script>
<script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
<script crossorigin src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<!-- To make the map appear, you must add your apikey -->
<script src="https://api-maps.yandex.ru/v3/?apikey=<YOUR_APIKEY>&lang=en_US" type="text/javascript"></script>
<script
data-plugins="transform-modules-umd"
data-presets="react, typescript"
type="text/babel"
src="./common.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="react, typescript" type="text/babel">
import type {
MapEventUpdateHandler,
MapEventResizeHandler,
DomEventHandler,
BehaviorMapEventHandler
} from '@yandex/ymaps3-types';
import {LOCATION, BEHAVIOR, EventListener, InfoMessage} from './common';
window.map = null;
main();
async function main() {
// For each object in the JS API, there is a React counterpart
// To use the React version of the API, include the module @yandex/ymaps3-reactify
const [ymaps3React] = await Promise.all([ymaps3.import('@yandex/ymaps3-reactify'), ymaps3.ready]);
const reactify = ymaps3React.reactify.bindTo(React, ReactDOM);
const {YMap, YMapDefaultSchemeLayer, YMapListener, YMapControls, YMapControl} = reactify.module(ymaps3);
// Using ymaps3-rectify, we turn a custom InfoMessage and EventListener into a React component
const {EventListener: EventListenerR} = reactify.module({EventListener});
const {InfoMessage: InfoMessageR} = reactify.module({InfoMessage});
const {useState, useCallback, useMemo} = React;
function App() {
// Status of map events
const [mapEvents, setMapEvents] = useState({
update: false,
resize: false
});
// Status of dom events
const [domEvents, setDomEvents] = useState({
click: false,
fastClick: false,
dblClick: false,
rightClick: false,
rightDblClick: false,
mouseMove: false,
mouseEnter: false,
mouseLeave: false,
mouseDown: false
});
// Status of behavior events
const [behaviorEvents, setBehaviorEvents] = useState({
scrollZoom: false,
drag: false,
mouseRotate: false,
mouseTilt: false
});
// Handler function for changing the status of the onUpdate event
const updateHandler: MapEventUpdateHandler = useCallback((object) => {
console.log('Update object: ', object);
object.mapInAction ? (mapEvents.update = true) : (mapEvents.update = false);
setMapEvents({...mapEvents});
}, []);
// Function that creates a handler function to change the status of the onResize event
const createResizeHandler = useCallback((): MapEventResizeHandler => {
const disableResizeEvent = _.debounce(() => {
mapEvents.resize = false;
setMapEvents({...mapEvents});
}, 250);
return function (object) {
console.log('Resize object: ', object);
mapEvents.resize = true;
setMapEvents({...mapEvents});
disableResizeEvent();
};
}, []);
// Function that creates a handler function to change the status of dom events
const createDomEventHandler = useCallback((eventType: keyof typeof domEvents): DomEventHandler => {
const disableEvent = _.debounce(() => {
domEvents[eventType] = false;
setDomEvents({...domEvents});
}, 250);
return function (object, event) {
console.log(`${eventType} object: `, object, `\n${eventType} event: `, event);
domEvents[eventType] = true;
setDomEvents({...domEvents});
disableEvent();
};
}, []);
// Function that creates a handler function to change the status of behavior event
const createBehaviorEventHandler = useCallback((isStart: boolean): BehaviorMapEventHandler => {
return function (object) {
if (object.type === 'dblClick') return;
if (isStart) {
console.log('actionStart object: ', object);
} else {
console.log('actionEnd object: ', object);
}
behaviorEvents[object.type] = isStart;
setBehaviorEvents({...behaviorEvents});
};
}, []);
return (
// Initialize the map and pass initialization parameters
<YMap location={LOCATION} showScaleInCopyrights={true} behaviors={BEHAVIOR} ref={(x) => (map = x)}>
{/* Add a map scheme layer */}
<YMapDefaultSchemeLayer />
{/* Add a shared container for controls to the map.
Using YMapControls you can change the position of the control */}
<YMapControls position="top left" orientation="horizontal">
<YMapControl>
{/* Add an EventListener control to the map to display the status of dom events */}
<EventListenerR title="Dom Events" events={domEvents} />
</YMapControl>
<YMapControl>
{/* Add an EventListener control to the map to display the status of map events */}
<EventListenerR title="Map Events" events={mapEvents} />
{/* Add an EventListener control to the map to display the status of behavior events */}
<EventListenerR title="Behavior Events" events={behaviorEvents} />
</YMapControl>
</YMapControls>
{/* Add a listener to the map and pass the handlers functions for the events you want to process
These are just some of the events, you can see them all in the documentation */}
<YMapListener
onUpdate={updateHandler}
onResize={useMemo(() => createResizeHandler(), [])}
onClick={useMemo(() => createDomEventHandler('click'), [])}
onFastClick={useMemo(() => createDomEventHandler('fastClick'), [])}
onDblClick={useMemo(() => createDomEventHandler('dblClick'), [])}
onContextMenu={useMemo(() => createDomEventHandler('rightClick'), [])}
onRightDblClick={useMemo(() => createDomEventHandler('rightDblClick'), [])}
onMouseMove={useMemo(() => createDomEventHandler('mouseMove'), [])}
onMouseEnter={useMemo(() => createDomEventHandler('mouseEnter'), [])}
onMouseLeave={useMemo(() => createDomEventHandler('mouseLeave'), [])}
onMouseDown={useMemo(() => createDomEventHandler('mouseDown'), [])}
onActionStart={useMemo(() => createBehaviorEventHandler(true), [])}
onActionEnd={useMemo(() => createBehaviorEventHandler(false), [])}
/>
<YMapControls position="top right">
{/* Add a custom information message control to the map */}
<InfoMessageR text="Open the console to see the parameters of the executed event." />
</YMapControls>
</YMap>
);
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('app')
);
}
</script>
<!-- prettier-ignore -->
<style> html, body, #app { width: 100%; height: 100%; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .toolbar { position: absolute; z-index: 1000; top: 0; left: 0; display: flex; align-items: center; padding: 16px; } .toolbar a { padding: 16px; } </style>
<link rel="stylesheet" href="./common.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<script crossorigin src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
<script crossorigin src="https://cdn.jsdelivr.net/npm/@babel/standalone@7/babel.min.js"></script>
<script crossorigin src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<!-- To make the map appear, you must add your apikey -->
<script src="https://api-maps.yandex.ru/v3/?apikey=<YOUR_APIKEY>&lang=en_US" type="text/javascript"></script>
<script
data-plugins="transform-modules-umd"
data-presets="typescript"
type="text/babel"
src="./common.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel"></script>
<!-- prettier-ignore -->
<style> html, body, #app { width: 100%; height: 100%; margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .toolbar { position: absolute; z-index: 1000; top: 0; left: 0; display: flex; align-items: center; padding: 16px; } .toolbar a { padding: 16px; } </style>
<link rel="stylesheet" href="./common.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
.events {
width: 180px;
padding: 10px 0;
display: flex;
align-items: center;
flex-direction: column;
gap: 7px 0;
}
.events:nth-child(2)::before {
content: '';
display: block;
border-top: 1px solid #c0c0c1;
padding-top: 7px;
width: 75%;
}
.events__title {
font-size: 20px;
font-weight: bold;
}
.events__list {
width: 100%;
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
}
.events__item {
width: 100%;
padding: 5px 0;
border-top: 1px solid #000;
font-size: 18px;
text-align: center;
}
.events__item:last-child {
border-bottom: 1px solid #000;
}
.events__item_active {
background-color: rgba(0, 122, 252, 0.7);
}
.infoWindow {
width: 300px;
padding: 15px;
padding-left: 50px;
position: relative;
border-radius: 15px;
background-color: rgba(255, 255, 255, 0.9);
font-size: 16px;
}
.infoWindow__icon {
width: 30px;
height: 30px;
position: absolute;
top: 50%;
left: 10px;
transform: translateY(-50%);
}
import type lodash from 'lodash';
import type {YMapLocationRequest, BehaviorType} from '@yandex/ymaps3-types';
declare global {
const _: typeof lodash;
}
export const LOCATION: YMapLocationRequest = {
center: [37.623082, 55.75254], // starting position [lng, lat]
zoom: 9 // starting zoom
};
// An array of enabled map behaviors
export const BEHAVIOR: BehaviorType[] = ['drag', 'scrollZoom', 'dblClick', 'mouseRotate', 'mouseTilt'];
/* Initialize a custom EventListener control
Assign a value to it after loading the map api */
export let EventListener = null;
type mapEventsType = {
title: string;
events: {
update: boolean;
resize: boolean;
};
};
type domEventsType = {
title: string;
events: {
click: boolean;
fastClick: boolean;
dblClick: boolean;
rightClick: boolean;
rightDblClick: boolean;
mouseMove: boolean;
mouseEnter: boolean;
mouseLeave: boolean;
mouseDown: boolean;
};
};
type behaviorEventsType = {
title: string;
events: {
scrollZoom: boolean;
drag: boolean;
mouseRotate: boolean;
mouseTilt: boolean;
};
};
type EventListenerProps = mapEventsType | domEventsType | behaviorEventsType;
/* Initialize a custom information message control
Assign a value to it after loading the map api */
export let InfoMessage = null;
interface InfoMessageProps {
text: string;
}
// Wait for the api to load to access the entity system (YMapComplexEntity)
ymaps3.ready.then(() => {
class EventListenerClass extends ymaps3.YMapComplexEntity<EventListenerProps> {
private _element: HTMLDivElement;
private _detachDom: () => void;
// Method for create a DOM control element
_createElement() {
const {title, events} = this._props;
// Create a root element
const rootElement = document.createElement('div');
rootElement.className = 'events';
// Create an events title element
const eventsTitle = document.createElement('div');
eventsTitle.textContent = title;
eventsTitle.className = 'events__title';
rootElement.appendChild(eventsTitle);
// Create an events list element
const eventsList = document.createElement('ul');
eventsList.className = 'events__list';
rootElement.appendChild(eventsList);
// Iterate through the events and create list items
for (let event in events) {
const eventElement = document.createElement('li');
eventElement.className = 'events__item';
eventElement.textContent = event;
eventElement.id = event;
eventsList.appendChild(eventElement);
}
return rootElement;
}
// Method that is used when updating the parameters of control
_onUpdate() {
const {events} = this._props;
for (let event in events) {
const eventElement = document.getElementById(event);
if (!eventElement) return;
if (events[event]) {
eventElement.classList.add('events__item_active');
} else {
eventElement.classList.remove('events__item_active');
}
}
}
// Method for attaching the control to the map
_onAttach() {
this._element = this._createElement();
this._detachDom = ymaps3.useDomContext(this, this._element, this._element);
}
// Method for detaching control from the map
_onDetach() {
this._detachDom();
this._detachDom = null;
this._element = null;
}
}
EventListener = EventListenerClass;
class InfoMessageClass extends ymaps3.YMapComplexEntity<InfoMessageProps> {
private _element!: HTMLDivElement;
private _detachDom!: () => void;
// Method for create a DOM control element
_createElement(props: InfoMessageProps) {
// Create a root element
const infoWindow = document.createElement('div');
infoWindow.className = 'infoWindow';
infoWindow.textContent = props.text;
// Create an icon element
const infoIcon = document.createElement('img');
infoIcon.src = '../info-icon.svg';
infoIcon.className = 'infoWindow__icon';
infoWindow.appendChild(infoIcon);
return infoWindow;
}
// Method for attaching the control to the map
_onAttach() {
this._element = this._createElement(this._props);
this._detachDom = ymaps3.useDomContext(this, this._element, this._element);
}
// Method for detaching control from the map
_onDetach() {
this._detachDom();
this._detachDom = undefined;
this._element = undefined;
}
}
InfoMessage = InfoMessageClass;
});