Customize camera animations
Customize camera animations using AnimationOptions
.
Note
If you want to test this example, edit it in JSFiddle or CodePen and replace the "YOUR-OWN-API-KEY" and "YOUR-OWN-VPM-ID" placeholders with your actual api key and vpm id.<!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://unpkg.com/unl-map-js@0.1.5/lib/unl-map-js.js"></script><link href="https://unpkg.com/unl-map-js@0.1.5/lib/unl-map-js.css" rel="stylesheet" /><linkhref="https://unpkg.com/maplibre-gl@2.1.9/dist/maplibre-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>// 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.var easingFunctions = {// start slow and gradually increase speedeaseInCubic: function (t) {return t * t * t;},// start fast with a long, slow wind-downeaseOutQuint: function (t) {return 1 - Math.pow(1 - t, 5);},// slow start and finish with fast middleeaseInOutCirc: function (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: function (t) {var n1 = 7.5625;var 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 formvar durationValueSpan = document.getElementById("durationValue");var durationInput = document.getElementById("duration");durationValueSpan.innerHTML = durationInput.value / 1000 + " seconds";durationInput.addEventListener("change", function (e) {durationValueSpan.innerHTML = e.target.value / 1000 + " seconds";}); var animateLabel = document.getElementById("animateLabel");var animateValue = document.getElementById("animate");animateValue.addEventListener("change", function (e) {animateLabel.innerHTML = e.target.checked ? "Yes" : "No";}); var map = new UnlSdk.Map({container: "map",apiKey: "YOUR-OWN-API-KEY",vpmId: "YOUR-OWN-VPM-ID",center: [-95, 40],zoom: 3,}); map.on("load", function () {// 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": ["Fira GO Regular"],"text-offset": [0, 0.6],"text-anchor": "top",},}); var animateButton = document.getElementById("animateButton");animateButton.addEventListener("click", function () {var easingInput = document.getElementById("easing");var easingFn =easingFunctions[easingInput.options[easingInput.selectedIndex].value];var duration = parseInt(durationInput.value, 10);var animate = animateValue.checked;var offsetX = parseInt(document.getElementById("offset-x").value, 10);var offsetY = parseInt(document.getElementById("offset-y").value, 10); var 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.var 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>