Add render options for vector tile layers
This commit is contained in:
@@ -43,6 +43,7 @@ function tileUrlFunction(tileCoord) {
|
|||||||
var map = new ol.Map({
|
var map = new ol.Map({
|
||||||
layers: [
|
layers: [
|
||||||
new ol.layer.VectorTile({
|
new ol.layer.VectorTile({
|
||||||
|
renderMode: 'vector',
|
||||||
preload: Infinity,
|
preload: Infinity,
|
||||||
source: new ol.source.VectorTile({
|
source: new ol.source.VectorTile({
|
||||||
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
|
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
|
||||||
|
|||||||
@@ -3798,6 +3798,7 @@ olx.layer.VectorOptions.prototype.visible;
|
|||||||
* maxResolution: (number|undefined),
|
* maxResolution: (number|undefined),
|
||||||
* opacity: (number|undefined),
|
* opacity: (number|undefined),
|
||||||
* renderBuffer: (number|undefined),
|
* renderBuffer: (number|undefined),
|
||||||
|
* renderMode: (ol.layer.VectorTileRenderType|string|undefined),
|
||||||
* renderOrder: (function(ol.Feature, ol.Feature):number|undefined),
|
* renderOrder: (function(ol.Feature, ol.Feature):number|undefined),
|
||||||
* source: (ol.source.VectorTile|undefined),
|
* source: (ol.source.VectorTile|undefined),
|
||||||
* style: (ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined),
|
* style: (ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined),
|
||||||
@@ -3822,6 +3823,22 @@ olx.layer.VectorTileOptions;
|
|||||||
olx.layer.VectorTileOptions.prototype.renderBuffer;
|
olx.layer.VectorTileOptions.prototype.renderBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render mode for vector tiles:
|
||||||
|
* * `'image'`: Vector tiles are rendered as images. Great performance, but
|
||||||
|
* point symbols and texts are always rotated with the view and pixels are
|
||||||
|
* scaled during zoom animations.
|
||||||
|
* * `'hybrid'`: Polygon and line elements are rendered as images, so pixels
|
||||||
|
* are scaled during zoom animations. Point symbols and texts are accurately
|
||||||
|
* rendered as vectors and can stay upright on rotated views.
|
||||||
|
* * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering
|
||||||
|
* even during animations, but slower performance than the other options.
|
||||||
|
* The default is `'hybrid'`.
|
||||||
|
* @type {ol.layer.VectorTileRenderType|string|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.layer.VectorTileOptions.prototype.renderMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render order. Function to be used when sorting features before rendering. By
|
* Render order. Function to be used when sorting features before rendering. By
|
||||||
* default features are drawn in the order that they are created.
|
* default features are drawn in the order that they are created.
|
||||||
@@ -4361,7 +4378,6 @@ olx.source.TileImageOptions.prototype.wrapX;
|
|||||||
* cacheSize: (number|undefined),
|
* cacheSize: (number|undefined),
|
||||||
* format: (ol.format.Feature|undefined),
|
* format: (ol.format.Feature|undefined),
|
||||||
* logo: (string|olx.LogoOptions|undefined),
|
* logo: (string|olx.LogoOptions|undefined),
|
||||||
* opaque: (boolean|undefined),
|
|
||||||
* projection: ol.proj.ProjectionLike,
|
* projection: ol.proj.ProjectionLike,
|
||||||
* state: (ol.source.State|undefined),
|
* state: (ol.source.State|undefined),
|
||||||
* tileClass: (function(new: ol.VectorTile, ol.TileCoord,
|
* tileClass: (function(new: ol.VectorTile, ol.TileCoord,
|
||||||
@@ -4412,14 +4428,6 @@ olx.source.VectorTileOptions.prototype.format;
|
|||||||
olx.source.VectorTileOptions.prototype.logo;
|
olx.source.VectorTileOptions.prototype.logo;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the layer is opaque.
|
|
||||||
* @type {boolean|undefined}
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
olx.source.VectorTileOptions.prototype.opaque;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Projection.
|
* Projection.
|
||||||
* @type {ol.proj.ProjectionLike}
|
* @type {ol.proj.ProjectionLike}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
goog.provide('ol.layer.VectorTile');
|
goog.provide('ol.layer.VectorTile');
|
||||||
|
|
||||||
|
goog.require('goog.asserts');
|
||||||
goog.require('ol.layer.Vector');
|
goog.require('ol.layer.Vector');
|
||||||
goog.require('ol.object');
|
goog.require('ol.object');
|
||||||
|
|
||||||
@@ -13,6 +14,26 @@ ol.layer.VectorTileProperty = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum {string}
|
||||||
|
* Render mode for vector tiles:
|
||||||
|
* * `'image'`: Vector tiles are rendered as images. Great performance, but
|
||||||
|
* point symbols and texts are always rotated with the view and pixels are
|
||||||
|
* scaled during zoom animations.
|
||||||
|
* * `'hybrid'`: Polygon and line elements are rendered as images, so pixels
|
||||||
|
* are scaled during zoom animations. Point symbols and texts are accurately
|
||||||
|
* rendered as vectors and can stay upright on rotated views.
|
||||||
|
* * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering
|
||||||
|
* even during animations, but slower performance than the other options.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.layer.VectorTileRenderType = {
|
||||||
|
IMAGE: 'image',
|
||||||
|
HYBRID: 'hybrid',
|
||||||
|
VECTOR: 'vector'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @classdesc
|
* @classdesc
|
||||||
* Layer for vector tile data that is rendered client-side.
|
* Layer for vector tile data that is rendered client-side.
|
||||||
@@ -38,6 +59,18 @@ ol.layer.VectorTile = function(opt_options) {
|
|||||||
this.setUseInterimTilesOnError(options.useInterimTilesOnError ?
|
this.setUseInterimTilesOnError(options.useInterimTilesOnError ?
|
||||||
options.useInterimTilesOnError : true);
|
options.useInterimTilesOnError : true);
|
||||||
|
|
||||||
|
goog.asserts.assert(options.renderMode == undefined ||
|
||||||
|
options.renderMode == ol.layer.VectorTileRenderType.IMAGE ||
|
||||||
|
options.renderMode == ol.layer.VectorTileRenderType.HYBRID ||
|
||||||
|
options.renderMode == ol.layer.VectorTileRenderType.VECTOR,
|
||||||
|
'renderMode needs to be \'image\', \'hybrid\' or \'vector\'');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {ol.layer.VectorTileRenderType|string}
|
||||||
|
*/
|
||||||
|
this.renderMode_ = options.renderMode || ol.layer.VectorTileRenderType.HYBRID;
|
||||||
|
|
||||||
};
|
};
|
||||||
goog.inherits(ol.layer.VectorTile, ol.layer.Vector);
|
goog.inherits(ol.layer.VectorTile, ol.layer.Vector);
|
||||||
|
|
||||||
@@ -53,6 +86,14 @@ ol.layer.VectorTile.prototype.getPreload = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {ol.layer.VectorTileRenderType|string} The render mode.
|
||||||
|
*/
|
||||||
|
ol.layer.VectorTile.prototype.getRenderMode = function() {
|
||||||
|
return this.renderMode_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether we use interim tiles on error.
|
* Whether we use interim tiles on error.
|
||||||
* @return {boolean} Use interim tiles on error.
|
* @return {boolean} Use interim tiles on error.
|
||||||
|
|||||||
@@ -1995,41 +1995,41 @@ ol.render.canvas.ReplayGroup.prototype.isEmpty = function() {
|
|||||||
* @param {number} viewRotation View rotation.
|
* @param {number} viewRotation View rotation.
|
||||||
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
|
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
|
||||||
* to skip.
|
* to skip.
|
||||||
* @param {boolean=} opt_clip Clip at `maxExtent`. Default is true.
|
* @param {Array.<ol.render.ReplayType>=} opt_replayTypes Ordered replay types
|
||||||
|
* to replay. Default is {@link ol.render.REPLAY_ORDER}
|
||||||
*/
|
*/
|
||||||
ol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio,
|
ol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio,
|
||||||
transform, viewRotation, skippedFeaturesHash, opt_clip) {
|
transform, viewRotation, skippedFeaturesHash, opt_replayTypes) {
|
||||||
|
|
||||||
/** @type {Array.<number>} */
|
/** @type {Array.<number>} */
|
||||||
var zs = Object.keys(this.replaysByZIndex_).map(Number);
|
var zs = Object.keys(this.replaysByZIndex_).map(Number);
|
||||||
zs.sort(ol.array.numberSafeCompareFunction);
|
zs.sort(ol.array.numberSafeCompareFunction);
|
||||||
|
|
||||||
if (opt_clip !== false) {
|
// setup clipping so that the parts of over-simplified geometries are not
|
||||||
// setup clipping so that the parts of over-simplified geometries are not
|
// visible outside the current extent when panning
|
||||||
// visible outside the current extent when panning
|
var maxExtent = this.maxExtent_;
|
||||||
var maxExtent = this.maxExtent_;
|
var minX = maxExtent[0];
|
||||||
var minX = maxExtent[0];
|
var minY = maxExtent[1];
|
||||||
var minY = maxExtent[1];
|
var maxX = maxExtent[2];
|
||||||
var maxX = maxExtent[2];
|
var maxY = maxExtent[3];
|
||||||
var maxY = maxExtent[3];
|
var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY];
|
||||||
var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY];
|
ol.geom.flat.transform.transform2D(
|
||||||
ol.geom.flat.transform.transform2D(
|
flatClipCoords, 0, 8, 2, transform, flatClipCoords);
|
||||||
flatClipCoords, 0, 8, 2, transform, flatClipCoords);
|
context.save();
|
||||||
context.save();
|
context.beginPath();
|
||||||
context.beginPath();
|
context.moveTo(flatClipCoords[0], flatClipCoords[1]);
|
||||||
context.moveTo(flatClipCoords[0], flatClipCoords[1]);
|
context.lineTo(flatClipCoords[2], flatClipCoords[3]);
|
||||||
context.lineTo(flatClipCoords[2], flatClipCoords[3]);
|
context.lineTo(flatClipCoords[4], flatClipCoords[5]);
|
||||||
context.lineTo(flatClipCoords[4], flatClipCoords[5]);
|
context.lineTo(flatClipCoords[6], flatClipCoords[7]);
|
||||||
context.lineTo(flatClipCoords[6], flatClipCoords[7]);
|
context.closePath();
|
||||||
context.closePath();
|
context.clip();
|
||||||
context.clip();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.REPLAY_ORDER;
|
||||||
var i, ii, j, jj, replays, replay;
|
var i, ii, j, jj, replays, replay;
|
||||||
for (i = 0, ii = zs.length; i < ii; ++i) {
|
for (i = 0, ii = zs.length; i < ii; ++i) {
|
||||||
replays = this.replaysByZIndex_[zs[i].toString()];
|
replays = this.replaysByZIndex_[zs[i].toString()];
|
||||||
for (j = 0, jj = ol.render.REPLAY_ORDER.length; j < jj; ++j) {
|
for (j = 0, jj = replayTypes.length; j < jj; ++j) {
|
||||||
replay = replays[ol.render.REPLAY_ORDER[j]];
|
replay = replays[replayTypes[j]];
|
||||||
if (replay !== undefined) {
|
if (replay !== undefined) {
|
||||||
replay.replay(context, pixelRatio, transform, viewRotation,
|
replay.replay(context, pixelRatio, transform, viewRotation,
|
||||||
skippedFeaturesHash);
|
skippedFeaturesHash);
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ goog.require('ol.TileState');
|
|||||||
goog.require('ol.array');
|
goog.require('ol.array');
|
||||||
goog.require('ol.dom');
|
goog.require('ol.dom');
|
||||||
goog.require('ol.extent');
|
goog.require('ol.extent');
|
||||||
goog.require('ol.layer.Tile');
|
|
||||||
goog.require('ol.render.EventType');
|
goog.require('ol.render.EventType');
|
||||||
goog.require('ol.renderer.canvas.Layer');
|
goog.require('ol.renderer.canvas.Layer');
|
||||||
|
goog.require('ol.size');
|
||||||
goog.require('ol.source.Tile');
|
goog.require('ol.source.Tile');
|
||||||
goog.require('ol.vec.Mat4');
|
goog.require('ol.vec.Mat4');
|
||||||
|
|
||||||
@@ -19,29 +19,29 @@ goog.require('ol.vec.Mat4');
|
|||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @extends {ol.renderer.canvas.Layer}
|
* @extends {ol.renderer.canvas.Layer}
|
||||||
* @param {ol.layer.Tile} tileLayer Tile layer.
|
* @param {ol.layer.Tile|ol.layer.VectorTile} tileLayer Tile layer.
|
||||||
*/
|
*/
|
||||||
ol.renderer.canvas.TileLayer = function(tileLayer) {
|
ol.renderer.canvas.TileLayer = function(tileLayer) {
|
||||||
|
|
||||||
goog.base(this, tileLayer);
|
goog.base(this, tileLayer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @protected
|
||||||
* @type {CanvasRenderingContext2D}
|
* @type {CanvasRenderingContext2D}
|
||||||
*/
|
*/
|
||||||
this.context_ = ol.dom.createCanvasContext2D();
|
this.context = ol.dom.createCanvasContext2D();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @protected
|
||||||
* @type {Array.<ol.Tile|undefined>}
|
* @type {Array.<ol.Tile|undefined>}
|
||||||
*/
|
*/
|
||||||
this.renderedTiles_ = null;
|
this.renderedTiles = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @protected
|
||||||
* @type {ol.Extent}
|
* @type {ol.Extent}
|
||||||
*/
|
*/
|
||||||
this.tmpExtent_ = ol.extent.createEmpty();
|
this.tmpExtent = ol.extent.createEmpty();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -55,6 +55,12 @@ ol.renderer.canvas.TileLayer = function(tileLayer) {
|
|||||||
*/
|
*/
|
||||||
this.imageTransform_ = goog.vec.Mat4.createNumber();
|
this.imageTransform_ = goog.vec.Mat4.createNumber();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @protected
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.zDirection = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer);
|
goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer);
|
||||||
|
|
||||||
@@ -64,127 +70,9 @@ goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer);
|
|||||||
*/
|
*/
|
||||||
ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
|
ol.renderer.canvas.TileLayer.prototype.composeFrame = function(
|
||||||
frameState, layerState, context) {
|
frameState, layerState, context) {
|
||||||
var pixelRatio = frameState.pixelRatio;
|
|
||||||
var viewState = frameState.viewState;
|
|
||||||
var center = viewState.center;
|
|
||||||
var projection = viewState.projection;
|
|
||||||
var resolution = viewState.resolution;
|
|
||||||
var rotation = viewState.rotation;
|
|
||||||
var size = frameState.size;
|
|
||||||
var offsetX = Math.round(pixelRatio * size[0] / 2);
|
|
||||||
var offsetY = Math.round(pixelRatio * size[1] / 2);
|
|
||||||
var pixelScale = pixelRatio / resolution;
|
|
||||||
var layer = this.getLayer();
|
|
||||||
var source = layer.getSource();
|
|
||||||
goog.asserts.assertInstanceof(source, ol.source.Tile,
|
|
||||||
'source is an ol.source.Tile');
|
|
||||||
var tileGutter = source.getGutter(projection);
|
|
||||||
|
|
||||||
var transform = this.getTransform(frameState, 0);
|
var transform = this.getTransform(frameState, 0);
|
||||||
|
|
||||||
this.dispatchPreComposeEvent(context, frameState, transform);
|
this.dispatchPreComposeEvent(context, frameState, transform);
|
||||||
|
this.renderTileImages(context, frameState, layerState);
|
||||||
var renderContext = context;
|
|
||||||
var hasRenderListeners = layer.hasListener(ol.render.EventType.RENDER);
|
|
||||||
var drawOffsetX, drawOffsetY, drawScale, drawSize;
|
|
||||||
if (rotation || hasRenderListeners) {
|
|
||||||
renderContext = this.context_;
|
|
||||||
var renderCanvas = renderContext.canvas;
|
|
||||||
var tilePixelRatio = source.getTilePixelRatio(pixelRatio);
|
|
||||||
drawScale = tilePixelRatio / pixelRatio;
|
|
||||||
var width = context.canvas.width * drawScale;
|
|
||||||
var height = context.canvas.height * drawScale;
|
|
||||||
// Make sure the canvas is big enough for all possible rotation angles
|
|
||||||
drawSize = Math.round(Math.sqrt(width * width + height * height));
|
|
||||||
if (renderCanvas.width != drawSize) {
|
|
||||||
renderCanvas.width = renderCanvas.height = drawSize;
|
|
||||||
} else {
|
|
||||||
renderContext.clearRect(0, 0, drawSize, drawSize);
|
|
||||||
}
|
|
||||||
drawOffsetX = (drawSize - width) / 2 / drawScale;
|
|
||||||
drawOffsetY = (drawSize - height) / 2 / drawScale;
|
|
||||||
pixelScale *= drawScale;
|
|
||||||
offsetX = Math.round(drawScale * (offsetX + drawOffsetX))
|
|
||||||
offsetY = Math.round(drawScale * (offsetY + drawOffsetY));
|
|
||||||
}
|
|
||||||
|
|
||||||
// for performance reasons, context.save / context.restore is not used
|
|
||||||
// to save and restore the transformation matrix and the opacity.
|
|
||||||
// see http://jsperf.com/context-save-restore-versus-variable
|
|
||||||
var alpha = renderContext.globalAlpha;
|
|
||||||
renderContext.globalAlpha = layerState.opacity;
|
|
||||||
|
|
||||||
var tileGrid = source.getTileGridForProjection(projection);
|
|
||||||
var tilesToDraw = this.renderedTiles_;
|
|
||||||
|
|
||||||
var pixelExtents;
|
|
||||||
var opaque = source.getOpaque(projection) && layerState.opacity == 1;
|
|
||||||
if (!opaque) {
|
|
||||||
tilesToDraw.reverse();
|
|
||||||
pixelExtents = [];
|
|
||||||
}
|
|
||||||
for (var i = 0, ii = tilesToDraw.length; i < ii; ++i) {
|
|
||||||
var tile = tilesToDraw[i];
|
|
||||||
var tileCoord = tile.getTileCoord();
|
|
||||||
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
|
|
||||||
var currentZ = tileCoord[0];
|
|
||||||
// Calculate all insert points by tile widths from a common origin to avoid
|
|
||||||
// gaps caused by rounding
|
|
||||||
var origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(
|
|
||||||
tileGrid.getTileCoordForCoordAndZ(center, currentZ, this.tmpTileCoord_)));
|
|
||||||
var w = Math.round(ol.extent.getWidth(tileExtent) * pixelScale);
|
|
||||||
var h = Math.round(ol.extent.getHeight(tileExtent) * pixelScale);
|
|
||||||
var left = Math.round((tileExtent[0] - origin[0]) * pixelScale / w) * w +
|
|
||||||
offsetX + Math.round((origin[0] - center[0]) * pixelScale);
|
|
||||||
var top = Math.round((origin[1] - tileExtent[3]) * pixelScale / h) * h +
|
|
||||||
offsetY + Math.round((center[1] - origin[1]) * pixelScale);
|
|
||||||
if (!opaque) {
|
|
||||||
var pixelExtent = [left, top, left + w, top + h];
|
|
||||||
// Create a clip mask for regions in this low resolution tile that are
|
|
||||||
// already filled by a higher resolution tile
|
|
||||||
renderContext.save();
|
|
||||||
for (var j = 0, jj = pixelExtents.length; j < jj; ++j) {
|
|
||||||
var clipExtent = pixelExtents[j];
|
|
||||||
if (ol.extent.intersects(pixelExtent, clipExtent)) {
|
|
||||||
renderContext.beginPath();
|
|
||||||
// counter-clockwise (outer ring) for current tile
|
|
||||||
renderContext.moveTo(pixelExtent[0], pixelExtent[1]);
|
|
||||||
renderContext.lineTo(pixelExtent[0], pixelExtent[3]);
|
|
||||||
renderContext.lineTo(pixelExtent[2], pixelExtent[3]);
|
|
||||||
renderContext.lineTo(pixelExtent[2], pixelExtent[1]);
|
|
||||||
// clockwise (inner ring) for higher resolution tile
|
|
||||||
renderContext.moveTo(clipExtent[0], clipExtent[1]);
|
|
||||||
renderContext.lineTo(clipExtent[2], clipExtent[1]);
|
|
||||||
renderContext.lineTo(clipExtent[2], clipExtent[3]);
|
|
||||||
renderContext.lineTo(clipExtent[0], clipExtent[3]);
|
|
||||||
renderContext.closePath();
|
|
||||||
renderContext.clip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pixelExtents.push(pixelExtent);
|
|
||||||
}
|
|
||||||
var tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection);
|
|
||||||
renderContext.drawImage(tile.getImage(), tileGutter, tileGutter,
|
|
||||||
tilePixelSize[0], tilePixelSize[1], left, top, w, h);
|
|
||||||
if (!opaque) {
|
|
||||||
renderContext.restore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasRenderListeners) {
|
|
||||||
var dX = drawOffsetX - offsetX / drawScale + offsetX;
|
|
||||||
var dY = drawOffsetY - offsetY / drawScale + offsetY;
|
|
||||||
var imageTransform = ol.vec.Mat4.makeTransform2D(this.imageTransform_,
|
|
||||||
drawSize / 2 - dX, drawSize / 2 - dY, pixelScale, -pixelScale,
|
|
||||||
-rotation, -center[0] + dX / pixelScale, -center[1] - dY / pixelScale);
|
|
||||||
this.dispatchRenderEvent(renderContext, frameState, imageTransform);
|
|
||||||
}
|
|
||||||
if (rotation || hasRenderListeners) {
|
|
||||||
context.drawImage(renderContext.canvas, -Math.round(drawOffsetX),
|
|
||||||
-Math.round(drawOffsetY), drawSize / drawScale, drawSize / drawScale);
|
|
||||||
}
|
|
||||||
renderContext.globalAlpha = alpha;
|
|
||||||
|
|
||||||
this.dispatchPostComposeEvent(context, frameState, transform);
|
this.dispatchPostComposeEvent(context, frameState, transform);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -200,11 +88,11 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
|
|||||||
var projection = viewState.projection;
|
var projection = viewState.projection;
|
||||||
|
|
||||||
var tileLayer = this.getLayer();
|
var tileLayer = this.getLayer();
|
||||||
goog.asserts.assertInstanceof(tileLayer, ol.layer.Tile,
|
|
||||||
'layer is an instance of ol.layer.Tile');
|
|
||||||
var tileSource = tileLayer.getSource();
|
var tileSource = tileLayer.getSource();
|
||||||
|
goog.asserts.assertInstanceof(tileSource, ol.source.Tile,
|
||||||
|
'source is an ol.source.Tile');
|
||||||
var tileGrid = tileSource.getTileGridForProjection(projection);
|
var tileGrid = tileSource.getTileGridForProjection(projection);
|
||||||
var z = tileGrid.getZForResolution(viewState.resolution);
|
var z = tileGrid.getZForResolution(viewState.resolution, this.zDirection);
|
||||||
var tileResolution = tileGrid.getResolution(z);
|
var tileResolution = tileGrid.getResolution(z);
|
||||||
var center = viewState.center;
|
var center = viewState.center;
|
||||||
var extent;
|
var extent;
|
||||||
@@ -291,7 +179,7 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.renderedTiles_ = renderables;
|
this.renderedTiles = renderables;
|
||||||
|
|
||||||
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
||||||
this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,
|
this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,
|
||||||
@@ -308,13 +196,13 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
|
|||||||
*/
|
*/
|
||||||
ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function(
|
ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function(
|
||||||
pixel, frameState, callback, thisArg) {
|
pixel, frameState, callback, thisArg) {
|
||||||
var canvas = this.context_.canvas;
|
var canvas = this.context.canvas;
|
||||||
var size = frameState.size;
|
var size = frameState.size;
|
||||||
canvas.width = size[0];
|
canvas.width = size[0];
|
||||||
canvas.height = size[1];
|
canvas.height = size[1];
|
||||||
this.composeFrame(frameState, this.getLayer().getLayerState(), this.context_);
|
this.composeFrame(frameState, this.getLayer().getLayerState(), this.context);
|
||||||
|
|
||||||
var imageData = this.context_.getImageData(
|
var imageData = this.context.getImageData(
|
||||||
pixel[0], pixel[1], 1, 1).data;
|
pixel[0], pixel[1], 1, 1).data;
|
||||||
|
|
||||||
if (imageData[3] > 0) {
|
if (imageData[3] > 0) {
|
||||||
@@ -323,3 +211,140 @@ ol.renderer.canvas.TileLayer.prototype.forEachLayerAtPixel = function(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {CanvasRenderingContext2D} context Context.
|
||||||
|
* @param {olx.FrameState} frameState Frame state.
|
||||||
|
* @param {ol.layer.LayerState} layerState Layer state.
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
ol.renderer.canvas.TileLayer.prototype.renderTileImages = function(context, frameState, layerState) {
|
||||||
|
var pixelRatio = frameState.pixelRatio;
|
||||||
|
var viewState = frameState.viewState;
|
||||||
|
var center = viewState.center;
|
||||||
|
var projection = viewState.projection;
|
||||||
|
var resolution = viewState.resolution;
|
||||||
|
var rotation = viewState.rotation;
|
||||||
|
var size = frameState.size;
|
||||||
|
var offsetX = Math.round(pixelRatio * size[0] / 2);
|
||||||
|
var offsetY = Math.round(pixelRatio * size[1] / 2);
|
||||||
|
var pixelScale = pixelRatio / resolution;
|
||||||
|
var layer = this.getLayer();
|
||||||
|
var source = layer.getSource();
|
||||||
|
goog.asserts.assertInstanceof(source, ol.source.Tile,
|
||||||
|
'source is an ol.source.Tile');
|
||||||
|
var tileGutter = source.getGutter(projection);
|
||||||
|
var tileGrid = source.getTileGridForProjection(projection);
|
||||||
|
|
||||||
|
var hasRenderListeners = layer.hasListener(ol.render.EventType.RENDER);
|
||||||
|
var renderContext = context;
|
||||||
|
var drawOffsetX, drawOffsetY, drawScale, drawSize;
|
||||||
|
if (rotation || hasRenderListeners) {
|
||||||
|
renderContext = this.context;
|
||||||
|
var renderCanvas = renderContext.canvas;
|
||||||
|
var drawZ = tileGrid.getZForResolution(resolution);
|
||||||
|
var drawTileSize = source.getTilePixelSize(drawZ, pixelRatio, projection);
|
||||||
|
var tileSize = ol.size.toSize(tileGrid.getTileSize(drawZ));
|
||||||
|
drawScale = drawTileSize[0] / tileSize[0];
|
||||||
|
var width = context.canvas.width * drawScale;
|
||||||
|
var height = context.canvas.height * drawScale;
|
||||||
|
// Make sure the canvas is big enough for all possible rotation angles
|
||||||
|
drawSize = Math.round(Math.sqrt(width * width + height * height));
|
||||||
|
if (renderCanvas.width != drawSize) {
|
||||||
|
renderCanvas.width = renderCanvas.height = drawSize;
|
||||||
|
} else {
|
||||||
|
renderContext.clearRect(0, 0, drawSize, drawSize);
|
||||||
|
}
|
||||||
|
drawOffsetX = (drawSize - width) / 2 / drawScale;
|
||||||
|
drawOffsetY = (drawSize - height) / 2 / drawScale;
|
||||||
|
pixelScale *= drawScale;
|
||||||
|
offsetX = Math.round(drawScale * (offsetX + drawOffsetX))
|
||||||
|
offsetY = Math.round(drawScale * (offsetY + drawOffsetY));
|
||||||
|
}
|
||||||
|
// for performance reasons, context.save / context.restore is not used
|
||||||
|
// to save and restore the transformation matrix and the opacity.
|
||||||
|
// see http://jsperf.com/context-save-restore-versus-variable
|
||||||
|
var alpha = renderContext.globalAlpha;
|
||||||
|
renderContext.globalAlpha = layerState.opacity;
|
||||||
|
|
||||||
|
var tilesToDraw = this.renderedTiles;
|
||||||
|
|
||||||
|
var pixelExtents;
|
||||||
|
var opaque = source.getOpaque(projection) && layerState.opacity == 1;
|
||||||
|
if (!opaque) {
|
||||||
|
tilesToDraw.reverse();
|
||||||
|
pixelExtents = [];
|
||||||
|
}
|
||||||
|
for (var i = 0, ii = tilesToDraw.length; i < ii; ++i) {
|
||||||
|
var tile = tilesToDraw[i];
|
||||||
|
var tileCoord = tile.getTileCoord();
|
||||||
|
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
|
||||||
|
var currentZ = tileCoord[0];
|
||||||
|
// Calculate all insert points by tile widths from a common origin to avoid
|
||||||
|
// gaps caused by rounding
|
||||||
|
var origin = ol.extent.getBottomLeft(tileGrid.getTileCoordExtent(
|
||||||
|
tileGrid.getTileCoordForCoordAndZ(center, currentZ, this.tmpTileCoord_)));
|
||||||
|
var w = Math.round(ol.extent.getWidth(tileExtent) * pixelScale);
|
||||||
|
var h = Math.round(ol.extent.getHeight(tileExtent) * pixelScale);
|
||||||
|
var left = Math.round((tileExtent[0] - origin[0]) * pixelScale / w) * w +
|
||||||
|
offsetX + Math.round((origin[0] - center[0]) * pixelScale);
|
||||||
|
var top = Math.round((origin[1] - tileExtent[3]) * pixelScale / h) * h +
|
||||||
|
offsetY + Math.round((center[1] - origin[1]) * pixelScale);
|
||||||
|
if (!opaque) {
|
||||||
|
var pixelExtent = [left, top, left + w, top + h];
|
||||||
|
// Create a clip mask for regions in this low resolution tile that are
|
||||||
|
// already filled by a higher resolution tile
|
||||||
|
renderContext.save();
|
||||||
|
for (var j = 0, jj = pixelExtents.length; j < jj; ++j) {
|
||||||
|
var clipExtent = pixelExtents[j];
|
||||||
|
if (ol.extent.intersects(pixelExtent, clipExtent)) {
|
||||||
|
renderContext.beginPath();
|
||||||
|
// counter-clockwise (outer ring) for current tile
|
||||||
|
renderContext.moveTo(pixelExtent[0], pixelExtent[1]);
|
||||||
|
renderContext.lineTo(pixelExtent[0], pixelExtent[3]);
|
||||||
|
renderContext.lineTo(pixelExtent[2], pixelExtent[3]);
|
||||||
|
renderContext.lineTo(pixelExtent[2], pixelExtent[1]);
|
||||||
|
// clockwise (inner ring) for higher resolution tile
|
||||||
|
renderContext.moveTo(clipExtent[0], clipExtent[1]);
|
||||||
|
renderContext.lineTo(clipExtent[2], clipExtent[1]);
|
||||||
|
renderContext.lineTo(clipExtent[2], clipExtent[3]);
|
||||||
|
renderContext.lineTo(clipExtent[0], clipExtent[3]);
|
||||||
|
renderContext.closePath();
|
||||||
|
renderContext.clip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pixelExtents.push(pixelExtent);
|
||||||
|
}
|
||||||
|
var tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection);
|
||||||
|
var image = tile.getImage();
|
||||||
|
if (image) {
|
||||||
|
renderContext.drawImage(image, tileGutter, tileGutter,
|
||||||
|
tilePixelSize[0], tilePixelSize[1], left, top, w, h);
|
||||||
|
}
|
||||||
|
if (!opaque) {
|
||||||
|
renderContext.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasRenderListeners) {
|
||||||
|
var dX = drawOffsetX - offsetX / drawScale + offsetX;
|
||||||
|
var dY = drawOffsetY - offsetY / drawScale + offsetY;
|
||||||
|
var imageTransform = ol.vec.Mat4.makeTransform2D(this.imageTransform_,
|
||||||
|
drawSize / 2 - dX, drawSize / 2 - dY, pixelScale, -pixelScale,
|
||||||
|
-rotation, -center[0] + dX / pixelScale, -center[1] - dY / pixelScale);
|
||||||
|
this.dispatchRenderEvent(renderContext, frameState, imageTransform);
|
||||||
|
}
|
||||||
|
if (rotation || hasRenderListeners) {
|
||||||
|
context.drawImage(renderContext.canvas, -Math.round(drawOffsetX),
|
||||||
|
-Math.round(drawOffsetY), drawSize / drawScale, drawSize / drawScale);
|
||||||
|
}
|
||||||
|
renderContext.globalAlpha = alpha;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
* @return {ol.layer.Tile|ol.layer.VectorTile}
|
||||||
|
*/
|
||||||
|
ol.renderer.canvas.TileLayer.prototype.getLayer;
|
||||||
|
|||||||
@@ -4,91 +4,107 @@ goog.require('goog.asserts');
|
|||||||
goog.require('ol.events');
|
goog.require('ol.events');
|
||||||
goog.require('goog.vec.Mat4');
|
goog.require('goog.vec.Mat4');
|
||||||
goog.require('ol.Feature');
|
goog.require('ol.Feature');
|
||||||
goog.require('ol.TileRange');
|
|
||||||
goog.require('ol.TileState');
|
|
||||||
goog.require('ol.VectorTile');
|
goog.require('ol.VectorTile');
|
||||||
goog.require('ol.ViewHint');
|
|
||||||
goog.require('ol.array');
|
goog.require('ol.array');
|
||||||
goog.require('ol.dom');
|
|
||||||
goog.require('ol.extent');
|
goog.require('ol.extent');
|
||||||
goog.require('ol.geom.flat.transform');
|
|
||||||
goog.require('ol.layer.VectorTile');
|
goog.require('ol.layer.VectorTile');
|
||||||
goog.require('ol.proj');
|
goog.require('ol.proj');
|
||||||
goog.require('ol.proj.Units');
|
goog.require('ol.proj.Units');
|
||||||
goog.require('ol.render.EventType');
|
goog.require('ol.render.EventType');
|
||||||
|
goog.require('ol.render.canvas');
|
||||||
goog.require('ol.render.canvas.ReplayGroup');
|
goog.require('ol.render.canvas.ReplayGroup');
|
||||||
goog.require('ol.renderer.canvas.Layer');
|
goog.require('ol.renderer.canvas.TileLayer');
|
||||||
goog.require('ol.renderer.vector');
|
goog.require('ol.renderer.vector');
|
||||||
goog.require('ol.size');
|
goog.require('ol.size');
|
||||||
goog.require('ol.source.VectorTile');
|
goog.require('ol.source.VectorTile');
|
||||||
goog.require('ol.vec.Mat4');
|
goog.require('ol.vec.Mat4');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {!Object.<string, Array.<ol.render.ReplayType>>}
|
||||||
|
*/
|
||||||
|
ol.renderer.canvas.IMAGE_REPLAYS = {
|
||||||
|
'image': ol.render.REPLAY_ORDER,
|
||||||
|
'hybrid': [ol.render.ReplayType.POLYGON, ol.render.ReplayType.LINE_STRING]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @const
|
||||||
|
* @type {!Object.<string, Array.<ol.render.ReplayType>>}
|
||||||
|
*/
|
||||||
|
ol.renderer.canvas.VECTOR_REPLAYS = {
|
||||||
|
'hybrid': [ol.render.ReplayType.IMAGE, ol.render.ReplayType.TEXT],
|
||||||
|
'vector': ol.render.REPLAY_ORDER
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @extends {ol.renderer.canvas.Layer}
|
* @extends {ol.renderer.canvas.TileLayer}
|
||||||
* @param {ol.layer.VectorTile} layer VectorTile layer.
|
* @param {ol.layer.VectorTile} layer VectorTile layer.
|
||||||
*/
|
*/
|
||||||
ol.renderer.canvas.VectorTileLayer = function(layer) {
|
ol.renderer.canvas.VectorTileLayer = function(layer) {
|
||||||
|
|
||||||
goog.base(this, layer);
|
goog.base(this, layer);
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {CanvasRenderingContext2D}
|
|
||||||
*/
|
|
||||||
this.context_ = ol.dom.createCanvasContext2D();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.dirty_ = false;
|
this.dirty_ = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {Array.<ol.VectorTile>}
|
|
||||||
*/
|
|
||||||
this.renderedTiles_ = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {ol.Extent}
|
|
||||||
*/
|
|
||||||
this.tmpExtent_ = ol.extent.createEmpty();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @type {ol.Size}
|
|
||||||
*/
|
|
||||||
this.tmpSize_ = [NaN, NaN];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {!goog.vec.Mat4.Number}
|
* @type {!goog.vec.Mat4.Number}
|
||||||
*/
|
*/
|
||||||
this.tmpTransform_ = goog.vec.Mat4.createNumber();
|
this.tmpTransform_ = goog.vec.Mat4.createNumber();
|
||||||
|
|
||||||
|
// Use lower resolution for pure vector rendering. Closest resolution otherwise.
|
||||||
|
this.zDirection =
|
||||||
|
layer.getRenderMode() == ol.layer.VectorTileRenderType.VECTOR ? 1 : 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
goog.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.Layer);
|
goog.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.TileLayer);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(frameState, layerState, context) {
|
ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(
|
||||||
|
frameState, layerState, context) {
|
||||||
|
var transform = this.getTransform(frameState, 0);
|
||||||
|
this.dispatchPreComposeEvent(context, frameState, transform);
|
||||||
|
this.renderTileImages(context, frameState, layerState);
|
||||||
|
this.renderTileReplays_(context, frameState, layerState);
|
||||||
|
this.dispatchPostComposeEvent(context, frameState, transform);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {CanvasRenderingContext2D} context Context.
|
||||||
|
* @param {olx.FrameState} frameState Frame state.
|
||||||
|
* @param {ol.layer.LayerState} layerState Layer state.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.renderer.canvas.VectorTileLayer.prototype.renderTileReplays_ = function(
|
||||||
|
context, frameState, layerState) {
|
||||||
|
|
||||||
|
var layer = this.getLayer();
|
||||||
|
var replays = ol.renderer.canvas.VECTOR_REPLAYS[layer.getRenderMode()];
|
||||||
|
if (!replays) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var pixelRatio = frameState.pixelRatio;
|
var pixelRatio = frameState.pixelRatio;
|
||||||
var skippedFeatureUids = layerState.managed ?
|
var skippedFeatureUids = layerState.managed ?
|
||||||
frameState.skippedFeatureUids : {};
|
frameState.skippedFeatureUids : {};
|
||||||
var viewState = frameState.viewState;
|
var viewState = frameState.viewState;
|
||||||
var center = viewState.center;
|
var center = viewState.center;
|
||||||
var projection = viewState.projection;
|
|
||||||
var resolution = viewState.resolution;
|
var resolution = viewState.resolution;
|
||||||
var rotation = viewState.rotation;
|
var rotation = viewState.rotation;
|
||||||
var size = frameState.size;
|
var size = frameState.size;
|
||||||
var pixelScale = pixelRatio / resolution;
|
var pixelScale = pixelRatio / resolution;
|
||||||
var layer = this.getLayer();
|
|
||||||
var source = layer.getSource();
|
var source = layer.getSource();
|
||||||
goog.asserts.assertInstanceof(source, ol.source.VectorTile,
|
goog.asserts.assertInstanceof(source, ol.source.VectorTile,
|
||||||
'Source is an ol.source.VectorTile');
|
'Source is an ol.source.VectorTile');
|
||||||
@@ -96,14 +112,12 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(frameState,
|
|||||||
|
|
||||||
var transform = this.getTransform(frameState, 0);
|
var transform = this.getTransform(frameState, 0);
|
||||||
|
|
||||||
this.dispatchPreComposeEvent(context, frameState, transform);
|
|
||||||
|
|
||||||
var replayContext;
|
var replayContext;
|
||||||
if (layer.hasListener(ol.render.EventType.RENDER)) {
|
if (layer.hasListener(ol.render.EventType.RENDER)) {
|
||||||
// resize and clear
|
// resize and clear
|
||||||
this.context_.canvas.width = context.canvas.width;
|
this.context.canvas.width = context.canvas.width;
|
||||||
this.context_.canvas.height = context.canvas.height;
|
this.context.canvas.height = context.canvas.height;
|
||||||
replayContext = this.context_;
|
replayContext = this.context;
|
||||||
} else {
|
} else {
|
||||||
replayContext = context;
|
replayContext = context;
|
||||||
}
|
}
|
||||||
@@ -113,80 +127,39 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(frameState,
|
|||||||
var alpha = replayContext.globalAlpha;
|
var alpha = replayContext.globalAlpha;
|
||||||
replayContext.globalAlpha = layerState.opacity;
|
replayContext.globalAlpha = layerState.opacity;
|
||||||
|
|
||||||
var tilesToDraw = this.renderedTiles_;
|
var tilesToDraw = this.renderedTiles;
|
||||||
var tileGrid = source.getTileGrid();
|
var tileGrid = source.getTileGrid();
|
||||||
|
|
||||||
var currentZ, height, i, ii, insertPoint, insertTransform, offsetX, offsetY;
|
var currentZ, i, ii, offsetX, offsetY, origin, pixelSpace, replayState;
|
||||||
var origin, pixelSpace, replayState, resolutionRatio, tile, tileCenter;
|
var tile, tileExtent, tilePixelResolution, tileResolution, tileTransform;
|
||||||
var tileContext, tileExtent, tilePixelResolution, tilePixelSize;
|
|
||||||
var tileResolution, tileSize, tileTransform, width;
|
|
||||||
for (i = 0, ii = tilesToDraw.length; i < ii; ++i) {
|
for (i = 0, ii = tilesToDraw.length; i < ii; ++i) {
|
||||||
tile = tilesToDraw[i];
|
tile = tilesToDraw[i];
|
||||||
replayState = tile.getReplayState();
|
replayState = tile.getReplayState();
|
||||||
tileExtent = tileGrid.getTileCoordExtent(
|
tileExtent = tileGrid.getTileCoordExtent(
|
||||||
tile.getTileCoord(), this.tmpExtent_);
|
tile.getTileCoord(), this.tmpExtent);
|
||||||
currentZ = tile.getTileCoord()[0];
|
currentZ = tile.getTileCoord()[0];
|
||||||
tileSize = ol.size.toSize(tileGrid.getTileSize(currentZ), this.tmpSize_);
|
|
||||||
pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS;
|
pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS;
|
||||||
tileResolution = tileGrid.getResolution(currentZ);
|
tileResolution = tileGrid.getResolution(currentZ);
|
||||||
tilePixelResolution = tileResolution / tilePixelRatio;
|
tilePixelResolution = tileResolution / tilePixelRatio;
|
||||||
resolutionRatio = tileResolution / resolution;
|
|
||||||
offsetX = Math.round(pixelRatio * size[0] / 2);
|
offsetX = Math.round(pixelRatio * size[0] / 2);
|
||||||
offsetY = Math.round(pixelRatio * size[1] / 2);
|
offsetY = Math.round(pixelRatio * size[1] / 2);
|
||||||
width = tileSize[0] * pixelRatio * resolutionRatio;
|
|
||||||
height = tileSize[1] * pixelRatio * resolutionRatio;
|
if (pixelSpace) {
|
||||||
var unscaledPixelTileSize = tileSize[0] * pixelRatio;
|
origin = ol.extent.getTopLeft(tileExtent);
|
||||||
if (width < unscaledPixelTileSize / 4 || width > unscaledPixelTileSize * 4) {
|
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
|
||||||
if (pixelSpace) {
|
offsetX, offsetY,
|
||||||
origin = ol.extent.getTopLeft(tileExtent);
|
pixelScale * tilePixelResolution,
|
||||||
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
|
pixelScale * tilePixelResolution,
|
||||||
offsetX, offsetY,
|
rotation,
|
||||||
pixelScale * tilePixelResolution,
|
(origin[0] - center[0]) / tilePixelResolution,
|
||||||
pixelScale * tilePixelResolution,
|
(center[1] - origin[1]) / tilePixelResolution);
|
||||||
rotation,
|
|
||||||
(origin[0] - center[0]) / tilePixelResolution,
|
|
||||||
(center[1] - origin[1]) / tilePixelResolution);
|
|
||||||
} else {
|
|
||||||
tileTransform = transform;
|
|
||||||
}
|
|
||||||
replayState.replayGroup.replay(replayContext, pixelRatio,
|
|
||||||
tileTransform, rotation, skippedFeatureUids);
|
|
||||||
} else {
|
} else {
|
||||||
tilePixelSize = source.getTilePixelSize(currentZ, pixelRatio, projection);
|
tileTransform = transform;
|
||||||
if (pixelSpace) {
|
|
||||||
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
|
|
||||||
0, 0,
|
|
||||||
pixelScale * tilePixelResolution, pixelScale * tilePixelResolution,
|
|
||||||
rotation,
|
|
||||||
-tilePixelSize[0] / 2, -tilePixelSize[1] / 2);
|
|
||||||
} else {
|
|
||||||
tileCenter = ol.extent.getCenter(tileExtent);
|
|
||||||
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
|
|
||||||
0, 0,
|
|
||||||
pixelScale, -pixelScale,
|
|
||||||
-rotation,
|
|
||||||
-tileCenter[0], -tileCenter[1]);
|
|
||||||
}
|
|
||||||
tileContext = tile.getContext();
|
|
||||||
if (replayState.resolution !== resolution ||
|
|
||||||
replayState.rotation !== rotation) {
|
|
||||||
replayState.resolution = resolution;
|
|
||||||
replayState.rotation = rotation;
|
|
||||||
tileContext.canvas.width = width + 0.5;
|
|
||||||
tileContext.canvas.height = height + 0.5;
|
|
||||||
tileContext.translate(width / 2, height / 2);
|
|
||||||
tileContext.rotate(-rotation);
|
|
||||||
replayState.replayGroup.replay(tileContext, pixelRatio,
|
|
||||||
tileTransform, rotation, skippedFeatureUids, false);
|
|
||||||
}
|
|
||||||
insertTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
|
|
||||||
0, 0, pixelScale, -pixelScale, 0, -center[0], -center[1]);
|
|
||||||
insertPoint = ol.geom.flat.transform.transform2D(
|
|
||||||
ol.extent.getTopLeft(tileExtent), 0, 1, 2, insertTransform);
|
|
||||||
replayContext.drawImage(tileContext.canvas,
|
|
||||||
Math.round(insertPoint[0] + offsetX),
|
|
||||||
Math.round(insertPoint[1]) + offsetY);
|
|
||||||
}
|
}
|
||||||
|
ol.render.canvas.rotateAtOffset(replayContext, -rotation, offsetX, offsetY);
|
||||||
|
replayState.replayGroup.replay(replayContext, pixelRatio,
|
||||||
|
tileTransform, rotation, skippedFeatureUids, replays);
|
||||||
|
ol.render.canvas.rotateAtOffset(replayContext, rotation, offsetX, offsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replayContext != context) {
|
if (replayContext != context) {
|
||||||
@@ -194,19 +167,18 @@ ol.renderer.canvas.VectorTileLayer.prototype.composeFrame = function(frameState,
|
|||||||
context.drawImage(replayContext.canvas, 0, 0);
|
context.drawImage(replayContext.canvas, 0, 0);
|
||||||
}
|
}
|
||||||
replayContext.globalAlpha = alpha;
|
replayContext.globalAlpha = alpha;
|
||||||
|
|
||||||
this.dispatchPostComposeEvent(context, frameState, transform);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.VectorTile} tile Tile.
|
* @param {ol.VectorTile} tile Tile.
|
||||||
* @param {ol.layer.VectorTile} layer Vector tile layer.
|
* @param {olx.FrameState} frameState Frame state.
|
||||||
* @param {number} pixelRatio Pixel ratio.
|
|
||||||
* @param {ol.proj.Projection} projection Projection.
|
|
||||||
*/
|
*/
|
||||||
ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile,
|
ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile,
|
||||||
layer, pixelRatio, projection) {
|
frameState) {
|
||||||
|
var layer = this.getLayer();
|
||||||
|
var pixelRatio = frameState.pixelRatio;
|
||||||
|
var projection = frameState.viewState.projection;
|
||||||
var revision = layer.getRevision();
|
var revision = layer.getRevision();
|
||||||
var renderOrder = layer.getRenderOrder() || null;
|
var renderOrder = layer.getRenderOrder() || null;
|
||||||
|
|
||||||
@@ -226,21 +198,20 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile,
|
|||||||
var tileCoord = tile.getTileCoord();
|
var tileCoord = tile.getTileCoord();
|
||||||
var tileProjection = tile.getProjection();
|
var tileProjection = tile.getProjection();
|
||||||
var pixelSpace = tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS;
|
var pixelSpace = tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS;
|
||||||
var extent, reproject;
|
var resolution = tileGrid.getResolution(tileCoord[0]);
|
||||||
|
var extent, reproject, tileResolution;
|
||||||
if (pixelSpace) {
|
if (pixelSpace) {
|
||||||
var tilePixelSize = source.getTilePixelSize(tileCoord[0], pixelRatio,
|
var tilePixelRatio = tileResolution = source.getTilePixelRatio(pixelRatio);
|
||||||
tile.getProjection());
|
var tileSize = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]));
|
||||||
extent = [0, 0, tilePixelSize[0], tilePixelSize[1]];
|
extent = [0, 0, tileSize[0] * tilePixelRatio, tileSize[1] * tilePixelRatio];
|
||||||
} else {
|
} else {
|
||||||
|
tileResolution = resolution;
|
||||||
extent = tileGrid.getTileCoordExtent(tileCoord);
|
extent = tileGrid.getTileCoordExtent(tileCoord);
|
||||||
if (!ol.proj.equivalent(projection, tileProjection)) {
|
if (!ol.proj.equivalent(projection, tileProjection)) {
|
||||||
reproject = true;
|
reproject = true;
|
||||||
tile.setProjection(projection);
|
tile.setProjection(projection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var resolution = tileGrid.getResolution(tileCoord[0]);
|
|
||||||
var tileResolution =
|
|
||||||
pixelSpace ? source.getTilePixelRatio(pixelRatio) : resolution;
|
|
||||||
replayState.dirty = false;
|
replayState.dirty = false;
|
||||||
var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
|
var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
|
||||||
tileResolution, layer.getRenderBuffer());
|
tileResolution, layer.getRenderBuffer());
|
||||||
@@ -307,7 +278,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
|
|||||||
/** @type {Object.<string, boolean>} */
|
/** @type {Object.<string, boolean>} */
|
||||||
var features = {};
|
var features = {};
|
||||||
|
|
||||||
var replayables = this.renderedTiles_;
|
var replayables = this.renderedTiles;
|
||||||
var source = layer.getSource();
|
var source = layer.getSource();
|
||||||
goog.asserts.assertInstanceof(source, ol.source.VectorTile,
|
goog.asserts.assertInstanceof(source, ol.source.VectorTile,
|
||||||
'Source is an ol.source.VectorTile');
|
'Source is an ol.source.VectorTile');
|
||||||
@@ -319,7 +290,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
|
|||||||
tile = replayables[i];
|
tile = replayables[i];
|
||||||
tileCoord = tile.getTileCoord();
|
tileCoord = tile.getTileCoord();
|
||||||
tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord,
|
tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord,
|
||||||
this.tmpExtent_);
|
this.tmpExtent);
|
||||||
if (!ol.extent.containsCoordinate(tileExtent, coordinate)) {
|
if (!ol.extent.containsCoordinate(tileExtent, coordinate)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -369,116 +340,17 @@ ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = function(frameState, layerState) {
|
ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = function(frameState, layerState) {
|
||||||
var layer = /** @type {ol.layer.Vector} */ (this.getLayer());
|
var prepared = goog.base(this, 'prepareFrame', frameState, layerState);
|
||||||
goog.asserts.assertInstanceof(layer, ol.layer.VectorTile,
|
if (prepared) {
|
||||||
'layer is an instance of ol.layer.VectorTile');
|
var skippedFeatures = Object.keys(frameState.skippedFeatureUids_ || {});
|
||||||
var source = layer.getSource();
|
for (var i = 0, ii = this.renderedTiles.length; i < ii; ++i) {
|
||||||
goog.asserts.assertInstanceof(source, ol.source.VectorTile,
|
var tile = this.renderedTiles[i];
|
||||||
'Source is an ol.source.VectorTile');
|
goog.asserts.assertInstanceof(tile, ol.VectorTile, 'got an ol.VectorTile');
|
||||||
|
this.createReplayGroup(tile, frameState);
|
||||||
this.updateAttributions(
|
this.renderTileImage(tile, frameState, layerState, skippedFeatures);
|
||||||
frameState.attributions, source.getAttributions());
|
|
||||||
this.updateLogos(frameState, source);
|
|
||||||
|
|
||||||
var animating = frameState.viewHints[ol.ViewHint.ANIMATING];
|
|
||||||
var interacting = frameState.viewHints[ol.ViewHint.INTERACTING];
|
|
||||||
var updateWhileAnimating = layer.getUpdateWhileAnimating();
|
|
||||||
var updateWhileInteracting = layer.getUpdateWhileInteracting();
|
|
||||||
|
|
||||||
if (!this.dirty_ && (!updateWhileAnimating && animating) ||
|
|
||||||
(!updateWhileInteracting && interacting)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var extent = frameState.extent;
|
|
||||||
if (layerState.extent) {
|
|
||||||
extent = ol.extent.getIntersection(extent, layerState.extent);
|
|
||||||
}
|
|
||||||
if (ol.extent.isEmpty(extent)) {
|
|
||||||
// Return false to prevent the rendering of the layer.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewState = frameState.viewState;
|
|
||||||
var projection = viewState.projection;
|
|
||||||
var resolution = viewState.resolution;
|
|
||||||
var pixelRatio = frameState.pixelRatio;
|
|
||||||
|
|
||||||
var tileGrid = source.getTileGrid();
|
|
||||||
var resolutions = tileGrid.getResolutions();
|
|
||||||
var z = resolutions.length - 1;
|
|
||||||
while (z > 0 && resolutions[z] < resolution) {
|
|
||||||
--z;
|
|
||||||
}
|
|
||||||
var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
|
|
||||||
this.updateUsedTiles(frameState.usedTiles, source, z, tileRange);
|
|
||||||
this.manageTilePyramid(frameState, source, tileGrid, pixelRatio,
|
|
||||||
projection, extent, z, layer.getPreload());
|
|
||||||
this.scheduleExpireCache(frameState, source);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {Object.<number, Object.<string, ol.VectorTile>>}
|
|
||||||
*/
|
|
||||||
var tilesToDrawByZ = {};
|
|
||||||
tilesToDrawByZ[z] = {};
|
|
||||||
|
|
||||||
var findLoadedTiles = this.createLoadedTileFinder(source, projection,
|
|
||||||
tilesToDrawByZ);
|
|
||||||
|
|
||||||
var useInterimTilesOnError = layer.getUseInterimTilesOnError();
|
|
||||||
|
|
||||||
var tmpExtent = this.tmpExtent_;
|
|
||||||
var tmpTileRange = new ol.TileRange(0, 0, 0, 0);
|
|
||||||
var childTileRange, fullyLoaded, tile, tileState, x, y;
|
|
||||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
|
||||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
|
||||||
|
|
||||||
tile = source.getTile(z, x, y, pixelRatio, projection);
|
|
||||||
goog.asserts.assertInstanceof(tile, ol.VectorTile,
|
|
||||||
'Tile is an ol.VectorTile');
|
|
||||||
tileState = tile.getState();
|
|
||||||
if (tileState == ol.TileState.LOADED ||
|
|
||||||
tileState == ol.TileState.EMPTY ||
|
|
||||||
(tileState == ol.TileState.ERROR && !useInterimTilesOnError)) {
|
|
||||||
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fullyLoaded = tileGrid.forEachTileCoordParentTileRange(
|
|
||||||
tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);
|
|
||||||
if (!fullyLoaded) {
|
|
||||||
childTileRange = tileGrid.getTileCoordChildTileRange(
|
|
||||||
tile.tileCoord, tmpTileRange, tmpExtent);
|
|
||||||
if (childTileRange) {
|
|
||||||
findLoadedTiles(z + 1, childTileRange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return prepared;
|
||||||
this.dirty_ = false;
|
|
||||||
|
|
||||||
/** @type {Array.<number>} */
|
|
||||||
var zs = Object.keys(tilesToDrawByZ).map(Number);
|
|
||||||
zs.sort(ol.array.numberSafeCompareFunction);
|
|
||||||
var replayables = [];
|
|
||||||
var i, ii, currentZ, tileCoordKey, tilesToDraw;
|
|
||||||
for (i = 0, ii = zs.length; i < ii; ++i) {
|
|
||||||
currentZ = zs[i];
|
|
||||||
tilesToDraw = tilesToDrawByZ[currentZ];
|
|
||||||
for (tileCoordKey in tilesToDraw) {
|
|
||||||
tile = tilesToDraw[tileCoordKey];
|
|
||||||
if (tile.getState() == ol.TileState.LOADED) {
|
|
||||||
replayables.push(tile);
|
|
||||||
this.createReplayGroup(tile, layer, pixelRatio, projection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.renderedTiles_ = replayables;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -508,3 +380,65 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = function(feature, s
|
|||||||
}
|
}
|
||||||
return loading;
|
return loading;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ol.VectorTile} tile Tile.
|
||||||
|
* @param {olx.FrameState} frameState Frame state.
|
||||||
|
* @param {ol.layer.LayerState} layerState Layer state.
|
||||||
|
* @param {Array.<string>} skippedFeatures Skipped features.
|
||||||
|
*/
|
||||||
|
ol.renderer.canvas.VectorTileLayer.prototype.renderTileImage = function(
|
||||||
|
tile, frameState, layerState, skippedFeatures) {
|
||||||
|
var layer = this.getLayer();
|
||||||
|
var replays = ol.renderer.canvas.IMAGE_REPLAYS[layer.getRenderMode()];
|
||||||
|
if (!replays) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var pixelRatio = frameState.pixelRatio;
|
||||||
|
var replayState = tile.getReplayState();
|
||||||
|
var revision = layer.getRevision();
|
||||||
|
if (!ol.array.equals(replayState.skippedFeatures, skippedFeatures) ||
|
||||||
|
replayState.renderedTileRevision !== revision) {
|
||||||
|
replayState.skippedFeatures = skippedFeatures;
|
||||||
|
replayState.renderedTileRevision = revision;
|
||||||
|
var tileContext = tile.getContext();
|
||||||
|
var source = layer.getSource();
|
||||||
|
var tileGrid = source.getTileGrid();
|
||||||
|
var currentZ = tile.getTileCoord()[0];
|
||||||
|
var resolution = tileGrid.getResolution(currentZ);
|
||||||
|
var tileSize = ol.size.toSize(tileGrid.getTileSize(currentZ));
|
||||||
|
var tileResolution = tileGrid.getResolution(currentZ);
|
||||||
|
var resolutionRatio = tileResolution / resolution;
|
||||||
|
var width = tileSize[0] * pixelRatio * resolutionRatio;
|
||||||
|
var height = tileSize[1] * pixelRatio * resolutionRatio;
|
||||||
|
tileContext.canvas.width = width / resolutionRatio + 0.5;
|
||||||
|
tileContext.canvas.height = height / resolutionRatio + 0.5;
|
||||||
|
tileContext.scale(1 / resolutionRatio, 1 / resolutionRatio)
|
||||||
|
tileContext.translate(width / 2, height / 2);
|
||||||
|
var pixelSpace = tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS;
|
||||||
|
var pixelScale = pixelRatio / resolution;
|
||||||
|
var tilePixelRatio = source.getTilePixelRatio(pixelRatio);
|
||||||
|
var tilePixelResolution = tileResolution / tilePixelRatio;
|
||||||
|
var tileExtent = tileGrid.getTileCoordExtent(
|
||||||
|
tile.getTileCoord(), this.tmpExtent);
|
||||||
|
var tileTransform;
|
||||||
|
if (pixelSpace) {
|
||||||
|
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
|
||||||
|
0, 0,
|
||||||
|
pixelScale * tilePixelResolution, pixelScale * tilePixelResolution,
|
||||||
|
0,
|
||||||
|
-tileSize[0] * tilePixelRatio / 2, -tileSize[1] * tilePixelRatio / 2);
|
||||||
|
} else {
|
||||||
|
var tileCenter = ol.extent.getCenter(tileExtent);
|
||||||
|
tileTransform = ol.vec.Mat4.makeTransform2D(this.tmpTransform_,
|
||||||
|
0, 0,
|
||||||
|
pixelScale, -pixelScale,
|
||||||
|
0,
|
||||||
|
-tileCenter[0], -tileCenter[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
replayState.replayGroup.replay(tileContext, pixelRatio,
|
||||||
|
tileTransform, 0, frameState.skippedFeatureUids || {}, replays);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ goog.require('ol.VectorTile');
|
|||||||
goog.require('ol.events');
|
goog.require('ol.events');
|
||||||
goog.require('ol.events.EventType');
|
goog.require('ol.events.EventType');
|
||||||
goog.require('ol.featureloader');
|
goog.require('ol.featureloader');
|
||||||
|
goog.require('ol.size');
|
||||||
goog.require('ol.source.UrlTile');
|
goog.require('ol.source.UrlTile');
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ ol.source.VectorTile = function(options) {
|
|||||||
cacheSize: options.cacheSize !== undefined ? options.cacheSize : 128,
|
cacheSize: options.cacheSize !== undefined ? options.cacheSize : 128,
|
||||||
extent: options.extent,
|
extent: options.extent,
|
||||||
logo: options.logo,
|
logo: options.logo,
|
||||||
opaque: options.opaque,
|
opaque: false,
|
||||||
projection: options.projection,
|
projection: options.projection,
|
||||||
state: options.state,
|
state: options.state,
|
||||||
tileGrid: options.tileGrid,
|
tileGrid: options.tileGrid,
|
||||||
@@ -88,6 +89,15 @@ ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projectio
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.source.VectorTile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {
|
||||||
|
var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));
|
||||||
|
return [tileSize[0] * pixelRatio, tileSize[1] * pixelRatio];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.VectorTile} vectorTile Vector tile.
|
* @param {ol.VectorTile} vectorTile Vector tile.
|
||||||
* @param {string} url URL.
|
* @param {string} url URL.
|
||||||
|
|||||||
@@ -472,10 +472,15 @@ ol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} resolution Resolution.
|
* @param {number} resolution Resolution.
|
||||||
|
* @param {number=} opt_direction If 0, the nearest resolution will be used.
|
||||||
|
* If 1, the nearest lower resolution will be used. If -1, the nearest
|
||||||
|
* higher resolution will be used. Default is 0.
|
||||||
* @return {number} Z.
|
* @return {number} Z.
|
||||||
*/
|
*/
|
||||||
ol.tilegrid.TileGrid.prototype.getZForResolution = function(resolution) {
|
ol.tilegrid.TileGrid.prototype.getZForResolution = function(
|
||||||
var z = ol.array.linearFindNearest(this.resolutions_, resolution, 0);
|
resolution, opt_direction) {
|
||||||
|
var z = ol.array.linearFindNearest(this.resolutions_, resolution,
|
||||||
|
opt_direction || 0);
|
||||||
return ol.math.clamp(z, this.minZoom, this.maxZoom);
|
return ol.math.clamp(z, this.minZoom, this.maxZoom);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ goog.require('ol.proj.Projection');
|
|||||||
* @typedef {{
|
* @typedef {{
|
||||||
* dirty: boolean,
|
* dirty: boolean,
|
||||||
* renderedRenderOrder: (null|function(ol.Feature, ol.Feature):number),
|
* renderedRenderOrder: (null|function(ol.Feature, ol.Feature):number),
|
||||||
|
* renderedTileRevision: number,
|
||||||
* renderedRevision: number,
|
* renderedRevision: number,
|
||||||
* replayGroup: ol.render.IReplayGroup}}
|
* replayGroup: ol.render.IReplayGroup,
|
||||||
|
* skippedFeatures: Array.<string>}}
|
||||||
*/
|
*/
|
||||||
ol.TileReplayState;
|
ol.TileReplayState;
|
||||||
|
|
||||||
@@ -70,7 +72,9 @@ ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
|
|||||||
dirty: false,
|
dirty: false,
|
||||||
renderedRenderOrder: null,
|
renderedRenderOrder: null,
|
||||||
renderedRevision: -1,
|
renderedRevision: -1,
|
||||||
replayGroup: null
|
renderedTileRevision: -1,
|
||||||
|
replayGroup: null,
|
||||||
|
skippedFeatures: []
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,8 +104,9 @@ ol.VectorTile.prototype.getContext = function() {
|
|||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
ol.VectorTile.prototype.disposeInternal = function() {
|
ol.VectorTile.prototype.getImage = function() {
|
||||||
goog.base(this, 'disposeInternal');
|
return this.replayState_.renderedTileRevision == -1 ?
|
||||||
|
null : this.context_.canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,29 @@ describe('ol.layer.VectorTile', function() {
|
|||||||
expect(layer.getUseInterimTilesOnError()).to.be(true);
|
expect(layer.getUseInterimTilesOnError()).to.be(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('provides default renderMode', function() {
|
||||||
|
expect(layer.getRenderMode()).to.be('hybrid');
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('constructor (options)', function() {
|
||||||
|
var layer = new ol.layer.VectorTile({
|
||||||
|
renderMode: 'vector',
|
||||||
|
source: new ol.source.VectorTile({})
|
||||||
|
});
|
||||||
|
expect(layer.getRenderMode()).to.be('vector');
|
||||||
|
layer = new ol.layer.VectorTile({
|
||||||
|
renderMode: 'image',
|
||||||
|
source: new ol.source.VectorTile({})
|
||||||
|
});
|
||||||
|
expect(layer.getRenderMode()).to.be('image');
|
||||||
|
expect(function() {
|
||||||
|
layer = new ol.layer.VectorTile({
|
||||||
|
renderMode: 'foo',
|
||||||
|
source: new ol.source.VectorTile({})
|
||||||
|
});
|
||||||
|
}).to.throwException();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -52,16 +52,24 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
|||||||
map.addLayer(layer);
|
map.addLayer(layer);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a new instance', function() {
|
|
||||||
var renderer = new ol.renderer.canvas.VectorTileLayer(layer);
|
|
||||||
expect(renderer).to.be.a(ol.renderer.canvas.VectorTileLayer);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
document.body.removeChild(target);
|
document.body.removeChild(target);
|
||||||
map.dispose();
|
map.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('creates a new instance', function() {
|
||||||
|
var renderer = new ol.renderer.canvas.VectorTileLayer(layer);
|
||||||
|
expect(renderer).to.be.a(ol.renderer.canvas.VectorTileLayer);
|
||||||
|
expect(renderer.zDirection).to.be(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses lower resolution for pure vector rendering', function() {
|
||||||
|
layer.renderMode_ = 'vector';
|
||||||
|
var renderer = new ol.renderer.canvas.VectorTileLayer(layer);
|
||||||
|
expect(renderer).to.be.a(ol.renderer.canvas.VectorTileLayer);
|
||||||
|
expect(renderer.zDirection).to.be(1);
|
||||||
|
});
|
||||||
|
|
||||||
it('gives precedence to feature styles over layer styles', function() {
|
it('gives precedence to feature styles over layer styles', function() {
|
||||||
var spy = sinon.spy(map.getRenderer().getLayerRenderer(layer),
|
var spy = sinon.spy(map.getRenderer().getLayerRenderer(layer),
|
||||||
'renderFeature');
|
'renderFeature');
|
||||||
@@ -134,7 +142,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
frameState.layerStates[goog.getUid(layer)] = {};
|
frameState.layerStates[goog.getUid(layer)] = {};
|
||||||
renderer.renderedTiles_ = [new TileClass([0, 0, -1])];
|
renderer.renderedTiles = [new TileClass([0, 0, -1])];
|
||||||
renderer.forEachFeatureAtCoordinate(
|
renderer.forEachFeatureAtCoordinate(
|
||||||
coordinate, frameState, spy, undefined);
|
coordinate, frameState, spy, undefined);
|
||||||
expect(spy.callCount).to.be(1);
|
expect(spy.callCount).to.be(1);
|
||||||
|
|||||||
@@ -1028,6 +1028,53 @@ describe('ol.tilegrid.TileGrid', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getZForResolution (lower)', function() {
|
||||||
|
it('returns the expected z value', function() {
|
||||||
|
var tileGrid = new ol.tilegrid.TileGrid({
|
||||||
|
resolutions: resolutions,
|
||||||
|
origin: origin,
|
||||||
|
tileSize: tileSize
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tileGrid.getZForResolution(2000, 1)).to.eql(0);
|
||||||
|
expect(tileGrid.getZForResolution(1000, 1)).to.eql(0);
|
||||||
|
expect(tileGrid.getZForResolution(900, 1)).to.eql(0);
|
||||||
|
expect(tileGrid.getZForResolution(750, 1)).to.eql(0);
|
||||||
|
expect(tileGrid.getZForResolution(625, 1)).to.eql(0);
|
||||||
|
expect(tileGrid.getZForResolution(500, 1)).to.eql(1);
|
||||||
|
expect(tileGrid.getZForResolution(475, 1)).to.eql(1);
|
||||||
|
expect(tileGrid.getZForResolution(375, 1)).to.eql(1);
|
||||||
|
expect(tileGrid.getZForResolution(250, 1)).to.eql(2);
|
||||||
|
expect(tileGrid.getZForResolution(200, 1)).to.eql(2);
|
||||||
|
expect(tileGrid.getZForResolution(125, 1)).to.eql(2);
|
||||||
|
expect(tileGrid.getZForResolution(100, 1)).to.eql(3);
|
||||||
|
expect(tileGrid.getZForResolution(50, 1)).to.eql(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getZForResolution (higher)', function() {
|
||||||
|
it('returns the expected z value', function() {
|
||||||
|
var tileGrid = new ol.tilegrid.TileGrid({
|
||||||
|
resolutions: resolutions,
|
||||||
|
origin: origin,
|
||||||
|
tileSize: tileSize
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tileGrid.getZForResolution(2000, -1)).to.eql(0);
|
||||||
|
expect(tileGrid.getZForResolution(1000, -1)).to.eql(0);
|
||||||
|
expect(tileGrid.getZForResolution(900, -1)).to.eql(1);
|
||||||
|
expect(tileGrid.getZForResolution(750, -1)).to.eql(1);
|
||||||
|
expect(tileGrid.getZForResolution(625, -1)).to.eql(1);
|
||||||
|
expect(tileGrid.getZForResolution(500, -1)).to.eql(1);
|
||||||
|
expect(tileGrid.getZForResolution(475, -1)).to.eql(2);
|
||||||
|
expect(tileGrid.getZForResolution(375, -1)).to.eql(2);
|
||||||
|
expect(tileGrid.getZForResolution(250, -1)).to.eql(2);
|
||||||
|
expect(tileGrid.getZForResolution(200, -1)).to.eql(3);
|
||||||
|
expect(tileGrid.getZForResolution(125, -1)).to.eql(3);
|
||||||
|
expect(tileGrid.getZForResolution(100, -1)).to.eql(3);
|
||||||
|
expect(tileGrid.getZForResolution(50, -1)).to.eql(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
goog.require('ol.Coordinate');
|
goog.require('ol.Coordinate');
|
||||||
|
|||||||
Reference in New Issue
Block a user