Context menu
vanilla.html
react.html
vue.html
variables.ts
variables.css
common.ts
common.css
<!DOCTYPE html>
<html>
<head>
<title>Vanilla example ymaps3-context-menu</title>
<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>
<!-- 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"
src="../variables.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
import type {LngLat} from '@yandex/ymaps3-types';
import {InfoPanelControl} from './common';
import {LOCATION, MARKER_LOCATION} from '../variables';
window.map = null;
main();
async function main() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapListener, YMapControls} = ymaps3;
const {YMapContextMenu, YMapContextMenuItem} = await ymaps3.import('@yandex/ymaps3-context-menu');
const {YMapDefaultMarker} = await ymaps3.import('@yandex/ymaps3-default-ui-theme');
let contextMenuLngLat: LngLat = null;
map = new YMap(document.getElementById('app'), {location: LOCATION});
map.addChild(new YMapDefaultSchemeLayer({}));
map.addChild(new YMapDefaultFeaturesLayer({}));
const contextMenu = new YMapContextMenu({
visible: false,
screenCoordinates: [0, 0]
});
contextMenu
.addChild(
new YMapContextMenuItem({
text: 'Zoom in',
visible: true,
icon: '../zoomInIcon.svg',
onClick: () => {
map.update({location: {zoom: map.zoom + 1, duration: 500, easing: 'ease-in-out'}});
markerMenuItem.update({visible: false});
contextMenu.update({visible: false});
}
})
)
.addChild(
new YMapContextMenuItem({
text: 'Zoom out',
visible: true,
icon: '../zoomOutIcon.svg',
onClick: () => {
map.update({location: {zoom: map.zoom - 1, duration: 600, easing: 'ease-in-out'}});
markerMenuItem.update({visible: false});
contextMenu.update({visible: false});
}
})
)
.addChild(
new YMapContextMenuItem({
text: 'Center by it',
visible: true,
icon: '../centerByItIcon.svg',
onClick: () => {
map.setLocation({center: contextMenuLngLat, duration: 400, easing: 'ease-in-out'});
markerMenuItem.update({visible: false});
contextMenu.update({visible: false});
}
})
);
const markerMenuItem = new YMapContextMenuItem({
text: 'Marker item',
visible: false,
order: 1,
onClick: () => {
contextMenu.update({visible: false});
markerMenuItem.update({visible: false});
alert('click on marker!');
}
});
contextMenu.addChild(markerMenuItem);
map.addChild(contextMenu);
map.addChild(
new YMapDefaultMarker({
coordinates: MARKER_LOCATION,
iconName: 'fallback',
size: 'normal'
})
);
const listener = new YMapListener({
onContextMenu: (object, event) => {
if (object && object.entity instanceof ymaps3.YMapMarker) {
markerMenuItem.update({visible: true});
} else {
markerMenuItem.update({visible: false});
}
contextMenuLngLat = event.coordinates;
contextMenu.update({
visible: true,
screenCoordinates: event.screenCoordinates
});
},
onActionStart: () => {
contextMenu.update({visible: false});
}
});
map.addChild(listener);
map.addChild(new YMapControls({position: 'top left'}, [new InfoPanelControl()]));
}
</script>
<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="../variables.css" />
<link rel="stylesheet" href="./common.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>React example ymaps3-context-menu</title>
<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>
<!-- 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"
src="../variables.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="react, typescript" type="text/babel">
import type {BehaviorMapEventHandler, DomEventHandler, LngLat} from '@yandex/ymaps3-types';
import {LOCATION, MARKER_LOCATION} from '../variables';
import {InfoPanelControl} from './common';
window.map = null;
main();
async function main() {
const [ymaps3React] = await Promise.all([ymaps3.import('@yandex/ymaps3-reactify'), ymaps3.ready]);
const reactify = ymaps3React.reactify.bindTo(React, ReactDOM);
const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapListener, YMapControls} =
reactify.module(ymaps3);
const {useState} = React;
const {YMapContextMenu, YMapContextMenuItem} = reactify.module(await ymaps3.import('@yandex/ymaps3-context-menu'));
const {YMapDefaultMarker} = reactify.module(await ymaps3.import('@yandex/ymaps3-default-ui-theme'));
const InfoPanelControlR = reactify.entity(InfoPanelControl);
const App = () => {
const [location, setLocation] = useState(LOCATION);
const [visibleContextMenu, setVisibleContextMenu] = useState(false);
const [visibleMarkerItem, setVisibleMarkerItem] = useState(false);
const [screenCoordinates, setScreenCoordinates] = useState<[number, number]>();
const [contextMenuLngLat, setContextMenuLngLat] = useState<LngLat>();
const onContextMenu: DomEventHandler = (object, event) => {
if (object && object.entity instanceof ymaps3.YMapMarker) {
setVisibleMarkerItem(true);
} else {
setVisibleMarkerItem(false);
}
setContextMenuLngLat(event.coordinates);
setVisibleContextMenu(true);
setScreenCoordinates(event.screenCoordinates);
};
const onActionStart: BehaviorMapEventHandler = () => {
setVisibleContextMenu(false);
};
const zoomIn = () => {
setLocation({zoom: map.zoom + 1, duration: 600, easing: 'ease-in-out'});
setVisibleContextMenu(false);
};
const zoomOut = () => {
setLocation({zoom: map.zoom - 1, duration: 400, easing: 'ease-in-out'});
setVisibleContextMenu(false);
};
const centerByIt = () => {
setLocation({center: contextMenuLngLat, duration: 500, easing: 'ease-in-out'});
setVisibleContextMenu(false);
};
const clickOnMarker = () => {
setVisibleContextMenu(false);
alert('click on marker!');
};
return (
<YMap location={location} ref={(x) => (map = x)}>
<YMapDefaultSchemeLayer />
<YMapDefaultFeaturesLayer />
<YMapContextMenu visible={visibleContextMenu} screenCoordinates={screenCoordinates}>
<YMapContextMenuItem icon="../zoomInIcon.svg" text="Zoom in" visible={true} onClick={zoomIn} />
<YMapContextMenuItem icon="../zoomOutIcon.svg" text="Zoom out" visible={true} onClick={zoomOut} />
<YMapContextMenuItem
icon="../centerByItIcon.svg"
text="Center by it"
visible={true}
onClick={centerByIt}
/>
<YMapContextMenuItem
text="Marker item"
visible={visibleMarkerItem}
order={1}
onClick={clickOnMarker}
/>
</YMapContextMenu>
<YMapDefaultMarker iconName="fallback" size="normal" coordinates={MARKER_LOCATION} />
<YMapListener onContextMenu={onContextMenu} onActionStart={onActionStart} />
<YMapControls position="top left">
<InfoPanelControlR />
</YMapControls>
</YMap>
);
};
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('app')
);
}
</script>
<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="../variables.css" />
<link rel="stylesheet" href="./common.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Vue example ymaps3-context-menu</title>
<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>
<!-- 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"
src="../variables.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
import type {BehaviorMapEventHandler, DomEventHandler, LngLat} from '@yandex/ymaps3-types';
import {LOCATION, MARKER_LOCATION} from '../variables';
import {InfoPanelControl} from './common';
window.map = null;
main();
async function main() {
const [ymaps3Vue] = await Promise.all([ymaps3.import('@yandex/ymaps3-vuefy'), ymaps3.ready]);
const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapListener, YMapControls} = vuefy.module(ymaps3);
const {YMapContextMenu, YMapContextMenuItem} = vuefy.module(await ymaps3.import('@yandex/ymaps3-context-menu'));
const {YMapDefaultMarker} = vuefy.module(await ymaps3.import('@yandex/ymaps3-default-ui-theme'));
const InfoPanelControlV = vuefy.entity(InfoPanelControl);
const app = Vue.createApp({
components: {
YMap,
YMapDefaultSchemeLayer,
YMapDefaultFeaturesLayer,
YMapListener,
YMapContextMenu,
YMapContextMenuItem,
YMapDefaultMarker,
YMapControls,
InfoPanelControlV
},
setup() {
const refMap = (ref) => {
window.map = ref?.entity;
};
const location = Vue.ref(LOCATION);
const visibleContextMenu = Vue.ref(false);
const visibleMarkerItem = Vue.ref(false);
const screenCoordinates = Vue.ref<[number, number]>();
const contextMenuLngLat = Vue.ref<LngLat>();
const onContextMenu: DomEventHandler = (object, event) => {
if (object && object.entity instanceof ymaps3.YMapMarker) {
visibleMarkerItem.value = true;
} else {
visibleMarkerItem.value = false;
}
contextMenuLngLat.value = event.coordinates;
visibleContextMenu.value = true;
screenCoordinates.value = event.screenCoordinates;
};
const onActionStart: BehaviorMapEventHandler = () => {
visibleContextMenu.value = false;
};
const zoomIn = () => {
location.value = {
zoom: map.zoom + 1,
duration: 400,
easing: 'ease-in-out'
};
visibleContextMenu.value = false;
};
const zoomOut = () => {
location.value = {
zoom: map.zoom - 1,
duration: 600,
easing: 'ease-in-out'
};
visibleContextMenu.value = false;
};
const centerByIt = () => {
location.value = {center: contextMenuLngLat.value, duration: 500, easing: 'ease-in-out'};
visibleContextMenu.value = false;
};
const clickOnMarker = () => {
visibleContextMenu.value = false;
alert('click on marker!');
};
return {
location,
visibleContextMenu,
refMap,
visibleMarkerItem,
screenCoordinates,
contextMenuLngLat,
clickOnMarker,
centerByIt,
zoomOut,
zoomIn,
onActionStart,
onContextMenu,
MARKER_LOCATION
};
},
template: `
<YMap :location="location" :ref="refMap">
<YMapDefaultSchemeLayer />
<YMapDefaultFeaturesLayer />
<YMapContextMenu :visible="visibleContextMenu" :screenCoordinates="screenCoordinates">
<YMapContextMenuItem icon="../zoomInIcon.svg" text="Zoom in" :visible="true" :onClick="zoomIn" />
<YMapContextMenuItem icon="../zoomOutIcon.svg" text="Zoom out" :visible="true" :onClick="zoomOut" />
<YMapContextMenuItem icon="../centerByItIcon.svg" text="Center by it" :visible="true" :onClick="centerByIt" />
<YMapContextMenuItem text="Marker item" :visible="visibleMarkerItem" :order="1" :onClick="clickOnMarker" />
</YMapContextMenu>
<YMapDefaultMarker :coordinates="MARKER_LOCATION" iconName="fallback" size="normal" />
<YMapListener :onContextMenu="onContextMenu" :onActionStart="onActionStart" />
<YMapControls position="top left">
<InfoPanelControlV />
</YMapControls>
</YMap>`
});
app.mount('#app');
}
</script>
<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="../variables.css" />
<link rel="stylesheet" href="./common.css" />
</head>
<body>
<div id="app"></div>
</body>
</html>
import type {LngLat, YMapLocationRequest} from '@yandex/ymaps3-types';
export const MARKER_LOCATION: LngLat = [37.623082, 55.75254];
export const LOCATION: YMapLocationRequest = {
center: [37.623082, 55.75254], // starting position [lng, lat]
zoom: 9 // starting zoom
};
:root {
--panel-background-color: #212326;
--panel-color: #fff;
}
import type {LngLat, YMapLocationRequest} from '@yandex/ymaps3-types';
ymaps3.import.registerCdn('https://cdn.jsdelivr.net/npm/{package}', [
'@yandex/ymaps3-default-ui-theme@0.0',
'@yandex/ymaps3-context-menu@0.0'
]);
export let InfoPanelControl = null;
ymaps3.ready.then(() => {
class InfoPanelControlClass extends ymaps3.YMapComplexEntity<{}> {
private readonly __text = 'Click on marker with right button';
constructor() {
super({});
const container = document.createElement('div');
container.classList.add('info');
const iconElement = document.createElement('div');
iconElement.classList.add('icon');
container.appendChild(iconElement);
const textElement = document.createElement('div');
textElement.textContent = this.__text;
container.appendChild(textElement);
this.addChild(new ymaps3.YMapControl({transparent: true}, container));
}
}
InfoPanelControl = InfoPanelControlClass;
});
.info {
display: flex;
flex-direction: row;
align-items: center;
padding: 8px 12px;
font-size: 14px;
font-style: normal;
line-height: 20px;
color: var(--panel-color);
border-radius: 12px;
background-color: var(--panel-background-color);
box-shadow: 0 0 2px 0 rgba(95, 105, 131, 0.08), 0 2px 4px 0 rgba(95, 105, 131, 0.2);
gap: 6px;
}
.icon {
display: block;
width: 16px;
height: 16px;
background-image: url(./iconRightButton.svg);
}