2
votes

I've created a map in Openlayers 3 that is based off the "doBounce" (pan & bounce animation) from this sample script (goo.gl/YoR7Ta). Here's FIDDLE #1 for the basic doBounce animation.

What I'm aiming for is to have the map also do a zoom animation to a specific zoom level AFTER the "doBounce" animation. Each location will have a different zoom level. For example, when I click on "North Coast", it does the "doBounce" animation, then does a zoom animation to zoom level of 10. And when I click "Fraser River", it does "doBounce", then a zoom animation to zoom level of 12.

I've spent the past few days trying to figure out how to do it & have searched through google & stackoverflow with no luck.

The best I could come up with was putting together this hacky FIDDLE #2 that at least lets me do some kind of zoom animation afterwards ...but it's not quite what I want.

Here's my modified "doBounce" script from the second fiddle:

function doBounce(location) {
    var duration = 2500;
    var start = +new Date();

    //REMOVE COMMENT FROM NEXT LINE TO SEE TEMP FIX SO ZOOM OCCURS EACH TIME
    //map.getView().setResolution(500);

    var bounce = ol.animation.bounce({
        duration: duration,
        resolution: view.getResolution() * 5,
        start: start
    });

    var pan = ol.animation.pan({
        duration: duration,
        source: view.getCenter(),
        start: start
    });

    var zoom = ol.animation.zoom({
        resolution: view.getResolution(),
        duration: 800,
        easing: ol.easing.linear,
      start: start + 2500
    });

    map.beforeRender(bounce, pan);
    view.setCenter(location);

    setTimeout(function() {
        map.beforeRender(zoom);
        view.setResolution(250);
    }, 2510);
}

I used a timeout to delay the zoom animation until the "deBouce" animation has finished. This finally allowed me to have a zoom animation but it would only happen on the first click. The following clicks would not show a zoom animation (I assume because ol.animation.bounce() returns the same resolution it started with).

To fix this, I added view.setResolution(500); at the start of the function so that it changes the resolution. This way, at least the zoom animation would work on each click. You can see what I mean by running the fiddle and then removing the commented line and running it again.

Is there a way to have each location smoothly zoom into a specific zoom level after the "doBounce" animation?

I'm fairly new to Javascript & Openlayers so any help or suggestions are greatly appreciated.

1
have you tried map.beforeRender(bounce, pan, zoom); ? - grateful
don't change the resolution, change the zoom level jsfiddle.net/joherro3/wcn8vt0g/7 - Jose Hermosilla Rodrigo
@grateful - Yes, I tried but it seems to trigger the zoom animation at the same time as the other animations, causing it to create an entire different animation that still doesn't result in a different zoom level. I think that's because the bounce animation and zoom animation both need to use getResolution. Here's the fiddle trying that method. - nnamerz
@JoseHermosillaRodrigo - How would I make it so each location has a different zoom level. And also, when playing around with your variation, I noticed that if you trigger the first animation, then manually zoom in to the map and then click to trigger a second animation, it doesn't zoom out gradually anymore. It just jumps to the proper zoom level and then pans to the new location. Here's the fiddle (I adjusted the initial zoom level and your zoom level to help show what I was referring to). - nnamerz

1 Answers

2
votes

You could structure this flow chaining (calling in sequence) your functions with a promise helper library like Q.js. It can be like this:

function flyTo(location) {
  var final_zoom = 12,
      initial_zoom = 4;

  zoom(initial_zoom)
    .then(function() {
      console.info('Zoomed Out!');
      return panTo(location);
    })
    .then(function() {
      console.info('Panned to ... ');
      return zoom(final_zoom);
    })
    .then(function() {
      console.log('done!');
    });
}

Or shorter:

function flyTo(location) {
  var final_zoom = 12,
      initial_zoom = 4;

  zoom(initial_zoom)
    .then(panTo.bind(null, location))
    .then(zoom.bind(null, final_zoom))
    .then(function() {
        console.log('done!');
    });
}

Other functions:

function zoom(zoom_level) {
  var duration = 500;
  var deferred = Q.defer();
  var zoom = ol.animation.zoom({
    duration: duration,
    resolution: view.getResolution()
  });

  map.beforeRender(zoom);
  view.setZoom(zoom_level);

  Q.delay(duration).then(deferred.resolve);
  return deferred.promise;
}

function panTo(location) {
  var duration = 1500;
  var deferred = Q.defer();
  var pan = ol.animation.pan({
    duration: duration,
    source: view.getCenter()
  });

  map.beforeRender(pan);
  view.setCenter(location);

  Q.delay(duration)
    .then(deferred.resolve); // <---- here's where things happen
  return deferred.promise;
}

(fiddle)