No more percentage based positioning.

Client zoom now supports both over- and undersampling.
This commit is contained in:
ahocevar
2012-06-10 16:53:56 +02:00
parent 405cebd482
commit f0ad48597f
12 changed files with 202 additions and 331 deletions
+90 -115
View File
@@ -168,8 +168,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
/**
* Property: gridResolution
* {Number} The resolution of the current grid. Used for backbuffering.
* This property is updated each the grid is initialized.
* {Number} The resolution of the current grid. Used for backbuffer and
* client zoom. This property is updated every time the grid is
* initialized.
*/
gridResolution: null,
@@ -458,7 +459,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
}
if(!zoomChanged || this.transitionEffect === 'resize') {
this.applyBackBuffer(serverResolution);
this.applyBackBuffer(resolution);
}
this.initSingleTile(bounds);
@@ -477,25 +478,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.map.getMaxExtent()
});
if(resolution !== serverResolution) {
bounds = this.map.calculateBounds(null, serverResolution);
if(forceReTile) {
// stretch the layer div
var scale = serverResolution / resolution;
this.transformDiv(scale);
}
} else {
// reset the layer width, height, left, top, to deal with
// the case where the layer was previously transformed
this.div.style.width = '100%';
this.div.style.height = '100%';
this.div.style.left = '0%';
this.div.style.top = '0%';
}
if(forceReTile) {
if(zoomChanged && this.transitionEffect === 'resize') {
this.applyBackBuffer(serverResolution);
this.applyBackBuffer(resolution);
}
this.initGriddedTiles(bounds);
} else {
@@ -620,7 +605,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
/**
* Method: getServerResolution
* Return the closest highest server-supported resolution. Throw an
* Return the closest server-supported resolution. Throw an
* exception if none is found in the serverResolutions array.
*
* Parameters:
@@ -628,23 +613,24 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* map resolution is used.
*
* Returns:
* {Number} The closest highest server resolution value.
* {Number} The closest server resolution value.
*/
getServerResolution: function(resolution) {
var distance = Number.POSITIVE_INFINITY;
resolution = resolution || this.map.getResolution();
if(this.serverResolutions &&
OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) {
var i, serverResolution;
var i, newDistance, newResolution, serverResolution;
for(i=this.serverResolutions.length-1; i>= 0; i--) {
serverResolution = this.serverResolutions[i];
if(serverResolution > resolution) {
resolution = serverResolution;
newResolution = this.serverResolutions[i];
newDistance = Math.abs(newResolution - resolution);
if (newDistance > distance) {
break;
}
distance = newDistance;
serverResolution = newResolution;
}
if(i === -1) {
throw 'no appropriate resolution in serverResolutions';
}
resolution = serverResolution;
}
return resolution;
},
@@ -665,33 +651,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.map.getZoomForResolution(resolution) + (this.zoomOffset || 0);
},
/**
* Method: transformDiv
* Transform the layer div.
*
* Parameters:
* scale - {Number} The value by which the layer div is to
* be scaled.
*/
transformDiv: function(scale) {
// scale the layer div
this.div.style.width = 100 * scale + '%';
this.div.style.height = 100 * scale + '%';
// and translate the layer div as necessary
var size = this.map.getSize();
var lcX = parseInt(this.map.layerContainerDiv.style.left, 10);
var lcY = parseInt(this.map.layerContainerDiv.style.top, 10);
var x = (lcX - (size.w / 2.0)) * (scale - 1);
var y = (lcY - (size.h / 2.0)) * (scale - 1);
this.div.style.left = x + '%';
this.div.style.top = y + '%';
},
/**
* Method: getResolutionScale
* Return the value by which the layer is currently scaled.
@@ -733,21 +692,26 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
};
this.backBufferResolution = this.gridResolution;
}
var style = backBuffer.style;
// scale the back buffer
var ratio = this.backBufferResolution / resolution;
style.width = 100 * ratio + '%';
style.height = 100 * ratio + '%';
// scale the tiles inside the back buffer
var tiles = backBuffer.childNodes, tile;
for (var i=tiles.length-1; i>=0; --i) {
tile = tiles[i];
tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px';
tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px';
tile.style.width = Math.round(ratio * tile._w) + 'px';
tile.style.height = Math.round(ratio * tile._h) + 'px';
}
// and position it (based on the grid's top-left corner)
var position = this.getViewPortPxFromLonLat(
this.backBufferLonLat, resolution);
var leftOffset = parseInt(this.map.layerContainerDiv.style.left, 10);
var topOffset = parseInt(this.map.layerContainerDiv.style.top, 10);
backBuffer.style.left = Math.round(position.x - leftOffset) + '%';
backBuffer.style.top = Math.round(position.y - topOffset) + '%';
var leftOffset = this.map.layerContainerOriginPx.x;
var topOffset = this.map.layerContainerOriginPx.y;
backBuffer.style.left = Math.round(position.x - leftOffset) + 'px';
backBuffer.style.top = Math.round(position.y - topOffset) + 'px';
},
/**
@@ -765,19 +729,17 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
backBuffer.id = this.div.id + '_bb';
backBuffer.className = 'olBackBuffer';
backBuffer.style.position = 'absolute';
backBuffer.style.width = '100%';
backBuffer.style.height = '100%';
for(var i=0, lenI=this.grid.length; i<lenI; i++) {
for(var j=0, lenJ=this.grid[i].length; j<lenJ; j++) {
var tile = this.grid[i][j].createBackBuffer();
if(!tile) {
continue;
var tile = this.grid[i][j],
markup = this.grid[i][j].createBackBuffer();
if (markup) {
markup._i = i;
markup._j = j;
markup._w = tile.size.w;
markup._h = tile.size.h;
backBuffer.appendChild(markup);
}
// to be able to correctly position the back buffer we
// place the tiles grid at (0, 0) in the back buffer
tile.style.top = (i * this.tileSize.h) + '%';
tile.style.left = (j * this.tileSize.w) + '%';
backBuffer.appendChild(tile);
}
}
}
@@ -923,16 +885,22 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var tilelon = resolution * this.tileSize.w;
var tilelat = resolution * this.tileSize.h;
var ratio = resolution / this.map.getResolution(),
tileSize = {
w: Math.round(this.tileSize.w * ratio),
h: Math.round(this.tileSize.h * ratio)
};
var offsetlon = bounds.left - origin.lon;
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * this.tileSize.w;
var tileoffsetx = -tilecolremain * tileSize.w;
var tileoffsetlon = origin.lon + tilecol * tilelon;
var offsetlat = bounds.top - (origin.lat + tilelat);
var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = -tilerowremain * this.tileSize.h;
var tileoffsety = -tilerowremain * tileSize.h;
var tileoffsetlat = origin.lat + tilerow * tilelat;
return {
@@ -982,19 +950,25 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
// tiles required to cover the viewport plus at least one for panning
var viewSize = this.map.getSize();
var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
2 * this.buffer + 1;
var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
2 * this.buffer + 1;
var origin = this.getTileOrigin();
var resolution = this.getServerResolution();
var tileLayout = this.calculateGridLayout(bounds, origin, resolution);
var resolution = this.map.getResolution(),
serverResolution = this.getServerResolution(),
ratio = resolution / serverResolution,
tileSize = {
w: this.tileSize.w / ratio,
h: this.tileSize.h / ratio
};
var minRows = Math.ceil(viewSize.h/tileSize.h) +
2 * this.buffer + 1;
var minCols = Math.ceil(viewSize.w/tileSize.w) +
2 * this.buffer + 1;
var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution);
var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
var tileoffsety = Math.round(tileLayout.tileoffsety);
var tileoffsetlon = tileLayout.tileoffsetlon;
var tileoffsetlat = tileLayout.tileoffsetlat;
@@ -1006,8 +980,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var rowidx = 0;
var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
var layerContainerDivLeft = this.map.layerContainerOriginPx.x;
var layerContainerDivTop = this.map.layerContainerOriginPx.y;
var tileData = [], center = this.map.getCenter();
do {
@@ -1051,27 +1025,29 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
});
tileoffsetlon += tilelon;
tileoffsetx += this.tileSize.w;
tileoffsetx += tileSize.w;
} while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
|| colidx < minCols);
tileoffsetlat -= tilelat;
tileoffsety += this.tileSize.h;
tileoffsety += tileSize.h;
} while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
|| rowidx < minRows);
//shave off exceess rows and colums
this.removeExcessTiles(rowidx, colidx);
var resolution = this.getServerResolution(),
immediately = resolution === this.gridResolution;
// store the resolution of the grid
this.gridResolution = this.getServerResolution();
this.gridResolution = resolution;
//now actually draw the tiles
tileData.sort(function(a, b) {
return a.distance - b.distance;
});
for (var i=0, ii=tileData.length; i<ii; ++i) {
tileData[i].tile.draw();
tileData[i].tile.draw(immediately);
}
},
@@ -1194,28 +1170,27 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
return;
}
var buffer = this.buffer + 1;
var scale = this.getResolutionScale();
while(true) {
var tlTile = this.grid[0][0];
var tlViewPort = {
x: (this.grid[0][0].position.x * scale) +
parseInt(this.div.style.left, 10) +
parseInt(this.map.layerContainerDiv.style.left),
y: (this.grid[0][0].position.y * scale) +
parseInt(this.div.style.top, 10) +
parseInt(this.map.layerContainerDiv.style.top)
x: tlTile.position.x +
this.map.layerContainerOriginPx.x,
y: tlTile.position.y +
this.map.layerContainerOriginPx.y
};
var ratio = this.getServerResolution() / this.map.getResolution();
var tileSize = {
w: this.tileSize.w * scale,
h: this.tileSize.h * scale
w: Math.round(this.tileSize.w * ratio),
h: Math.round(this.tileSize.h * ratio)
};
if (tlViewPort.x > -tileSize.w * (buffer - 1)) {
this.shiftColumn(true);
this.shiftColumn(true, tileSize);
} else if (tlViewPort.x < -tileSize.w * buffer) {
this.shiftColumn(false);
this.shiftColumn(false, tileSize);
} else if (tlViewPort.y > -tileSize.h * (buffer - 1)) {
this.shiftRow(true);
this.shiftRow(true, tileSize);
} else if (tlViewPort.y < -tileSize.h * buffer) {
this.shiftRow(false);
this.shiftRow(false, tileSize);
} else {
break;
}
@@ -1229,15 +1204,15 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* Parameters:
* prepend - {Boolean} if true, prepend to beginning.
* if false, then append to end
* tileSize - {<OpenLayers.Size>} rendered tile size
*/
shiftRow:function(prepend) {
shiftRow:function(prepend, tileSize) {
var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
var grid = this.grid;
var modelRow = grid[modelRowIndex];
var resolution = this.getServerResolution();
var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
var deltaLat = resolution * -deltaY;
var sign = prepend ? -1 : 1;
var deltaLat = this.getServerResolution() * -sign * this.tileSize.h;
var row = (prepend) ? grid.pop() : grid.shift();
@@ -1247,7 +1222,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var position = modelTile.position.clone();
bounds.bottom = bounds.bottom + deltaLat;
bounds.top = bounds.top + deltaLat;
position.y = position.y + deltaY;
position.y = position.y + sign * tileSize.h;
row[i].moveTo(bounds, position);
}
@@ -1265,11 +1240,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* Parameters:
* prepend - {Boolean} if true, prepend to beginning.
* if false, then append to end
* tileSize - {<OpenLayers.Size>} rendered tile size
*/
shiftColumn: function(prepend) {
var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
var resolution = this.getServerResolution();
var deltaLon = resolution * deltaX;
shiftColumn: function(prepend, tileSize) {
var sign = prepend ? -1 : 1;
var deltaLon = this.getServerResolution() * sign * this.tileSize.w;
for (var i=0, len=this.grid.length; i<len; i++) {
var row = this.grid[i];
@@ -1280,7 +1255,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var position = modelTile.position.clone();
bounds.left = bounds.left + deltaLon;
bounds.right = bounds.right + deltaLon;
position.x = position.x + deltaX;
position.x = position.x + sign * tileSize.w;
var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
tile.moveTo(bounds, position);
+2 -2
View File
@@ -482,9 +482,9 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
viewHeight = viewSize.h,
offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2,
offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2;
offsetLeft += parseInt(this.map.layerContainerDiv.style.left, 10);
offsetLeft += this.map.layerContainerOriginPx.x;
offsetLeft = -Math.round(offsetLeft);
offsetTop += parseInt(this.map.layerContainerDiv.style.top, 10);
offsetTop += this.map.layerContainerOriginPx.y;
offsetTop = -Math.round(offsetTop);
this.div.style.left = offsetLeft + 'px';