diff --git a/src/ol/renderer/Composite.js b/src/ol/renderer/Composite.js
index 1857e3dc42..6ec58ffe7d 100644
--- a/src/ol/renderer/Composite.js
+++ b/src/ol/renderer/Composite.js
@@ -4,7 +4,11 @@ goog.require('ol.renderer.MapRenderer');
goog.require('ol.renderer.LayerRenderer');
goog.require('ol.layer.Layer');
goog.require('ol.Loc');
+
goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.style');
+goog.require('goog.math.Coordinate');
/**
* @constructor
@@ -21,23 +25,62 @@ ol.renderer.Composite = function(container) {
*/
this.renderers_ = [];
- var target = document.createElement("div");
- target.className = "ol-renderer-composite";
- target.style.position = "absolute";
- target.style.height = "100%";
- target.style.width = "100%";
- container.appendChild(target);
+ /**
+ * Pixel buffer for renderer container.
+ *
+ * @type {number}
+ * @private
+ */
+ 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
+ * @type {Element}
* @private
*/
this.target_ = target;
+
+ /**
+ * The cumulative offset from the original position of the target element.
+ *
+ * @type {goog.math.Coordinate}
+ * @private
+ */
+ this.targetOffset_ = new goog.math.Coordinate(0, 0);
+
+ /**
+ * @type {Object}
+ * @private
+ */
+ this.layerContainers_ = {};
};
-
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
@@ -46,13 +89,37 @@ goog.inherits(ol.renderer.Composite, ol.renderer.MapRenderer);
*/
ol.renderer.Composite.prototype.draw = function(layers, center, resolution, animate) {
// TODO: deal with layer order and removal
- for (var i=0, ii=layers.length; i} layers
* @param {ol.Loc} center
diff --git a/src/ol/renderer/TileLayerRenderer.js b/src/ol/renderer/TileLayerRenderer.js
index 0a01910432..f390764f0a 100644
--- a/src/ol/renderer/TileLayerRenderer.js
+++ b/src/ol/renderer/TileLayerRenderer.js
@@ -37,14 +37,14 @@ ol.renderer.TileLayerRenderer = function(container, layer) {
this.tileSize_ = layer.getTileSize();
/**
- * @type {number}
+ * @type {boolean}
*/
- this.xRight_ = layer.getXRight() ? 1 : -1;
+ this.xRight_ = layer.getXRight();
/**
- * @type {number}
+ * @type {boolean}
*/
- this.yDown_ = layer.getYDown() ? 1 : -1;
+ this.yDown_ = layer.getYDown();
/**
* @type {number|undefined}
@@ -82,12 +82,6 @@ ol.renderer.TileLayerRenderer = function(container, layer) {
*/
this.renderedZ_ = undefined;
- /**
- * @type {goog.math.Size}
- * @private
- */
- this.containerSize_ = null;
-
};
goog.inherits(ol.renderer.TileLayerRenderer, ol.renderer.LayerRenderer);
@@ -114,18 +108,6 @@ ol.renderer.TileLayerRenderer.prototype.getPreferredResAndZ_ = function(resoluti
return [r, z];
};
-/**
- * @return {goog.math.Size}
- */
-ol.renderer.TileLayerRenderer.prototype.getContainerSize_ = function() {
- // TODO: listen for resize and set this.constainerSize_ null
- // https://github.com/openlayers/ol3/issues/2
- if (goog.isNull(this.containerSize_)) {
- this.containerSize_ = goog.style.getSize(this.container_);
- }
- return this.containerSize_;
-};
-
/**
* Tiles rendered at the current resolution;
* @type {Object}
@@ -147,73 +129,72 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) {
var tileZ = pair[1];
var scale = resolution / tileResolution;
- var pxMapSize = this.getContainerSize_();
+ var containerSize = this.getContainerSize();
var xRight = this.xRight_;
var yDown = this.yDown_;
- var halfMapWidth = (resolution * pxMapSize.width) / 2;
- var halfMapHeight = (resolution * pxMapSize.height) / 2;
+ var halfMapWidth = (resolution * containerSize.width) / 2;
+ var halfMapHeight = (resolution * containerSize.height) / 2;
var centerX = center.getX();
var centerY = center.getY();
- var mapMinX = centerX - halfMapWidth;
- var mapMaxY = centerY + halfMapHeight;
- var pxOffsetX = Math.round((mapMinX - this.tileOrigin_[0]) / resolution);
- var pxOffsetY = Math.round((this.tileOrigin_[1] - mapMaxY) / resolution);
- // this gives us the desired size in fractional pixels
- var pxTileWidth = this.tileSize_[0] / scale;
- var pxTileHeight = this.tileSize_[1] / scale;
+ // calculate vector from tile origin to map top-left (in integer pixel space)
+ var tileOrigin = this.tileOrigin_;
+ var mapOrigin = [centerX - halfMapWidth, centerY + halfMapHeight];
+ var pxMap = [
+ Math.round((mapOrigin[0] - tileOrigin[0]) / resolution),
+ Math.round((tileOrigin[1] - mapOrigin[1]) / resolution)
+ ];
+
+ // desired tile size in fractional pixels
+ var fpxTileWidth = this.tileSize_[0] / scale;
+ var fpxTileHeight = this.tileSize_[1] / scale;
- // this is the index of the top left tile
- var leftTileX = Math.floor(xRight * pxOffsetX / pxTileWidth);
- var topTileY = Math.floor(yDown * pxOffsetY / pxTileHeight);
-
- var pxMinX;
- if (xRight > 0) {
- pxMinX = Math.round(leftTileX * pxTileWidth) - pxOffsetX;
- } else {
- pxMinX = Math.round((-leftTileX-1) * pxTileWidth) - pxOffsetX;
- }
- var pxMinY;
- if (yDown > 0) {
- pxMinY = Math.round(topTileY * pxTileHeight) - pxOffsetY;
- } else {
- pxMinY = Math.round((-topTileY-1) * pxTileHeight) - pxOffsetY;
- }
-
- var pxTileLeft = pxMinX;
- var pxTileTop = pxMinY;
-
- var numTilesWide = Math.ceil(pxMapSize.width / pxTileWidth);
- var numTilesHigh = Math.ceil(pxMapSize.height / pxTileHeight);
+ // calculate vector from tile origin to top-left tile (in integer pixel space)
+ var colsLeft = Math.floor(pxMap[0] / fpxTileWidth);
+ var rowsAbove = Math.floor(pxMap[1] / fpxTileHeight);
+ var pxTile = [Math.round(colsLeft * fpxTileWidth), Math.round(rowsAbove * fpxTileHeight)];
- // assume a buffer of zero for now
- if (pxMinX < 0) {
+ // offset vector from container origin to top-left tile (in integer pixel space)
+ var pxOffsetX = Math.round(pxTile[0] - pxMap[0] - this.containerOffset_.x);
+ var pxOffsetY = Math.round(pxTile[1] - pxMap[1] - this.containerOffset_.y);
+
+ // index of the top left tile
+ var leftTileX = xRight ? colsLeft : (-colsLeft - 1);
+ var topTileY = yDown ? rowsAbove : (-rowsAbove - 1);
+
+ var numTilesWide = Math.ceil(containerSize.width / fpxTileWidth);
+ var numTilesHigh = Math.ceil(containerSize.height / fpxTileHeight);
+ if (this.containerOffset_.x !== -pxOffsetX) {
numTilesWide += 1;
}
- if (pxMinY < 0) {
+ if (this.containerOffset_.y !== -pxOffsetY) {
numTilesHigh += 1;
}
+
+ var pxMinX = pxOffsetX;
+ var pxMinY = pxOffsetY;
+ var pxTileLeft = pxMinX;
- var tileX, tileY, tile, img, pxTileRight, pxTileBottom, xyz, append;
+ var tileX, tileY, tile, img, pxTileBottom, pxTileRight, pxTileTop, xyz, append;
var fragment = document.createDocumentFragment();
var newTiles = false;
for (var i=0; i 0);
- var yDown = (this.yDown_ > 0);
+ var xRight = this.xRight_;
+ var yDown = this.yDown_;
var top = this.renderedTop_;
var right = this.renderedRight_;
var bottom = this.renderedBottom_;
@@ -285,7 +266,7 @@ ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
if (prune) {
tile = this.renderedTiles_[xyz];
delete this.renderedTiles_[xyz];
- this.target_.removeChild(tile.getImg());
+ this.container_.removeChild(tile.getImg());
}
}
};
@@ -299,7 +280,7 @@ ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
*/
ol.renderer.TileLayerRenderer.prototype.changeResolution_ = function(center, resolution) {
this.renderedTiles_ = {};
- goog.dom.removeChildren(this.target_);
+ goog.dom.removeChildren(this.container_);
};