From b2722542feef255d4718c60be72dbe4535b73e63 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Sun, 10 Mar 2019 09:34:40 +0100 Subject: [PATCH] Simplify vector tile projection handling --- changelog/upgrade-notes.md | 52 ++++++++++++++ src/ol/VectorTile.js | 71 ++++--------------- src/ol/featureloader.js | 8 ++- src/ol/format/Feature.js | 8 --- src/ol/format/MVT.js | 39 +++++----- src/ol/renderer/canvas/VectorTileLayer.js | 17 ----- src/ol/source/VectorTile.js | 31 ++++---- test/spec/ol/format/mvt.test.js | 30 ++++---- .../renderer/canvas/vectortilelayer.test.js | 30 +------- test/spec/ol/vectortile.test.js | 43 ++++++----- 10 files changed, 148 insertions(+), 181 deletions(-) diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index b03d2f346a..1ba1139f5a 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -99,6 +99,58 @@ Due to the constraint above (layers can only be added to a single map), the over Previously, a graticule was not a layer. Now it is. See the graticule example for details on how to add a graticule layer to your map. +##### `ol/format/Feature` API change + +The `getLastExtent()` method, which was required for custom `tileLoadFunction`s in `ol/source/Vector`, has been removed because it is no longer needed (see below). + +##### `ol/VectorTile` API changes + +* Removal of the `getProjection()` and `setProjection()` methods. These were used in custom `tileLoadFunction`s on `ol/source/VectorTile`, which work differently now (see below). +* Removal of the `getExtent()` and `setExtent()` methods. These were used in custom `tileLoadFunction`s on `ol/source/VectorTile`, which work differently now (see below). + +##### Custom tileLoadFunction on a VectorTile source needs changes + +Previously, applications needed to call `setProjection()` and `setExtent()` on the tile in a custom `tileLoadFunction` on `ol/source/VectorTile`. The format's `getLastExtent()` method was used to get the extent. All this is no longer needed. Instead, the `extent` (first argument to the loader function) and `projection` (third argument to the loader function) are simply passed as `extent` and `featureProjection` options to the format's `readFeatures()` method. + +Example for an old `tileLoadFunction`: + +```js +function(tile, url) { + tile.setLoader(function() { + fetch(url).then(function(response) { + response.arrayBuffer().then(function(data) { + var format = tile.getFormat(); + tile.setProjection(format.readProjection(data)); + tile.setFeatures(format.readFeatures(data, { + // featureProjection is not required for ol/format/MVT + featureProjection: map.getView().getProjection() + })); + tile.setExtent(format.getLastExtent()); + }) + }) + } +}); +``` + +This function needs to be changed to: + +```js +function(tile, url) { + tile.setLoader(function(extent, resolution, projection) { + fetch(url).then(function(response) { + response.arrayBuffer().then(function(data) { + var format = tile.getFormat(); + tile.setFeatures(format.readFeatures(data, { + // extent is only required for ol/format/MVT + extent: extent, + featureProjection: projection + })); + }) + }) + } +}); +``` + ##### Drop of support for the experimental WebGL renderer The WebGL map and layers renderers are gone, replaced by a `WebGLHelper` function that provides a lightweight, diff --git a/src/ol/VectorTile.js b/src/ol/VectorTile.js index 5ec352a03c..92c10c4420 100644 --- a/src/ol/VectorTile.js +++ b/src/ol/VectorTile.js @@ -24,10 +24,10 @@ class VectorTile extends Tile { this.consumers = 0; /** - * @private + * Extent of this tile; set by the source. * @type {import("./extent.js").Extent} */ - this.extent_ = null; + this.extent = null; /** * @private @@ -48,11 +48,16 @@ class VectorTile extends Tile { this.loader_; /** - * Data projection - * @private + * Feature projection of this tile; set by the source. * @type {import("./proj/Projection.js").default} */ - this.projection_ = null; + this.projection = null; + + /** + * Resolution of this tile; set by the source. + * @type {number} + */ + this.resolution; /** * @private @@ -76,15 +81,6 @@ class VectorTile extends Tile { super.disposeInternal(); } - /** - * Gets the extent of the vector tile. - * @return {import("./extent.js").Extent} The extent. - * @api - */ - getExtent() { - return this.extent_; - } - /** * Get the feature format assigned for reading this tile's features. * @return {import("./format/Feature.js").default} Feature format. @@ -95,8 +91,7 @@ class VectorTile extends Tile { } /** - * Get the features for this tile. Geometries will be in the projection returned - * by {@link module:ol/VectorTile~VectorTile#getProjection}. + * Get the features for this tile. Geometries will be in the view projection. * @return {Array} Features. * @api */ @@ -111,16 +106,6 @@ class VectorTile extends Tile { return this.url_; } - /** - * Get the feature projection of features returned by - * {@link module:ol/VectorTile~VectorTile#getFeatures}. - * @return {import("./proj/Projection.js").default} Feature projection. - * @api - */ - getProjection() { - return this.projection_; - } - /** * @inheritDoc */ @@ -128,7 +113,7 @@ class VectorTile extends Tile { if (this.state == TileState.IDLE) { this.setState(TileState.LOADING); this.tileLoadFunction_(this, this.url_); - this.loader_(null, NaN, null); + this.loader_(this.extent, this.resolution, this.projection); } } @@ -136,11 +121,8 @@ class VectorTile extends Tile { * Handler for successful tile load. * @param {Array} features The loaded features. * @param {import("./proj/Projection.js").default} dataProjection Data projection. - * @param {import("./extent.js").Extent} extent Extent. */ - onLoad(features, dataProjection, extent) { - this.setProjection(dataProjection); - this.setExtent(extent); + onLoad(features, dataProjection) { this.setFeatures(features); } @@ -151,22 +133,6 @@ class VectorTile extends Tile { this.setState(TileState.ERROR); } - /** - * Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s - * `tileLoadFunction`. Sets the extent of the vector tile. This is only required - * for tiles in projections with `tile-pixels` as units. The extent should be - * set to `[0, 0, tilePixelSize, tilePixelSize]`, where `tilePixelSize` is - * calculated by multiplying the tile size with the tile pixel ratio. For - * sources using {@link module:ol/format/MVT~MVT} as feature format, the - * {@link module:ol/format/MVT~MVT#getLastExtent} method will return the correct - * extent. - * @param {import("./extent.js").Extent} extent The extent. - * @api - */ - setExtent(extent) { - this.extent_ = extent; - } - /** * Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`. * Sets the features for the tile. @@ -178,17 +144,6 @@ class VectorTile extends Tile { this.setState(TileState.LOADED); } - /** - * Function for use in an {@link module:ol/source/VectorTile~VectorTile}'s `tileLoadFunction`. - * Sets the projection of the features that were added with - * {@link module:ol/VectorTile~VectorTile#setFeatures}. - * @param {import("./proj/Projection.js").default} projection Feature projection. - * @api - */ - setProjection(projection) { - this.projection_ = projection; - } - /** * Set the feature loader for reading this tile's features. * @param {import("./featureloader.js").FeatureLoader} loader Feature loader. diff --git a/src/ol/featureloader.js b/src/ol/featureloader.js index 6300aa6b42..449bae839f 100644 --- a/src/ol/featureloader.js +++ b/src/ol/featureloader.js @@ -83,9 +83,11 @@ export function loadFeaturesXhr(url, format, success, failure) { source = /** @type {ArrayBuffer} */ (xhr.response); } if (source) { - success.call(this, format.readFeatures(source, - {featureProjection: projection}), - format.readProjection(source), format.getLastExtent()); + success.call(this, format.readFeatures(source, { + extent: extent, + featureProjection: projection + }), + format.readProjection(source)); } else { failure.call(this); } diff --git a/src/ol/format/Feature.js b/src/ol/format/Feature.js index 1cba700b0e..a426546bb2 100644 --- a/src/ol/format/Feature.js +++ b/src/ol/format/Feature.js @@ -111,14 +111,6 @@ class FeatureFormat { }, options); } - /** - * Get the extent from the source of the last {@link readFeatures} call. - * @return {import("../extent.js").Extent} Tile extent. - */ - getLastExtent() { - return null; - } - /** * @abstract * @return {import("./FormatType.js").default} Format. diff --git a/src/ol/format/MVT.js b/src/ol/format/MVT.js index b92205f4a7..914bb72abd 100644 --- a/src/ol/format/MVT.js +++ b/src/ol/format/MVT.js @@ -19,6 +19,7 @@ import {linearRingIsClockwise} from '../geom/flat/orient.js'; import Projection from '../proj/Projection.js'; import Units from '../proj/Units.js'; import RenderFeature from '../render/Feature.js'; +import {get} from '../proj.js'; /** @@ -83,12 +84,6 @@ class MVT extends FeatureFormat { */ this.layers_ = options.layers ? options.layers : null; - /** - * @private - * @type {import("../extent.js").Extent} - */ - this.extent_ = null; - } /** @@ -159,10 +154,10 @@ class MVT extends FeatureFormat { * @private * @param {PBF} pbf PBF * @param {Object} rawFeature Raw Mapbox feature. - * @param {import("./Feature.js").ReadOptions=} opt_options Read options. + * @param {import("./Feature.js").ReadOptions} options Read options. * @return {import("../Feature.js").FeatureLike} Feature. */ - createFeature_(pbf, rawFeature, opt_options) { + createFeature_(pbf, rawFeature, options) { const type = rawFeature.type; if (type === 0) { return null; @@ -181,6 +176,7 @@ class MVT extends FeatureFormat { if (this.featureClass_ === RenderFeature) { feature = new this.featureClass_(geometryType, flatCoordinates, ends, values, id); + feature.transform(options.dataProjection, options.featureProjection); } else { let geom; if (geometryType == GeometryType.POLYGON) { @@ -213,7 +209,7 @@ class MVT extends FeatureFormat { if (this.geometryName_) { feature.setGeometryName(this.geometryName_); } - const geometry = transformGeometryWithOptions(geom, false, this.adaptOptions(opt_options)); + const geometry = transformGeometryWithOptions(geom, false, options); feature.setGeometry(geometry); feature.setId(id); feature.setProperties(values, true); @@ -222,14 +218,6 @@ class MVT extends FeatureFormat { return feature; } - /** - * @inheritDoc - * @api - */ - getLastExtent() { - return this.extent_; - } - /** * @inheritDoc */ @@ -238,15 +226,22 @@ class MVT extends FeatureFormat { } /** - * @inheritDoc + * Read all features. + * + * @param {ArrayBuffer} source Source. + * @param {import("./Feature.js").ReadOptions=} opt_options Read options. + * @return {Array} Features. * @api */ readFeatures(source, opt_options) { const layers = this.layers_; + const options = /** @type {import("./Feature.js").ReadOptions} */ (this.adaptOptions(opt_options)); + const dataProjection = get(options.dataProjection); + dataProjection.setWorldExtent(options.extent); + options.dataProjection = dataProjection; const pbf = new PBF(/** @type {ArrayBuffer} */ (source)); const pbfLayers = pbf.readFields(layersPBFReader, {}); - /** @type {Array} */ const features = []; for (const name in pbfLayers) { if (layers && layers.indexOf(name) == -1) { @@ -254,11 +249,13 @@ class MVT extends FeatureFormat { } const pbfLayer = pbfLayers[name]; + const extent = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null; + dataProjection.setExtent(extent); + for (let i = 0, ii = pbfLayer.length; i < ii; ++i) { const rawFeature = readRawFeature(pbf, pbfLayer, i); - features.push(this.createFeature_(pbf, rawFeature)); + features.push(this.createFeature_(pbf, rawFeature, options)); } - this.extent_ = pbfLayer ? [0, 0, pbfLayer.extent, pbfLayer.extent] : null; } return features; diff --git a/src/ol/renderer/canvas/VectorTileLayer.js b/src/ol/renderer/canvas/VectorTileLayer.js index d10c9c5fdc..be8e05bc76 100644 --- a/src/ol/renderer/canvas/VectorTileLayer.js +++ b/src/ol/renderer/canvas/VectorTileLayer.js @@ -10,8 +10,6 @@ import EventType from '../../events/EventType.js'; import rbush from 'rbush'; import {buffer, containsCoordinate, equals, getIntersection, getTopLeft, intersects} from '../../extent.js'; import VectorTileRenderType from '../../layer/VectorTileRenderType.js'; -import {equivalent as equivalentProjection} from '../../proj.js'; -import Units from '../../proj/Units.js'; import ReplayType from '../../render/canvas/BuilderType.js'; import {labelCache} from '../../render/canvas.js'; import CanvasBuilderGroup from '../../render/canvas/BuilderGroup.js'; @@ -264,12 +262,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { const sharedExtent = getIntersection(tileExtent, sourceTileExtent); const bufferedExtent = equals(sourceTileExtent, sharedExtent) ? null : buffer(sharedExtent, layer.getRenderBuffer() * resolution, this.tmpExtent); - const tileProjection = sourceTile.getProjection(); - let reproject = false; - if (!equivalentProjection(projection, tileProjection)) { - reproject = true; - sourceTile.setProjection(projection); - } builderState.dirty = false; const builderGroup = new CanvasBuilderGroup(0, sharedExtent, resolution, pixelRatio, !!this.declutterTree_); @@ -298,15 +290,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer { } for (let i = 0, ii = features.length; i < ii; ++i) { const feature = features[i]; - if (reproject) { - if (tileProjection.getUnits() == Units.TILE_PIXELS) { - // projected tile extent - tileProjection.setWorldExtent(sourceTileExtent); - // tile extent in tile pixel space - tileProjection.setExtent(sourceTile.getExtent()); - } - feature.getGeometry().transform(tileProjection, projection); - } if (!bufferedExtent || intersects(bufferedExtent, feature.getGeometry().getExtent())) { render.call(this, feature); } diff --git a/src/ol/source/VectorTile.js b/src/ol/source/VectorTile.js index a98900d3ad..e05b933889 100644 --- a/src/ol/source/VectorTile.js +++ b/src/ol/source/VectorTile.js @@ -26,7 +26,7 @@ import {equals} from '../array.js'; * to `false` (e.g. for sources with polygons that represent administrative * boundaries or TopoJSON sources) allows the renderer to optimise fill and * stroke operations. - * @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection. + * @property {import("../proj.js").ProjectionLike} [projection='EPSG:3857'] Projection of the tile grid. * @property {import("./State.js").default} [state] Source state. * @property {typeof import("../VectorTile.js").default} [tileClass] Class used to instantiate image tiles. * Default is {@link module:ol/VectorTile}. @@ -35,18 +35,20 @@ import {equals} from '../array.js'; * @property {number|import("../size.js").Size} [tileSize=512] Optional tile size. * @property {import("../tilegrid/TileGrid.js").default} [tileGrid] Tile grid. * @property {import("../Tile.js").LoadFunction} [tileLoadFunction] - * Optional function to load a tile given a URL. Could look like this: + * Optional function to load a tile given a URL. Could look like this for pbf tiles: * ```js * function(tile, url) { - * tile.setLoader(function() { - * var data = // ... fetch data - * var format = tile.getFormat(); - * tile.setProjection(format.readProjection(data)); - * tile.setExtent(format.getLastExtent()); // line only required for ol/format/MVT - * tile.setFeatures(format.readFeatures(data, { - * // featureProjection is not required for ol/format/MVT - * featureProjection: map.getView().getProjection() - * })); + * tile.setLoader(function(extent, resolution, projection) { + * fetch(url).then(function(response) { + * response.arrayBuffer().then(function(data) { + * const format = tile.getFormat() // ol/format/MVT configured as source format + * const features = format.readFeatures(data, { + * extent: extent, + * featureProjection: projection + * }); + * tile.setFeatures(features); + * }); + * }); * } * }); * ``` @@ -187,9 +189,9 @@ class VectorTile extends UrlTile { const sourceTileGrid = this.tileGrid; const sourceExtent = sourceTileGrid.getExtent(); if (sourceExtent) { - getIntersection(extent, sourceTileGrid.getExtent(), extent); + getIntersection(extent, sourceExtent, extent); } - const sourceZ = sourceTileGrid.getZForResolution(resolution); + const sourceZ = sourceTileGrid.getZForResolution(resolution/*, 1*/); const minZoom = sourceTileGrid.getMinZoom(); let loadedZ = sourceZ + 1; @@ -215,6 +217,9 @@ class VectorTile extends UrlTile { tileUrl == undefined ? TileState.EMPTY : TileState.IDLE, tileUrl == undefined ? '' : tileUrl, this.format_, this.tileLoadFunction); + sourceTile.extent = sourceTileGrid.getTileCoordExtent(sourceTileCoord); + sourceTile.projection = projection; + sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]); this.sourceTiles_[tileKey] = sourceTile; empty = empty && sourceTile.getState() === TileState.EMPTY; listen(sourceTile, EventType.CHANGE, this.handleTileChange, this); diff --git a/test/spec/ol/format/mvt.test.js b/test/spec/ol/format/mvt.test.js index a1eefdd8ed..f4fb75a2a3 100644 --- a/test/spec/ol/format/mvt.test.js +++ b/test/spec/ol/format/mvt.test.js @@ -1,5 +1,4 @@ import Feature from '../../../../src/ol/Feature.js'; -import {getWidth} from '../../../../src/ol/extent.js'; import MVT from '../../../../src/ol/format/MVT.js'; import Point from '../../../../src/ol/geom/Point.js'; import Polygon from '../../../../src/ol/geom/Polygon.js'; @@ -22,15 +21,20 @@ where('ArrayBuffer.isView').describe('ol.format.MVT', function() { describe('#readFeatures', function() { + const options = { + featureProjection: 'EPSG:3857', + extent: [1824704.739223726, 6141868.096770482, 1827150.7241288517, 6144314.081675608] + }; + it('uses ol.render.Feature as feature class by default', function() { const format = new MVT({layers: ['water']}); - const features = format.readFeatures(data); + const features = format.readFeatures(data, options); expect(features[0]).to.be.a(RenderFeature); }); it('parses only specified layers', function() { const format = new MVT({layers: ['water']}); - const features = format.readFeatures(data); + const features = format.readFeatures(data, options); expect(features.length).to.be(10); }); @@ -64,29 +68,27 @@ where('ArrayBuffer.isView').describe('ol.format.MVT', function() { featureClass: Feature, layers: ['building'] }); - let features = format.readFeatures(data); + let features = format.readFeatures(data, options); expect(features[0].getId()).to.be(2); // ol.render.Feature format = new MVT({ layers: ['building'] }); - features = format.readFeatures(data); + features = format.readFeatures(data, options); expect(features[0].getId()).to.be(2); }); - it('sets the extent of the last readFeatures call', function() { - const format = new MVT(); - format.readFeatures(data); - const extent = format.getLastExtent(); - expect(getWidth(extent)).to.be(4096); - }); - }); }); describe('ol.format.MVT', function() { + const options = { + featureProjection: 'EPSG:3857', + extent: [1824704.739223726, 6141868.096770482, 1827150.7241288517, 6144314.081675608] + }; + describe('#createFeature_', function() { it('accepts a geometryName', function() { const format = new MVT({ @@ -176,7 +178,9 @@ describe('ol.format.MVT', function() { ends.push(10, 20); createdEnds = ends; }; - const feature = format.createFeature_({}, rawFeature); + format.dataProjection.setExtent([0, 0, 4096, 4096]); + format.dataProjection.setWorldExtent(options.extent); + const feature = format.createFeature_({}, rawFeature, format.adaptOptions(options)); expect(feature).to.be.a(RenderFeature); expect(feature.getType()).to.be('Polygon'); expect(feature.getFlatCoordinates()).to.equal(createdFlatCoordinates); diff --git a/test/spec/ol/renderer/canvas/vectortilelayer.test.js b/test/spec/ol/renderer/canvas/vectortilelayer.test.js index fb4f5c6d92..44ae93f074 100644 --- a/test/spec/ol/renderer/canvas/vectortilelayer.test.js +++ b/test/spec/ol/renderer/canvas/vectortilelayer.test.js @@ -9,8 +9,7 @@ import {getCenter} from '../../../../../src/ol/extent.js'; import MVT from '../../../../../src/ol/format/MVT.js'; import Point from '../../../../../src/ol/geom/Point.js'; import VectorTileLayer from '../../../../../src/ol/layer/VectorTile.js'; -import {get as getProjection, fromLonLat} from '../../../../../src/ol/proj.js'; -import Projection from '../../../../../src/ol/proj/Projection.js'; +import {get as getProjection} from '../../../../../src/ol/proj.js'; import {checkedFonts} from '../../../../../src/ol/render/canvas.js'; import RenderFeature from '../../../../../src/ol/render/Feature.js'; import CanvasVectorTileLayerRenderer from '../../../../../src/ol/renderer/canvas/VectorTileLayer.js'; @@ -64,7 +63,6 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { constructor() { super(...arguments); this.setFeatures([feature1, feature2, feature3]); - this.setProjection(getProjection('EPSG:4326')); this.setState(TileState.LOADED); tileCallback(this); } @@ -188,30 +186,6 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { }, 1600); }); - it('transforms geometries when tile and view projection are different', function() { - let tile; - tileCallback = function(t) { - tile = t; - }; - map.renderSync(); - expect(tile.getProjection()).to.equal(getProjection('EPSG:3857')); - expect(feature1.getGeometry().getCoordinates()).to.eql(fromLonLat([1, -1])); - }); - - it('Geometries are transformed from tile-pixels', function() { - const proj = new Projection({code: 'EPSG:3857', units: 'tile-pixels'}); - let tile; - tileCallback = function(t) { - t.setProjection(proj); - t.setExtent([0, 0, 4096, 4096]); - tile = t; - }; - map.renderSync(); - expect(tile.getProjection()).to.equal(getProjection('EPSG:3857')); - expect(feature1.getGeometry().getCoordinates()).to.eql([-20027724.40316874, 20047292.282409746]); - expect(feature3.flatCoordinates_).to.eql([-20027724.40316874, 20047292.282409746]); - }); - it('works for multiple layers that use the same source', function() { const layer2 = new VectorTileLayer({ source: source, @@ -240,7 +214,6 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { }) }); const sourceTile = new VectorTile([0, 0, 0], 2); - sourceTile.setProjection(getProjection('EPSG:3857')); sourceTile.features_ = []; sourceTile.getImage = function() { return document.createElement('canvas'); @@ -299,7 +272,6 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { beforeEach(function() { const sourceTile = new VectorTile([0, 0, 0]); sourceTile.setState(TileState.LOADED); - sourceTile.setProjection(getProjection('EPSG:3857')); source = new VectorTileSource({ tileClass: TileClass, tileGrid: createXYZ() diff --git a/test/spec/ol/vectortile.test.js b/test/spec/ol/vectortile.test.js index 485d397c7a..eca1156235 100644 --- a/test/spec/ol/vectortile.test.js +++ b/test/spec/ol/vectortile.test.js @@ -1,38 +1,43 @@ -import Feature from '../../../src/ol/Feature.js'; import {defaultLoadFunction} from '../../../src/ol/source/VectorTile.js'; import VectorTile from '../../../src/ol/VectorTile.js'; import {listen} from '../../../src/ol/events.js'; -import TextFeature from '../../../src/ol/format/TextFeature.js'; +import GeoJSON from '../../../src/ol/format/GeoJSON.js'; +import MVT from '../../../src/ol/format/MVT.js'; import {get as getProjection} from '../../../src/ol/proj.js'; -import Projection from '../../../src/ol/proj/Projection.js'; +import {createXYZ} from '../../../src/ol/tilegrid.js'; 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 - const format = new TextFeature(); - format.readProjection = function(source) { - return new Projection({ - code: '', - units: 'tile-pixels' - }); - }; - format.readFeatures = function(source, options) { - return [new Feature()]; - }; - + it('loader reprojects GeoJSON features', function(done) { + const format = new GeoJSON(); const tile = new VectorTile([0, 0, 0], null, null, format); const url = 'spec/ol/data/point.json'; - defaultLoadFunction(tile, url); const loader = tile.loader_; listen(tile, 'change', function(e) { - expect(tile.getFeatures().length).to.be.greaterThan(0); - expect(tile.getProjection().getUnits()).to.be('tile-pixels'); + expect(tile.getFeatures()[0].getGeometry().getFlatCoordinates()).to.eql([-9724792.346778862, 4164041.638405114]); done(); }); loader.call(tile, [], 1, getProjection('EPSG:3857')); }); + it('loader reprojects MVT features', function(done) { + const format = new MVT(); + const tileGrid = createXYZ({ + tileSize: 512 + }); + const tile = new VectorTile([14, 8938, 5680], null, null, format); + const url = 'spec/ol/data/14-8938-5680.vector.pbf'; + defaultLoadFunction(tile, url); + const loader = tile.loader_; + listen(tile, 'change', function(e) { + expect(tile.getFeatures()[1246].getGeometry().getFlatCoordinates()).to.eql([1827804.0218549764, 6144812.116688028]); + done(); + }); + const extent = tileGrid.getTileCoordExtent(tile.tileCoord); + loader.call(tile, extent, 1, getProjection('EPSG:3857')); + }); + + });