Display a hint when hovering over map elements
vanilla.html
react.html
vue.html
common.css
common.ts
variables.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>
<!-- To make the map appear, you must add your apikey -->
<script src="https://js.api.mappable.world/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 {LOCATION, MARKER_PROPS} from '../variables';
window.map = null;
main();
async function main() {
// Waiting for all api elements to be loaded
await mappable.ready;
// Create a custom control class for a hint window
class HintWindow extends mappable.MMapComplexEntity<{}> {
private _element: HTMLDivElement;
private _detachDom: () => void;
private _unwatchSearchContext: () => void;
// Method for create a DOM control element
_createElement() {
const windowElement = document.createElement('div');
windowElement.classList.add('hint_window');
const windowElementTitle = document.createElement('div');
windowElementTitle.classList.add('hint_window__title');
const windowElementText = document.createElement('div');
windowElementText.classList.add('hint_window__text');
windowElement.appendChild(windowElementTitle);
windowElement.appendChild(windowElementText);
return windowElement;
}
// Callback method triggered on hint context change, responsible for updating the text in the hint window
_searchContextListener() {
const hintContext = this._consumeContext<{hint: {title: string; text: string}}>(MMapHintContext)?.hint;
this._element.firstChild.textContent = hintContext?.title;
this._element.lastChild.textContent = hintContext?.text;
}
// Method for attaching the control to the map
protected _onAttach(): void {
this._element = this._createElement();
this._unwatchSearchContext = this._watchContext(MMapHintContext, this._searchContextListener.bind(this));
this._detachDom = mappable.useDomContext(this, this._element, this._element);
}
// Method for detaching control from the map
protected _onDetach(): void {
this._unwatchSearchContext();
this._detachDom();
}
}
const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapFeature} = mappable;
// Load the package with the hint, extract the class to create the hint object and the hint context
const {MMapHint, MMapHintContext} = await mappable.import('@mappable-world/mappable-hint');
// Load the package with the default marker, extract the class to create the default marker object
const {MMapDefaultMarker} = await mappable.import('@mappable-world/mappable-default-ui-theme');
// Initialize the map
map = new MMap(
// Pass the link to the HTMLElement of the container
document.getElementById('app'),
// Pass the map initialization parameters
{location: LOCATION},
[
// Add a map scheme layer
new MMapDefaultSchemeLayer({}),
// Add a layer of geo objects
new MMapDefaultFeaturesLayer({})
]
);
/* Create a hint object and add it to the map
As parameters, provide a function that returns the hint message of your geo object */
const hint = new MMapHint({hint: (object) => object?.properties?.hint});
map.addChild(hint);
// Add your custom hint window to the hint, which will be displayed when you hover over the geo object
hint.addChild(new HintWindow({}));
// Create and add markers to the map with a hint message (properties.hint)
map.addChild(new MMapDefaultMarker({...MARKER_PROPS}));
}
</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>
<!-- To make the map appear, you must add your apikey -->
<script src="https://js.api.mappable.world/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 {LOCATION, MARKER_PROPS} from '../variables';
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 @mappable-world/mappable-reactify
const [mappableReact] = await Promise.all([mappable.import('@mappable-world/mappable-reactify'), mappable.ready]);
const reactify = mappableReact.reactify.bindTo(React, ReactDOM);
const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapFeature} = reactify.module(mappable);
// Load the package with the hint, extract the class to create the hint object and the hint context
const {MMapHint, MMapHintContext} = reactify.module(await mappable.import('@mappable-world/mappable-hint'));
// Load the package with the default marker, extract the class to create the default marker object
const {MMapDefaultMarker} = reactify.module(await mappable.import('@mappable-world/mappable-default-ui-theme'));
const {useContext, useCallback} = React;
// Create a custom control component for a hint window
function HintWindow() {
const hintContext = useContext(MMapHintContext) as {
hint: {
title: string;
text: string;
};
};
// Use dangerouslySetInnerHTML because the hint message has <b> and <br> tags
return (
hintContext && (
<div className="hint_window">
<div className="hint_window__title">{hintContext.hint.title}</div>
<div className="hint_window__text">{hintContext.hint.text}</div>
</div>
)
);
}
function App() {
const getHint = useCallback((object) => object?.properties?.hint, []);
return (
// Initialize the map and pass initialization parameters
<MMap location={LOCATION} ref={(x) => (map = x)}>
{/* Add a map scheme layer */}
<MMapDefaultSchemeLayer />
{/* Add a layer of geo objects */}
<MMapDefaultFeaturesLayer />
{/* Add a hint component to the map
As parameters, provide a function that returns the hint message of your geo object */}
{/*
// @ts-ignore */}
<MMapHint hint={getHint}>
{/* Add your custom hint window to the hint, which will be displayed when you hover over the geo object */}
<HintWindow />
</MMapHint>
{/* Add markers to the map with a hint message (properties.hint) */}
<MMapDefaultMarker {...MARKER_PROPS} />
</MMap>
);
}
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>
<!-- To make the map appear, you must add your apikey -->
<script src="https://js.api.mappable.world/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 {LOCATION, MARKER_PROPS} from '../variables';
window.map = null;
async function main() {
// For each object in the JS API, there is a Vue counterpart
// To use the Vue version of the API, include the module @mappable-world/mappable-vuefy
const [mappableVue] = await Promise.all([mappable.import('@mappable-world/mappable-vuefy'), mappable.ready]);
const vuefy = mappableVue.vuefy.bindTo(Vue);
const {MMap, MMapDefaultSchemeLayer, MMapDefaultFeaturesLayer, MMapFeature} = vuefy.module(mappable);
// Load the package with the hint, extract the class to create the hint object and the hint context
const {MMapHint, MMapHintContext} = vuefy.module(await mappable.import('@mappable-world/mappable-hint'));
// Load the package with the default marker, extract the class to create the default marker object
const {MMapDefaultMarker} = vuefy.module(await mappable.import('@mappable-world/mappable-default-ui-theme'));
const HintWindow = Vue.defineComponent({
setup() {
// @ts-ignore
const hintContext = Vue.inject(MMapHintContext);
return {
hintContext
};
},
template: `
<div v-if="hintContext && hintContext.hint" class="hint_window">
<div class="hint_window__title">{{ hintContext.hint.title }}</div>
<div class="hint_window__text">{{ hintContext.hint.text }}</div>
</div>
`
});
const App = Vue.createApp({
components: {
MMap,
MMapDefaultSchemeLayer,
MMapDefaultFeaturesLayer,
MMapFeature,
MMapDefaultMarker,
HintWindow,
MMapHint,
MMapHintContext
},
setup() {
const refMap = (ref) => {
window.map = ref?.entity;
};
const getHint = (object) => {
return object?.properties?.hint;
};
return {
refMap,
LOCATION,
MARKER_PROPS,
getHint
};
},
template: `
<MMap :location="LOCATION" :ref="refMap">
<MMapDefaultSchemeLayer/>
<MMapDefaultFeaturesLayer/>
<MMapHint :hint="getHint">
<HintWindow/>
</MMapHint>
<MMapDefaultMarker v-bind="MARKER_PROPS"/>
</MMap>
`
});
App.mount('#app');
}
main();
</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>
.hint_window {
position: absolute;
transform: translate(40px, -50%);
padding: 14px;
background: #ffffff;
width: 246px;
border-radius: 8px;
box-shadow: 0px 4px 12px 0px rgba(95, 105, 131, 0.1), 0px 4px 24px 0px rgba(95, 105, 131, 0.04);
gap: 8px;
.hint_window__title {
font-weight: 500;
font-size: 20px;
color: #050d33;
margin-bottom: 8px;
}
.hint_window__text {
font-weight: 400;
font-size: 14px;
color: #7b7d85;
}
}
mappable.ready.then(() => {
mappable.import.registerCdn('https://cdn.jsdelivr.net/npm/{package}', [
'@mappable-world/mappable-default-ui-theme@0.0',
'@mappable-world/mappable-hint@0.0'
]);
});
import type {LngLat, MMapLocationRequest} from '@mappable-world/mappable-types';
export const LOCATION: MMapLocationRequest = {
center: [56.0224, 25.7911], // starting position [lng, lat]
zoom: 11.2 // starting zoom
};
/* An array of props for markers.
`properties.hint` stores the text that will be displayed when hovering over this marker */
export const MARKER_PROPS = {
coordinates: [56.0224, 25.7911] as LngLat,
size: 'normal',
iconName: 'fallback',
properties: {
hint: {
title: 'Title of that pop up',
text: 'Some useful information about a place. You can add whatever you want: pictures, buttons, different headings.'
}
}
};