New private movePyPx method to avoid going through all the unnecessary pixel-lonlat conversions. p=elemoine,me (closes #3062)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@11535 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2011-02-25 18:02:12 +00:00
parent 4c40f7c11f
commit 2d5f29c55e
5 changed files with 262 additions and 59 deletions

View File

@@ -569,6 +569,17 @@ OpenLayers.Layer = OpenLayers.Class({
this.display(display);
},
/**
* Method: moveByPx
* Move the layer based on pixel vector. To be implemented by subclasses.
*
* Parameters:
* dx - {Number} The x coord of the displacement vector.
* dy - {Number} The y coord of the displacement vector.
*/
moveByPx: function(dx, dy) {
},
/**
* Method: setMap
* Set the map property for the layer. This is done through an accessor
@@ -1201,22 +1212,17 @@ OpenLayers.Layer = OpenLayers.Class({
*/
getLonLatFromViewPortPx: function (viewPortPx) {
var lonlat = null;
if (viewPortPx != null) {
var size = this.map.getSize();
var center = this.map.getCenter();
if (center) {
var res = this.map.getResolution();
var map = this.map;
if (viewPortPx != null && map.minPx) {
var res = map.getResolution();
var maxExtent = map.getMaxExtent();
var lon = (viewPortPx.x - map.minPx.x) * res + maxExtent.left;
var lat = (map.minPx.y - viewPortPx.y) * res + maxExtent.top;
lonlat = new OpenLayers.LonLat(lon, lat);
var delta_x = viewPortPx.x - (size.w / 2);
var delta_y = viewPortPx.y - (size.h / 2);
lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
center.lat - delta_y * res);
if (this.wrapDateLine) {
lonlat = lonlat.wrapDateLine(this.maxExtent);
}
} // else { DEBUG STATEMENT }
if (this.wrapDateLine) {
lonlat = lonlat.wrapDateLine(this.maxExtent);
}
}
return lonlat;
},

View File

@@ -212,6 +212,22 @@ OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, {
this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
},
/**
* Method: moveByPx
* Move the layer based on pixel vector. To be implemented by subclasses.
*
* Parameters:
* dx - {Number} The x coord of the displacement vector.
* dy - {Number} The y coord of the displacement vector.
*/
moveByPx: function(dx, dy) {
OpenLayers.Layer.prototype.moveByPx.apply(this, arguments);
if (this.dragPanMapObject) {
this.dragPanMapObject(dx, -dy);
}
},
/**
* Method: moveTo
* Handle calls to move the layer.

View File

@@ -251,20 +251,38 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
this.initGriddedTiles(bounds);
} else {
// we might have to shift our buffer tiles, schedule
// that
if (this.timerId != null) {
window.clearTimeout(this.timerId);
}
this.timerId = window.setTimeout(
this._moveGriddedTiles,
this.tileLoadingDelay
);
this.scheduleMoveGriddedTiles();
}
}
}
},
/**
* Method: moveByPx
* Move the layer based on pixel vector.
*
* Parameters:
* dx - {Number}
* dy - {Number}
*/
moveByPx: function(dx, dy) {
this.scheduleMoveGriddedTiles();
},
/**
* Method: scheduleMoveGriddedTiles
* Schedule the move of tiles.
*/
scheduleMoveGriddedTiles: function() {
if (this.timerId != null) {
window.clearTimeout(this.timerId);
}
this.timerId = window.setTimeout(
this._moveGriddedTiles,
this.tileLoadingDelay
);
},
/**
* APIMethod: setTileSize
* Check if we are in singleTile mode and if so, set the size as a ratio
@@ -682,7 +700,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var shifted = true;
var buffer = this.buffer || 1;
var tlLayer = this.grid[0][0].position;
var tlViewPort = this.map.getViewPortPxFromLayerPx(tlLayer);
var offsetX = parseInt(this.map.layerContainerDiv.style.left);
var offsetY = parseInt(this.map.layerContainerDiv.style.top);
tlViewPort = tlLayer.add(offsetX, offsetY);
if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
this.shiftColumn(true);
} else if (tlViewPort.x < -this.tileSize.w * buffer) {

View File

@@ -415,6 +415,23 @@ OpenLayers.Map = OpenLayers.Class({
*/
paddingForPopups : null,
/**
* Property: minPx
* {<OpenLayers.Pixel>} Lower left of maxExtent in viewport pixel space.
* Used to verify in moveByPx that the new location we're moving to
* is valid. It is also used in the getLonLatFromViewPortPx function
* of Layer.
*/
minPx: null,
/**
* Property: maxPx
* {<OpenLayers.Pixel>} Top right of maxExtent in viewport pixel space.
* Used to verify in moveByPx that the new location we're moving to
* is valid.
*/
maxPx: null,
/**
* Constructor: OpenLayers.Map
* Constructor for a new OpenLayers.Map instance. There are two possible
@@ -1140,7 +1157,7 @@ OpenLayers.Map = OpenLayers.Class({
if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
// preserve center and scale when changing base layers
var center = this.getCenter();
var center = this.getCachedCenter();
var newResolution = OpenLayers.Util.getResolutionFromScale(
this.getScale(), newBaseLayer.units
);
@@ -1402,7 +1419,7 @@ OpenLayers.Map = OpenLayers.Class({
this.layers[i].onMapResize();
}
var center = this.getCenter();
var center = this.getCachedCenter();
if (this.baseLayer != null && center != null) {
var zoom = this.getZoom();
@@ -1453,7 +1470,7 @@ OpenLayers.Map = OpenLayers.Class({
var extent = null;
if (center == null) {
center = this.getCenter();
center = this.getCachedCenter();
}
if (resolution == null) {
resolution = this.getResolution();
@@ -1493,12 +1510,27 @@ OpenLayers.Map = OpenLayers.Class({
*/
getCenter: function () {
var center = null;
if (this.center) {
center = this.center.clone();
var cachedCenter = this.getCachedCenter();
if (cachedCenter) {
center = cachedCenter.clone();
}
return center;
},
/**
* Method: getCachedCenter
*
* Returns:
* {<OpenLayers.LonLat>}
*/
getCachedCenter: function() {
if (!this.center && this.size) {
this.center = this.getLonLatFromViewPortPx(
new OpenLayers.Pixel(this.size.w / 2, this.size.h / 2)
);
}
return this.center;
},
/**
* APIMethod: getZoom
@@ -1527,19 +1559,27 @@ OpenLayers.Map = OpenLayers.Class({
animate: true,
dragging: false
});
// getCenter
var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
if (options.dragging) {
if (dx != 0 || dy != 0) {
this.moveByPx(dx, dy);
}
} else {
// if we don't have a center, we were using moveByPx previously
var forceSetCenter = !this.center;
// adjust
var newCenterPx = centerPx.add(dx, dy);
// getCenter
var centerPx = this.getViewPortPxFromLonLat(this.getCachedCenter());
// only call setCenter if not dragging or there has been a change
if (!options.dragging || !newCenterPx.equals(centerPx)) {
var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
if (options.animate) {
this.panTo(newCenterLonLat);
} else {
this.setCenter(newCenterLonLat, null, options.dragging);
// adjust
var newCenterPx = centerPx.add(dx, dy);
if (forceSetCenter || !newCenterPx.equals(centerPx)) {
var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
if (options.animate) {
this.panTo(newCenterLonLat);
} else {
this.setCenter(newCenterLonLat, null, options.dragging);
}
}
}
@@ -1558,7 +1598,7 @@ OpenLayers.Map = OpenLayers.Class({
if (!this.panTween) {
this.panTween = new OpenLayers.Tween(this.panMethod);
}
var center = this.getCenter();
var center = this.getCachedCenter();
// center will not change, don't do nothing
if (lonlat.lon == center.lon &&
@@ -1622,6 +1662,71 @@ OpenLayers.Map = OpenLayers.Class({
});
},
/**
* Method: moveByPx
* Drag the map by pixels.
*
* Parameters:
* dx - {Number}
* dy - {Number}
*/
moveByPx: function(dx, dy) {
dx = Math.round(dx);
dy = Math.round(dy);
var hw = this.size.w / 2;
var hh = this.size.h / 2;
var x = hw + dx;
var y = hh + dy;
var valid = y <= this.maxPx.y &&
y >= this.minPx.y;
var minX, maxX;
if (this.baseLayer.wrapDateLine === true) {
minX = this.minPx.x, maxX = this.maxPx.x;
} else {
valid = valid &&
x <= this.maxPx.x &&
x >= this.minPx.x;
}
if (this.restrictedExtent && valid) {
valid = !(this.maxPx.x - x < hw ||
x - this.minPx.x < hw ||
this.maxPx.y - y < hh ||
y - this.minPx.y < hh);
}
if (valid) {
this.center = null;
if (dx) {
this.layerContainerDiv.style.left =
parseInt(this.layerContainerDiv.style.left) - dx + "px";
this.minPx.x -= dx;
this.maxPx.x -= dx;
if (this.baseLayer.wrapDateLine === true) {
if (this.maxPx.x > maxX) {
this.maxPx.x -= (maxX - minX);
};
if (this.minPx.x < minX) {
this.minPx.x += (maxX - minX);
};
}
}
if (dy) {
this.layerContainerDiv.style.top =
parseInt(this.layerContainerDiv.style.top) - dy + "px";
this.minPx.y -= dy;
this.maxPx.y -= dy;
}
var layer, i, len;
for (i=0, len=this.layers.length; i<len; ++i) {
layer = this.layers[i];
if (layer.visibility) {
layer.moveByPx(dx, dy);
layer.events.triggerEvent("move");
}
}
this.events.triggerEvent("move");
}
},
/**
* Method: moveTo
*
@@ -1651,14 +1756,14 @@ OpenLayers.Map = OpenLayers.Class({
this.panTween.stop();
}
if (!this.center && !this.isValidLonLat(lonlat)) {
if (!this.getCachedCenter() && !this.isValidLonLat(lonlat)) {
lonlat = this.maxExtent.getCenterLonLat();
}
if(this.restrictedExtent != null) {
// In 3.0, decide if we want to change interpretation of maxExtent.
if(lonlat == null) {
lonlat = this.getCenter();
lonlat = this.center;
}
if(zoom == null) {
zoom = this.getZoom();
@@ -1705,7 +1810,7 @@ OpenLayers.Map = OpenLayers.Class({
}
if (centerChanged) {
if ((!zoomChanged) && (this.center)) {
if (!zoomChanged && this.center) {
// if zoom hasnt changed, just slide layerContainer
// (must be done before setting this.center to new value)
this.centerLayerContainer(lonlat);
@@ -1713,16 +1818,28 @@ OpenLayers.Map = OpenLayers.Class({
this.center = lonlat.clone();
}
var res = zoomChanged ?
this.getResolutionForZoom(zoom) : this.getResolution();
// (re)set the layerContainerDiv's location
if ((zoomChanged) || (this.layerContainerOrigin == null)) {
this.layerContainerOrigin = this.center.clone();
if (zoomChanged || this.layerContainerOrigin == null) {
this.layerContainerOrigin = this.getCachedCenter();
this.layerContainerDiv.style.left = "0px";
this.layerContainerDiv.style.top = "0px";
var maxExtent = this.getMaxExtent({restricted: true});
var maxExtentCenter = maxExtent.getCenterLonLat();
var lonDelta = this.center.lon - maxExtentCenter.lon;
var latDelta = maxExtentCenter.lat - this.center.lat;
var extentWidth = Math.round(maxExtent.getWidth() / res);
var extentHeight = Math.round(maxExtent.getHeight() / res);
var left = (this.size.w - extentWidth) / 2 - lonDelta / res;
var top = (this.size.h - extentHeight) / 2 - latDelta / res;
this.minPx = new OpenLayers.Pixel(left, top);
this.maxPx = new OpenLayers.Pixel(left + extentWidth, top + extentHeight);
}
if (zoomChanged) {
this.zoom = zoom;
this.resolution = this.getResolutionForZoom(zoom);
this.resolution = res;
// zoom level has changed, increment viewRequestID.
this.viewRequestID++;
}
@@ -1804,13 +1921,22 @@ OpenLayers.Map = OpenLayers.Class({
* lonlat - {<OpenLayers.LonLat>}
*/
centerLayerContainer: function (lonlat) {
var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
var newPx = this.getViewPortPxFromLonLat(lonlat);
if ((originPx != null) && (newPx != null)) {
this.layerContainerDiv.style.left = Math.round(originPx.x - newPx.x) + "px";
this.layerContainerDiv.style.top = Math.round(originPx.y - newPx.y) + "px";
var oldLeft = parseInt(this.layerContainerDiv.style.left);
var oldTop = parseInt(this.layerContainerDiv.style.top);
var newLeft = Math.round(originPx.x - newPx.x);
var newTop = Math.round(originPx.y - newPx.y);
this.layerContainerDiv.style.left = newLeft + "px";
this.layerContainerDiv.style.top = newTop + "px";
var dx = oldLeft - newLeft;
var dy = oldTop - newTop;
this.minPx.x -= dx;
this.maxPx.x -= dx;
this.minPx.y -= dy;
this.maxPx.y -= dy;
}
},
@@ -2225,7 +2351,7 @@ OpenLayers.Map = OpenLayers.Class({
var size = this.getSize();
var w_deg = size.w * res;
var h_deg = size.h * res;
var center = this.getCenter();
var center = this.getCachedCenter();
var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
center.lat - h_deg / 2,
@@ -2337,8 +2463,8 @@ OpenLayers.Map = OpenLayers.Class({
* {<OpenLayers.Size>} The geodesic size of the pixel in kilometers.
*/
getGeodesicPixelSize: function(px) {
var lonlat = px ? this.getLonLatFromPixel(px) : (this.getCenter() ||
new OpenLayers.LonLat(0, 0));
var lonlat = px ? this.getLonLatFromPixel(px) : (
this.getCachedCenter() || new OpenLayers.LonLat(0, 0));
var res = this.getResolution();
var left = lonlat.add(-res / 2, 0);
var right = lonlat.add(res / 2, 0);

View File

@@ -1323,7 +1323,7 @@
var m = {
'baseLayer': { 'units': {} },
'getSize': function() { return {'w': 10, 'h': 15}; },
'getCenter': function() { return {'lon': -5, 'lat': -25}; },
'getCachedCenter': function() { return {'lon': -5, 'lat': -25}; },
'zoomToExtent': function(extent, closest) {
t.ok(extent.equals(g_ExpectedExtent), "extent correctly calculated for zoomToExtent()");
t.ok(closest == g_Closest, "closest correctly passed on to zoomToExtent()");
@@ -1701,6 +1701,41 @@
map.destroy();
}
function test_moveByPx(t) {
t.plan(8);
var map = new OpenLayers.Map({
div: 'map',
maxExtent: new OpenLayers.Bounds(-50, -50, 50, 50),
restrictedExtent: new OpenLayers.Bounds(-10, -10, 10, 10),
layers: [
new OpenLayers.Layer('name', {isBaseLayer: true})
]
});
map.zoomToExtent(new OpenLayers.Bounds(-1, -1, 1, 1));
// check initial state
t.eq(map.layerContainerDiv.style.left, '0px', 'layer container left correct');
t.eq(map.layerContainerDiv.style.top, '0px', 'layer container top correct');
// move to a valid position
map.moveByPx(-455, 455);
t.eq(map.layerContainerDiv.style.left, '455px', 'layer container left correct');
t.eq(map.layerContainerDiv.style.top, '-455px', 'layer container top correct');
// move outside the max extent
map.moveByPx(-4500, 4500);
t.eq(map.layerContainerDiv.style.left, '455px', 'layer container left correct');
t.eq(map.layerContainerDiv.style.top, '-455px', 'layer container top correct');
// move outside the restricted extent
map.moveByPx(-500, 500);
t.eq(map.layerContainerDiv.style.left, '455px', 'layer container left correct');
t.eq(map.layerContainerDiv.style.top, '-455px', 'layer container top correct');
map.destroy();
}
</script>
</head>
<body>