diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index b0ec2e0590..17e80b9a10 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -1,5 +1,40 @@ ## Upgrade notes +### Next release + +#### Use `view.animate()` instead of `map.beforeRender()` and `ol.animation` functions + +The `map.beforeRender()` and `ol.animation` functions have been deprecated in favor of a new `view.animate()` function. Use of the deprecated functions will result in a warning during development. These functions are subject to removal in an upcoming release. + +For details on the `view.animate()` method, see the API docs and the view animation example. Upgrading should be relatively straightforward. For example, if you wanted to have an animated pan, zoom, and rotation previously, you might have done this: + +```js +var zoom = ol.animation.zoom({ + resolution: view.getResolution() +}); +var pan = ol.animation.pan({ + source: view.getCenter() +}); +var rotate = ol.animation.rotate({ + rotation: view.getRotation() +}); + +map.beforeRender(zoom, pan, rotate); + +map.setZoom(1); +map.setCenter([0, 0]); +map.setRotation(Math.PI); +``` + +Now, the same can be accomplished with this: +```js +view.animate({ + zoom: 1, + center: [0, 0], + rotation: Math.PI +}); +``` + ### v3.19.1 #### `ol.style.Fill` with `CanvasGradient` or `CanvasPattern` diff --git a/doc/tutorials/introduction.md b/doc/tutorials/introduction.md index 05c7a4d474..6858efb4cd 100644 --- a/doc/tutorials/introduction.md +++ b/doc/tutorials/introduction.md @@ -34,7 +34,7 @@ The library is intended for use on both desktop/laptop and mobile devices. OL3 uses a similar object hierarchy to the Closure library. There is a top-level `ol` namespace (basically, `var ol = {};`). Subdivisions of this are: * further namespaces, such as `ol.layer`; these have a lower-case initial -* simple objects containing static properties and methods, such as `ol.animation`; these also have a lower-case initial +* simple objects containing static properties and methods, such as `ol.easing`; these also have a lower-case initial * types, which have an upper-case initial. These are mainly 'classes', which here means a constructor function with prototypal inheritance, such as `ol.Map` or `ol.layer.Vector` (the Vector class within the layer namespace). There are however other, simpler, types, such as `ol.Extent`, which is an array. Class namespaces, such as `ol.layer` have a base class type with the same name, such as `ol.layer.Layer`. These are mainly abstract classes, from which the other subclasses inherit. diff --git a/examples/animation.html b/examples/animation.html index e0de6e10a9..54fa0cd014 100644 --- a/examples/animation.html +++ b/examples/animation.html @@ -3,17 +3,17 @@ layout: example.html title: View Animation shortdesc: Demonstrates animated pan, zoom, and rotation. docs: > - This example shows how to use the beforeRender function on the Map to run one - or more animations. + This example shows how to use the view.animate() method to run + one or more animations. tags: "animation" ---
- - + + diff --git a/examples/animation.js b/examples/animation.js index dfdfdb697e..6765e4ee38 100644 --- a/examples/animation.js +++ b/examples/animation.js @@ -1,13 +1,35 @@ goog.require('ol.Map'); goog.require('ol.View'); -goog.require('ol.animation'); -goog.require('ol.control'); goog.require('ol.layer.Tile'); goog.require('ol.proj'); goog.require('ol.source.OSM'); +var london = ol.proj.fromLonLat([-0.12755, 51.507222]); +var moscow = ol.proj.fromLonLat([37.6178, 55.7517]); +var istanbul = ol.proj.fromLonLat([28.9744, 41.0128]); +var rome = ol.proj.fromLonLat([12.5, 41.9]); +var bern = ol.proj.fromLonLat([7.4458, 46.95]); -// from https://github.com/DmitryBaranovskiy/raphael +var view = new ol.View({ + center: istanbul, + zoom: 6 +}); + +var map = new ol.Map({ + target: 'map', + layers: [ + new ol.layer.Tile({ + preload: 4, + source: new ol.source.OSM() + }) + ], + // Improve user experience by loading tiles while animating. Will make + // animations stutter on mobile or slow devices. + loadTilesWhileAnimating: true, + view: view +}); + +// A bounce easing method (from https://github.com/DmitryBaranovskiy/raphael). function bounce(t) { var s = 7.5625, p = 2.75, l; if (t < (1 / p)) { @@ -29,159 +51,116 @@ function bounce(t) { return l; } -// from https://github.com/DmitryBaranovskiy/raphael +// An elastic easing method (from https://github.com/DmitryBaranovskiy/raphael). function elastic(t) { return Math.pow(2, -10 * t) * Math.sin((t - 0.075) * (2 * Math.PI) / 0.3) + 1; } -var london = ol.proj.fromLonLat([-0.12755, 51.507222]); -var moscow = ol.proj.fromLonLat([37.6178, 55.7517]); -var istanbul = ol.proj.fromLonLat([28.9744, 41.0128]); -var rome = ol.proj.fromLonLat([12.5, 41.9]); -var bern = ol.proj.fromLonLat([7.4458, 46.95]); -var madrid = ol.proj.fromLonLat([-3.683333, 40.4]); +function onClick(id, callback) { + document.getElementById(id).addEventListener('click', callback); +} -var view = new ol.View({ - // the view's initial state - center: istanbul, - zoom: 6 +onClick('rotate-left', function() { + view.animate({ + rotation: view.getRotation() + Math.PI / 2 + }); }); -var map = new ol.Map({ - layers: [ - new ol.layer.Tile({ - preload: 4, - source: new ol.source.OSM() - }) - ], - // Improve user experience by loading tiles while animating. Will make - // animations stutter on mobile or slow devices. - loadTilesWhileAnimating: true, - target: 'map', - controls: ol.control.defaults({ - attributionOptions: /** @type {olx.control.AttributionOptions} */ ({ - collapsible: false - }) - }), - view: view +onClick('rotate-right', function() { + view.animate({ + rotation: view.getRotation() - Math.PI / 2 + }); }); -var rotateLeft = document.getElementById('rotate-left'); -rotateLeft.addEventListener('click', function() { - var rotateLeft = ol.animation.rotate({ - duration: 2000, - rotation: -4 * Math.PI +onClick('rotate-around-rome', function() { + view.animate({ + rotation: view.getRotation() + 2 * Math.PI, + anchor: rome }); - map.beforeRender(rotateLeft); -}, false); -var rotateRight = document.getElementById('rotate-right'); -rotateRight.addEventListener('click', function() { - var rotateRight = ol.animation.rotate({ - duration: 2000, - rotation: 4 * Math.PI - }); - map.beforeRender(rotateRight); -}, false); +}); -var rotateAroundRome = document.getElementById('rotate-around-rome'); -rotateAroundRome.addEventListener('click', function() { - var currentRotation = view.getRotation(); - var rotateAroundRome = ol.animation.rotate({ - anchor: rome, - duration: 1000, - rotation: currentRotation +onClick('pan-to-london', function() { + view.animate({ + center: london, + duration: 2000 }); - map.beforeRender(rotateAroundRome); - view.rotate(currentRotation + (Math.PI / 2), rome); -}, false); +}); -var panToLondon = document.getElementById('pan-to-london'); -panToLondon.addEventListener('click', function() { - var pan = ol.animation.pan({ +onClick('elastic-to-moscow', function() { + view.animate({ + center: moscow, duration: 2000, - source: /** @type {ol.Coordinate} */ (view.getCenter()) + easing: elastic }); - map.beforeRender(pan); - view.setCenter(london); -}, false); +}); -var elasticToMoscow = document.getElementById('elastic-to-moscow'); -elasticToMoscow.addEventListener('click', function() { - var pan = ol.animation.pan({ +onClick('bounce-to-istanbul', function() { + view.animate({ + center: istanbul, duration: 2000, - easing: elastic, - source: /** @type {ol.Coordinate} */ (view.getCenter()) + easing: bounce }); - map.beforeRender(pan); - view.setCenter(moscow); -}, false); +}); -var bounceToIstanbul = document.getElementById('bounce-to-istanbul'); -bounceToIstanbul.addEventListener('click', function() { - var pan = ol.animation.pan({ - duration: 2000, - easing: bounce, - source: /** @type {ol.Coordinate} */ (view.getCenter()) - }); - map.beforeRender(pan); - view.setCenter(istanbul); -}, false); - -var spinToRome = document.getElementById('spin-to-rome'); -spinToRome.addEventListener('click', function() { - var duration = 2000; - var start = +new Date(); - var pan = ol.animation.pan({ - duration: duration, - source: /** @type {ol.Coordinate} */ (view.getCenter()), - start: start - }); - var rotate = ol.animation.rotate({ - duration: duration, +onClick('spin-to-rome', function() { + view.animate({ + center: rome, rotation: 2 * Math.PI, - start: start + duration: 2000 }); - map.beforeRender(pan, rotate); - view.setCenter(rome); -}, false); +}); -var flyToBern = document.getElementById('fly-to-bern'); -flyToBern.addEventListener('click', function() { +function flyTo(location, done) { var duration = 2000; - var start = +new Date(); - var pan = ol.animation.pan({ - duration: duration, - source: /** @type {ol.Coordinate} */ (view.getCenter()), - start: start - }); - var bounce = ol.animation.bounce({ - duration: duration, - resolution: 4 * view.getResolution(), - start: start - }); - map.beforeRender(pan, bounce); - view.setCenter(bern); -}, false); + var zoom = view.getZoom(); + var parts = 2; + var called = false; + function callback(complete) { + --parts; + if (called) { + return; + } + if (parts === 0 || !complete) { + called = true; + done(complete); + } + } + view.animate({ + center: location, + duration: duration + }, callback); + view.animate({ + zoom: zoom - 1, + duration: duration / 2 + }, { + zoom: zoom, + duration: duration / 2 + }, callback); +} -var spiralToMadrid = document.getElementById('spiral-to-madrid'); -spiralToMadrid.addEventListener('click', function() { - var duration = 2000; - var start = +new Date(); - var pan = ol.animation.pan({ - duration: duration, - source: /** @type {ol.Coordinate} */ (view.getCenter()), - start: start - }); - var bounce = ol.animation.bounce({ - duration: duration, - resolution: 2 * view.getResolution(), - start: start - }); - var rotate = ol.animation.rotate({ - duration: duration, - rotation: -4 * Math.PI, - start: start - }); - map.beforeRender(pan, bounce, rotate); - view.setCenter(madrid); -}, false); +onClick('fly-to-bern', function() { + flyTo(bern, function() {}); +}); + +function tour() { + var locations = [london, bern, rome, moscow, istanbul]; + var index = -1; + function next(more) { + if (more) { + ++index; + if (index < locations.length) { + var delay = index === 0 ? 0 : 750; + setTimeout(function() { + flyTo(locations[index], next); + }, delay); + } else { + alert('Tour complete'); + } + } else { + alert('Tour cancelled'); + } + } + next(true); +} + +onClick('tour', tour); diff --git a/examples/geolocation-orientation.js b/examples/geolocation-orientation.js index a14a908355..17c0eefeda 100644 --- a/examples/geolocation-orientation.js +++ b/examples/geolocation-orientation.js @@ -130,26 +130,6 @@ function addPosition(position, heading, m, speed) { } } -var previousM = 0; -// change center and rotation before render -map.beforeRender(function(map, frameState) { - if (frameState !== null) { - // use sampling period to get a smooth transition - var m = frameState.time - deltaMean * 1.5; - m = Math.max(m, previousM); - previousM = m; - // interpolate position along positions LineString - var c = positions.getCoordinateAtM(m, true); - var view = frameState.viewState; - if (c) { - view.center = getCenterWithHeading(c, -c[2], view.resolution); - view.rotation = -c[2]; - marker.setPosition(c); - } - } - return true; // Force animation to continue -}); - // recenters the view by putting the given coordinates at 3/4 from the top or // the screen function getCenterWithHeading(position, rotation, resolution) { @@ -162,9 +142,19 @@ function getCenterWithHeading(position, rotation, resolution) { ]; } -// postcompose callback -function render() { - map.render(); +var previousM = 0; +function updateView() { + // use sampling period to get a smooth transition + var m = Date.now() - deltaMean * 1.5; + m = Math.max(m, previousM); + previousM = m; + // interpolate position along positions LineString + var c = positions.getCoordinateAtM(m, true); + if (c) { + view.setCenter(getCenterWithHeading(c, -c[2], view.getResolution())); + view.setRotation(-c[2]); + marker.setPosition(c); + } } // geolocate device @@ -172,7 +162,7 @@ var geolocateBtn = document.getElementById('geolocate'); geolocateBtn.addEventListener('click', function() { geolocation.setTracking(true); // Start position tracking - map.on('postcompose', render); + map.on('postcompose', updateView); map.render(); disableButtons(); @@ -214,7 +204,7 @@ simulateBtn.addEventListener('click', function() { } geolocate(); - map.on('postcompose', render); + map.on('postcompose', updateView); map.render(); disableButtons(); diff --git a/examples/side-by-side.css b/examples/side-by-side.css new file mode 100644 index 0000000000..aabe991891 --- /dev/null +++ b/examples/side-by-side.css @@ -0,0 +1,7 @@ +@media (min-width: 800px) { + .half { + padding: 0 10px; + width: 50%; + float: left; + } +} diff --git a/examples/side-by-side.html b/examples/side-by-side.html index 4defaff50b..557751535f 100644 --- a/examples/side-by-side.html +++ b/examples/side-by-side.html @@ -6,10 +6,14 @@ docs: > Two maps (one with the Canvas renderer, one with the WebGL renderer) share the same center, resolution, rotation and layers. tags: "side-by-side, canvas, webgl" --- -

Canvas

-
-

WebGL

-
-