mapsplugin / cordova-plugin-googlemaps

Google Maps plugin for Cordova
Apache License 2.0
1.66k stars 912 forks source link

Animating map view re-positioning #50

Closed stevesims closed 8 years ago

stevesims commented 10 years ago

I'd really like to animate the position of the map view. The scenario I'm imagining is that the user presses a button and the map slides to the right to reveal a menu hidden underneath the map (displayed in the cordova web view).

I've looked at the code, and it seems to me that the logical place to put support for this on the JS side would be to add an "animated" flag to the map.refreshLayout method. I guess that the animation duration could be a default value which could get overridden in params passed into the getMap method.

wf9a5m75 commented 10 years ago

You can change the animate duration using the duration parameter. And could you show me your snippet code that you imagine for 'animated' flag?

The biggest problem is that the native side can not detect when CSS transition is started. Because W3C does not define an event when the transition starts. That's why the map can not move with the div tag.

One solution I can give you is that if your Javascript can detect when the div slides, you can generate an image data using map.toDataURL(). You can pass it to tag. It means: (1) generate the image using toDataURL() (2) then insert the map div, and hide the map (3) the sliding start (4) show the map, and remove the image when the sliding is finished.

However map.toDataURL() takes a few time (how long is depends on device). As far as my test, Android works good with this idea, but iPhone takes the time longer.

So in my example code, I just hide the map when the slide bar is opened, then show the map again after moving is finished. https://github.com/wf9a5m75/phonegap-googlemaps-plugin/blob/master/example/v1.0.9-example/js/example.js#L55 example-v1 0 7

stevesims commented 10 years ago

Thanks again for the quick response.

Your example hiding the map makes good sense.

You're of course right - you can't listen out for CSS transition events. Even if you could, I'd suspect you'd have a hard time keeping the map position properly in sync with the DOM.

I like your idea of using toDataURL. That feels like it could work quite well. As a work-around to the fact that it takes time for the cordova bridge to pass the data URL back to the DOM I'd suggest that one could periodically update a cached image so it's there ready, so you wouldn't have to call toDataURL when the "click to move map" happens. I'm thinking one could listen for an event that says "the map has finished updating" and then grab an image.

My own use-case is simpler than your example - given the design I'm working with I don't need to worry about syncing up the animation of the map with other things in the DOM as I only need to move the map itself.

As for code snippets, I was thinking that one would do something like this:

// update position of map holder element
mapHolder.classList.add("offset");
// refresh plugin map position, asking for it to be animated
map.refreshLayout(true);

The "offset" class would just do an abrupt position change of the mapHolder (the element that had been set as the div for the map).

This would mean that refreshLayout in googlemaps-cdv-plugin.js would change to:

  App.prototype.refreshLayout = function(animated) {
    onMapResize(undefined, animated);
  };

and onMapResize would become:

  function onMapResize(event, animated) {
    var self = window.plugin.google.maps.Map;
    var div = self.get("div");
    if (!div) {
      return;
    }
    if (isDom(div) == false) {
      self.set("div", null);
      cordova.exec(null, self.errorHandler, PLUGIN_NAME, 'setDiv', []);
    } else {
      var divSize = getDivSize(div);
      cordova.exec(null, self.errorHandler, PLUGIN_NAME, 'resizeMap', [divSize, animated]);
    }    
  }

I can probably come up with some Obj-C code for the iOS plugin too if that'd help.

wf9a5m75 commented 10 years ago

Thanks for your idea. I also have been considering the pre-cached idea, but I haven't tested yet, because I don't have enough time.

Could you show me some Obj-C code? I will consider this.

stevesims commented 10 years ago

I'll endeavour to try to whip up some Obj-C code later today that animates the position change on iOS.

wf9a5m75 commented 10 years ago

Thank you

stevesims commented 10 years ago

Pull request includes code that implements this idea (animated flag on JS map.refreshLayout method), much as described above.

Only iOS code has been implemented, but Android should be unaffected. I've also not had a chance to try this out to see if it affects non-embedded maps.

wf9a5m75 commented 10 years ago

@stevesims This feature will not implement in version 1.0.12, because I need more test and adjustment. Also I need the time to implement for Android. So if you want to use this feature, please do it on your fork. However this feature will be implemented in near the feature.

stevesims commented 10 years ago

I've finally got around to implementing my Android code for this. My "android-slide" branch now includes this code.

I wouldn't say this is really finished per-se. My code works, but the animation duration is hard-coded (this should really have a setting, as we've previously discussed). The code probably could be significantly tidier/shorter too.

The animation code sits inside the updateMapViewLayout method inside GoogleMaps.java. This will use a more efficient TranslateAnimation if the view is only moving (i.e. it's width and height are staying the same), otherwise it uses a custom ResizeMoveAnimation (implemented in ResizeMoveAnimation.java).

This code is not extensively tested - but it works for me! :-)

wf9a5m75 commented 10 years ago

Sorry for late response. And thank you @stevesims , I will check in couple of days.

wf9a5m75 commented 9 years ago

Implement this feature for iOS in v1.2.0.

wf9a5m75 commented 9 years ago

The animation causes the map center position is misaligned. (The map center position moves to left-top)

I need more test, and I detach the code from v1.2.0 temporally.

hirbod commented 8 years ago

dropped for now due to limited time