Merge branch 'renderer'

This commit is contained in:
Tim Schaub
2012-07-07 17:17:59 -06:00
4 changed files with 219 additions and 102 deletions
+98 -12
View File
@@ -4,7 +4,11 @@ goog.require('ol.renderer.MapRenderer');
goog.require('ol.renderer.LayerRenderer'); goog.require('ol.renderer.LayerRenderer');
goog.require('ol.layer.Layer'); goog.require('ol.layer.Layer');
goog.require('ol.Loc'); goog.require('ol.Loc');
goog.require('goog.array'); goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.style');
goog.require('goog.math.Coordinate');
/** /**
* @constructor * @constructor
@@ -21,23 +25,62 @@ ol.renderer.Composite = function(container) {
*/ */
this.renderers_ = []; this.renderers_ = [];
var target = document.createElement("div"); /**
target.className = "ol-renderer-composite"; * Pixel buffer for renderer container.
target.style.position = "absolute"; *
target.style.height = "100%"; * @type {number}
target.style.width = "100%"; * @private
container.appendChild(target); */
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 * @private
*/ */
this.target_ = target; 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); 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.<ol.layer.Layer>} layers * @param {Array.<ol.layer.Layer>} layers
* @param {ol.Loc} center * @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) { ol.renderer.Composite.prototype.draw = function(layers, center, resolution, animate) {
// TODO: deal with layer order and removal // TODO: deal with layer order and removal
for (var i=0, ii=layers.length; i<ii; ++i) {
this.getOrCreateRenderer(layers[i], i).draw(center, resolution); if (this.renderedResolution_) {
if (resolution !== this.renderedResolution_) {
// TODO: apply transition to old target
this.shiftTarget(0, 0);
}
}
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.renderedCenter_ = center; this.renderedCenter_ = center;
this.renderedResolution_ = resolution;
// update each layer renderer
var renderer, container;
for (var i=0, ii=layers.length; i<ii; ++i) {
renderer = this.getOrCreateRenderer(layers[i]);
renderer.setContainerOffset(this.targetOffset_);
renderer.draw(center, resolution);
}
}; };
/** /**
* @param {ol.layer.Layer} layer * @param {ol.layer.Layer} layer
* @param {number} index * @param {number} index
@@ -68,6 +135,7 @@ ol.renderer.Composite.prototype.getOrCreateRenderer = function(layer, index) {
/** /**
* @param {ol.layer.Layer} layer * @param {ol.layer.Layer} layer
* @return {ol.renderer.LayerRenderer}
*/ */
ol.renderer.Composite.prototype.getRenderer = function(layer) { ol.renderer.Composite.prototype.getRenderer = function(layer) {
function finder(candidate) { function finder(candidate) {
@@ -76,13 +144,31 @@ ol.renderer.Composite.prototype.getRenderer = function(layer) {
return goog.array.find(this.renderers_, finder); return goog.array.find(this.renderers_, finder);
}; };
/**
* @param {ol.renderer.LayerRenderer}
* @return {Element}
*/
ol.renderer.Composite.prototype.getRendererContainer = function(renderer) {
var container = this.layerContainers_[goog.getUid(renderer)];
goog.asserts.assert(goog.isDef(container));
return container;
};
/** /**
* @param {ol.layer.Layer} layer * @param {ol.layer.Layer} layer
*/ */
ol.renderer.Composite.prototype.createRenderer = function(layer) { ol.renderer.Composite.prototype.createRenderer = function(layer) {
var Renderer = this.pickRendererType(layer); var Renderer = this.pickRendererType(layer);
goog.asserts.assert(Renderer, "No supported renderer for layer: " + 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;
}; };
/** /**
+39 -10
View File
@@ -1,5 +1,8 @@
goog.provide('ol.renderer.LayerRenderer'); goog.provide('ol.renderer.LayerRenderer');
goog.require('goog.math.Coordinate');
goog.require('goog.math.Size');
/** /**
* A single layer renderer that will be created by the composite map renderer. * A single layer renderer that will be created by the composite map renderer.
* *
@@ -15,24 +18,50 @@ ol.renderer.LayerRenderer = function(container, layer) {
*/ */
this.container_ = container; this.container_ = container;
/**
* @type {goog.math.Size}
* @private
*/
this.containerSize_ = null;
/**
* Pixel offset between the layer renderer container and the composite
* renderer container. These will always be integer values.
*
* @type {goog.math.Coordinate}
* @protected
*/
this.containerOffset_ = new goog.math.Coordinate(0, 0);
/** /**
* @type {!ol.layer.Layer} * @type {!ol.layer.Layer}
* @protected * @protected
*/ */
this.layer_ = 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 * @return {goog.math.Size}
* @protected * @protected
*/ */
this.target_ = target; ol.renderer.LayerRenderer.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_;
};
/**
* Set the pixel offset between the layer renderer container and the composite
* renderer container.
*
* @param {goog.math.Coordinate} offset Integer pixel offset.
*/
ol.renderer.LayerRenderer.prototype.setContainerOffset = function(offset) {
this.containerOffset_ = offset;
}; };
/** /**
+21
View File
@@ -1,6 +1,7 @@
goog.provide('ol.renderer.MapRenderer'); goog.provide('ol.renderer.MapRenderer');
goog.require('goog.style'); goog.require('goog.style');
goog.require('goog.math.Size');
/** /**
* @constructor * @constructor
@@ -14,6 +15,12 @@ ol.renderer.MapRenderer = function(container) {
*/ */
this.container_ = container; this.container_ = container;
/**
* @type {goog.math.Size}
* @private
*/
this.containerSize_ = null;
/** /**
* @type {ol.Loc} * @type {ol.Loc}
* @protected * @protected
@@ -28,6 +35,20 @@ ol.renderer.MapRenderer = function(container) {
}; };
/**
* @return {goog.math.Size}
* @protected
*/
ol.renderer.MapRenderer.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_;
};
/** /**
* @param {Array.<ol.layer.Layer>} layers * @param {Array.<ol.layer.Layer>} layers
* @param {ol.Loc} center * @param {ol.Loc} center
+57 -76
View File
@@ -37,14 +37,14 @@ ol.renderer.TileLayerRenderer = function(container, layer) {
this.tileSize_ = layer.getTileSize(); 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} * @type {number|undefined}
@@ -82,12 +82,6 @@ ol.renderer.TileLayerRenderer = function(container, layer) {
*/ */
this.renderedZ_ = undefined; this.renderedZ_ = undefined;
/**
* @type {goog.math.Size}
* @private
*/
this.containerSize_ = null;
}; };
goog.inherits(ol.renderer.TileLayerRenderer, ol.renderer.LayerRenderer); goog.inherits(ol.renderer.TileLayerRenderer, ol.renderer.LayerRenderer);
@@ -114,18 +108,6 @@ ol.renderer.TileLayerRenderer.prototype.getPreferredResAndZ_ = function(resoluti
return [r, z]; 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; * Tiles rendered at the current resolution;
* @type {Object} * @type {Object}
@@ -147,73 +129,72 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) {
var tileZ = pair[1]; var tileZ = pair[1];
var scale = resolution / tileResolution; var scale = resolution / tileResolution;
var pxMapSize = this.getContainerSize_(); var containerSize = this.getContainerSize();
var xRight = this.xRight_; var xRight = this.xRight_;
var yDown = this.yDown_; var yDown = this.yDown_;
var halfMapWidth = (resolution * pxMapSize.width) / 2; var halfMapWidth = (resolution * containerSize.width) / 2;
var halfMapHeight = (resolution * pxMapSize.height) / 2; var halfMapHeight = (resolution * containerSize.height) / 2;
var centerX = center.getX(); var centerX = center.getX();
var centerY = center.getY(); 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 // calculate vector from tile origin to map top-left (in integer pixel space)
var pxTileWidth = this.tileSize_[0] / scale; var tileOrigin = this.tileOrigin_;
var pxTileHeight = this.tileSize_[1] / scale; var mapOrigin = [centerX - halfMapWidth, centerY + halfMapHeight];
var pxMap = [
Math.round((mapOrigin[0] - tileOrigin[0]) / resolution),
Math.round((tileOrigin[1] - mapOrigin[1]) / resolution)
];
// this is the index of the top left tile // desired tile size in fractional pixels
var leftTileX = Math.floor(xRight * pxOffsetX / pxTileWidth); var fpxTileWidth = this.tileSize_[0] / scale;
var topTileY = Math.floor(yDown * pxOffsetY / pxTileHeight); var fpxTileHeight = this.tileSize_[1] / scale;
var pxMinX; // calculate vector from tile origin to top-left tile (in integer pixel space)
if (xRight > 0) { var colsLeft = Math.floor(pxMap[0] / fpxTileWidth);
pxMinX = Math.round(leftTileX * pxTileWidth) - pxOffsetX; var rowsAbove = Math.floor(pxMap[1] / fpxTileHeight);
} else { var pxTile = [Math.round(colsLeft * fpxTileWidth), Math.round(rowsAbove * fpxTileHeight)];
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; // offset vector from container origin to top-left tile (in integer pixel space)
var pxTileTop = pxMinY; var pxOffsetX = Math.round(pxTile[0] - pxMap[0] - this.containerOffset_.x);
var pxOffsetY = Math.round(pxTile[1] - pxMap[1] - this.containerOffset_.y);
var numTilesWide = Math.ceil(pxMapSize.width / pxTileWidth); // index of the top left tile
var numTilesHigh = Math.ceil(pxMapSize.height / pxTileHeight); var leftTileX = xRight ? colsLeft : (-colsLeft - 1);
var topTileY = yDown ? rowsAbove : (-rowsAbove - 1);
// assume a buffer of zero for now var numTilesWide = Math.ceil(containerSize.width / fpxTileWidth);
if (pxMinX < 0) { var numTilesHigh = Math.ceil(containerSize.height / fpxTileHeight);
if (this.containerOffset_.x !== -pxOffsetX) {
numTilesWide += 1; numTilesWide += 1;
} }
if (pxMinY < 0) { if (this.containerOffset_.y !== -pxOffsetY) {
numTilesHigh += 1; numTilesHigh += 1;
} }
var tileX, tileY, tile, img, pxTileRight, pxTileBottom, xyz, append; var pxMinX = pxOffsetX;
var pxMinY = pxOffsetY;
var pxTileLeft = pxMinX;
var tileX, tileY, tile, img, pxTileBottom, pxTileRight, pxTileTop, xyz, append;
var fragment = document.createDocumentFragment(); var fragment = document.createDocumentFragment();
var newTiles = false; var newTiles = false;
for (var i=0; i<numTilesWide; ++i) { for (var i=0; i<numTilesWide; ++i) {
pxTileTop = pxMinY; pxTileTop = pxMinY;
tileX = leftTileX + (i * xRight); tileX = xRight ? leftTileX + i : leftTileX - i;
if (scale !== 1) { if (scale !== 1) {
pxTileRight = Math.round(pxMinX + ((i+1) * pxTileWidth)); pxTileRight = Math.round(pxMinX + ((i+1) * fpxTileWidth));
} else { } else {
pxTileRight = pxTileLeft + pxTileWidth; pxTileRight = pxTileLeft + fpxTileWidth;
} }
for (var j=0; j<numTilesHigh; ++j) { for (var j=0; j<numTilesHigh; ++j) {
append = false; append = false;
tileY = topTileY + (j * yDown); tileY = yDown ? topTileY + j : topTile - j;
xyz = tileX + "," + tileY + "," + tileZ; xyz = tileX + "," + tileY + "," + tileZ;
if (scale !== 1) { if (scale !== 1) {
pxTileBottom = Math.round(pxMinY + ((j+1) * pxTileHeight)); pxTileBottom = Math.round(pxMinY + ((j+1) * fpxTileHeight));
} else { } else {
pxTileBottom = pxTileTop + pxTileHeight; pxTileBottom = pxTileTop + fpxTileHeight;
} }
img = null; img = null;
tile = this.renderedTiles_[xyz]; tile = this.renderedTiles_[xyz];
@@ -225,18 +206,18 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) {
} }
this.renderedTiles_[xyz] = tile; this.renderedTiles_[xyz] = tile;
img = tile.getImg(); img = tile.getImg();
goog.dom.appendChild(fragment, img); img.style.top = pxTileTop + "px";
newTiles = true; img.style.left = pxTileLeft + "px";
} /**
} else { * We need to set the size here even if the scale is 1
img = tile.getImg(); * because the image may have been scaled previously. If
} * we want to avoid setting size unnecessarily, the tile
if (img) { * should keep track of the scale.
img.style.top = pxTileTop + "px"; */
img.style.left = pxTileLeft + "px";
if (scale !== 1) {
img.style.height = (pxTileRight - pxTileLeft) + "px"; img.style.height = (pxTileRight - pxTileLeft) + "px";
img.style.width = (pxTileBottom - pxTileTop) + "px"; img.style.width = (pxTileBottom - pxTileTop) + "px";
goog.dom.appendChild(fragment, img);
newTiles = true;
} }
} }
pxTileTop = pxTileBottom; pxTileTop = pxTileBottom;
@@ -244,7 +225,7 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) {
pxTileLeft = pxTileRight; pxTileLeft = pxTileRight;
} }
if (newTiles) { if (newTiles) {
this.target_.appendChild(fragment); this.container_.appendChild(fragment);
} }
this.renderedResolution_ = resolution; this.renderedResolution_ = resolution;
this.renderedTop_ = topTileY; this.renderedTop_ = topTileY;
@@ -262,8 +243,8 @@ ol.renderer.TileLayerRenderer.prototype.draw = function(center, resolution) {
*/ */
ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() { ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
var index, prune, x, y, z, tile; var index, prune, x, y, z, tile;
var xRight = (this.xRight_ > 0); var xRight = this.xRight_;
var yDown = (this.yDown_ > 0); var yDown = this.yDown_;
var top = this.renderedTop_; var top = this.renderedTop_;
var right = this.renderedRight_; var right = this.renderedRight_;
var bottom = this.renderedBottom_; var bottom = this.renderedBottom_;
@@ -285,7 +266,7 @@ ol.renderer.TileLayerRenderer.prototype.removeInvisibleTiles_ = function() {
if (prune) { if (prune) {
tile = this.renderedTiles_[xyz]; tile = this.renderedTiles_[xyz];
delete 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) { ol.renderer.TileLayerRenderer.prototype.changeResolution_ = function(center, resolution) {
this.renderedTiles_ = {}; this.renderedTiles_ = {};
goog.dom.removeChildren(this.target_); goog.dom.removeChildren(this.container_);
}; };