Merge pull request #3256 from tsauerwein/overlay-panIntoView
Add autoPan option to ol.Overlay
This commit is contained in:
@@ -29,9 +29,12 @@ closer.onclick = function() {
|
||||
/**
|
||||
* Create an overlay to anchor the popup to the map.
|
||||
*/
|
||||
var overlay = new ol.Overlay({
|
||||
element: container
|
||||
});
|
||||
var overlay = new ol.Overlay(/** @type {olx.OverlayOptions} */ ({
|
||||
element: container,
|
||||
autoPanAnimation: {
|
||||
duration: 250
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
/**
|
||||
@@ -60,7 +63,7 @@ var map = new ol.Map({
|
||||
/**
|
||||
* Add a click handler to the map to render the popup.
|
||||
*/
|
||||
map.on('click', function(evt) {
|
||||
map.on('singleclick', function(evt) {
|
||||
var coordinate = evt.coordinate;
|
||||
var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
|
||||
coordinate, 'EPSG:3857', 'EPSG:4326'));
|
||||
|
||||
@@ -310,7 +310,10 @@ olx.MapOptions.prototype.view;
|
||||
* position: (ol.Coordinate|undefined),
|
||||
* positioning: (ol.OverlayPositioning|string|undefined),
|
||||
* stopEvent: (boolean|undefined),
|
||||
* insertFirst: (boolean|undefined)}}
|
||||
* insertFirst: (boolean|undefined),
|
||||
* autoPan: (boolean|undefined),
|
||||
* autoPanAnimation: (olx.animation.PanOptions|undefined),
|
||||
* autoPanMargin: (number|undefined)}}
|
||||
* @api stable
|
||||
*/
|
||||
olx.OverlayOptions;
|
||||
@@ -376,6 +379,35 @@ olx.OverlayOptions.prototype.stopEvent;
|
||||
olx.OverlayOptions.prototype.insertFirst;
|
||||
|
||||
|
||||
/**
|
||||
* If set to `true` the map is panned when calling `setPosition`, so that the
|
||||
* overlay is entirely visible in the current viewport.
|
||||
* The default is `true`.
|
||||
* @type {boolean|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.OverlayOptions.prototype.autoPan;
|
||||
|
||||
|
||||
/**
|
||||
* The options used to create a `ol.animation.pan` animation. This animation
|
||||
* is only used when `autoPan` is enabled. By default the default options for
|
||||
* `ol.animation.pan` are used. If set to `null` the panning is not animated.
|
||||
* @type {olx.animation.PanOptions|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.OverlayOptions.prototype.autoPanAnimation;
|
||||
|
||||
|
||||
/**
|
||||
* The margin (in pixels) between the overlay and the borders of the map when
|
||||
* autopanning. The default is `20`.
|
||||
* @type {number|undefined}
|
||||
* @api
|
||||
*/
|
||||
olx.OverlayOptions.prototype.autoPanMargin;
|
||||
|
||||
|
||||
/**
|
||||
* Object literal with config options for the projection.
|
||||
* @typedef {{code: string,
|
||||
|
||||
@@ -298,3 +298,35 @@ ol.dom.transformElement2D =
|
||||
// content size.
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the current computed width for the given element including margin,
|
||||
* padding and border.
|
||||
* Equivalent to jQuery's `$(el).outerWidth(true)`.
|
||||
* @param {!Element} element Element.
|
||||
* @return {number}
|
||||
*/
|
||||
ol.dom.outerWidth = function(element) {
|
||||
var width = element.offsetWidth;
|
||||
var style = element.currentStyle || window.getComputedStyle(element);
|
||||
width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);
|
||||
|
||||
return width;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the current computed height for the given element including margin,
|
||||
* padding and border.
|
||||
* Equivalent to jQuery's `$(el).outerHeight(true)`.
|
||||
* @param {!Element} element Element.
|
||||
* @return {number}
|
||||
*/
|
||||
ol.dom.outerHeight = function(element) {
|
||||
var height = element.offsetHeight;
|
||||
var style = element.currentStyle || window.getComputedStyle(element);
|
||||
height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
|
||||
|
||||
return height;
|
||||
};
|
||||
|
||||
@@ -11,6 +11,9 @@ goog.require('ol.Coordinate');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.MapEventType');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.animation');
|
||||
goog.require('ol.dom');
|
||||
goog.require('ol.extent');
|
||||
|
||||
|
||||
/**
|
||||
@@ -90,6 +93,26 @@ ol.Overlay = function(options) {
|
||||
this.element_ = goog.dom.createElement(goog.dom.TagName.DIV);
|
||||
this.element_.style.position = 'absolute';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.autoPan_ = goog.isDef(options.autoPan) ? options.autoPan : true;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {olx.animation.PanOptions}
|
||||
*/
|
||||
this.autoPanAnimation_ = goog.isDef(options.autoPanAnimation) ?
|
||||
options.autoPanAnimation : /** @type {olx.animation.PanOptions} */ ({});
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.autoPanMargin_ = goog.isDef(options.autoPanMargin) ?
|
||||
options.autoPanMargin : 20;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {{bottom_: string,
|
||||
@@ -291,6 +314,9 @@ ol.Overlay.prototype.handleOffsetChanged = function() {
|
||||
*/
|
||||
ol.Overlay.prototype.handlePositionChanged = function() {
|
||||
this.updatePixelPosition_();
|
||||
if (goog.isDef(this.get(ol.OverlayProperty.POSITION)) && this.autoPan_) {
|
||||
this.panIntoView_();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -364,6 +390,89 @@ goog.exportProperty(
|
||||
ol.Overlay.prototype.setPosition);
|
||||
|
||||
|
||||
/**
|
||||
* Pan the map so that the overlay is entirely visible in the current viewport
|
||||
* (if necessary).
|
||||
* @private
|
||||
*/
|
||||
ol.Overlay.prototype.panIntoView_ = function() {
|
||||
goog.asserts.assert(this.autoPan_);
|
||||
var map = this.getMap();
|
||||
|
||||
if (!goog.isDef(map) || goog.isNull(map.getTargetElement())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mapRect = this.getRect_(map.getTargetElement(), map.getSize());
|
||||
var element = this.getElement();
|
||||
goog.asserts.assert(!goog.isNull(element) && goog.isDef(element));
|
||||
var overlayRect = this.getRect_(element,
|
||||
[ol.dom.outerWidth(element), ol.dom.outerHeight(element)]);
|
||||
|
||||
var margin = this.autoPanMargin_;
|
||||
if (!ol.extent.containsExtent(mapRect, overlayRect)) {
|
||||
// the overlay is not completely inside the viewport, so pan the map
|
||||
var offsetLeft = overlayRect[0] - mapRect[0];
|
||||
var offsetRight = mapRect[2] - overlayRect[2];
|
||||
var offsetTop = overlayRect[1] - mapRect[1];
|
||||
var offsetBottom = mapRect[3] - overlayRect[3];
|
||||
|
||||
var delta = [0, 0];
|
||||
if (offsetLeft < 0) {
|
||||
// move map to the left
|
||||
delta[0] = offsetLeft - margin;
|
||||
} else if (offsetRight < 0) {
|
||||
// move map to the right
|
||||
delta[0] = Math.abs(offsetRight) + margin;
|
||||
}
|
||||
if (offsetTop < 0) {
|
||||
// move map up
|
||||
delta[1] = offsetTop - margin;
|
||||
} else if (offsetBottom < 0) {
|
||||
// move map down
|
||||
delta[1] = Math.abs(offsetBottom) + margin;
|
||||
}
|
||||
|
||||
if (delta[0] !== 0 || delta[1] !== 0) {
|
||||
var center = map.getView().getCenter();
|
||||
goog.asserts.assert(goog.isDef(center));
|
||||
var centerPx = map.getPixelFromCoordinate(center);
|
||||
var newCenterPx = [
|
||||
centerPx[0] + delta[0],
|
||||
centerPx[1] + delta[1]
|
||||
];
|
||||
|
||||
if (!goog.isNull(this.autoPanAnimation_)) {
|
||||
this.autoPanAnimation_.source = center;
|
||||
map.beforeRender(ol.animation.pan(this.autoPanAnimation_));
|
||||
}
|
||||
map.getView().setCenter(map.getCoordinateFromPixel(newCenterPx));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the extent of an element relative to the document
|
||||
* @param {Element|undefined} element The element.
|
||||
* @param {ol.Size|undefined} size The size of the element.
|
||||
* @return {ol.Extent}
|
||||
* @private
|
||||
*/
|
||||
ol.Overlay.prototype.getRect_ = function(element, size) {
|
||||
goog.asserts.assert(!goog.isNull(element) && goog.isDef(element));
|
||||
goog.asserts.assert(goog.isDef(size));
|
||||
|
||||
var offset = goog.style.getPageOffset(element);
|
||||
return [
|
||||
offset.x,
|
||||
offset.y,
|
||||
offset.x + size[0],
|
||||
offset.y + size[1]
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the positioning for this overlay.
|
||||
* @param {ol.OverlayPositioning} positioning how the overlay is
|
||||
|
||||
Reference in New Issue
Block a user