diff --git a/src/ol/renderer/Composite.js b/src/ol/renderer/Composite.js
index 6ec58ffe7d..602d0c86fa 100644
--- a/src/ol/renderer/Composite.js
+++ b/src/ol/renderer/Composite.js
@@ -33,31 +33,27 @@ ol.renderer.Composite = function(container) {
*/
this.buffer_ = 128;
- var containerSize = this.getContainerSize();
- var width = containerSize.width + (2 * this.buffer_);
- var height = containerSize.height + (2 * this.buffer_);
-
- var target = goog.dom.createDom('div', {
- 'class': 'ol-renderer-composite',
- 'style': 'width:' + width + 'px;height:' + height + 'px;' +
- 'top:-' + this.buffer_ + 'px;left:-' + this.buffer_ + 'px;' +
- 'position:absolute'
- });
- goog.dom.appendChild(container, target);
-
/**
* @type {Element}
* @private
*/
- this.target_ = target;
+ this.target_ = null;
/**
- * The cumulative offset from the original position of the target element.
+ * The current top left corner location of the target element (map coords).
+ *
+ * @type {ol.Loc}
+ * @private
+ */
+ this.targetOrigin_ = null;
+
+ /**
+ * The pixel offset of the target element with respect to its container.
*
* @type {goog.math.Coordinate}
* @private
*/
- this.targetOffset_ = new goog.math.Coordinate(0, 0);
+ this.targetOffset_ = null;
/**
* @type {Object}
@@ -68,19 +64,6 @@ ol.renderer.Composite = function(container) {
};
goog.inherits(ol.renderer.Composite, ol.renderer.MapRenderer);
-/**
- * Adjust the position of the renderer target by some offset.
- *
- * @param {number} x The x-offset (in pixel space)
- * @param {number} y The y-offset (in pixel space)
- */
-ol.renderer.Composite.prototype.shiftTarget = function(x, y) {
- var newX = this.targetOffset_.x + x;
- var newY = this.targetOffset_.y + y;
- this.targetOffset_ = new goog.math.Coordinate(newX, newY);
- goog.style.setPosition(this.target_, newX-this.buffer_, newY-this.buffer_);
-};
-
/**
* @param {Array.
} layers
* @param {ol.Loc} center
@@ -88,46 +71,124 @@ ol.renderer.Composite.prototype.shiftTarget = function(x, y) {
* @param {boolean} animate
*/
ol.renderer.Composite.prototype.draw = function(layers, center, resolution, animate) {
+ if (goog.isNull(this.target_)) {
+ // first rendering
+ this.createTarget_(center, resolution);
+ }
+
// TODO: deal with layer order and removal
if (this.renderedResolution_) {
if (resolution !== this.renderedResolution_) {
// TODO: apply transition to old target
- this.shiftTarget(0, 0);
+ this.resetTarget_(center, resolution);
}
}
this.renderedResolution_ = resolution;
// shift target element to account for center change
if (this.renderedCenter_) {
- this.shiftTarget(
- Math.round((this.renderedCenter_.getX() - center.getX()) / resolution),
- Math.round((center.getY() - this.renderedCenter_.getY()) / resolution)
- );
+ this.shiftTarget_(center, resolution);
}
this.renderedCenter_ = center;
// update each layer renderer
- var renderer, container;
-
+ var renderer;
for (var i=0, ii=layers.length; i}
- */
-ol.renderer.TileLayerRenderer.prototype.getPreferredResAndZ_ = function(resolution) {
- var minDiff = Number.POSITIVE_INFINITY;
- var candidate, diff, z, r;
- for (var i=0, ii=this.layerResolutions_.length; i} ijz
+ * @param {number} resolution
+ * @return {goog.math.Box}
+ */
+ol.renderer.TileLayerRenderer.prototype.getTilePixelBox_ = function(ijz, resolution) {
+ var tileResolution = this.layerResolutions_[ijz[2]];
+ var scale = resolution / tileResolution;
+ var tileSize = this.tileSize_;
+
+ // desired tile size (in fractional pixels)
+ var fpxTileWidth = tileSize[0] / scale;
+ var fpxTileHeight = tileSize[1] / scale;
+
+ var col = ijz[0];
+ var left = Math.round(col * fpxTileWidth); // inclusive
+ var right = Math.round((col + 1) * fpxTileWidth); // exclusive
+
+ var row = ijz[1];
+ var top = Math.round(row * fpxTileHeight); // inclusive
+ var bottom = Math.round((row + 1) * fpxTileWidth); // exclusive
+
+ return new goog.math.Box(top, right, bottom, left);
+};
+
+/**
+ * @param {ol.Loc} loc
+ * @param {number} resolution
+ * @return {goog.math.Coordinate}
+ */
+ol.renderer.TileLayerRenderer.prototype.getNormalizedTileCoord_ = function(loc, resolution) {
+ var tileOrigin = this.tileOrigin_;
+ var tileSize = this.tileSize_;
+ var pair = this.getPreferredResAndZ_(resolution);
+ var tileResolution = pair[0];
+ var z = pair[1];
+ var scale = resolution / tileResolution;
+
+ // offset from tile origin in pixel space
+ var dx = Math.round((loc.getX() - tileOrigin[0]) / resolution);
+ var dy = Math.round((tileOrigin[1] - loc.getY()) / resolution);
+
+ // desired tile size (in fractional pixels)
+ var fpxTileWidth = tileSize[0] / scale;
+ var fpxTileHeight = tileSize[1] / scale;
+
+ // determine normalized col number (0 based, ascending right)
+ var col = Math.floor(dx / fpxTileWidth);
+ // determine normalized row number (0 based, ascending down)
+ var row = Math.floor(dy / fpxTileHeight);
+
+ var box = this.getTilePixelBox_([col, row, z], resolution);
+
+ // adjust col to allow for stretched tiles
+ if (dx < box.left) {
+ col -= 1;
+ } else if (dx >= box.right) {
+ col += 1;
+ }
+
+ // adjust row to allow for stretched tiles
+ if (dy < box.top) {
+ row -= 1;
+ } else if (dy >= box.bottom) {
+ row += 1;
+ }
+
+ return new goog.math.Coordinate(col, row);
+};
+
+/**
+ * @param {number} resolution
+ * @return {Array.}
+ */
+ol.renderer.TileLayerRenderer.prototype.getPreferredResAndZ_ = (function() {
+ var cache = {};
+ return function(resolution) {
+ if (resolution in cache) {
+ return cache[resolution];
+ }
+ var minDiff = Number.POSITIVE_INFINITY;
+ var candidate, diff, z, r;
+ for (var i=0, ii=this.layerResolutions_.length; i} ijz
+ * @return {Array.}
+ */
+ol.renderer.TileLayerRenderer.prototype.getTileCoordsFromNormalizedCoords_ = function(ijz) {
+ return [
+ this.xRight_ ? ijz[0] : -ijz[0] - 1,
+ this.yDown_ ? ijz[1] : -ijz[1] - 1,
+ ijz[2]
+ ];
+};
+
+/**
+ * @param {ol.Loc} center
+ * @param {number} resolution
+ * @return {goog.math.Box}
+ */
+ol.renderer.TileLayerRenderer.prototype.getTileBox_ = function(center, resolution) {
+ var size = this.getContainerSize();
+ var halfWidth = size.width / 2;
+ var halfHeight = size.height / 2;
+
+ var leftTop = new ol.Loc(
+ center.getX() - (resolution * halfWidth),
+ center.getY() + (resolution * halfHeight));
+
+ var rightBottom = new ol.Loc(
+ center.getX() + (resolution * halfWidth),
+ center.getY() - (resolution * halfHeight));
+
+ var ltCoord = this.getNormalizedTileCoord_(leftTop, resolution);
+ var rbCoord = this.getNormalizedTileCoord_(rightBottom, resolution);
+
+ // right and bottom are treated as excluded, so we increment for the box
+ rbCoord.x += 1;
+ rbCoord.y += 1;
+
+ return goog.math.Box.boundingBox(ltCoord, rbCoord);
+};
/**
* Get rid of tiles outside the rendered extent.
*/
ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
- var index, prune, x, y, z, tile;
- var xRight = this.xRight_;
- var yDown = this.yDown_;
- var top = this.renderedTop_;
- var right = this.renderedRight_;
- var bottom = this.renderedBottom_;
- var left = this.renderedLeft_;
- for (var xyz in this.renderedTiles_) {
- index = xyz.split(",");
- x = +index[0];
- y = +index[1];
+ var index, prune, i, j, z, tile;
+ var box = this.renderedTileBox_;
+ for (var ijz in this.renderedTiles_) {
+ index = ijz.split(",");
+ i = +index[0];
+ j = +index[1];
z = +index[2];
prune = this.renderedZ_ !== z ||
- // beyond on the left side
- (xRight ? x < left : x > left) ||
- // beyond on the right side
- (xRight ? x > right : x < right) ||
- // above
- (yDown ? y < top : y > top) ||
- // below
- (yDown ? y > bottom : y < bottom);
+ i < box.left || // beyond on the left side
+ i >= box.right || // beyond on the right side
+ j < box.top || // above
+ j >= box.bottom; // below
if (prune) {
- tile = this.renderedTiles_[xyz];
- delete this.renderedTiles_[xyz];
+ tile = this.renderedTiles_[ijz];
+ delete this.renderedTiles_[ijz];
this.container_.removeChild(tile.getImg());
}
}
@@ -275,10 +306,12 @@ ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
* Deal with changes in resolution.
* TODO: implement the animation
*
- * @param {ol.Loc} center New center.
* @param {number} resolution New resolution.
*/
-ol.renderer.TileLayerRenderer.prototype.changeResolution_ = function(center, resolution) {
+ol.renderer.TileLayerRenderer.prototype.changeResolution_ = function(resolution) {
+ var pair = this.getPreferredResAndZ_(resolution);
+ this.renderedZ_ = pair[1];
+ this.renderedResolution_ = resolution;
this.renderedTiles_ = {};
goog.dom.removeChildren(this.container_);
};