Add decluttering for images and text
This commit is contained in:
@@ -4,6 +4,7 @@ goog.require('ol');
|
||||
goog.require('ol.LayerType');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.dom');
|
||||
goog.require('ol.ext.rbush');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.render.EventType');
|
||||
goog.require('ol.render.canvas');
|
||||
@@ -23,6 +24,13 @@ ol.renderer.canvas.VectorLayer = function(vectorLayer) {
|
||||
|
||||
ol.renderer.canvas.Layer.call(this, vectorLayer);
|
||||
|
||||
/**
|
||||
* Declutter tree.
|
||||
* @private
|
||||
*/
|
||||
this.declutterTree_ = vectorLayer.getDeclutter() ?
|
||||
ol.ext.rbush(9, ['[0]', '[1]', '[2]', '[3]']) : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
@@ -209,6 +217,9 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
|
||||
if (clipped) {
|
||||
context.restore();
|
||||
}
|
||||
if (this.declutterTree_) {
|
||||
this.declutterTree_.clear();
|
||||
}
|
||||
this.postCompose(context, frameState, layerState, transform);
|
||||
|
||||
};
|
||||
@@ -226,7 +237,7 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(c
|
||||
var layer = this.getLayer();
|
||||
/** @type {Object.<string, boolean>} */
|
||||
var features = {};
|
||||
return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
|
||||
var result = this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
|
||||
rotation, hitTolerance, {},
|
||||
/**
|
||||
* @param {ol.Feature|ol.render.Feature} feature Feature.
|
||||
@@ -238,7 +249,11 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(c
|
||||
features[key] = true;
|
||||
return callback.call(thisArg, feature, layer);
|
||||
}
|
||||
});
|
||||
}, null);
|
||||
if (this.declutterTree_) {
|
||||
this.declutterTree_.clear();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -317,7 +332,7 @@ ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, lay
|
||||
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(
|
||||
ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, resolution,
|
||||
pixelRatio, vectorSource.getOverlaps(), vectorLayer.getRenderBuffer());
|
||||
pixelRatio, vectorSource.getOverlaps(), this.declutterTree_, vectorLayer.getRenderBuffer());
|
||||
vectorSource.loadFeatures(extent, resolution, projection);
|
||||
/**
|
||||
* @param {ol.Feature} feature Feature.
|
||||
|
||||
@@ -4,6 +4,7 @@ goog.require('ol');
|
||||
goog.require('ol.LayerType');
|
||||
goog.require('ol.TileState');
|
||||
goog.require('ol.dom');
|
||||
goog.require('ol.ext.rbush');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.layer.VectorTileRenderType');
|
||||
goog.require('ol.proj');
|
||||
@@ -33,6 +34,12 @@ ol.renderer.canvas.VectorTileLayer = function(layer) {
|
||||
|
||||
ol.renderer.canvas.TileLayer.call(this, layer);
|
||||
|
||||
/**
|
||||
* Declutter tree.
|
||||
* @private
|
||||
*/
|
||||
this.declutterTree_ = layer.getDeclutter() ? ol.ext.rbush(9, ['[0]', '[1]', '[2]', '[3]']) : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
@@ -54,7 +61,6 @@ ol.renderer.canvas.VectorTileLayer = function(layer) {
|
||||
// Use lower resolution for pure vector rendering. Closest resolution otherwise.
|
||||
this.zDirection =
|
||||
layer.getRenderMode() == ol.layer.VectorTileRenderType.VECTOR ? 1 : 0;
|
||||
|
||||
};
|
||||
ol.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.TileLayer);
|
||||
|
||||
@@ -150,6 +156,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
|
||||
var resolution = tileGrid.getResolution(tile.tileCoord[0]);
|
||||
var tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
|
||||
|
||||
var zIndexKeys = {};
|
||||
for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
|
||||
var sourceTile = tile.getTile(tile.tileKeys[t]);
|
||||
if (sourceTile.getState() == ol.TileState.ERROR) {
|
||||
@@ -168,8 +175,8 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
|
||||
sourceTile.setProjection(projection);
|
||||
}
|
||||
replayState.dirty = false;
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(0, sharedExtent,
|
||||
resolution, pixelRatio, source.getOverlaps(), layer.getRenderBuffer());
|
||||
var replayGroup = new ol.render.canvas.ReplayGroup(0, sharedExtent, resolution,
|
||||
pixelRatio, source.getOverlaps(), this.declutterTree_, layer.getRenderBuffer());
|
||||
var squaredTolerance = ol.renderer.vector.getSquaredTolerance(
|
||||
resolution, pixelRatio);
|
||||
|
||||
@@ -217,6 +224,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
|
||||
}
|
||||
}
|
||||
replayGroup.finish();
|
||||
for (var r in replayGroup.getReplays()) {
|
||||
zIndexKeys[r] = true;
|
||||
}
|
||||
sourceTile.setReplayGroup(layer, tile.tileCoord.toString(), replayGroup);
|
||||
}
|
||||
replayState.renderedRevision = revision;
|
||||
@@ -246,6 +256,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
|
||||
var rotation = frameState.viewState.rotation;
|
||||
hitTolerance = hitTolerance == undefined ? 0 : hitTolerance;
|
||||
var layer = this.getLayer();
|
||||
var declutterReplays = layer.getDeclutter() ? {} : null;
|
||||
/** @type {Object.<string, boolean>} */
|
||||
var features = {};
|
||||
|
||||
@@ -283,9 +294,12 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
|
||||
features[key] = true;
|
||||
return callback.call(thisArg, feature, layer);
|
||||
}
|
||||
});
|
||||
}, declutterReplays);
|
||||
}
|
||||
}
|
||||
if (this.declutterTree_) {
|
||||
this.declutterTree_.clear();
|
||||
}
|
||||
return found;
|
||||
};
|
||||
|
||||
@@ -335,14 +349,16 @@ ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(
|
||||
*/
|
||||
ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, frameState, layerState) {
|
||||
var layer = this.getLayer();
|
||||
var declutterReplays = layer.getDeclutter() ? {} : null;
|
||||
var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
|
||||
var renderMode = layer.getRenderMode();
|
||||
var replays = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];
|
||||
var replayTypes = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];
|
||||
var pixelRatio = frameState.pixelRatio;
|
||||
var rotation = frameState.viewState.rotation;
|
||||
var size = frameState.size;
|
||||
var offsetX = Math.round(pixelRatio * size[0] / 2);
|
||||
var offsetY = Math.round(pixelRatio * size[1] / 2);
|
||||
ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);
|
||||
var tiles = this.renderedTiles;
|
||||
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
|
||||
var clips = [];
|
||||
@@ -355,21 +371,23 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
|
||||
var tileCoord = tile.tileCoord;
|
||||
var worldOffset = tileGrid.getTileCoordExtent(tileCoord)[0] -
|
||||
tileGrid.getTileCoordExtent(tile.wrappedTileCoord)[0];
|
||||
var transform = undefined;
|
||||
for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
|
||||
var sourceTile = tile.getTile(tile.tileKeys[t]);
|
||||
if (sourceTile.getState() == ol.TileState.ERROR) {
|
||||
continue;
|
||||
}
|
||||
var replayGroup = sourceTile.getReplayGroup(layer, tileCoord.toString());
|
||||
if (renderMode != ol.layer.VectorTileRenderType.VECTOR && !replayGroup.hasReplays(replays)) {
|
||||
if (renderMode != ol.layer.VectorTileRenderType.VECTOR && !replayGroup.hasReplays(replayTypes)) {
|
||||
continue;
|
||||
}
|
||||
if (!transform) {
|
||||
transform = this.getTransform(frameState, worldOffset);
|
||||
}
|
||||
var currentZ = sourceTile.tileCoord[0];
|
||||
var transform = this.getTransform(frameState, worldOffset);
|
||||
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) {
|
||||
@@ -389,12 +407,16 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
|
||||
context.clip();
|
||||
}
|
||||
}
|
||||
replayGroup.replay(context, transform, rotation, {}, replays);
|
||||
replayGroup.replay(context, transform, rotation, {}, replayTypes, declutterReplays);
|
||||
context.restore();
|
||||
clips.push(currentClip);
|
||||
zs.push(currentZ);
|
||||
}
|
||||
}
|
||||
if (declutterReplays) {
|
||||
ol.render.canvas.ReplayGroup.replayDeclutter(declutterReplays, context, rotation);
|
||||
this.declutterTree_.clear();
|
||||
}
|
||||
ol.renderer.canvas.TileLayer.prototype.postCompose.apply(this, arguments);
|
||||
};
|
||||
|
||||
@@ -462,7 +484,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.renderTileImage_ = function(
|
||||
ol.transform.scale(transform, pixelScale, -pixelScale);
|
||||
ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);
|
||||
var replayGroup = sourceTile.getReplayGroup(layer, tile.tileCoord.toString());
|
||||
replayGroup.replay(context, transform, 0, {}, replays, true);
|
||||
replayGroup.replay(context, transform, 0, {}, replays);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@ ol.renderer.vector.renderCircleGeometry_ = function(replayGroup, geometry, style
|
||||
if (textStyle) {
|
||||
var textReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||
textReplay.setTextStyle(textStyle);
|
||||
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
|
||||
textReplay.drawText(geometry, feature);
|
||||
}
|
||||
};
|
||||
@@ -180,7 +180,7 @@ ol.renderer.vector.renderLineStringGeometry_ = function(replayGroup, geometry, s
|
||||
if (textStyle) {
|
||||
var textReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||
textReplay.setTextStyle(textStyle);
|
||||
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
|
||||
textReplay.drawText(geometry, feature);
|
||||
}
|
||||
};
|
||||
@@ -205,7 +205,7 @@ ol.renderer.vector.renderMultiLineStringGeometry_ = function(replayGroup, geomet
|
||||
if (textStyle) {
|
||||
var textReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||
textReplay.setTextStyle(textStyle);
|
||||
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
|
||||
textReplay.drawText(geometry, feature);
|
||||
}
|
||||
};
|
||||
@@ -231,7 +231,7 @@ ol.renderer.vector.renderMultiPolygonGeometry_ = function(replayGroup, geometry,
|
||||
if (textStyle) {
|
||||
var textReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||
textReplay.setTextStyle(textStyle);
|
||||
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
|
||||
textReplay.drawText(geometry, feature);
|
||||
}
|
||||
};
|
||||
@@ -252,14 +252,14 @@ ol.renderer.vector.renderPointGeometry_ = function(replayGroup, geometry, style,
|
||||
}
|
||||
var imageReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.IMAGE);
|
||||
imageReplay.setImageStyle(imageStyle);
|
||||
imageReplay.setImageStyle(imageStyle, replayGroup.addDeclutter(false));
|
||||
imageReplay.drawPoint(geometry, feature);
|
||||
}
|
||||
var textStyle = style.getText();
|
||||
if (textStyle) {
|
||||
var textReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||
textReplay.setTextStyle(textStyle);
|
||||
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(!!imageStyle));
|
||||
textReplay.drawText(geometry, feature);
|
||||
}
|
||||
};
|
||||
@@ -280,14 +280,14 @@ ol.renderer.vector.renderMultiPointGeometry_ = function(replayGroup, geometry, s
|
||||
}
|
||||
var imageReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.IMAGE);
|
||||
imageReplay.setImageStyle(imageStyle);
|
||||
imageReplay.setImageStyle(imageStyle, replayGroup.addDeclutter(false));
|
||||
imageReplay.drawMultiPoint(geometry, feature);
|
||||
}
|
||||
var textStyle = style.getText();
|
||||
if (textStyle) {
|
||||
var textReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||
textReplay.setTextStyle(textStyle);
|
||||
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(!!imageStyle));
|
||||
textReplay.drawText(geometry, feature);
|
||||
}
|
||||
};
|
||||
@@ -313,7 +313,7 @@ ol.renderer.vector.renderPolygonGeometry_ = function(replayGroup, geometry, styl
|
||||
if (textStyle) {
|
||||
var textReplay = replayGroup.getReplay(
|
||||
style.getZIndex(), ol.render.ReplayType.TEXT);
|
||||
textReplay.setTextStyle(textStyle);
|
||||
textReplay.setTextStyle(textStyle, replayGroup.addDeclutter(false));
|
||||
textReplay.drawText(geometry, feature);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user