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); 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 * Method: setMap
* Set the map property for the layer. This is done through an accessor * Set the map property for the layer. This is done through an accessor
@@ -1201,22 +1212,17 @@ OpenLayers.Layer = OpenLayers.Class({
*/ */
getLonLatFromViewPortPx: function (viewPortPx) { getLonLatFromViewPortPx: function (viewPortPx) {
var lonlat = null; var lonlat = null;
if (viewPortPx != null) { var map = this.map;
var size = this.map.getSize(); if (viewPortPx != null && map.minPx) {
var center = this.map.getCenter(); var res = map.getResolution();
if (center) { var maxExtent = map.getMaxExtent();
var res = this.map.getResolution(); 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); if (this.wrapDateLine) {
var delta_y = viewPortPx.y - (size.h / 2); lonlat = lonlat.wrapDateLine(this.maxExtent);
}
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 }
} }
return lonlat; 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; 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 * Method: moveTo
* Handle calls to move the layer. * 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)) { if (forceReTile || !tilesBounds.containsBounds(bounds, true)) {
this.initGriddedTiles(bounds); this.initGriddedTiles(bounds);
} else { } else {
// we might have to shift our buffer tiles, schedule this.scheduleMoveGriddedTiles();
// that
if (this.timerId != null) {
window.clearTimeout(this.timerId);
}
this.timerId = window.setTimeout(
this._moveGriddedTiles,
this.tileLoadingDelay
);
} }
} }
} }
}, },
/**
* 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 * APIMethod: setTileSize
* Check if we are in singleTile mode and if so, set the size as a ratio * 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 shifted = true;
var buffer = this.buffer || 1; var buffer = this.buffer || 1;
var tlLayer = this.grid[0][0].position; 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)) { if (tlViewPort.x > -this.tileSize.w * (buffer - 1)) {
this.shiftColumn(true); this.shiftColumn(true);
} else if (tlViewPort.x < -this.tileSize.w * buffer) { } else if (tlViewPort.x < -this.tileSize.w * buffer) {

View File

@@ -415,6 +415,23 @@ OpenLayers.Map = OpenLayers.Class({
*/ */
paddingForPopups : null, 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: OpenLayers.Map
* Constructor for a new OpenLayers.Map instance. There are two possible * 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) { if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
// preserve center and scale when changing base layers // preserve center and scale when changing base layers
var center = this.getCenter(); var center = this.getCachedCenter();
var newResolution = OpenLayers.Util.getResolutionFromScale( var newResolution = OpenLayers.Util.getResolutionFromScale(
this.getScale(), newBaseLayer.units this.getScale(), newBaseLayer.units
); );
@@ -1402,7 +1419,7 @@ OpenLayers.Map = OpenLayers.Class({
this.layers[i].onMapResize(); this.layers[i].onMapResize();
} }
var center = this.getCenter(); var center = this.getCachedCenter();
if (this.baseLayer != null && center != null) { if (this.baseLayer != null && center != null) {
var zoom = this.getZoom(); var zoom = this.getZoom();
@@ -1453,7 +1470,7 @@ OpenLayers.Map = OpenLayers.Class({
var extent = null; var extent = null;
if (center == null) { if (center == null) {
center = this.getCenter(); center = this.getCachedCenter();
} }
if (resolution == null) { if (resolution == null) {
resolution = this.getResolution(); resolution = this.getResolution();
@@ -1493,12 +1510,27 @@ OpenLayers.Map = OpenLayers.Class({
*/ */
getCenter: function () { getCenter: function () {
var center = null; var center = null;
if (this.center) { var cachedCenter = this.getCachedCenter();
center = this.center.clone(); if (cachedCenter) {
center = cachedCenter.clone();
} }
return center; 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 * APIMethod: getZoom
@@ -1527,19 +1559,27 @@ OpenLayers.Map = OpenLayers.Class({
animate: true, animate: true,
dragging: false dragging: false
}); });
// getCenter if (options.dragging) {
var centerPx = this.getViewPortPxFromLonLat(this.getCenter()); 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 // getCenter
var newCenterPx = centerPx.add(dx, dy); var centerPx = this.getViewPortPxFromLonLat(this.getCachedCenter());
// only call setCenter if not dragging or there has been a change // adjust
if (!options.dragging || !newCenterPx.equals(centerPx)) { var newCenterPx = centerPx.add(dx, dy);
var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
if (options.animate) { if (forceSetCenter || !newCenterPx.equals(centerPx)) {
this.panTo(newCenterLonLat); var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
} else { if (options.animate) {
this.setCenter(newCenterLonLat, null, options.dragging); this.panTo(newCenterLonLat);
} else {
this.setCenter(newCenterLonLat, null, options.dragging);
}
} }
} }
@@ -1558,7 +1598,7 @@ OpenLayers.Map = OpenLayers.Class({
if (!this.panTween) { if (!this.panTween) {
this.panTween = new OpenLayers.Tween(this.panMethod); this.panTween = new OpenLayers.Tween(this.panMethod);
} }
var center = this.getCenter(); var center = this.getCachedCenter();
// center will not change, don't do nothing // center will not change, don't do nothing
if (lonlat.lon == center.lon && 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 * Method: moveTo
* *
@@ -1651,14 +1756,14 @@ OpenLayers.Map = OpenLayers.Class({
this.panTween.stop(); this.panTween.stop();
} }
if (!this.center && !this.isValidLonLat(lonlat)) { if (!this.getCachedCenter() && !this.isValidLonLat(lonlat)) {
lonlat = this.maxExtent.getCenterLonLat(); lonlat = this.maxExtent.getCenterLonLat();
} }
if(this.restrictedExtent != null) { if(this.restrictedExtent != null) {
// In 3.0, decide if we want to change interpretation of maxExtent. // In 3.0, decide if we want to change interpretation of maxExtent.
if(lonlat == null) { if(lonlat == null) {
lonlat = this.getCenter(); lonlat = this.center;
} }
if(zoom == null) { if(zoom == null) {
zoom = this.getZoom(); zoom = this.getZoom();
@@ -1705,7 +1810,7 @@ OpenLayers.Map = OpenLayers.Class({
} }
if (centerChanged) { if (centerChanged) {
if ((!zoomChanged) && (this.center)) { if (!zoomChanged && this.center) {
// if zoom hasnt changed, just slide layerContainer // if zoom hasnt changed, just slide layerContainer
// (must be done before setting this.center to new value) // (must be done before setting this.center to new value)
this.centerLayerContainer(lonlat); this.centerLayerContainer(lonlat);
@@ -1713,16 +1818,28 @@ OpenLayers.Map = OpenLayers.Class({
this.center = lonlat.clone(); this.center = lonlat.clone();
} }
var res = zoomChanged ?
this.getResolutionForZoom(zoom) : this.getResolution();
// (re)set the layerContainerDiv's location // (re)set the layerContainerDiv's location
if ((zoomChanged) || (this.layerContainerOrigin == null)) { if (zoomChanged || this.layerContainerOrigin == null) {
this.layerContainerOrigin = this.center.clone(); this.layerContainerOrigin = this.getCachedCenter();
this.layerContainerDiv.style.left = "0px"; this.layerContainerDiv.style.left = "0px";
this.layerContainerDiv.style.top = "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) { if (zoomChanged) {
this.zoom = zoom; this.zoom = zoom;
this.resolution = this.getResolutionForZoom(zoom); this.resolution = res;
// zoom level has changed, increment viewRequestID. // zoom level has changed, increment viewRequestID.
this.viewRequestID++; this.viewRequestID++;
} }
@@ -1804,13 +1921,22 @@ OpenLayers.Map = OpenLayers.Class({
* lonlat - {<OpenLayers.LonLat>} * lonlat - {<OpenLayers.LonLat>}
*/ */
centerLayerContainer: function (lonlat) { centerLayerContainer: function (lonlat) {
var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin); var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
var newPx = this.getViewPortPxFromLonLat(lonlat); var newPx = this.getViewPortPxFromLonLat(lonlat);
if ((originPx != null) && (newPx != null)) { if ((originPx != null) && (newPx != null)) {
this.layerContainerDiv.style.left = Math.round(originPx.x - newPx.x) + "px"; var oldLeft = parseInt(this.layerContainerDiv.style.left);
this.layerContainerDiv.style.top = Math.round(originPx.y - newPx.y) + "px"; 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 size = this.getSize();
var w_deg = size.w * res; var w_deg = size.w * res;
var h_deg = size.h * 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, var extent = new OpenLayers.Bounds(center.lon - w_deg / 2,
center.lat - h_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. * {<OpenLayers.Size>} The geodesic size of the pixel in kilometers.
*/ */
getGeodesicPixelSize: function(px) { getGeodesicPixelSize: function(px) {
var lonlat = px ? this.getLonLatFromPixel(px) : (this.getCenter() || var lonlat = px ? this.getLonLatFromPixel(px) : (
new OpenLayers.LonLat(0, 0)); this.getCachedCenter() || new OpenLayers.LonLat(0, 0));
var res = this.getResolution(); var res = this.getResolution();
var left = lonlat.add(-res / 2, 0); var left = lonlat.add(-res / 2, 0);
var right = lonlat.add(res / 2, 0); var right = lonlat.add(res / 2, 0);

View File

@@ -1323,7 +1323,7 @@
var m = { var m = {
'baseLayer': { 'units': {} }, 'baseLayer': { 'units': {} },
'getSize': function() { return {'w': 10, 'h': 15}; }, '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) { 'zoomToExtent': function(extent, closest) {
t.ok(extent.equals(g_ExpectedExtent), "extent correctly calculated for zoomToExtent()"); t.ok(extent.equals(g_ExpectedExtent), "extent correctly calculated for zoomToExtent()");
t.ok(closest == g_Closest, "closest correctly passed on to zoomToExtent()"); t.ok(closest == g_Closest, "closest correctly passed on to zoomToExtent()");
@@ -1701,6 +1701,41 @@
map.destroy(); 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> </script>
</head> </head>
<body> <body>