From 0650d93d17af2176a6539ff32323bc5aa1e0c739 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Wed, 4 Jul 2012 22:17:56 -0600 Subject: [PATCH 1/5] Let the composite renderer manage containers. --- src/ol/renderer/Composite.js | 31 +++++++++++++++++++++------- src/ol/renderer/LayerRenderer.js | 12 ----------- src/ol/renderer/TileLayerRenderer.js | 6 +++--- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/ol/renderer/Composite.js b/src/ol/renderer/Composite.js index 1857e3dc42..505d9e4a9f 100644 --- a/src/ol/renderer/Composite.js +++ b/src/ol/renderer/Composite.js @@ -4,7 +4,9 @@ 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'); /** * @constructor @@ -20,13 +22,12 @@ ol.renderer.Composite = function(container) { * @private */ 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); + + var target = goog.dom.createDom('div', { + 'class': 'ol-renderer-composite', + 'style': 'width:100%;height:100%;top:0;left:0;position:absolute' + }); + goog.dom.appendChild(container, target); /** * @type Element @@ -34,6 +35,12 @@ ol.renderer.Composite = function(container) { */ this.target_ = target; + /** + * @type Object + * @private + */ + this.layerContainers_ = {}; + }; goog.inherits(ol.renderer.Composite, ol.renderer.MapRenderer); @@ -82,7 +89,15 @@ ol.renderer.Composite.prototype.getRenderer = function(layer) { ol.renderer.Composite.prototype.createRenderer = function(layer) { var Renderer = this.pickRendererType(layer); goog.asserts.assert(Renderer, "No supported renderer for layer: " + layer); - return new Renderer(this.target_, layer); + + var container = goog.dom.createDom('div', { + 'class': 'ol-renderer-composite-layer', + 'style': 'width:100%;height:100%;top:0;left:0;position:absolute' + }); + goog.dom.appendChild(this.target_, container); + var renderer = new Renderer(container, layer); + this.layerContainers_[goog.getUid(renderer)] = container; + return renderer; }; /** diff --git a/src/ol/renderer/LayerRenderer.js b/src/ol/renderer/LayerRenderer.js index d5d863a015..6d9bd151de 100644 --- a/src/ol/renderer/LayerRenderer.js +++ b/src/ol/renderer/LayerRenderer.js @@ -21,18 +21,6 @@ ol.renderer.LayerRenderer = function(container, layer) { */ this.layer_ = layer; - var target = goog.dom.createDom('div', { - 'class': 'ol-renderer-layer', - 'style': 'position:absolute;height:1px:width:1px' - }); - goog.dom.appendChild(container, target); - - /** - * @type Element - * @protected - */ - this.target_ = target; - }; /** diff --git a/src/ol/renderer/TileLayerRenderer.js b/src/ol/renderer/TileLayerRenderer.js index 0a01910432..375a1049a6 100644 --- a/src/ol/renderer/TileLayerRenderer.js +++ b/src/ol/renderer/TileLayerRenderer.js @@ -244,7 +244,7 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) { pxTileLeft = pxTileRight; } if (newTiles) { - this.target_.appendChild(fragment); + this.container_.appendChild(fragment); } this.renderedResolution_ = resolution; this.renderedTop_ = topTileY; @@ -285,7 +285,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 +299,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_); }; From 523f4d61fc064743e3cf298bdf3dc61ba501bbd9 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sat, 7 Jul 2012 13:13:07 -0600 Subject: [PATCH 2/5] Shift container for all layer renderers together. --- src/ol/renderer/Composite.js | 56 +++++++++++++-- src/ol/renderer/LayerRenderer.js | 21 ++++++ src/ol/renderer/TileLayerRenderer.js | 103 +++++++++++++-------------- 3 files changed, 120 insertions(+), 60 deletions(-) diff --git a/src/ol/renderer/Composite.js b/src/ol/renderer/Composite.js index 505d9e4a9f..054392bf70 100644 --- a/src/ol/renderer/Composite.js +++ b/src/ol/renderer/Composite.js @@ -7,6 +7,8 @@ goog.require('ol.Loc'); goog.require('goog.array'); goog.require('goog.dom'); +goog.require('goog.style'); +goog.require('goog.math.Coordinate'); /** * @constructor @@ -30,19 +32,25 @@ ol.renderer.Composite = function(container) { goog.dom.appendChild(container, target); /** - * @type Element + * @type {Element} * @private */ this.target_ = target; + + /** + * @type {goog.math.Coordinate} + * @private + */ + this.targetOffset_ = new goog.math.Coordinate(0, 0); /** - * @type Object + * @type {Object} * @private */ this.layerContainers_ = {}; + }; - goog.inherits(ol.renderer.Composite, ol.renderer.MapRenderer); /** @@ -53,13 +61,38 @@ 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 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 pixel space) + var colsLeft = Math.floor(pxMap[0] / pxTileWidth); + var rowsAbove = Math.floor(pxMap[1] / pxTileHeight); + var pxTile = [colsLeft * pxTileWidth, rowsAbove * pxTileHeight]; - // assume a buffer of zero for now - if (pxMinX < 0) { + // offset vector from container origin to top-left tile (in pixel space) + var pxOffsetX = pxTile[0] - pxMap[0] - this.containerOffset_.x; + var pxOffsetY = 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 / pxTileWidth); + var numTilesHigh = Math.ceil(containerSize.height / pxTileHeight); + if (pxOffsetX !== 0) { numTilesWide += 1; } - if (pxMinY < 0) { + if (pxOffsetY !== 0) { 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_; From c0777cc0039b06ca6fe00f9963774f1d9b8052ae Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sat, 7 Jul 2012 15:19:49 -0600 Subject: [PATCH 3/5] Working with integer pixel space. --- src/ol/renderer/TileLayerRenderer.js | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ol/renderer/TileLayerRenderer.js b/src/ol/renderer/TileLayerRenderer.js index 1c7e598a83..8315744952 100644 --- a/src/ol/renderer/TileLayerRenderer.js +++ b/src/ol/renderer/TileLayerRenderer.js @@ -156,37 +156,37 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) { var centerX = center.getX(); var centerY = center.getY(); - // calculate vector from tile origin to map top-left (in pixel space) + // 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 = [ - (mapOrigin[0] - tileOrigin[0]) / resolution, - (tileOrigin[1] - mapOrigin[1]) / resolution + Math.round((mapOrigin[0] - tileOrigin[0]) / resolution), + Math.round((tileOrigin[1] - mapOrigin[1]) / resolution) ]; // desired tile size in fractional pixels - var pxTileWidth = this.tileSize_[0] / scale; - var pxTileHeight = this.tileSize_[1] / scale; + var fpxTileWidth = this.tileSize_[0] / scale; + var fpxTileHeight = this.tileSize_[1] / scale; - // calculate vector from tile origin to top-left tile (in pixel space) - var colsLeft = Math.floor(pxMap[0] / pxTileWidth); - var rowsAbove = Math.floor(pxMap[1] / pxTileHeight); - var pxTile = [colsLeft * pxTileWidth, rowsAbove * 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)]; - // offset vector from container origin to top-left tile (in pixel space) - var pxOffsetX = pxTile[0] - pxMap[0] - this.containerOffset_.x; - var pxOffsetY = pxTile[1] - pxMap[1] - this.containerOffset_.y; + // 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 / pxTileWidth); - var numTilesHigh = Math.ceil(containerSize.height / pxTileHeight); - if (pxOffsetX !== 0) { + var numTilesWide = Math.ceil(containerSize.width / fpxTileWidth); + var numTilesHigh = Math.ceil(containerSize.height / fpxTileHeight); + if (this.containerOffset_.x !== -pxOffsetX) { numTilesWide += 1; } - if (pxOffsetY !== 0) { + if (this.containerOffset_.y !== -pxOffsetY) { numTilesHigh += 1; } @@ -201,18 +201,18 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) { pxTileTop = pxMinY; tileX = xRight ? leftTileX + i : leftTileX - i; if (scale !== 1) { - pxTileRight = Math.round(pxMinX + ((i+1) * pxTileWidth)); + pxTileRight = Math.round(pxMinX + ((i+1) * fpxTileWidth)); } else { - pxTileRight = pxTileLeft + pxTileWidth; + pxTileRight = pxTileLeft + fpxTileWidth; } for (var j=0; j Date: Sat, 7 Jul 2012 15:42:08 -0600 Subject: [PATCH 4/5] Resize images in case they were previously scaled. --- src/ol/renderer/TileLayerRenderer.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ol/renderer/TileLayerRenderer.js b/src/ol/renderer/TileLayerRenderer.js index 8315744952..1082cb962e 100644 --- a/src/ol/renderer/TileLayerRenderer.js +++ b/src/ol/renderer/TileLayerRenderer.js @@ -226,10 +226,14 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) { img = tile.getImg(); img.style.top = pxTileTop + "px"; img.style.left = pxTileLeft + "px"; - if (scale !== 1) { - img.style.height = (pxTileRight - pxTileLeft) + "px"; - img.style.width = (pxTileBottom - pxTileTop) + "px"; - } + /** + * We need to set the size here even if the scale is 1 + * because the image may have been scaled previously. If + * we want to avoid setting size unnecessarily, the tile + * should keep track of the scale. + */ + img.style.height = (pxTileRight - pxTileLeft) + "px"; + img.style.width = (pxTileBottom - pxTileTop) + "px"; goog.dom.appendChild(fragment, img); newTiles = true; } From ddd57426b5d79671c9b67f0e1558e014c10efddd Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sat, 7 Jul 2012 16:50:22 -0600 Subject: [PATCH 5/5] Allow renderer to have a buffer. --- src/ol/renderer/Composite.js | 43 ++++++++++++++++++++++------ src/ol/renderer/LayerRenderer.js | 20 +++++++++++++ src/ol/renderer/MapRenderer.js | 21 ++++++++++++++ src/ol/renderer/TileLayerRenderer.js | 22 ++------------ 4 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/ol/renderer/Composite.js b/src/ol/renderer/Composite.js index 054392bf70..6ec58ffe7d 100644 --- a/src/ol/renderer/Composite.js +++ b/src/ol/renderer/Composite.js @@ -24,10 +24,24 @@ ol.renderer.Composite = function(container) { * @private */ this.renderers_ = []; + + /** + * 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:100%;height:100%;top:0;left:0;position:absolute' + 'style': 'width:' + width + 'px;height:' + height + 'px;' + + 'top:-' + this.buffer_ + 'px;left:-' + this.buffer_ + 'px;' + + 'position:absolute' }); goog.dom.appendChild(container, target); @@ -38,6 +52,8 @@ ol.renderer.Composite = function(container) { this.target_ = target; /** + * The cumulative offset from the original position of the target element. + * * @type {goog.math.Coordinate} * @private */ @@ -48,11 +64,23 @@ ol.renderer.Composite = function(container) { * @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 @@ -65,24 +93,23 @@ ol.renderer.Composite.prototype.draw = function(layers, center, resolution, anim if (this.renderedResolution_) { if (resolution !== this.renderedResolution_) { // TODO: apply transition to old target - this.targetOffset_ = new goog.math.Coordinate(0, 0); - goog.style.setPosition(this.target_, this.targetOffset_); + this.shiftTarget(0, 0); } } this.renderedResolution_ = resolution; // shift target element to account for center change if (this.renderedCenter_) { - this.targetOffset_ = new goog.math.Coordinate( - this.targetOffset_.x + Math.round((this.renderedCenter_.getX() - center.getX()) / resolution), - this.targetOffset_.y + Math.round((center.getY() - this.renderedCenter_.getY()) / resolution) + this.shiftTarget( + Math.round((this.renderedCenter_.getX() - center.getX()) / resolution), + Math.round((center.getY() - this.renderedCenter_.getY()) / resolution) ); - goog.style.setPosition(this.target_, this.targetOffset_); } this.renderedCenter_ = center; // update each layer renderer var renderer, container; + 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 1082cb962e..f390764f0a 100644 --- a/src/ol/renderer/TileLayerRenderer.js +++ b/src/ol/renderer/TileLayerRenderer.js @@ -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,7 +129,7 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) { var tileZ = pair[1]; var scale = resolution / tileResolution; - var containerSize = this.getContainerSize_(); + var containerSize = this.getContainerSize(); var xRight = this.xRight_; var yDown = this.yDown_; @@ -155,7 +137,7 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) { var halfMapHeight = (resolution * containerSize.height) / 2; var centerX = center.getX(); var centerY = center.getY(); - + // calculate vector from tile origin to map top-left (in integer pixel space) var tileOrigin = this.tileOrigin_; var mapOrigin = [centerX - halfMapWidth, centerY + halfMapHeight];