Decouple source and rendered tile grid of vector tile sources
This commit is contained in:
@@ -3,7 +3,7 @@ layout: example.html
|
||||
title: Advanced Mapbox Vector Tiles
|
||||
shortdesc: Example of a Mapbox vector tiles map with custom tile grid.
|
||||
docs: >
|
||||
A vector tiles map which reuses the same tiles for subsequent zoom levels to save bandwidth on mobile devices. **Note**: No map will be visible when the access token has expired.
|
||||
A vector tiles map which reuses the same source tiles for subsequent zoom levels to save bandwidth on mobile devices. **Note**: No map will be visible when the access token has expired.
|
||||
tags: "mapbox, vector, tiles, mobile"
|
||||
resources:
|
||||
- resources/mapbox-streets-v6-style.js
|
||||
|
||||
@@ -15,25 +15,16 @@ goog.require('ol.tilegrid.TileGrid');
|
||||
|
||||
var key = 'pk.eyJ1IjoiYWhvY2V2YXIiLCJhIjoiRk1kMWZaSSJ9.E5BkluenyWQMsBLsuByrmg';
|
||||
|
||||
// For how many zoom levels do we want to use the same vector tiles?
|
||||
// 1 means "use tiles from all zoom levels". 2 means "use the same tiles for 2
|
||||
// subsequent zoom levels".
|
||||
var reuseZoomLevels = 2;
|
||||
|
||||
// Offset of loaded tiles from web mercator zoom level 0.
|
||||
// 0 means "At map zoom level 0, use tiles from zoom level 0". 1 means "At map
|
||||
// zoom level 0, use tiles from zoom level 1".
|
||||
var zoomOffset = 1;
|
||||
|
||||
// Calculation of tile urls
|
||||
// Calculation of resolutions that match zoom levels 1, 3, 5, 7, 9, 11, 13, 15.
|
||||
var resolutions = [];
|
||||
for (var z = zoomOffset / reuseZoomLevels; z <= 22 / reuseZoomLevels; ++z) {
|
||||
resolutions.push(156543.03392804097 / Math.pow(2, z * reuseZoomLevels));
|
||||
for (var i = 0; i <= 7; ++i) {
|
||||
resolutions.push(156543.03392804097 / Math.pow(2, i * 2));
|
||||
}
|
||||
// Calculation of tile urls for zoom levels 1, 3, 5, 7, 9, 11, 13, 15.
|
||||
function tileUrlFunction(tileCoord) {
|
||||
return ('https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6/' +
|
||||
'{z}/{x}/{y}.vector.pbf?access_token=' + key)
|
||||
.replace('{z}', String(tileCoord[0] * reuseZoomLevels + zoomOffset))
|
||||
.replace('{z}', String(tileCoord[0] * 2 - 1))
|
||||
.replace('{x}', String(tileCoord[1]))
|
||||
.replace('{y}', String(-tileCoord[2] - 1))
|
||||
.replace('{a-d}', 'abcd'.substr(
|
||||
@@ -43,8 +34,6 @@ function tileUrlFunction(tileCoord) {
|
||||
var map = new ol.Map({
|
||||
layers: [
|
||||
new ol.layer.VectorTile({
|
||||
renderMode: 'vector',
|
||||
preload: Infinity,
|
||||
source: new ol.source.VectorTile({
|
||||
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
|
||||
'© <a href="https://www.openstreetmap.org/copyright">' +
|
||||
@@ -52,9 +41,10 @@ var map = new ol.Map({
|
||||
format: new ol.format.MVT(),
|
||||
tileGrid: new ol.tilegrid.TileGrid({
|
||||
extent: ol.proj.get('EPSG:3857').getExtent(),
|
||||
resolutions: resolutions
|
||||
resolutions: resolutions,
|
||||
tileSize: 512
|
||||
}),
|
||||
tilePixelRatio: 16,
|
||||
tilePixelRatio: 8,
|
||||
tileUrlFunction: tileUrlFunction
|
||||
}),
|
||||
style: createMapboxStreetsV6Style()
|
||||
|
||||
@@ -4864,7 +4864,7 @@ olx.source.VectorTileOptions.prototype.state;
|
||||
|
||||
|
||||
/**
|
||||
* Class used to instantiate image tiles. Default is {@link ol.VectorTile}.
|
||||
* Class used to instantiate vector tiles. Default is {@link ol.VectorTile}.
|
||||
* @type {function(new: ol.VectorTile, ol.TileCoord,
|
||||
* ol.TileState, string, ol.format.Feature,
|
||||
* ol.TileLoadFunctionType)|undefined}
|
||||
|
||||
@@ -70,8 +70,8 @@ ol.ImageTile.prototype.disposeInternal = function() {
|
||||
|
||||
|
||||
/**
|
||||
* Get the image element for this tile.
|
||||
* @inheritDoc
|
||||
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
* @api
|
||||
*/
|
||||
ol.ImageTile.prototype.getImage = function() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
goog.provide('ol.renderer.canvas.VectorTileLayer');
|
||||
|
||||
goog.require('ol');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.dom');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.proj');
|
||||
@@ -12,7 +13,6 @@ goog.require('ol.render.canvas.ReplayGroup');
|
||||
goog.require('ol.render.replay');
|
||||
goog.require('ol.renderer.canvas.TileLayer');
|
||||
goog.require('ol.renderer.vector');
|
||||
goog.require('ol.size');
|
||||
goog.require('ol.transform');
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ goog.require('ol.transform');
|
||||
*/
|
||||
ol.renderer.canvas.VectorTileLayer = function(layer) {
|
||||
|
||||
/**
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.context = null;
|
||||
|
||||
ol.renderer.canvas.TileLayer.call(this, layer);
|
||||
@@ -95,12 +98,12 @@ ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = function(frameState,
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.VectorTile} tile Tile.
|
||||
* @param {ol.VectorImageTile} tile Tile.
|
||||
* @param {olx.FrameState} frameState Frame state.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
|
||||
frameState) {
|
||||
ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
|
||||
tile, frameState) {
|
||||
var layer = this.getLayer();
|
||||
var pixelRatio = frameState.pixelRatio;
|
||||
var projection = frameState.viewState.projection;
|
||||
@@ -113,78 +116,89 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
|
||||
return;
|
||||
}
|
||||
|
||||
replayState.replayGroup = null;
|
||||
replayState.dirty = false;
|
||||
var sourceTiles = tile.getSourceTiles();
|
||||
for (var t = 0, tt = sourceTiles.length; t < tt; ++t) {
|
||||
var sourceTile = sourceTiles[t];
|
||||
sourceTile.replayGroup = null;
|
||||
replayState.dirty = false;
|
||||
|
||||
var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
|
||||
var tileGrid = source.getTileGrid();
|
||||
var tileCoord = tile.tileCoord;
|
||||
var tileProjection = tile.getProjection();
|
||||
var resolution = tileGrid.getResolution(tileCoord[0]);
|
||||
var extent, reproject, tileResolution;
|
||||
if (tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS) {
|
||||
var tilePixelRatio = tileResolution = source.getTilePixelRatio();
|
||||
var tileSize = ol.size.toSize(tileGrid.getTileSize(tileCoord[0]));
|
||||
extent = [0, 0, tileSize[0] * tilePixelRatio, tileSize[1] * tilePixelRatio];
|
||||
} else {
|
||||
tileResolution = resolution;
|
||||
extent = tileGrid.getTileCoordExtent(tileCoord);
|
||||
if (!ol.proj.equivalent(projection, tileProjection)) {
|
||||
reproject = true;
|
||||
tile.setProjection(projection);
|
||||
}
|
||||
}
|
||||
replayState.dirty = false;
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
|
||||
tileResolution, source.getOverlaps(), layer.getRenderBuffer());
|
||||
var squaredTolerance = ol.renderer.vector.getSquaredTolerance(
|
||||
tileResolution, pixelRatio);
|
||||
|
||||
/**
|
||||
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
||||
* @this {ol.renderer.canvas.VectorTileLayer}
|
||||
*/
|
||||
function renderFeature(feature) {
|
||||
var styles;
|
||||
var styleFunction = feature.getStyleFunction();
|
||||
if (styleFunction) {
|
||||
styles = styleFunction.call(/** @type {ol.Feature} */ (feature), resolution);
|
||||
var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
|
||||
var sourceTileGrid = source.getTileGrid();
|
||||
var sourceTileCoord = sourceTile.tileCoord;
|
||||
var tileProjection = sourceTile.getProjection();
|
||||
var tileGrid = source.getTileGridForProjection(projection);
|
||||
var resolution = tileGrid.getResolution(tile.tileCoord[0]);
|
||||
var sourceTileResolution = sourceTileGrid.getResolution(sourceTile.tileCoord[0]);
|
||||
var tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
|
||||
var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
|
||||
var sharedExtent = ol.extent.getIntersection(tileExtent, sourceTileExtent);
|
||||
var extent, reproject, tileResolution;
|
||||
if (tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS) {
|
||||
var tilePixelRatio = tileResolution = source.getTilePixelRatio();
|
||||
var transform = ol.transform.compose(this.tmpTransform_,
|
||||
0, 0,
|
||||
1 / sourceTileResolution * tilePixelRatio, -1 / sourceTileResolution * tilePixelRatio,
|
||||
0,
|
||||
-sourceTileExtent[0], -sourceTileExtent[3]);
|
||||
extent = (ol.transform.apply(transform, [sharedExtent[0], sharedExtent[3]])
|
||||
.concat(ol.transform.apply(transform, [sharedExtent[2], sharedExtent[1]])));
|
||||
} else {
|
||||
styleFunction = layer.getStyleFunction();
|
||||
tileResolution = resolution;
|
||||
extent = sharedExtent;
|
||||
if (!ol.proj.equivalent(projection, tileProjection)) {
|
||||
reproject = true;
|
||||
sourceTile.setProjection(projection);
|
||||
}
|
||||
}
|
||||
replayState.dirty = false;
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
|
||||
tileResolution, source.getOverlaps(), layer.getRenderBuffer());
|
||||
var squaredTolerance = ol.renderer.vector.getSquaredTolerance(
|
||||
tileResolution, pixelRatio);
|
||||
|
||||
/**
|
||||
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
||||
* @this {ol.renderer.canvas.VectorTileLayer}
|
||||
*/
|
||||
var renderFeature = function(feature) {
|
||||
var styles;
|
||||
var styleFunction = feature.getStyleFunction();
|
||||
if (styleFunction) {
|
||||
styles = styleFunction(feature, resolution);
|
||||
styles = styleFunction.call(/** @type {ol.Feature} */ (feature), resolution);
|
||||
} else {
|
||||
styleFunction = layer.getStyleFunction();
|
||||
if (styleFunction) {
|
||||
styles = styleFunction(feature, resolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (styles) {
|
||||
if (!Array.isArray(styles)) {
|
||||
styles = [styles];
|
||||
if (styles) {
|
||||
if (!Array.isArray(styles)) {
|
||||
styles = [styles];
|
||||
}
|
||||
var dirty = this.renderFeature(feature, squaredTolerance, styles,
|
||||
replayGroup);
|
||||
this.dirty_ = this.dirty_ || dirty;
|
||||
replayState.dirty = replayState.dirty || dirty;
|
||||
}
|
||||
var dirty = this.renderFeature(feature, squaredTolerance, styles,
|
||||
replayGroup);
|
||||
this.dirty_ = this.dirty_ || dirty;
|
||||
replayState.dirty = replayState.dirty || dirty;
|
||||
};
|
||||
|
||||
var features = sourceTile.getFeatures();
|
||||
if (renderOrder && renderOrder !== replayState.renderedRenderOrder) {
|
||||
features.sort(renderOrder);
|
||||
}
|
||||
}
|
||||
|
||||
var features = tile.getFeatures();
|
||||
if (renderOrder && renderOrder !== replayState.renderedRenderOrder) {
|
||||
features.sort(renderOrder);
|
||||
}
|
||||
var feature;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (reproject) {
|
||||
feature.getGeometry().transform(tileProjection, projection);
|
||||
var feature;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (reproject) {
|
||||
feature.getGeometry().transform(tileProjection, projection);
|
||||
}
|
||||
renderFeature.call(this, feature);
|
||||
}
|
||||
renderFeature.call(this, feature);
|
||||
replayGroup.finish();
|
||||
sourceTile.setReplayGroup(tile.tileCoord.toString(), replayGroup);
|
||||
}
|
||||
|
||||
replayGroup.finish();
|
||||
|
||||
replayState.renderedRevision = revision;
|
||||
replayState.renderedRenderOrder = renderOrder;
|
||||
replayState.replayGroup = replayGroup;
|
||||
replayState.resolution = NaN;
|
||||
};
|
||||
|
||||
|
||||
@@ -193,10 +207,10 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(tile,
|
||||
*/
|
||||
ol.renderer.canvas.VectorTileLayer.prototype.drawTileImage = function(
|
||||
tile, frameState, layerState, x, y, w, h, gutter) {
|
||||
var vectorTile = /** @type {ol.VectorTile} */ (tile);
|
||||
this.createReplayGroup_(vectorTile, frameState);
|
||||
var vectorImageTile = /** @type {ol.VectorImageTile} */ (tile);
|
||||
this.createReplayGroup_(vectorImageTile, frameState);
|
||||
if (this.context) {
|
||||
this.renderTileImage_(vectorTile, frameState, layerState);
|
||||
this.renderTileImage_(vectorImageTile, frameState, layerState);
|
||||
ol.renderer.canvas.TileLayer.prototype.drawTileImage.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
@@ -213,54 +227,62 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
|
||||
/** @type {Object.<string, boolean>} */
|
||||
var features = {};
|
||||
|
||||
/** @type {Array.<ol.VectorTile>} */
|
||||
var replayables = this.renderedTiles;
|
||||
/** @type {Array.<ol.VectorImageTile>} */
|
||||
var renderedTiles = this.renderedTiles;
|
||||
|
||||
var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
|
||||
var tileGrid = source.getTileGrid();
|
||||
var found, tileSpaceCoordinate;
|
||||
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
|
||||
var sourceTileGrid = source.getTileGrid();
|
||||
var bufferedExtent, found, tileSpaceCoordinate;
|
||||
var i, ii, origin, replayGroup;
|
||||
var tile, tileCoord, tileExtent, tilePixelRatio, tileResolution;
|
||||
for (i = 0, ii = replayables.length; i < ii; ++i) {
|
||||
tile = replayables[i];
|
||||
for (i = 0, ii = renderedTiles.length; i < ii; ++i) {
|
||||
tile = renderedTiles[i];
|
||||
tileCoord = tile.tileCoord;
|
||||
tileExtent = source.getTileGrid().getTileCoordExtent(tileCoord, this.tmpExtent);
|
||||
if (!ol.extent.containsCoordinate(ol.extent.buffer(tileExtent, hitTolerance * resolution), coordinate)) {
|
||||
tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
|
||||
bufferedExtent = ol.extent.buffer(tileExtent, hitTolerance * resolution, bufferedExtent);
|
||||
if (!ol.extent.containsCoordinate(bufferedExtent, coordinate)) {
|
||||
continue;
|
||||
}
|
||||
if (tile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) {
|
||||
origin = ol.extent.getTopLeft(tileExtent);
|
||||
tilePixelRatio = source.getTilePixelRatio();
|
||||
tileResolution = tileGrid.getResolution(tileCoord[0]) / tilePixelRatio;
|
||||
tileSpaceCoordinate = [
|
||||
(coordinate[0] - origin[0]) / tileResolution,
|
||||
(origin[1] - coordinate[1]) / tileResolution
|
||||
];
|
||||
resolution = tilePixelRatio;
|
||||
} else {
|
||||
tileSpaceCoordinate = coordinate;
|
||||
var sourceTiles = tile.getSourceTiles();
|
||||
for (var t = 0, tt = sourceTiles.length; t < tt; ++t) {
|
||||
var sourceTile = sourceTiles[t];
|
||||
if (sourceTile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) {
|
||||
var sourceTileCoord = sourceTile.tileCoord;
|
||||
var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord, this.tmpExtent);
|
||||
origin = ol.extent.getTopLeft(sourceTileExtent);
|
||||
tilePixelRatio = source.getTilePixelRatio();
|
||||
tileResolution = sourceTileGrid.getResolution(sourceTileCoord[0]) / tilePixelRatio;
|
||||
tileSpaceCoordinate = [
|
||||
(coordinate[0] - origin[0]) / tileResolution,
|
||||
(origin[1] - coordinate[1]) / tileResolution
|
||||
];
|
||||
resolution = tilePixelRatio;
|
||||
} else {
|
||||
tileSpaceCoordinate = coordinate;
|
||||
}
|
||||
replayGroup = sourceTile.getReplayGroup(tile.tileCoord);
|
||||
found = found || replayGroup.forEachFeatureAtCoordinate(
|
||||
tileSpaceCoordinate, resolution, rotation, hitTolerance, {},
|
||||
/**
|
||||
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
||||
* @return {?} Callback result.
|
||||
*/
|
||||
function(feature) {
|
||||
var key = ol.getUid(feature).toString();
|
||||
if (!(key in features)) {
|
||||
features[key] = true;
|
||||
return callback.call(thisArg, feature, layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
replayGroup = tile.getReplayState().replayGroup;
|
||||
found = found || replayGroup.forEachFeatureAtCoordinate(
|
||||
tileSpaceCoordinate, resolution, rotation, hitTolerance, {},
|
||||
/**
|
||||
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
||||
* @return {?} Callback result.
|
||||
*/
|
||||
function(feature) {
|
||||
var key = ol.getUid(feature).toString();
|
||||
if (!(key in features)) {
|
||||
features[key] = true;
|
||||
return callback.call(thisArg, feature, layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
return found;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Tile} tile Tile.
|
||||
* @param {ol.VectorTile} tile Tile.
|
||||
* @param {olx.FrameState} frameState Frame state.
|
||||
* @return {ol.Transform} transform Transform.
|
||||
* @private
|
||||
@@ -308,7 +330,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, frameState, layerState) {
|
||||
var renderMode = this.getLayer().getRenderMode();
|
||||
var layer = this.getLayer();
|
||||
var source = layer.getSource();
|
||||
var renderMode = layer.getRenderMode();
|
||||
var replays = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];
|
||||
if (replays) {
|
||||
var pixelRatio = frameState.pixelRatio;
|
||||
@@ -317,40 +341,55 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
|
||||
var offsetX = Math.round(pixelRatio * size[0] / 2);
|
||||
var offsetY = Math.round(pixelRatio * size[1] / 2);
|
||||
var tiles = this.renderedTiles;
|
||||
var tilePixelRatio = layer.getSource().getTilePixelRatio();
|
||||
var sourceTileGrid = source.getTileGrid();
|
||||
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
|
||||
var clips = [];
|
||||
var zs = [];
|
||||
for (var i = tiles.length - 1; i >= 0; --i) {
|
||||
var tile = /** @type {ol.VectorTile} */ (tiles[i]);
|
||||
// Create a clip mask for regions in this low resolution tile that are
|
||||
// already filled by a higher resolution tile
|
||||
var transform = this.getReplayTransform_(tile, frameState);
|
||||
var currentClip = tile.getReplayState().replayGroup.getClipCoords(transform);
|
||||
var currentZ = tile.tileCoord[0];
|
||||
context.save();
|
||||
context.globalAlpha = layerState.opacity;
|
||||
ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);
|
||||
for (var j = 0, jj = clips.length; j < jj; ++j) {
|
||||
var clip = clips[j];
|
||||
if (currentZ < zs[j]) {
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
context.lineTo(currentClip[2], currentClip[3]);
|
||||
context.lineTo(currentClip[4], currentClip[5]);
|
||||
context.lineTo(currentClip[6], currentClip[7]);
|
||||
// clockwise (inner ring) for higher resolution tile
|
||||
context.moveTo(clip[6], clip[7]);
|
||||
context.lineTo(clip[4], clip[5]);
|
||||
context.lineTo(clip[2], clip[3]);
|
||||
context.lineTo(clip[0], clip[1]);
|
||||
context.clip();
|
||||
}
|
||||
var tile = /** @type {ol.VectorImageTile} */ (tiles[i]);
|
||||
if (tile.getState() == ol.TileState.ABORT) {
|
||||
continue;
|
||||
}
|
||||
var tileCoord = tile.tileCoord;
|
||||
var worldOffset = tileGrid.getTileCoordExtent(tileCoord)[0] -
|
||||
tileGrid.getTileCoordExtent(tile.wrappedTileCoord)[0];
|
||||
var sourceTiles = tile.getSourceTiles();
|
||||
for (var t = 0, tt = sourceTiles.length; t < tt; ++t) {
|
||||
var sourceTile = sourceTiles[t];
|
||||
var currentZ = sourceTile.tileCoord[0];
|
||||
var sourceResolution = sourceTileGrid.getResolution(currentZ);
|
||||
var transform = this.getReplayTransform_(sourceTile, frameState);
|
||||
ol.transform.translate(transform, worldOffset * tilePixelRatio / sourceResolution, 0);
|
||||
var replayGroup = sourceTile.getReplayGroup(tileCoord.toString());
|
||||
var currentClip = replayGroup.getClipCoords(transform);
|
||||
context.save();
|
||||
context.globalAlpha = layerState.opacity;
|
||||
ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);
|
||||
// Create a clip mask for regions in this low resolution tile that are
|
||||
// already filled by a higher resolution tile
|
||||
for (var j = 0, jj = clips.length; j < jj; ++j) {
|
||||
var clip = clips[j];
|
||||
if (currentZ < zs[j]) {
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
context.lineTo(currentClip[2], currentClip[3]);
|
||||
context.lineTo(currentClip[4], currentClip[5]);
|
||||
context.lineTo(currentClip[6], currentClip[7]);
|
||||
// clockwise (inner ring) for higher resolution tile
|
||||
context.moveTo(clip[6], clip[7]);
|
||||
context.lineTo(clip[4], clip[5]);
|
||||
context.lineTo(clip[2], clip[3]);
|
||||
context.lineTo(clip[0], clip[1]);
|
||||
context.clip();
|
||||
}
|
||||
}
|
||||
replayGroup.replay(context, pixelRatio, transform, rotation, {}, replays);
|
||||
context.restore();
|
||||
clips.push(currentClip);
|
||||
zs.push(currentZ);
|
||||
}
|
||||
var replayGroup = tile.getReplayState().replayGroup;
|
||||
replayGroup.replay(context, pixelRatio, transform, rotation, {}, replays);
|
||||
context.restore();
|
||||
clips.push(currentClip);
|
||||
zs.push(currentZ);
|
||||
}
|
||||
}
|
||||
ol.renderer.canvas.TileLayer.prototype.postCompose.apply(this, arguments);
|
||||
@@ -386,7 +425,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = function(feature, s
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.VectorTile} tile Tile.
|
||||
* @param {ol.VectorImageTile} tile Tile.
|
||||
* @param {olx.FrameState} frameState Frame state.
|
||||
* @param {ol.LayerState} layerState Layer state.
|
||||
* @private
|
||||
@@ -399,28 +438,39 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderTileImage_ = function(
|
||||
var replays = ol.renderer.canvas.VectorTileLayer.IMAGE_REPLAYS[layer.getRenderMode()];
|
||||
if (replays && replayState.renderedTileRevision !== revision) {
|
||||
replayState.renderedTileRevision = revision;
|
||||
var tileCoord = tile.tileCoord;
|
||||
var z = tile.tileCoord[0];
|
||||
var tileCoord = tile.wrappedTileCoord;
|
||||
var z = tileCoord[0];
|
||||
var pixelRatio = frameState.pixelRatio;
|
||||
var source = layer.getSource();
|
||||
var tileGrid = source.getTileGrid();
|
||||
var sourceTileGrid = source.getTileGrid();
|
||||
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
|
||||
var resolution = tileGrid.getResolution(z);
|
||||
var tilePixelRatio = source.getTilePixelRatio();
|
||||
var transform = ol.transform.reset(this.tmpTransform_);
|
||||
if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {
|
||||
var renderPixelRatio = pixelRatio / tilePixelRatio;
|
||||
ol.transform.scale(transform, renderPixelRatio, renderPixelRatio);
|
||||
} else {
|
||||
var resolution = tileGrid.getResolution(z);
|
||||
var pixelScale = pixelRatio / resolution;
|
||||
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
|
||||
ol.transform.scale(transform, pixelScale, -pixelScale);
|
||||
ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);
|
||||
}
|
||||
|
||||
var context = tile.getContext();
|
||||
var size = source.getTilePixelSize(z, pixelRatio, frameState.viewState.projection);
|
||||
context.canvas.width = size[0];
|
||||
context.canvas.height = size[1];
|
||||
replayState.replayGroup.replay(context, pixelRatio, transform, 0, {}, replays);
|
||||
var tileExtent = tileGrid.getTileCoordExtent(tileCoord);
|
||||
var sourceTiles = tile.getSourceTiles();
|
||||
for (var i = 0, ii = sourceTiles.length; i < ii; ++i) {
|
||||
var sourceTile = sourceTiles[i];
|
||||
var sourceTileCoord = sourceTile.tileCoord;
|
||||
var pixelScale = pixelRatio / resolution;
|
||||
var transform = ol.transform.reset(this.tmpTransform_);
|
||||
if (sourceTile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {
|
||||
var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord, this.tmpExtent);
|
||||
var sourceResolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
|
||||
var renderPixelRatio = pixelRatio / tilePixelRatio * sourceResolution / resolution;
|
||||
ol.transform.scale(transform, renderPixelRatio, renderPixelRatio);
|
||||
var offsetX = (sourceTileExtent[0] - tileExtent[0]) / sourceResolution * tilePixelRatio;
|
||||
var offsetY = (tileExtent[3] - sourceTileExtent[3]) / sourceResolution * tilePixelRatio;
|
||||
ol.transform.translate(transform, Math.round(offsetX), Math.round(offsetY));
|
||||
} else {
|
||||
ol.transform.scale(transform, pixelScale, -pixelScale);
|
||||
ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);
|
||||
}
|
||||
var replayGroup = sourceTile.getReplayGroup(tile.tileCoord.toString());
|
||||
replayGroup.replay(context, pixelRatio, transform, 0, {}, replays);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -202,7 +202,8 @@ ol.reproj.Tile.prototype.disposeInternal = function() {
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Get the HTML Canvas element for this tile.
|
||||
* @return {HTMLCanvasElement} Canvas.
|
||||
*/
|
||||
ol.reproj.Tile.prototype.getImage = function() {
|
||||
return this.canvas_;
|
||||
|
||||
@@ -91,7 +91,6 @@ ol.inherits(ol.source.TileDebug.Tile_, ol.Tile);
|
||||
/**
|
||||
* Get the image element for this tile.
|
||||
* @return {HTMLCanvasElement} Image.
|
||||
* @override
|
||||
*/
|
||||
ol.source.TileDebug.Tile_.prototype.getImage = function() {
|
||||
if (this.canvas_) {
|
||||
|
||||
@@ -320,7 +320,6 @@ ol.inherits(ol.source.TileUTFGrid.Tile_, ol.Tile);
|
||||
/**
|
||||
* Get the image element for this tile.
|
||||
* @return {Image} Image.
|
||||
* @override
|
||||
*/
|
||||
ol.source.TileUTFGrid.Tile_.prototype.getImage = function() {
|
||||
return null;
|
||||
|
||||
@@ -2,9 +2,11 @@ goog.provide('ol.source.VectorTile');
|
||||
|
||||
goog.require('ol');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.VectorImageTile');
|
||||
goog.require('ol.VectorTile');
|
||||
goog.require('ol.events');
|
||||
goog.require('ol.events.EventType');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.size');
|
||||
goog.require('ol.source.UrlTile');
|
||||
|
||||
@@ -35,9 +37,8 @@ ol.source.VectorTile = function(options) {
|
||||
opaque: false,
|
||||
projection: options.projection,
|
||||
state: options.state,
|
||||
tileGrid: options.tileGrid,
|
||||
tileLoadFunction: options.tileLoadFunction ?
|
||||
options.tileLoadFunction : ol.VectorTile.defaultLoadFunction,
|
||||
options.tileLoadFunction : ol.VectorImageTile.defaultLoadFunction,
|
||||
tileUrlFunction: options.tileUrlFunction,
|
||||
tilePixelRatio: options.tilePixelRatio,
|
||||
url: options.url,
|
||||
@@ -51,6 +52,18 @@ ol.source.VectorTile = function(options) {
|
||||
*/
|
||||
this.format_ = options.format ? options.format : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string,ol.VectorTile>}
|
||||
*/
|
||||
this.sourceTiles_ = {};
|
||||
|
||||
/**
|
||||
* @type {ol.tilegrid.TileGrid}
|
||||
*/
|
||||
this.sourceTileGrid_ = options.tileGrid ||
|
||||
this.getTileGridForProjection(ol.proj.get(options.projection || 'EPSG:3857'));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
@@ -89,11 +102,13 @@ ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projectio
|
||||
tileCoord, projection);
|
||||
var tileUrl = urlTileCoord ?
|
||||
this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;
|
||||
var tile = new this.tileClass(
|
||||
var tile = new ol.VectorImageTile(
|
||||
tileCoord,
|
||||
tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
|
||||
tileUrl !== undefined ? tileUrl : '',
|
||||
this.format_, this.tileLoadFunction);
|
||||
this.format_, this.tileLoadFunction, urlTileCoord, this.tileUrlFunction,
|
||||
this.sourceTileGrid_, this.getTileGridForProjection(projection),
|
||||
this.sourceTiles_, pixelRatio, projection, this.tileClass);
|
||||
ol.events.listen(tile, ol.events.EventType.CHANGE,
|
||||
this.handleTileChange, this);
|
||||
|
||||
@@ -103,6 +118,14 @@ ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projectio
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.source.VectorTile.prototype.getTileGrid = function() {
|
||||
return this.sourceTileGrid_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -117,6 +140,6 @@ ol.source.VectorTile.prototype.getTilePixelRatio = function(opt_pixelRatio) {
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.source.VectorTile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {
|
||||
var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));
|
||||
var tileSize = ol.size.toSize(this.getTileGridForProjection(projection).getTileSize(z));
|
||||
return [Math.round(tileSize[0] * pixelRatio), Math.round(tileSize[1] * pixelRatio)];
|
||||
};
|
||||
|
||||
@@ -59,14 +59,6 @@ ol.Tile.prototype.changed = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
|
||||
* @abstract
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
*/
|
||||
ol.Tile.prototype.getImage = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} Key.
|
||||
*/
|
||||
|
||||
@@ -74,7 +74,7 @@ ol.tilegrid.createForExtent = function(extent, opt_maxZoom, opt_tileSize, opt_co
|
||||
/**
|
||||
* Creates a tile grid with a standard XYZ tiling scheme.
|
||||
* @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options.
|
||||
* @return {ol.tilegrid.TileGrid} Tile grid instance.
|
||||
* @return {!ol.tilegrid.TileGrid} Tile grid instance.
|
||||
* @api
|
||||
*/
|
||||
ol.tilegrid.createXYZ = function(opt_options) {
|
||||
|
||||
@@ -652,8 +652,7 @@ ol.TilePriorityFunction;
|
||||
* dirty: boolean,
|
||||
* renderedRenderOrder: (null|ol.RenderOrderFunction),
|
||||
* renderedTileRevision: number,
|
||||
* renderedRevision: number,
|
||||
* replayGroup: ol.render.ReplayGroup}}
|
||||
* renderedRevision: number}}
|
||||
*/
|
||||
ol.TileReplayState;
|
||||
|
||||
|
||||
288
src/ol/vectorimagetile.js
Normal file
288
src/ol/vectorimagetile.js
Normal file
@@ -0,0 +1,288 @@
|
||||
goog.provide('ol.VectorImageTile');
|
||||
|
||||
goog.require('ol');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.array');
|
||||
goog.require('ol.dom');
|
||||
goog.require('ol.events');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.events.EventType');
|
||||
goog.require('ol.featureloader');
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.Tile}
|
||||
* @param {ol.TileCoord} tileCoord Tile coordinate.
|
||||
* @param {ol.TileState} state State.
|
||||
* @param {string} src Data source url.
|
||||
* @param {ol.format.Feature} format Feature format.
|
||||
* @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
|
||||
* @param {ol.TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
|
||||
* @param {ol.TileUrlFunctionType} tileUrlFunction Tile url function.
|
||||
* @param {ol.tilegrid.TileGrid} sourceTileGrid Tile grid of the source.
|
||||
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid of the renderer.
|
||||
* @param {Object.<string,ol.VectorTile>} sourceTiles Source tiles.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {ol.proj.Projection} projection Projection.
|
||||
* @param {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string,
|
||||
* ol.format.Feature, ol.TileLoadFunctionType)} tileClass Class to
|
||||
* instantiate for source tiles.
|
||||
*/
|
||||
ol.VectorImageTile = function(tileCoord, state, src, format, tileLoadFunction,
|
||||
urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid, sourceTiles,
|
||||
pixelRatio, projection, tileClass) {
|
||||
|
||||
ol.Tile.call(this, tileCoord, state);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
this.context_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.format.Feature}
|
||||
*/
|
||||
this.format_ = format;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.FeatureLoader}
|
||||
*/
|
||||
this.loader_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.TileReplayState}
|
||||
*/
|
||||
this.replayState_ = {
|
||||
dirty: false,
|
||||
renderedRenderOrder: null,
|
||||
renderedRevision: -1,
|
||||
renderedTileRevision: -1
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string,ol.VectorTile>}
|
||||
*/
|
||||
this.sourceTiles_ = sourceTiles;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.usedSourceTileKeys_ = [];
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
this.src_ = src;
|
||||
|
||||
/**
|
||||
* @type {ol.TileCoord}
|
||||
*/
|
||||
this.wrappedTileCoord = urlTileCoord;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.EventsKey>}
|
||||
*/
|
||||
this.loadListenerKeys_ = [];
|
||||
|
||||
if (urlTileCoord) {
|
||||
var extent = tileGrid.getTileCoordExtent(urlTileCoord);
|
||||
var resolution = tileGrid.getResolution(tileCoord[0]);
|
||||
var sourceZ = sourceTileGrid.getZForResolution(resolution);
|
||||
sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
|
||||
var sharedExtent = ol.extent.getIntersection(extent,
|
||||
sourceTileGrid.getTileCoordExtent(sourceTileCoord));
|
||||
if (ol.extent.getWidth(sharedExtent) / resolution >= 0.5 &&
|
||||
ol.extent.getHeight(sharedExtent) / resolution >= 0.5) {
|
||||
// only include source tile if overlap is at least 1 pixel
|
||||
var sourceTileKey = sourceTileCoord.toString();
|
||||
var sourceTile = sourceTiles[sourceTileKey];
|
||||
if (!sourceTile) {
|
||||
var tileUrl = /** @type {string} */
|
||||
(tileUrlFunction(sourceTileCoord, pixelRatio, projection));
|
||||
sourceTile = sourceTiles[sourceTileKey] = new tileClass(
|
||||
sourceTileCoord, ol.TileState.IDLE, tileUrl, format, tileLoadFunction);
|
||||
}
|
||||
sourceTile.consumers++;
|
||||
this.usedSourceTileKeys_.push(sourceTileKey);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
};
|
||||
ol.inherits(ol.VectorImageTile, ol.Tile);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.VectorImageTile.prototype.disposeInternal = function() {
|
||||
var sourceTiles = this.getSourceTiles();
|
||||
for (var i = 0, ii = sourceTiles.length; i < ii; ++i) {
|
||||
var sourceTile = sourceTiles[i];
|
||||
sourceTile.consumers--;
|
||||
if (sourceTile.consumers == 0) {
|
||||
delete this.sourceTiles_[sourceTile.tileCoord.toString()];
|
||||
sourceTile.dispose();
|
||||
}
|
||||
}
|
||||
this.tileKeys.length = 0;
|
||||
this.sourceTiles_ = null;
|
||||
if (this.state == ol.TileState.LOADING) {
|
||||
this.loadListenerKeys_.forEach(ol.events.unlistenByKey);
|
||||
this.loadListenerKeys_.length = 0;
|
||||
}
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
this.state = ol.TileState.ABORT;
|
||||
this.changed();
|
||||
ol.Tile.prototype.disposeInternal.call(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {CanvasRenderingContext2D} The rendering context.
|
||||
*/
|
||||
ol.VectorImageTile.prototype.getContext = function() {
|
||||
if (!this.context_) {
|
||||
this.context_ = ol.dom.createCanvasContext2D();
|
||||
}
|
||||
return this.context_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the Canvas for this tile.
|
||||
* @return {HTMLCanvasElement} Canvas.
|
||||
* @api
|
||||
*/
|
||||
ol.VectorImageTile.prototype.getImage = function() {
|
||||
return this.replayState_.renderedTileRevision == -1 ?
|
||||
null : this.context_.canvas;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the feature format assigned for reading this tile's features.
|
||||
* @return {ol.format.Feature} Feature format.
|
||||
* @api
|
||||
*/
|
||||
ol.VectorImageTile.prototype.getFormat = function() {
|
||||
return this.format_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.Feature>} Features.
|
||||
*/
|
||||
ol.VectorImageTile.prototype.getFeatures = function() {
|
||||
return this.features_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.TileReplayState} The replay state.
|
||||
*/
|
||||
ol.VectorImageTile.prototype.getReplayState = function() {
|
||||
return this.replayState_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.VectorImageTile.prototype.getKey = function() {
|
||||
return this.usedSourceTileKeys_.join('/') + '/' + this.src_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Array.<ol.VectorTile>} Source tiles for this tile.
|
||||
*/
|
||||
ol.VectorImageTile.prototype.getSourceTiles = function() {
|
||||
return this.usedSourceTileKeys_.map(function(sourceTileKey) {
|
||||
return this.sourceTiles_[sourceTileKey];
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.VectorImageTile.prototype.load = function() {
|
||||
var leftToLoad = 0;
|
||||
if (this.state == ol.TileState.IDLE) {
|
||||
this.setState(ol.TileState.LOADING);
|
||||
}
|
||||
if (this.state == ol.TileState.LOADING) {
|
||||
this.usedSourceTileKeys_.forEach(function(sourceTileKey) {
|
||||
var sourceTile = this.sourceTiles_[sourceTileKey];
|
||||
if (sourceTile.state == ol.TileState.IDLE) {
|
||||
sourceTile.setLoader(this.loader_);
|
||||
sourceTile.load();
|
||||
}
|
||||
if (sourceTile.state == ol.TileState.LOADING) {
|
||||
var key = ol.events.listen(sourceTile, ol.events.EventType.CHANGE, function(e) {
|
||||
var state = sourceTile.getState();
|
||||
if (state == ol.TileState.LOADED ||
|
||||
state == ol.TileState.ERROR ||
|
||||
state == ol.TileState.EMPTY) {
|
||||
--leftToLoad;
|
||||
ol.events.unlistenByKey(key);
|
||||
ol.array.remove(this.loadListenerKeys_, key);
|
||||
if (leftToLoad == 0) {
|
||||
this.setState(ol.TileState.LOADED);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
this.loadListenerKeys_.push(key);
|
||||
++leftToLoad;
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
if (leftToLoad == 0) {
|
||||
setTimeout(function() {
|
||||
this.setState(ol.TileState.LOADED);
|
||||
}.bind(this), 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Features.
|
||||
* @api
|
||||
*/
|
||||
ol.VectorImageTile.prototype.setFeatures = function(features) {
|
||||
this.features_ = features;
|
||||
this.setState(ol.TileState.LOADED);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.TileState} tileState Tile state.
|
||||
*/
|
||||
ol.VectorImageTile.prototype.setState = function(tileState) {
|
||||
this.state = tileState;
|
||||
this.changed();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the loader for a tile.
|
||||
* @param {ol.VectorTile} tile Vector tile.
|
||||
* @param {string} url URL.
|
||||
*/
|
||||
ol.VectorImageTile.defaultLoadFunction = function(tile, url) {
|
||||
var loader = ol.featureloader.loadFeaturesXhr(
|
||||
url, tile.getFormat(), tile.onLoad_.bind(tile), tile.onError_.bind(tile));
|
||||
|
||||
tile.setLoader(loader);
|
||||
};
|
||||
@@ -3,8 +3,6 @@ goog.provide('ol.VectorTile');
|
||||
goog.require('ol');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.dom');
|
||||
goog.require('ol.featureloader');
|
||||
|
||||
|
||||
/**
|
||||
@@ -21,10 +19,9 @@ ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
|
||||
ol.Tile.call(this, tileCoord, state);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {CanvasRenderingContext2D}
|
||||
* @type {number}
|
||||
*/
|
||||
this.context_ = null;
|
||||
this.consumers = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -51,17 +48,7 @@ ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
|
||||
*/
|
||||
this.projection_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.TileReplayState}
|
||||
*/
|
||||
this.replayState_ = {
|
||||
dirty: false,
|
||||
renderedRenderOrder: null,
|
||||
renderedRevision: -1,
|
||||
renderedTileRevision: -1,
|
||||
replayGroup: null
|
||||
};
|
||||
this.replayGroups_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -79,26 +66,6 @@ ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
|
||||
ol.inherits(ol.VectorTile, ol.Tile);
|
||||
|
||||
|
||||
/**
|
||||
* @return {CanvasRenderingContext2D} The rendering context.
|
||||
*/
|
||||
ol.VectorTile.prototype.getContext = function() {
|
||||
if (!this.context_) {
|
||||
this.context_ = ol.dom.createCanvasContext2D();
|
||||
}
|
||||
return this.context_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
ol.VectorTile.prototype.getImage = function() {
|
||||
return this.replayState_.renderedTileRevision == -1 ?
|
||||
null : this.context_.canvas;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the feature format assigned for reading this tile's features.
|
||||
* @return {ol.format.Feature} Feature format.
|
||||
@@ -117,14 +84,6 @@ ol.VectorTile.prototype.getFeatures = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {ol.TileReplayState} The replay state.
|
||||
*/
|
||||
ol.VectorTile.prototype.getReplayState = function() {
|
||||
return this.replayState_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -141,6 +100,11 @@ ol.VectorTile.prototype.getProjection = function() {
|
||||
};
|
||||
|
||||
|
||||
ol.VectorTile.prototype.getReplayGroup = function(key) {
|
||||
return this.replayGroups_[key];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -192,6 +156,11 @@ ol.VectorTile.prototype.setProjection = function(projection) {
|
||||
};
|
||||
|
||||
|
||||
ol.VectorTile.prototype.setReplayGroup = function(key, replayGroup) {
|
||||
this.replayGroups_[key] = replayGroup;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.TileState} tileState Tile state.
|
||||
*/
|
||||
@@ -209,16 +178,3 @@ ol.VectorTile.prototype.setState = function(tileState) {
|
||||
ol.VectorTile.prototype.setLoader = function(loader) {
|
||||
this.loader_ = loader;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the loader for a tile.
|
||||
* @param {ol.VectorTile} tile Vector tile.
|
||||
* @param {string} url URL.
|
||||
*/
|
||||
ol.VectorTile.defaultLoadFunction = function(tile, url) {
|
||||
var loader = ol.featureloader.loadFeaturesXhr(
|
||||
url, tile.getFormat(), tile.onLoad_.bind(tile), tile.onError_.bind(tile));
|
||||
|
||||
tile.setLoader(loader);
|
||||
};
|
||||
|
||||
@@ -62,6 +62,11 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
||||
tileClass: TileClass,
|
||||
tileGrid: ol.tilegrid.createXYZ()
|
||||
});
|
||||
source.getTile = function() {
|
||||
var tile = ol.source.VectorTile.prototype.getTile.apply(source, arguments);
|
||||
tile.setState(ol.TileState.LOADED);
|
||||
return tile;
|
||||
};
|
||||
layer = new ol.layer.VectorTile({
|
||||
source: source,
|
||||
style: layerStyle
|
||||
@@ -156,12 +161,18 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
||||
tileGrid: ol.tilegrid.createXYZ()
|
||||
})
|
||||
});
|
||||
var tile = new ol.VectorTile([0, 0, 0], 2);
|
||||
tile.projection_ = ol.proj.get('EPSG:3857');
|
||||
tile.features_ = [];
|
||||
tile.getImage = function() {
|
||||
var sourceTile = new ol.VectorTile([0, 0, 0], 2);
|
||||
sourceTile.setProjection(ol.proj.get('EPSG:3857'));
|
||||
sourceTile.features_ = [];
|
||||
sourceTile.getImage = function() {
|
||||
return document.createElement('canvas');
|
||||
};
|
||||
var tile = new ol.VectorImageTile([0, 0, 0]);
|
||||
tile.wrappedTileCoord = [0, 0, 0];
|
||||
tile.setState(ol.TileState.LOADED);
|
||||
tile.getSourceTiles = function() {
|
||||
return [sourceTile];
|
||||
};
|
||||
layer.getSource().getTile = function() {
|
||||
return tile;
|
||||
};
|
||||
@@ -192,12 +203,18 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
||||
describe('#forEachFeatureAtCoordinate', function() {
|
||||
var layer, renderer, replayGroup;
|
||||
var TileClass = function() {
|
||||
ol.VectorTile.apply(this, arguments);
|
||||
ol.VectorImageTile.apply(this, arguments);
|
||||
this.setState('loaded');
|
||||
this.setProjection(ol.proj.get('EPSG:3857'));
|
||||
this.replayState_.replayGroup = replayGroup;
|
||||
var sourceTile = new ol.VectorTile();
|
||||
sourceTile.setProjection(ol.proj.get('EPSG:3857'));
|
||||
sourceTile.getReplayGroup = function() {
|
||||
return replayGroup;
|
||||
};
|
||||
this.getSourceTiles = function() {
|
||||
return [sourceTile];
|
||||
};
|
||||
};
|
||||
ol.inherits(TileClass, ol.VectorTile);
|
||||
ol.inherits(TileClass, ol.VectorImageTile);
|
||||
|
||||
beforeEach(function() {
|
||||
replayGroup = {};
|
||||
@@ -223,6 +240,7 @@ describe('ol.renderer.canvas.VectorTileLayer', function() {
|
||||
layerStates: {},
|
||||
skippedFeatureUids: {},
|
||||
viewState: {
|
||||
projection: ol.proj.get('EPSG:3857'),
|
||||
resolution: 1,
|
||||
rotation: 0
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
goog.provide('ol.test.source.VectorTile');
|
||||
|
||||
goog.require('ol.VectorTile');
|
||||
goog.require('ol.VectorImageTile');
|
||||
goog.require('ol.format.MVT');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.VectorTile');
|
||||
@@ -29,7 +29,7 @@ describe('ol.source.VectorTile', function() {
|
||||
describe('#getTile()', function() {
|
||||
it('creates a tile with the correct tile class', function() {
|
||||
tile = source.getTile(0, 0, 0, 1, ol.proj.get('EPSG:3857'));
|
||||
expect(tile).to.be.a(ol.VectorTile);
|
||||
expect(tile).to.be.a(ol.VectorImageTile);
|
||||
});
|
||||
it('sets the correct tileCoord on the created tile', function() {
|
||||
expect(tile.getTileCoord()).to.eql([0, 0, 0]);
|
||||
|
||||
43
test/spec/ol/vectorimagetile.test.js
Normal file
43
test/spec/ol/vectorimagetile.test.js
Normal file
@@ -0,0 +1,43 @@
|
||||
goog.provide('ol.test.VectorImageTile');
|
||||
|
||||
goog.require('ol.events');
|
||||
goog.require('ol.VectorImageTile');
|
||||
goog.require('ol.VectorTile');
|
||||
goog.require('ol.format.GeoJSON');
|
||||
goog.require('ol.proj');
|
||||
|
||||
|
||||
describe('ol.VectorImageTile', function() {
|
||||
|
||||
it('sets the loader function on source tiles', function() {
|
||||
var format = new ol.format.GeoJSON();
|
||||
var url = 'spec/ol/data/point.json';
|
||||
var tile = new ol.VectorImageTile([0, 0, 0], 0, url, format,
|
||||
ol.VectorImageTile.defaultLoadFunction,
|
||||
[0, 0, 0], function() {}, ol.tilegrid.createXYZ(), ol.tilegrid.createXYZ(), {},
|
||||
1, ol.proj.get('EPSG:3857'), ol.VectorTile);
|
||||
|
||||
tile.load();
|
||||
var loader = tile.getSourceTiles()[0].loader_;
|
||||
expect(typeof loader).to.be('function');
|
||||
});
|
||||
|
||||
it('loader sets features on the source tile', function(done) {
|
||||
var format = new ol.format.GeoJSON();
|
||||
var url = 'spec/ol/data/point.json';
|
||||
var tile = new ol.VectorImageTile([0, 0, 0], 0, url, format,
|
||||
ol.VectorImageTile.defaultLoadFunction, [0, 0, 0], function() {
|
||||
return url;
|
||||
}, ol.tilegrid.createXYZ(), ol.tilegrid.createXYZ(), {},
|
||||
1, ol.proj.get('EPSG:3857'), ol.VectorTile);
|
||||
|
||||
tile.load();
|
||||
var sourceTile = tile.getSourceTiles()[0];
|
||||
|
||||
ol.events.listen(sourceTile, 'change', function(e) {
|
||||
expect(sourceTile.getFeatures().length).to.be.greaterThan(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,39 +1,14 @@
|
||||
goog.provide('ol.test.VectorTile');
|
||||
|
||||
goog.require('ol.events');
|
||||
goog.require('ol.VectorImageTile');
|
||||
goog.require('ol.VectorTile');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.format.GeoJSON');
|
||||
goog.require('ol.format.TextFeature');
|
||||
goog.require('ol.proj');
|
||||
|
||||
|
||||
describe('ol.VectorTile.defaultLoadFunction()', function() {
|
||||
|
||||
it('sets the loader function on the tile', function() {
|
||||
var format = new ol.format.GeoJSON();
|
||||
var tile = new ol.VectorTile([0, 0, 0], null, null, format);
|
||||
var url = 'https://example.com/';
|
||||
|
||||
ol.VectorTile.defaultLoadFunction(tile, url);
|
||||
var loader = tile.loader_;
|
||||
expect(typeof loader).to.be('function');
|
||||
});
|
||||
|
||||
it('loader sets features on the tile', function(done) {
|
||||
var format = new ol.format.GeoJSON();
|
||||
var tile = new ol.VectorTile([0, 0, 0], null, null, format);
|
||||
var url = 'spec/ol/data/point.json';
|
||||
|
||||
ol.VectorTile.defaultLoadFunction(tile, url);
|
||||
var loader = tile.loader_;
|
||||
|
||||
ol.events.listen(tile, 'change', function(e) {
|
||||
expect(tile.getFeatures().length).to.be.greaterThan(0);
|
||||
done();
|
||||
});
|
||||
loader.call(tile, [], 1, ol.proj.get('EPSG:3857'));
|
||||
});
|
||||
describe('ol.VectorTile', function() {
|
||||
|
||||
it('loader sets features on the tile and updates proj units', function(done) {
|
||||
// mock format that return a tile-pixels feature
|
||||
@@ -51,7 +26,7 @@ describe('ol.VectorTile.defaultLoadFunction()', function() {
|
||||
var tile = new ol.VectorTile([0, 0, 0], null, null, format);
|
||||
var url = 'spec/ol/data/point.json';
|
||||
|
||||
ol.VectorTile.defaultLoadFunction(tile, url);
|
||||
ol.VectorImageTile.defaultLoadFunction(tile, url);
|
||||
var loader = tile.loader_;
|
||||
ol.events.listen(tile, 'change', function(e) {
|
||||
expect(tile.getFeatures().length).to.be.greaterThan(0);
|
||||
|
||||
Reference in New Issue
Block a user