Change camera position
vanilla.html
react.html
vue.html
variables.ts
sandbox.json
<!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="../variables.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
import {LOCATION} from '../variables';
window.map = null;
main();
async function main() {
// Waiting for all api elements to be loaded
await mappable.ready;
const {MMap, MMapDefaultSchemeLayer, MMapListener, MMapControls, MMapControlButton} = mappable;
// 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, showScaleInCopyrights: true, camera: {tilt: (40 * Math.PI) / 180}},
// Add a map scheme layer
[new MMapDefaultSchemeLayer({})]
);
let hasAutoRotate = true;
let frame = 0;
function onActionStartHandler() {
// Turn off the auto-rotation of the map flag at any event
hasAutoRotate = false;
autoRotateBtn.update({background: '#007afce6'});
}
// Creating a listener object
const mapListener = new MMapListener({
layer: 'any',
// Adding an onActionStart handler to the listener
onActionStart: onActionStartHandler
});
map.addChild(mapListener);
// Add a shared container for MMapControlButton's and add it to the map
const controls = new MMapControls({position: 'bottom'});
map.addChild(controls);
// Automatically rotate the camera
function startAutoRotationCamera() {
if (hasAutoRotate) {
// Divide degrees by 100 to slow rotation to ~10 degrees / sec
map.update({camera: {azimuth: map.azimuth + (10 * Math.PI) / 180 / 120}});
// Request the next frame of the animation
frame = requestAnimationFrame(startAutoRotationCamera);
} else {
// If the automatic rotation mode is stopped then cancel the request for the next animation frame
cancelAnimationFrame(frame);
}
}
startAutoRotationCamera();
// Add MMapControlButton's that will change the camera position when clicked
function autoRotateBtnHandler() {
hasAutoRotate = !hasAutoRotate;
autoRotateBtn.update({background: hasAutoRotate ? '#fd6466e6' : '#007afce6'});
startAutoRotationCamera();
}
const autoRotateBtn = new MMapControlButton({
text: 'Auto Rotate',
color: '#fff',
background: '#fd6466e6',
onClick: autoRotateBtnHandler
});
controls.addChild(autoRotateBtn);
function rotateLeftBtnHandler() {
onActionStartHandler();
// Rotate the camera 30 degrees to the left (degrees need to be converted to radians)
map.update({camera: {azimuth: map.azimuth - (30 * Math.PI) / 180, duration: 250}});
}
const rotateLeftBtn = new MMapControlButton({
text: 'Rotate Left',
color: '#fff',
background: '#007afce6',
onClick: rotateLeftBtnHandler
});
controls.addChild(rotateLeftBtn);
function rotateRightBtnHandler() {
onActionStartHandler();
// Rotate the camera 30 degrees to the right (degrees need to be converted to radians)
map.update({camera: {azimuth: map.azimuth + (30 * Math.PI) / 180, duration: 250}});
}
const rotateRightBtn = new MMapControlButton({
text: 'Rotate Right',
color: '#fff',
background: '#007afce6',
onClick: rotateRightBtnHandler
});
controls.addChild(rotateRightBtn);
function upTiltBtnHandler() {
onActionStartHandler();
// Tilt the camera up 10 degrees (degrees need to be converted to radians)
map.update({camera: {tilt: map.tilt - (10 * Math.PI) / 180, duration: 250}});
}
const upTiltBtn = new MMapControlButton({
text: 'Up Tilt',
color: '#fff',
background: '#007afce6',
onClick: upTiltBtnHandler
});
controls.addChild(upTiltBtn);
function downTiltBtnHandler() {
onActionStartHandler();
// Tilt the camera down 10 degrees (degrees need to be converted to radians)
map.update({camera: {tilt: map.tilt + (10 * Math.PI) / 180, duration: 250}});
}
const downTiltBtn = new MMapControlButton({
text: 'Down tilt',
color: '#fff',
background: '#007afce6',
onClick: downTiltBtnHandler
});
controls.addChild(downTiltBtn);
}
</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="react, typescript"
type="text/babel"
src="../variables.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="react, typescript" type="text/babel">
import {LOCATION} 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, MMapListener, MMapControls, MMapControlButton} =
reactify.module(mappable);
const {useState, useEffect, useRef, useCallback} = React;
function App() {
const [hasAutoRotate, setAutoRotate] = useState(true);
const [mapAzimuth, setMapAzimuth] = useState(0);
const [mapTilt, setMapTilt] = useState((40 * Math.PI) / 180);
const frame = useRef < number > null;
// Automatically rotate the camera
const startAutoRotationCamera = useCallback(() => {
if (hasAutoRotate) {
// Divide degrees by 100 to slow rotation to ~20 degrees / sec
setMapAzimuth(map.azimuth + (10 * Math.PI) / 180 / 100);
// Request the next frame of the animation
frame.current = requestAnimationFrame(startAutoRotationCamera);
} else {
// If the automatic rotation mode is stopped then cancel the request for the next animation frame
cancelAnimationFrame(frame.current);
}
}, [hasAutoRotate]);
useEffect(() => {
// Update ref to new animation frame ID
frame.current = requestAnimationFrame(startAutoRotationCamera);
// Kill animation cycle on component unmount
return () => cancelAnimationFrame(frame.current);
}, [startAutoRotationCamera]);
const onActionStartHandler = useCallback(() => {
// Turn off the auto-rotation of the map flag at any event
setAutoRotate(false);
}, []);
const autoRotateBtnHandler = useCallback(() => {
setAutoRotate((prevAutoRotate) => !prevAutoRotate);
}, []);
const rotateLeftBtnHandler = useCallback(() => {
onActionStartHandler();
// Rotate the camera 30 degrees to the left (degrees need to be converted to radians)
setMapAzimuth(map.azimuth - (30 * Math.PI) / 180);
}, []);
const rotateRightBtnHandler = useCallback(() => {
onActionStartHandler();
// Rotate the camera 30 degrees to the right (degrees need to be converted to radians)
setMapAzimuth(map.azimuth + (30 * Math.PI) / 180);
}, []);
const tiltUpBtnHandler = useCallback(() => {
onActionStartHandler();
// Tilt the camera up 10 degrees (degrees need to be converted to radians)
setMapTilt(map.tilt - (10 * Math.PI) / 180);
}, []);
const tiltDownBtnHandler = useCallback(() => {
onActionStartHandler();
// Tilt the camera down 10 degrees (degrees need to be converted to radians)
setMapTilt(map.tilt + (10 * Math.PI) / 180);
}, []);
return (
// Initialize the map and pass initialization parameters
<MMap
location={LOCATION}
showScaleInCopyrights={true}
camera={{azimuth: mapAzimuth, tilt: mapTilt, duration: hasAutoRotate ? 0 : 250}}
ref={(x) => (map = x)}
>
{/* Add a map scheme layer */}
<MMapDefaultSchemeLayer />
{/* Creating a listener component and adding an onActionStart handler to it */}
<MMapListener onActionStart={onActionStartHandler} />
{/* Add a shared container for MMapControlButton's */}
<MMapControls position="bottom">
{/* Add MMapControlButton's that will change the camera position when clicked */}
<MMapControlButton
text="Auto Rotate"
color="#fff"
background={hasAutoRotate ? '#fd6466e6' : '#007afce6'}
onClick={autoRotateBtnHandler}
/>
<MMapControlButton
text="Rotate Left"
color="#fff"
background="#007afce6"
onClick={rotateLeftBtnHandler}
/>
<MMapControlButton
text="Rotate Right"
color="#fff"
background="#007afce6"
onClick={rotateRightBtnHandler}
/>
<MMapControlButton text="Tilt Up" color="#fff" background="#007afce6" onClick={tiltUpBtnHandler} />
<MMapControlButton
text="Tilt Down"
color="#fff"
background="#007afce6"
onClick={tiltDownBtnHandler}
/>
</MMapControls>
</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="../variables.ts"
></script>
<script data-plugins="transform-modules-umd" data-presets="typescript" type="text/babel">
import {LOCATION} 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, MMapListener, MMapControls, MMapControlButton} = vuefy.module(mappable);
const app = Vue.createApp({
setup() {
const location = Vue.ref(LOCATION);
const refMap = (ref) => {
window.map = ref?.entity;
};
const hasAutoRotate = Vue.ref(true);
const mapAzimuth = Vue.ref(0);
const mapTilt = Vue.ref((40 * Math.PI) / 180);
let frameId;
const autoRotateCamera = () => {
if (hasAutoRotate.value) {
mapAzimuth.value += (10 * Math.PI) / 180 / 100;
frameId = requestAnimationFrame(autoRotateCamera);
}
};
Vue.onMounted(() => {
frameId = requestAnimationFrame(autoRotateCamera);
});
Vue.onUnmounted(() => {
cancelAnimationFrame(frameId);
});
const onActionStartHandler = () => {
hasAutoRotate.value = false;
};
const autoRotateBtnHandler = () => {
hasAutoRotate.value = !hasAutoRotate.value;
frameId = requestAnimationFrame(autoRotateCamera);
};
const rotateLeftBtnHandler = () => {
onActionStartHandler();
mapAzimuth.value = map.azimuth - (30 * Math.PI) / 180;
};
const rotateRightBtnHandler = () => {
onActionStartHandler();
mapAzimuth.value = map.azimuth + (30 * Math.PI) / 180;
};
const tiltUpBtnHandler = () => {
onActionStartHandler();
mapTilt.value = map.tilt - (10 * Math.PI) / 180;
};
const tiltDownBtnHandler = () => {
onActionStartHandler();
mapTilt.value = map.tilt + (10 * Math.PI) / 180;
};
return {
location,
refMap,
hasAutoRotate,
mapAzimuth,
mapTilt,
onActionStartHandler,
autoRotateBtnHandler,
rotateLeftBtnHandler,
rotateRightBtnHandler,
tiltUpBtnHandler,
tiltDownBtnHandler
};
},
components: {
MMap,
MMapDefaultSchemeLayer,
MMapListener,
MMapControls,
MMapControlButton
},
template: `
<MMap
:location="location"
:camera="{ azimuth: mapAzimuth, tilt: mapTilt, duration: hasAutoRotate ? 0 : 250 }"
:ref="refMap"
>
<MMapDefaultSchemeLayer />
<MMapListener @action-start="onActionStartHandler" />
<MMapControls position="bottom">
<MMapControlButton
text="Auto Rotate"
color="#fff"
:background="hasAutoRotate ? '#fd6466e6' : '#007afce6'"
@click="autoRotateBtnHandler"
/>
<MMapControlButton
text="Rotate Left"
color="#fff"
background="#007afce6"
@click="rotateLeftBtnHandler"
/>
<MMapControlButton
text="Rotate Right"
color="#fff"
background="#007afce6"
@click="rotateRightBtnHandler"
/>
<MMapControlButton
text="Tilt Up"
color="#fff"
background="#007afce6"
@click="tiltUpBtnHandler"
/>
<MMapControlButton
text="Tilt Down"
color="#fff"
background="#007afce6"
@click="tiltDownBtnHandler"
/>
</MMapControls>
</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>
</head>
<body>
<div id="app"></div>
</body>
</html>
import type {MMapLocationRequest} from '@mappable-world/mappable-types';
export const LOCATION: MMapLocationRequest = {
center: [55.35671, 25.24259], // starting position [lng, lat]
zoom: 17 // starting zoom
};
{"node": 20, "template": "static"}