Refactor DOM renderer to use only CSS transforms
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
goog.provide('ol.renderer.dom.Layer');
|
||||
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.renderer.Layer');
|
||||
|
||||
|
||||
@@ -13,6 +14,7 @@ goog.require('ol.renderer.Layer');
|
||||
* @param {!Element} target Target.
|
||||
*/
|
||||
ol.renderer.dom.Layer = function(mapRenderer, layer, target) {
|
||||
|
||||
goog.base(this, mapRenderer, layer);
|
||||
|
||||
/**
|
||||
@@ -21,27 +23,15 @@ ol.renderer.dom.Layer = function(mapRenderer, layer, target) {
|
||||
*/
|
||||
this.target = target;
|
||||
|
||||
/**
|
||||
* Top left corner of the target in map coords.
|
||||
*
|
||||
* @type {ol.Coordinate}
|
||||
* @protected
|
||||
*/
|
||||
this.origin = null;
|
||||
|
||||
this.handleLayerOpacityChange();
|
||||
this.handleLayerVisibleChange();
|
||||
|
||||
};
|
||||
goog.inherits(ol.renderer.dom.Layer, ol.renderer.Layer);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return {ol.renderer.Map} Map renderer.
|
||||
* @return {!Element} Target.
|
||||
*/
|
||||
ol.renderer.dom.Layer.prototype.getMapRenderer = function() {
|
||||
return /** @type {ol.renderer.dom.Map} */ (goog.base(this, 'getMapRenderer'));
|
||||
ol.renderer.dom.Layer.prototype.getTarget = function() {
|
||||
return this.target;
|
||||
};
|
||||
|
||||
|
||||
@@ -57,7 +47,7 @@ ol.renderer.dom.Layer.prototype.handleLayerLoad = function() {
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.dom.Layer.prototype.handleLayerOpacityChange = function() {
|
||||
goog.style.setOpacity(this.target, this.getLayer().getOpacity());
|
||||
this.getMap().render();
|
||||
};
|
||||
|
||||
|
||||
@@ -65,22 +55,11 @@ ol.renderer.dom.Layer.prototype.handleLayerOpacityChange = function() {
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.dom.Layer.prototype.handleLayerVisibleChange = function() {
|
||||
goog.style.showElement(this.target, this.getLayer().getVisible());
|
||||
this.getMap().render();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Render.
|
||||
* @param {number} time Time.
|
||||
*/
|
||||
ol.renderer.dom.Layer.prototype.renderFrame = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Set the location of the top left corner of the target.
|
||||
*
|
||||
* @param {ol.Coordinate} origin Origin.
|
||||
*/
|
||||
ol.renderer.dom.Layer.prototype.setOrigin = function(origin) {
|
||||
this.origin = origin;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// FIXME re-enable rotation when supported
|
||||
|
||||
goog.provide('ol.renderer.dom.Map');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
@@ -36,69 +38,10 @@ ol.renderer.dom.Map = function(container, map) {
|
||||
|
||||
goog.dom.insertChildAt(container, this.layersPane_, 0);
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.layerPanes_ = {};
|
||||
|
||||
/**
|
||||
* @type {ol.Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.renderedCenter_ = null;
|
||||
|
||||
/**
|
||||
* @type {number | undefined}
|
||||
* @private
|
||||
*/
|
||||
this.renderedResolution_ = undefined;
|
||||
|
||||
/**
|
||||
* @type {ol.Size}
|
||||
* @private
|
||||
*/
|
||||
this.renderedSize_ = null;
|
||||
|
||||
/**
|
||||
* @type {number | undefined}
|
||||
* @private
|
||||
*/
|
||||
this.renderedRotation_ = undefined;
|
||||
|
||||
/**
|
||||
* The origin (top left) of the layers pane in map coordinates.
|
||||
*
|
||||
* @type {ol.Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.layersPaneOrigin_ = null;
|
||||
};
|
||||
goog.inherits(ol.renderer.dom.Map, ol.renderer.Map);
|
||||
|
||||
|
||||
/**
|
||||
* Apply the given transform to the layers pane.
|
||||
* @param {number} dx Translation along the x-axis.
|
||||
* @param {number} dy Translation along the y-axis.
|
||||
* @param {number} rotation Rotation angle.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.dom.Map.prototype.applyTransform_ = function(dx, dy, rotation) {
|
||||
var transform =
|
||||
'translate(' + Math.round(dx) + 'px, ' + Math.round(dy) + 'px) ' +
|
||||
'rotate(' + rotation.toFixed(6) + 'rad) ' +
|
||||
'scale3d(1, 1, 1)';
|
||||
|
||||
var style = this.layersPane_.style;
|
||||
style.WebkitTransform = transform;
|
||||
style.MozTransform = transform;
|
||||
style.OTransform = transform;
|
||||
style.msTransform = transform;
|
||||
style.transform = transform;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -109,20 +52,10 @@ ol.renderer.dom.Map.prototype.canRotate = goog.functions.TRUE;
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) {
|
||||
|
||||
if (layer instanceof ol.layer.TileLayer) {
|
||||
|
||||
var layerPane = goog.dom.createElement(goog.dom.TagName.DIV);
|
||||
layerPane.className = 'ol-layer';
|
||||
layerPane.style.position = 'absolute';
|
||||
goog.dom.appendChild(this.layersPane_, layerPane);
|
||||
|
||||
var layerRenderer = new ol.renderer.dom.TileLayer(this, layer, layerPane);
|
||||
|
||||
this.layerPanes_[goog.getUid(layerRenderer)] = layerPane;
|
||||
|
||||
var layerRenderer = new ol.renderer.dom.TileLayer(this, layer);
|
||||
goog.dom.appendChild(this.layersPane_, layerRenderer.getTarget());
|
||||
return layerRenderer;
|
||||
|
||||
} else {
|
||||
goog.asserts.assert(false);
|
||||
return null;
|
||||
@@ -158,123 +91,28 @@ ol.renderer.dom.Map.prototype.handleViewChanged = function() {
|
||||
|
||||
|
||||
/**
|
||||
* Render the map. Sets up the layers pane on first render and adjusts its
|
||||
* position as needed on subsequent calls.
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.dom.Map.prototype.renderFrame = function(time) {
|
||||
|
||||
var map = this.getMap();
|
||||
if (!map.isDef()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var view = map.getView().getView2D();
|
||||
var mapCenter = view.getCenter();
|
||||
var mapSize = map.getSize();
|
||||
var mapResolution = view.getResolution();
|
||||
var mapRotation = view.getRotation();
|
||||
|
||||
goog.asserts.assert(goog.isDefAndNotNull(mapCenter));
|
||||
goog.asserts.assert(goog.isDef(mapResolution));
|
||||
goog.asserts.assert(goog.isDef(mapRotation));
|
||||
goog.asserts.assert(goog.isDefAndNotNull(mapSize));
|
||||
|
||||
if (goog.isNull(this.renderedCenter_)) {
|
||||
// first rendering
|
||||
goog.asserts.assert(!goog.isDef(this.renderedResolution_));
|
||||
goog.asserts.assert(!goog.isDef(this.renderedRotation_));
|
||||
goog.asserts.assert(goog.isNull(this.renderedSize_));
|
||||
this.resetLayersPane_();
|
||||
} else {
|
||||
goog.asserts.assert(goog.isDef(this.renderedResolution_));
|
||||
goog.asserts.assert(!goog.isNull(this.renderedSize_));
|
||||
if (mapResolution !== this.renderedResolution_ ||
|
||||
!mapSize.equals(this.renderedSize_)) {
|
||||
// resolution or size changed, adjust layers pane
|
||||
this.resetLayersPane_();
|
||||
} else if (!mapCenter.equals(this.renderedCenter_) ||
|
||||
mapRotation !== this.renderedRotation_) {
|
||||
// same resolution and size, new center or rotation
|
||||
this.transformLayersPane_();
|
||||
}
|
||||
}
|
||||
|
||||
this.renderedCenter_ = mapCenter;
|
||||
this.renderedResolution_ = mapResolution;
|
||||
this.renderedRotation_ = mapRotation;
|
||||
this.renderedSize_ = mapSize;
|
||||
|
||||
var requestRenderFrame = false;
|
||||
this.forEachReadyVisibleLayer(function(layer, layerRenderer) {
|
||||
if (layerRenderer.renderFrame(time)) {
|
||||
requestRenderFrame = true;
|
||||
}
|
||||
});
|
||||
var layers = map.getLayers();
|
||||
if (goog.isDef(layers)) {
|
||||
layers.forEach(function(layer) {
|
||||
var layerRenderer = this.getLayerRenderer(layer);
|
||||
if (layerRenderer.renderFrame(time)) {
|
||||
requestRenderFrame = true;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (requestRenderFrame) {
|
||||
map.requestRenderFrame();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reset the layers pane to its initial position.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.dom.Map.prototype.resetLayersPane_ = function() {
|
||||
var map = this.map;
|
||||
var mapSize = map.getSize();
|
||||
var halfWidth = mapSize.width / 2;
|
||||
var halfHeight = mapSize.height / 2;
|
||||
var view = /** @type {ol.View2D} */ (map.getView().getView2D());
|
||||
var center = view.getCenter();
|
||||
var resolution = view.getResolution();
|
||||
var origin = new ol.Coordinate(
|
||||
center.x - resolution * halfWidth,
|
||||
center.y + resolution * halfHeight);
|
||||
this.layersPaneOrigin_ = origin;
|
||||
this.setTransformOrigin_(halfWidth, halfHeight);
|
||||
this.applyTransform_(0, 0, view.getRotation());
|
||||
goog.object.forEach(this.layerRenderers, function(layerRenderer) {
|
||||
layerRenderer.setOrigin(origin);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the transform-origin CSS property of the layers pane.
|
||||
* @param {number} x The x-axis origin.
|
||||
* @param {number} y The y-axis origin.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.dom.Map.prototype.setTransformOrigin_ = function(x, y) {
|
||||
var origin = Math.round(x) + 'px ' + Math.round(y) + 'px';
|
||||
var style = this.layersPane_.style;
|
||||
style.WebkitTransformOrigin = origin;
|
||||
style.MozTransformOrigin = origin;
|
||||
style.OTransformOrigin = origin;
|
||||
style.msTransformOrigin = origin;
|
||||
style.transformOrigin = origin;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply the appropriate transform to the layers pane.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.dom.Map.prototype.transformLayersPane_ = function() {
|
||||
var map = this.map;
|
||||
var view = map.getView();
|
||||
var resolution = view.getResolution();
|
||||
var center = view.getCenter();
|
||||
var size = map.getSize();
|
||||
var origin = this.layersPaneOrigin_;
|
||||
var ox = (center.x - origin.x) / resolution;
|
||||
var oy = (origin.y - center.y) / resolution;
|
||||
this.setTransformOrigin_(ox, oy);
|
||||
var dx = ox - (size.width / 2);
|
||||
var dy = oy - (size.height / 2);
|
||||
this.applyTransform_(-dx, -dy, view.getRotation());
|
||||
};
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
// FIXME probably need to reset TileLayerZ if offsets get too large
|
||||
// FIXME when zooming out, preserve higher Z divs to avoid white flash
|
||||
|
||||
goog.provide('ol.renderer.dom.TileLayer');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.math.Vec2');
|
||||
goog.require('goog.style');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Size');
|
||||
goog.require('ol.TileCoord');
|
||||
goog.require('ol.TileRange');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.dom');
|
||||
goog.require('ol.renderer.dom.Layer');
|
||||
goog.require('ol.tilegrid.TileGrid');
|
||||
|
||||
|
||||
|
||||
@@ -16,73 +25,42 @@ goog.require('ol.renderer.dom.Layer');
|
||||
* @extends {ol.renderer.dom.Layer}
|
||||
* @param {ol.renderer.Map} mapRenderer Map renderer.
|
||||
* @param {ol.layer.TileLayer} tileLayer Tile layer.
|
||||
* @param {!Element} target Target.
|
||||
*/
|
||||
ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer, target) {
|
||||
ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer) {
|
||||
|
||||
var target = goog.dom.createElement(goog.dom.TagName.DIV);
|
||||
target.className = 'ol-layer';
|
||||
target.style.position = 'absolute';
|
||||
|
||||
goog.base(this, mapRenderer, tileLayer, target);
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderedTiles_ = {};
|
||||
this.renderedVisible_ = true;
|
||||
|
||||
/**
|
||||
* @type {number|undefined}
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.renderedMapResolution_ = undefined;
|
||||
this.renderedOpacity_ = 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<number, ol.renderer.dom.TileLayerZ_>}
|
||||
*/
|
||||
this.tileLayerZs_ = {};
|
||||
|
||||
};
|
||||
goog.inherits(ol.renderer.dom.TileLayer, ol.renderer.dom.Layer);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @return {ol.layer.TileLayer} Layer.
|
||||
* @return {ol.layer.TileLayer} Tile layer.
|
||||
*/
|
||||
ol.renderer.dom.TileLayer.prototype.getLayer = function() {
|
||||
return /** @type {ol.layer.TileLayer} */ (goog.base(this, 'getLayer'));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the pixel offset between the tile origin and the container origin.
|
||||
* @private
|
||||
* @param {number} z Z.
|
||||
* @param {number} resolution Resolution.
|
||||
* @return {ol.Coordinate} Offset.
|
||||
*/
|
||||
ol.renderer.dom.TileLayer.prototype.getTileOffset_ = function(z, resolution) {
|
||||
var tileLayer = this.getLayer();
|
||||
var tileSource = tileLayer.getTileSource();
|
||||
var tileGrid = tileSource.getTileGrid();
|
||||
var tileOrigin = tileGrid.getOrigin(z);
|
||||
var offset = new ol.Coordinate(
|
||||
Math.round((this.origin.x - tileOrigin.x) / resolution),
|
||||
Math.round((tileOrigin.y - this.origin.y) / resolution));
|
||||
return offset;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get rid of all tiles that weren't drawn in the most recent rendering.
|
||||
* @param {Object.<number, Object.<string, ol.Tile>>} tilesDrawnByZ Tiles just
|
||||
* rendered.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.dom.TileLayer.prototype.removeExtraTiles_ =
|
||||
function(tilesDrawnByZ) {
|
||||
var key, tileCoord, tilesDrawn, tile;
|
||||
for (key in this.renderedTiles_) {
|
||||
tileCoord = ol.TileCoord.createFromString(key);
|
||||
tilesDrawn = tilesDrawnByZ[tileCoord.z];
|
||||
if (!(tilesDrawn && key in tilesDrawn)) {
|
||||
tile = this.renderedTiles_[key];
|
||||
delete this.renderedTiles_[key];
|
||||
goog.dom.removeNode(tile.getImage(this));
|
||||
}
|
||||
}
|
||||
ol.renderer.dom.TileLayer.prototype.getTileLayer = function() {
|
||||
return /** @type {ol.layer.TileLayer} */ (this.getLayer());
|
||||
};
|
||||
|
||||
|
||||
@@ -92,74 +70,85 @@ ol.renderer.dom.TileLayer.prototype.removeExtraTiles_ =
|
||||
ol.renderer.dom.TileLayer.prototype.renderFrame = function(time) {
|
||||
|
||||
var map = this.getMap();
|
||||
if (!map.isDef()) {
|
||||
goog.asserts.assert(map.isDef());
|
||||
|
||||
var view = map.getView().getView2D();
|
||||
var mapCenter = /** @type {!ol.Coordinate} */ (view.getCenter());
|
||||
var mapResolution = /** @type {number} */ (view.getResolution());
|
||||
var mapSize = /** @type {!ol.Size} */ (map.getSize());
|
||||
var mapRotatedExtent = /** @type {!ol.Extent} */
|
||||
(view.getRotatedExtent(mapSize));
|
||||
var mapRotation = view.getRotation();
|
||||
var mapScale = 1 / mapResolution;
|
||||
|
||||
var tileLayer = this.getTileLayer();
|
||||
|
||||
var visible = tileLayer.getVisible();
|
||||
if (!visible) {
|
||||
if (this.renderedVisible_) {
|
||||
goog.style.showElement(this.target, false);
|
||||
this.renderedVisible_ = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
var mapSize = /** @type {ol.Size} */ (map.getSize());
|
||||
var view = map.getView().getView2D();
|
||||
var mapExtent = /** @type {!ol.Extent} */ (view.getRotatedExtent(mapSize));
|
||||
var mapResolution = /** @type {number} */ (view.getResolution());
|
||||
var resolutionChanged = (mapResolution !== this.renderedMapResolution_);
|
||||
|
||||
var tileLayer = this.getLayer();
|
||||
var opacity = tileLayer.getOpacity();
|
||||
if (opacity != this.renderedOpacity_) {
|
||||
goog.style.setOpacity(this.target, opacity);
|
||||
this.renderedOpacity_ = opacity;
|
||||
}
|
||||
|
||||
var tileSource = tileLayer.getTileSource();
|
||||
var tileGrid = tileSource.getTileGrid();
|
||||
|
||||
// z represents the "best" resolution
|
||||
var z = tileGrid.getZForResolution(mapResolution);
|
||||
|
||||
/**
|
||||
* @type {Object.<number, Object.<string, ol.Tile>>}
|
||||
*/
|
||||
/** @type {Object.<number, Object.<string, ol.Tile>>} */
|
||||
var tilesToDrawByZ = {};
|
||||
tilesToDrawByZ[z] = {};
|
||||
|
||||
var tileRange =
|
||||
tileGrid.getTileRangeForExtentAndResolution(mapExtent, mapResolution);
|
||||
var tileRange = tileGrid.getTileRangeForExtentAndResolution(
|
||||
mapRotatedExtent, mapResolution);
|
||||
|
||||
var allTilesLoaded = true;
|
||||
|
||||
// first pass through the tile range to determine all the tiles needed
|
||||
tilesToDrawByZ[z] = {};
|
||||
tileRange.forEachTileCoord(z, function(tileCoord) {
|
||||
|
||||
var tile = tileSource.getTile(tileCoord);
|
||||
|
||||
if (goog.isNull(tile)) {
|
||||
// we're outside the source's extent, continue
|
||||
return;
|
||||
}
|
||||
|
||||
var key = tile.tileCoord.toString();
|
||||
var state = tile.getState();
|
||||
if (state == ol.TileState.IDLE) {
|
||||
var tileState = tile.getState();
|
||||
if (tileState == ol.TileState.IDLE) {
|
||||
tile.load();
|
||||
} else if (state == ol.TileState.LOADED) {
|
||||
tilesToDrawByZ[z][key] = tile;
|
||||
} else if (tileState == ol.TileState.LOADED) {
|
||||
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
|
||||
return;
|
||||
} else if (tileState == ol.TileState.ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
allTilesLoaded = false;
|
||||
|
||||
/**
|
||||
* Look for already loaded tiles at alternate z that can serve as
|
||||
* placeholders until tiles at the current z have loaded.
|
||||
*
|
||||
* TODO: make this more efficent for filling partial holes
|
||||
*/
|
||||
// FIXME this could be more efficient about filling partial holes
|
||||
tileGrid.forEachTileCoordParentTileRange(
|
||||
tileCoord,
|
||||
function(altZ, altTileRange) {
|
||||
function(z, tileRange) {
|
||||
var fullyCovered = true;
|
||||
altTileRange.forEachTileCoord(altZ, function(altTileCoord) {
|
||||
var tileKey = altTileCoord.toString();
|
||||
if (tilesToDrawByZ[altZ] && tilesToDrawByZ[altZ][tileKey]) {
|
||||
tileRange.forEachTileCoord(z, function(tileCoord) {
|
||||
var tileCoordKey = tileCoord.toString();
|
||||
if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) {
|
||||
return;
|
||||
}
|
||||
var altTile = tileSource.getTile(altTileCoord);
|
||||
if (!goog.isNull(altTile) &&
|
||||
altTile.getState() == ol.TileState.LOADED) {
|
||||
if (!(altZ in tilesToDrawByZ)) {
|
||||
tilesToDrawByZ[altZ] = {};
|
||||
var tile = tileSource.getTile(tileCoord);
|
||||
if (!goog.isNull(tile) &&
|
||||
tile.getState() == ol.TileState.LOADED) {
|
||||
if (!tilesToDrawByZ[z]) {
|
||||
tilesToDrawByZ[z] = {};
|
||||
}
|
||||
tilesToDrawByZ[altZ][tileKey] = altTile;
|
||||
tilesToDrawByZ[z][tileCoordKey] = tile;
|
||||
} else {
|
||||
fullyCovered = false;
|
||||
}
|
||||
@@ -173,57 +162,227 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = function(time) {
|
||||
var zs = goog.array.map(goog.object.getKeys(tilesToDrawByZ), Number);
|
||||
goog.array.sort(zs);
|
||||
|
||||
var fragment = document.createDocumentFragment();
|
||||
var altFragment = document.createDocumentFragment();
|
||||
var newTiles = false;
|
||||
var newAltTiles = false;
|
||||
for (var i = 0, ii = zs.length; i < ii; ++i) {
|
||||
var tileZ = zs[i];
|
||||
var tilesToDraw = tilesToDrawByZ[tileZ];
|
||||
var tileOffset = this.getTileOffset_(tileZ, mapResolution);
|
||||
for (var key in tilesToDraw) {
|
||||
var tile = tilesToDraw[key];
|
||||
var tileCoord = tile.tileCoord;
|
||||
var pixelBounds = tileGrid.getPixelBoundsForTileCoordAndResolution(
|
||||
tileCoord, mapResolution);
|
||||
var img = tile.getImage(this);
|
||||
var style = img.style;
|
||||
var append = !(key in this.renderedTiles_);
|
||||
if (append || resolutionChanged) {
|
||||
style.left = (pixelBounds.minX - tileOffset.x) + 'px';
|
||||
style.top = (-pixelBounds.maxY - tileOffset.y) + 'px';
|
||||
style.width = pixelBounds.getWidth() + 'px';
|
||||
style.height = pixelBounds.getHeight() + 'px';
|
||||
}
|
||||
if (append) {
|
||||
this.renderedTiles_[key] = tile;
|
||||
style.position = 'absolute';
|
||||
if (tileZ === z) {
|
||||
goog.dom.appendChild(fragment, img);
|
||||
newTiles = true;
|
||||
} else {
|
||||
goog.dom.appendChild(altFragment, img);
|
||||
newAltTiles = true;
|
||||
/** @type {Object.<number, boolean>} */
|
||||
var newTileLayerZKeys = {};
|
||||
|
||||
var tileSize = tileGrid.getTileSize();
|
||||
var iz, tileCoordKey, tileCoordOrigin, tileLayerZ, tileLayerZKey, tilesToDraw;
|
||||
for (iz = 0; iz < zs.length; ++iz) {
|
||||
tileLayerZKey = zs[iz];
|
||||
if (tileLayerZKey in this.tileLayerZs_) {
|
||||
tileLayerZ = this.tileLayerZs_[tileLayerZKey];
|
||||
} else {
|
||||
tileCoordOrigin =
|
||||
tileGrid.getTileCoordForCoordAndZ(mapCenter, tileLayerZKey);
|
||||
tileLayerZ = new ol.renderer.dom.TileLayerZ_(tileGrid, tileCoordOrigin);
|
||||
newTileLayerZKeys[tileLayerZKey] = true;
|
||||
this.tileLayerZs_[tileLayerZKey] = tileLayerZ;
|
||||
}
|
||||
tilesToDraw = tilesToDrawByZ[tileLayerZKey];
|
||||
for (tileCoordKey in tilesToDraw) {
|
||||
tileLayerZ.addTile(tilesToDraw[tileCoordKey]);
|
||||
}
|
||||
tileLayerZ.finalizeAddTiles();
|
||||
}
|
||||
|
||||
/** @type {Array.<number>} */
|
||||
var tileLayerZKeys =
|
||||
goog.array.map(goog.object.getKeys(this.tileLayerZs_), Number);
|
||||
goog.array.sort(tileLayerZKeys);
|
||||
|
||||
var i, j, origin, resolution;
|
||||
var transform = goog.vec.Mat4.createNumber();
|
||||
for (i = 0; i < tileLayerZKeys.length; ++i) {
|
||||
tileLayerZKey = tileLayerZKeys[i];
|
||||
tileLayerZ = this.tileLayerZs_[tileLayerZKey];
|
||||
if (!(tileLayerZKey in tilesToDrawByZ)) {
|
||||
goog.dom.removeNode(tileLayerZ.target);
|
||||
delete this.tileLayerZs_[tileLayerZKey];
|
||||
continue;
|
||||
}
|
||||
resolution = tileLayerZ.getResolution();
|
||||
origin = tileLayerZ.getOrigin();
|
||||
goog.vec.Mat4.makeIdentity(transform);
|
||||
goog.vec.Mat4.translate(
|
||||
transform, mapSize.width / 2, mapSize.height / 2, 0);
|
||||
if (goog.isDef(mapRotation)) {
|
||||
goog.vec.Mat4.rotateZ(transform, mapRotation);
|
||||
}
|
||||
goog.vec.Mat4.scale(
|
||||
transform, resolution / mapResolution, resolution / mapResolution, 1);
|
||||
goog.vec.Mat4.translate(transform, (origin.x - mapCenter.x) / resolution,
|
||||
(mapCenter.y - origin.y) / resolution, 0);
|
||||
tileLayerZ.setTransform(transform);
|
||||
if (tileLayerZKey in newTileLayerZKeys) {
|
||||
for (j = tileLayerZKey - 1; j >= 0; --j) {
|
||||
if (j in this.tileLayerZs_) {
|
||||
goog.dom.insertSiblingAfter(
|
||||
tileLayerZ.target, this.tileLayerZs_[j].target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newAltTiles) {
|
||||
var child = this.target.firstChild;
|
||||
if (child) {
|
||||
goog.dom.insertSiblingBefore(altFragment, child);
|
||||
if (j < 0) {
|
||||
goog.dom.insertChildAt(this.target, tileLayerZ.target, 0);
|
||||
}
|
||||
} else {
|
||||
goog.dom.appendChild(this.target, altFragment);
|
||||
tileLayerZ.removeTilesOutsideExtent(mapRotatedExtent);
|
||||
}
|
||||
}
|
||||
if (newTiles) {
|
||||
goog.dom.appendChild(this.target, fragment);
|
||||
|
||||
if (visible && !this.renderedVisible_) {
|
||||
goog.style.showElement(this.target, true);
|
||||
this.renderedVisible_ = true;
|
||||
}
|
||||
|
||||
this.renderedMapResolution_ = mapResolution;
|
||||
|
||||
this.removeExtraTiles_(tilesToDrawByZ);
|
||||
|
||||
return !allTilesLoaded;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @private
|
||||
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
|
||||
* @param {ol.TileCoord} tileCoordOrigin Tile coord origin.
|
||||
*/
|
||||
ol.renderer.dom.TileLayerZ_ = function(tileGrid, tileCoordOrigin) {
|
||||
|
||||
/**
|
||||
* @type {!Element}
|
||||
*/
|
||||
this.target = goog.dom.createElement(goog.dom.TagName.DIV);
|
||||
this.target.style.position = 'absolute';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.tilegrid.TileGrid}
|
||||
*/
|
||||
this.tileGrid_ = tileGrid;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.TileCoord}
|
||||
*/
|
||||
this.tileCoordOrigin_ = tileCoordOrigin;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!ol.Coordinate}
|
||||
*/
|
||||
this.origin_ = /** @type {!ol.Coordinate} */
|
||||
(tileGrid.getTileCoordExtent(tileCoordOrigin).getTopLeft());
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.resolution_ = tileGrid.getResolution(tileCoordOrigin.z);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, ol.Tile>}
|
||||
*/
|
||||
this.tiles_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {DocumentFragment}
|
||||
*/
|
||||
this.documentFragment_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {goog.vec.Mat4.AnyType}
|
||||
*/
|
||||
this.transform_ = goog.vec.Mat4.createNumberIdentity();
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Tile} tile Tile.
|
||||
*/
|
||||
ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile) {
|
||||
var tileCoord = tile.tileCoord;
|
||||
goog.asserts.assert(tileCoord.z == this.tileCoordOrigin_.z);
|
||||
var tileCoordKey = tileCoord.toString();
|
||||
if (tileCoordKey in this.tiles_) {
|
||||
return;
|
||||
}
|
||||
var tileSize = this.tileGrid_.getTileSize();
|
||||
var image = tile.getImage(this);
|
||||
var style = image.style;
|
||||
style.position = 'absolute';
|
||||
style.left =
|
||||
((tileCoord.x - this.tileCoordOrigin_.x) * tileSize.width) + 'px';
|
||||
style.top =
|
||||
((this.tileCoordOrigin_.y - tileCoord.y) * tileSize.height) + 'px';
|
||||
if (goog.isNull(this.documentFragment_)) {
|
||||
this.documentFragment_ = document.createDocumentFragment();
|
||||
}
|
||||
goog.dom.appendChild(this.documentFragment_, image);
|
||||
this.tiles_[tileCoordKey] = tile;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
ol.renderer.dom.TileLayerZ_.prototype.finalizeAddTiles = function() {
|
||||
if (!goog.isNull(this.documentFragment_)) {
|
||||
goog.dom.appendChild(this.target, this.documentFragment_);
|
||||
this.documentFragment_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!ol.Coordinate} Origin.
|
||||
*/
|
||||
ol.renderer.dom.TileLayerZ_.prototype.getOrigin = function() {
|
||||
return this.origin_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Resolution.
|
||||
*/
|
||||
ol.renderer.dom.TileLayerZ_.prototype.getResolution = function() {
|
||||
return this.resolution_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Extent} extent Extent.
|
||||
*/
|
||||
ol.renderer.dom.TileLayerZ_.prototype.removeTilesOutsideExtent =
|
||||
function(extent) {
|
||||
var tileRange =
|
||||
this.tileGrid_.getTileRangeForExtentAndZ(extent, this.tileCoordOrigin_.z);
|
||||
var tilesToRemove = [];
|
||||
var tile, tileCoordKey;
|
||||
for (tileCoordKey in this.tiles_) {
|
||||
tile = this.tiles_[tileCoordKey];
|
||||
if (!tileRange.contains(tile.tileCoord)) {
|
||||
tilesToRemove.push(tile);
|
||||
}
|
||||
}
|
||||
var i;
|
||||
for (i = 0; i < tilesToRemove.length; ++i) {
|
||||
tile = tilesToRemove[i];
|
||||
tileCoordKey = tile.tileCoord.toString();
|
||||
goog.dom.removeNode(tile.getImage(this));
|
||||
delete this.tiles_[tileCoordKey];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.vec.Mat4.AnyType} transform Transform.
|
||||
*/
|
||||
ol.renderer.dom.TileLayerZ_.prototype.setTransform = function(transform) {
|
||||
if (!goog.vec.Mat4.equals(transform, this.transform_)) {
|
||||
ol.dom.transformElement2D(this.target, transform);
|
||||
goog.vec.Mat4.setFromArray(this.transform_, transform);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user