Merge pull request #10301 from ahocevar/getfeatures-fixes

Create hit detection data per layer and without requestAnimationFrame
This commit is contained in:
Andreas Hocevar
2019-11-29 09:44:09 +01:00
committed by GitHub
4 changed files with 74 additions and 54 deletions
+2 -2
View File
@@ -61,9 +61,9 @@ class VectorRenderTile extends Tile {
this.errorSourceTileKeys = {}; this.errorSourceTileKeys = {};
/** /**
* @type {ImageData} * @type {Object<number, ImageData>}
*/ */
this.hitDetectionImageData = null; this.hitDetectionImageData = {};
/** /**
* @private * @private
+1 -5
View File
@@ -232,7 +232,6 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
getFeatures(pixel) { getFeatures(pixel) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (!this.hitDetectionImageData_ && !this.animatingOrInteracting_) { if (!this.hitDetectionImageData_ && !this.animatingOrInteracting_) {
requestAnimationFrame(function() {
const size = [this.context.canvas.width, this.context.canvas.height]; const size = [this.context.canvas.width, this.context.canvas.height];
apply(this.pixelTransform, size); apply(this.pixelTransform, size);
const center = this.renderedCenter_; const center = this.renderedCenter_;
@@ -270,11 +269,8 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
this.hitDetectionImageData_ = createHitDetectionImageData(size, transforms, this.hitDetectionImageData_ = createHitDetectionImageData(size, transforms,
this.renderedFeatures_, layer.getStyleFunction(), extent, resolution, rotation); this.renderedFeatures_, layer.getStyleFunction(), extent, resolution, rotation);
resolve(hitDetect(pixel, this.renderedFeatures_, this.hitDetectionImageData_));
}.bind(this));
} else {
resolve(hitDetect(pixel, this.renderedFeatures_, this.hitDetectionImageData_));
} }
resolve(hitDetect(pixel, this.renderedFeatures_, this.hitDetectionImageData_));
}.bind(this)); }.bind(this));
} }
+7 -8
View File
@@ -221,7 +221,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
executorGroups[i].dispose(); executorGroups[i].dispose();
} }
} }
tile.hitDetectionImageData = null; delete tile.hitDetectionImageData[layerUid];
tile.executorGroups[layerUid] = []; tile.executorGroups[layerUid] = [];
for (let t = 0, tt = sourceTiles.length; t < tt; ++t) { for (let t = 0, tt = sourceTiles.length; t < tt; ++t) {
const sourceTile = sourceTiles[t]; const sourceTile = sourceTiles[t];
@@ -341,6 +341,7 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
getFeatures(pixel) { getFeatures(pixel) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer()); const layer = /** @type {import("../../layer/VectorTile.js").default} */ (this.getLayer());
const layerUid = getUid(layer);
const source = layer.getSource(); const source = layer.getSource();
const projection = this.renderedProjection; const projection = this.renderedProjection;
const projectionExtent = projection.getExtent(); const projectionExtent = projection.getExtent();
@@ -377,7 +378,8 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
const features = tile.getSourceTiles().reduce(function(accumulator, sourceTile) { const features = tile.getSourceTiles().reduce(function(accumulator, sourceTile) {
return accumulator.concat(sourceTile.getFeatures()); return accumulator.concat(sourceTile.getFeatures());
}, []); }, []);
if (!tile.hitDetectionImageData) { let hitDetectionImageData = tile.hitDetectionImageData[layerUid];
if (!hitDetectionImageData && !this.animatingOrInteracting_) {
const tileSize = toSize(tileGrid.getTileSize(tileGrid.getZForResolution(resolution))); const tileSize = toSize(tileGrid.getTileSize(tileGrid.getZForResolution(resolution)));
const size = [tileSize[0] / 2, tileSize[1] / 2]; const size = [tileSize[0] / 2, tileSize[1] / 2];
const rotation = this.renderedRotation_; const rotation = this.renderedRotation_;
@@ -385,16 +387,13 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
this.getRenderTransform(tileGrid.getTileCoordCenter(tile.wrappedTileCoord), this.getRenderTransform(tileGrid.getTileCoordCenter(tile.wrappedTileCoord),
resolution, 0, 0.5, size[0], size[1], 0) resolution, 0, 0.5, size[0], size[1], 0)
]; ];
requestAnimationFrame(function() { hitDetectionImageData = createHitDetectionImageData(tileSize, transforms,
tile.hitDetectionImageData = createHitDetectionImageData(tileSize, transforms,
features, layer.getStyleFunction(), features, layer.getStyleFunction(),
tileGrid.getTileCoordExtent(tile.wrappedTileCoord), tileGrid.getTileCoordExtent(tile.wrappedTileCoord),
tile.getReplayState(layer).renderedResolution, rotation); tile.getReplayState(layer).renderedResolution, rotation);
resolve(hitDetect(tilePixel, features, tile.hitDetectionImageData)); tile.hitDetectionImageData[layerUid] = hitDetectionImageData;
});
} else {
resolve(hitDetect(tilePixel, features, tile.hitDetectionImageData));
} }
resolve(hitDetect(tilePixel, features, hitDetectionImageData));
}.bind(this)); }.bind(this));
} }
+25
View File
@@ -125,8 +125,33 @@ describe('ol.layer.VectorTile', function() {
layer.getFeatures(pixel).then(function(features) { layer.getFeatures(pixel).then(function(features) {
expect(features[0].get('name')).to.be('feature1'); expect(features[0].get('name')).to.be('feature1');
done(); done();
}).catch(done);
}); });
}); });
it('does not give false positives', function(done) {
map.once('rendercomplete', function() {
const pixel = map.getPixelFromCoordinate(fromLonLat([0, 0]));
layer.getFeatures(pixel).then(function(features) {
expect(features.length).to.be(0);
done();
}).catch(done);
});
});
it('stores separate hit detection data for each layer that uses the source', function(done) {
const layer2 = new VectorTileLayer({
source: layer.getSource()
});
map.addLayer(layer2);
map.once('rendercomplete', function() {
const pixel = map.getPixelFromCoordinate(fromLonLat([-36, 0]));
Promise.all([layer.getFeatures(pixel), layer2.getFeatures(pixel)]).then(function(result) {
const tile = layer.getSource().tileCache.get('0/0/0');
expect(Object.keys(tile.hitDetectionImageData).length).to.be(2);
done();
}).catch(done);
});
}); });
}); });