Customize camera animations
Customize camera animations using AnimationOptions
.
<!DOCTYPE html><html><head><meta charset="utf-8" /><title>Customize camera animations</title><meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /><script src="https://cdn.ndrive.com/nmapsgl/v.1.6.8/nmaps-gl.js"></script><link href="https://cdn.ndrive.com/nmapsgl/v.1.6.8/nmaps-gl.css" rel="stylesheet" /><style> body { margin: 0; padding: 0; } #map { position: absolute; top: 0; bottom: 0; width: 100%; }</style></head><body><style>.map-overlay {font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;position: absolute;width: 200px;top: 0;left: 0;padding: 10px;} .map-overlay .map-overlay-inner {background-color: #fff;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);border-radius: 3px;padding: 10px;margin-bottom: 10px;} .map-overlay-inner fieldset {border: none;padding: 0;margin: 0 0 10px;} .map-overlay-inner fieldset:last-child {margin: 0;} .map-overlay-inner select {width: 100%;} .map-overlay-inner p {margin: 0;} .map-overlay-inner label {display: block;font-weight: bold;} .map-overlay-inner button {background-color: cornflowerblue;color: white;border-radius: 5px;display: inline-block;height: 20px;border: none;cursor: pointer;} .map-overlay-inner button:focus {outline: none;} .map-overlay-inner button:hover {background-color: blue;box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.1);-webkit-transition: background-color 500ms linear;-ms-transition: background-color 500ms linear;transition: background-color 500ms linear;} .offset > label,.offset > input {display: inline;} #animateLabel {display: inline-block;min-width: 20px;}</style> <div id="map"></div><div class="map-overlay top"><div class="map-overlay-inner"><fieldset><label>Select easing function</label><select id="easing" name="easing"><option value="easeInCubic">Ease In Cubic</option><option value="easeOutQuint">Ease Out Quint</option><option value="easeInOutCirc">Ease In/Out Circ</option><option value="easeOutBounce">Ease Out Bounce</option></select></fieldset><fieldset><label for="duration">Set animation duration</label><p id="durationValue"></p><inputtype="range"id="duration"name="duration"min="0"max="10000"step="500"value="1000"/></fieldset><fieldset><label>Animate camera motion</label><label for="animate" id="animateLabel">Yes</label><input type="checkbox" id="animate" name="animate" checked /></fieldset><fieldset class="offset"><label for="offset-x">Offset-X</label><inputtype="number"id="offset-x"name="offset-x"min="-200"max="200"step="50"value="0"/></fieldset><fieldset class="offset"><label for="offset-y">Offset-Y</label><inputtype="number"id="offset-y"name="offset-y"min="-200"max="200"step="50"value="0"/><p>Offsets can be negative</p></fieldset><button type="button" id="animateButton" name="test-animation">Test Animation</button></div></div> <script> // TO MAKE THE MAP APPEAR YOU MUST ADD YOUR ACCESS TOKEN nmapsgl.accessToken = '<your access token here>'; // declare various easing functions.// easing functions mathematically describe// how fast a value changes during an animation.// each function takes a parameter t that represents// the progress of the animation.// t is in a range of 0 to 1 where 0 is the initial// state and 1 is the completed state.const easingFunctions = {// start slow and gradually increase speedeaseInCubic: (t) => {return t * t * t;},// start fast with a long, slow wind-downeaseOutQuint: (t) => {return 1 - Math.pow(1 - t, 5);},// slow start and finish with fast middleeaseInOutCirc: (t) => {return t < 0.5? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2: (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2;},// fast start with a "bounce" at the endeaseOutBounce: (t) => {const n1 = 7.5625;const d1 = 2.75; if (t < 1 / d1) {return n1 * t * t;} else if (t < 2 / d1) {return n1 * (t -= 1.5 / d1) * t + 0.75;} else if (t < 2.5 / d1) {return n1 * (t -= 2.25 / d1) * t + 0.9375;} else {return n1 * (t -= 2.625 / d1) * t + 0.984375;}}}; // set up some helpful UX on the formconst durationValueSpan = document.getElementById('durationValue');const durationInput = document.getElementById('duration');durationValueSpan.innerHTML = durationInput.value / 1000 + ' seconds';durationInput.addEventListener('change', (e) => {durationValueSpan.innerHTML = e.target.value / 1000 + ' seconds';}); const animateLabel = document.getElementById('animateLabel');const animateValue = document.getElementById('animate');animateValue.addEventListener('change', (e) => {animateLabel.innerHTML = e.target.checked ? 'Yes' : 'No';}); const map = new nmapsgl.Map({container: 'map',style: 'Streets',center: [-95, 40],zoom: 3}); map.on('load', () => {// add a layer to display the map's center pointmap.addSource('center', {'type': 'geojson','data': {'type': 'Point','coordinates': [-94, 40]}});map.addLayer({'id': 'center','type': 'symbol','source': 'center','layout': {'icon-image': 'marker-15','text-field': 'Center: [-94, 40]','text-font': ['Open Sans Regular'],'text-offset': [0, 0.6],'text-anchor': 'top'}}); const animateButton = document.getElementById('animateButton');animateButton.addEventListener('click', () => {const easingInput = document.getElementById('easing');const easingFn =easingFunctions[easingInput.options[easingInput.selectedIndex].value];const duration = parseInt(durationInput.value, 10);const animate = animateValue.checked;const offsetX = parseInt(document.getElementById('offset-x').value,10);const offsetY = parseInt(document.getElementById('offset-y').value,10); const animationOptions = {duration: duration,easing: easingFn,offset: [offsetX, offsetY],animate: animate,essential: true // animation will happen even if user has `prefers-reduced-motion` setting on}; // Create a random location to fly to by offsetting the map's// initial center point by up to 10 degrees.const center = [-95 + (Math.random() - 0.5) * 20,40 + (Math.random() - 0.5) * 20]; // merge animationOptions with other flyTo optionsanimationOptions.center = center; map.flyTo(animationOptions);// update 'center' source and layer to show our new map center// compare this center point to where the camera ends up when an offset is appliedmap.getSource('center').setData({'type': 'Point','coordinates': center});map.setLayoutProperty('center','text-field','Center: [' +center[0].toFixed(1) +', ' +center[1].toFixed(1) +']');});});</script> </body></html>