diff --git a/src/ol/control/overviewmapcontrol.js b/src/ol/control/overviewmapcontrol.js index f09c70d849..66b5d9b616 100644 --- a/src/ol/control/overviewmapcontrol.js +++ b/src/ol/control/overviewmapcontrol.js @@ -12,9 +12,11 @@ goog.require('ol.Collection'); goog.require('ol.Map'); goog.require('ol.MapEventType'); goog.require('ol.Object'); +goog.require('ol.ObjectEventType'); goog.require('ol.Overlay'); goog.require('ol.OverlayPositioning'); goog.require('ol.View'); +goog.require('ol.ViewProperty'); goog.require('ol.control.Control'); goog.require('ol.coordinate'); goog.require('ol.css'); @@ -155,54 +157,89 @@ goog.inherits(ol.control.OverviewMap, ol.control.Control); * @api */ ol.control.OverviewMap.prototype.setMap = function(map) { - var currentMap = this.getMap(); - - if (goog.isNull(map) && !goog.isNull(currentMap)) { - goog.events.unlisten( - currentMap, ol.Object.getChangeEventType(ol.MapProperty.VIEW), - this.handleViewChanged_, false, this); + var oldMap = this.getMap(); + if (map === oldMap) { + return; + } + if (oldMap) { + var oldView = oldMap.getView(); + if (oldView) { + this.unbindView_(oldView); + } } - goog.base(this, 'setMap', map); - if (!goog.isNull(map)) { + if (map) { + this.listenerKeys.push(goog.events.listen( + map, ol.ObjectEventType.PROPERTYCHANGE, + this.handleMapPropertyChange_, false, this)); - // if no layers were set for the overviewmap map, then bind with - // those in the main map + // TODO: to really support map switching, this would need to be reworked if (this.ovmap_.getLayers().getLength() === 0) { this.ovmap_.setLayerGroup(map.getLayerGroup()); } - // bind current map view, or any new one - this.bindView_(); - - goog.events.listen( - map, ol.Object.getChangeEventType(ol.MapProperty.VIEW), - this.handleViewChanged_, false, this); - - this.ovmap_.updateSize(); - this.resetExtent_(); + var view = map.getView(); + if (view) { + this.bindView_(view); + if (view.isDef()) { + this.ovmap_.updateSize(); + this.resetExtent_(); + } + } } }; /** - * Bind some actions to the main map view. + * Handle map property changes. This only deals with changes to the map's view. + * @param {ol.ObjectEvent} event The propertychange event. * @private */ -ol.control.OverviewMap.prototype.bindView_ = function() { - var map = this.getMap(); - var view = map.getView(); - - // if the map does not have a view, we can't act upon it - if (goog.isNull(view)) { - return; +ol.control.OverviewMap.prototype.handleMapPropertyChange_ = function(event) { + if (event.key === ol.MapProperty.VIEW) { + var oldView = /** @type {ol.View} */ (event.oldValue); + if (oldView) { + this.unbindView_(oldView); + } + var newView = this.getMap().getView(); + this.bindView_(newView); } +}; - // FIXME - the overviewmap view rotation currently follows the one used - // by the main map view. We could support box rotation instead. The choice - // between the 2 modes would be made in a single option - // this.ovmap_.getView().bindTo(ol.ViewProperty.ROTATION, view); + +/** + * Register listeners for view property changes. + * @param {ol.View} view The view. + * @private + */ +ol.control.OverviewMap.prototype.bindView_ = function(view) { + goog.events.listen(view, + ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), + this.handleRotationChanged_, false, this); +}; + + +/** + * Unregister listeners for view property changes. + * @param {ol.View} view The view. + * @private + */ +ol.control.OverviewMap.prototype.unbindView_ = function(view) { + goog.events.unlisten(view, + ol.Object.getChangeEventType(ol.ViewProperty.ROTATION), + this.handleRotationChanged_, false, this); +}; + + +/** + * Handle rotation changes to the main map. + * TODO: This should rotate the extent rectrangle instead of the + * overview map's view. + * @private + */ +ol.control.OverviewMap.prototype.handleRotationChanged_ = function() { + this.ovmap_.getView().setRotation(this.getMap().getView().getRotation()); }; @@ -217,16 +254,6 @@ ol.control.OverviewMap.render = function(mapEvent) { }; -/** - * Called on main map view changed. - * @param {goog.events.Event} event Event. - * @private - */ -ol.control.OverviewMap.prototype.handleViewChanged_ = function(event) { - this.bindView_(); -}; - - /** * Reset the overview map extent if the box size (width or * height) is less than the size of the overview map size times minRatio diff --git a/src/ol/view.js b/src/ol/view.js index 7a7325bf5c..4b2b50cfe4 100644 --- a/src/ol/view.js +++ b/src/ol/view.js @@ -1,5 +1,6 @@ goog.provide('ol.View'); goog.provide('ol.ViewHint'); +goog.provide('ol.ViewProperty'); goog.require('goog.array'); goog.require('goog.asserts'); diff --git a/test/spec/ol/control/overviewmapcontrol.test.js b/test/spec/ol/control/overviewmapcontrol.test.js new file mode 100644 index 0000000000..30de52b4c9 --- /dev/null +++ b/test/spec/ol/control/overviewmapcontrol.test.js @@ -0,0 +1,92 @@ +goog.provide('ol.test.control.OverviewMap'); + +describe('ol.control.OverviewMap', function() { + var map, target; + + beforeEach(function() { + target = document.createElement('div'); + document.body.appendChild(target); + map = new ol.Map({ + target: target + }); + }); + + afterEach(function() { + goog.dispose(map); + document.body.removeChild(target); + map = null; + target = null; + }); + + describe('constructor', function() { + it('creates an overview map with the default options', function() { + var control = new ol.control.OverviewMap(); + expect(control).to.be.a(ol.control.OverviewMap); + expect(control).to.be.a(ol.control.Control); + }); + }); + + describe('setMap()', function() { + + it('keeps ovmap view rotation in sync with map view rotation', function() { + var view = new ol.View({ + center: [0, 0], + zoom: 0, + rotation: 0 + }); + map.setView(view); + + var control = new ol.control.OverviewMap(); + map.addControl(control); + var ovView = control.ovmap_.getView(); + expect(ovView.getRotation()).to.be(0); + + view.setRotation(Math.PI / 4); + expect(ovView.getRotation()).to.be(Math.PI / 4); + }); + + it('maintains rotation in sync if view added later', function() { + var control = new ol.control.OverviewMap(); + map.addControl(control); + var ovView = control.ovmap_.getView(); + expect(ovView.getRotation()).to.be(0); + + var view = new ol.View({ + center: [0, 0], + zoom: 0, + rotation: 0 + }); + map.setView(view); + view.setRotation(Math.PI / 4); + expect(ovView.getRotation()).to.be(Math.PI / 4); + }); + + it('stops listening to old maps', function() { + var control = new ol.control.OverviewMap(); + var ovView = control.ovmap_.getView(); + + var view = new ol.View({ + center: [0, 0], + zoom: 0, + rotation: 0 + }); + map.setView(view); + map.addControl(control); + + view.setRotation(Math.PI / 8); + expect(ovView.getRotation()).to.be(Math.PI / 8); + + map.removeControl(control); + + view.setRotation(Math.PI / 4); + expect(ovView.getRotation()).to.be(Math.PI / 8); + }); + + }); + +}); + +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.control.Control'); +goog.require('ol.control.OverviewMap');