Reuse declutter tree for hit detection

Replaying for hit detection no longer declutters, but uses the declutter tree
from the previous rendered frame.
This commit is contained in:
Andreas Hocevar
2017-11-27 13:29:32 +01:00
parent 841e79b0e8
commit ac195c46b1
5 changed files with 36 additions and 48 deletions

View File

@@ -483,8 +483,9 @@ ol.render.canvas.Replay.prototype.setStrokeStyle_ = function(context, instructio
/**
* @param {ol.DeclutterGroup} declutterGroup Declutter group.
* @param {ol.Feature|ol.render.Feature} feature Feature.
*/
ol.render.canvas.Replay.prototype.renderDeclutter_ = function(declutterGroup) {
ol.render.canvas.Replay.prototype.renderDeclutter_ = function(declutterGroup, feature) {
if (declutterGroup && declutterGroup.length > 5) {
var groupCount = declutterGroup[4];
if (groupCount == 1 || groupCount == declutterGroup.length - 5) {
@@ -493,7 +494,8 @@ ol.render.canvas.Replay.prototype.renderDeclutter_ = function(declutterGroup) {
minX: /** @type {number} */ (declutterGroup[0]),
minY: /** @type {number} */ (declutterGroup[1]),
maxX: /** @type {number} */ (declutterGroup[2]),
maxY: /** @type {number} */ (declutterGroup[3])
maxY: /** @type {number} */ (declutterGroup[3]),
value: feature
};
if (!this.declutterTree.collides(box)) {
this.declutterTree.insert(box);
@@ -651,7 +653,7 @@ ol.render.canvas.Replay.prototype.replay_ = function(
// Remaining arguments in DRAW_IMAGE are in alphabetical order
anchorX = /** @type {number} */ (instruction[4]);
anchorY = /** @type {number} */ (instruction[5]);
declutterGroup = /** @type {ol.DeclutterGroup} */ (instruction[6]);
declutterGroup = featureCallback ? null : /** @type {ol.DeclutterGroup} */ (instruction[6]);
var height = /** @type {number} */ (instruction[7]);
var opacity = /** @type {number} */ (instruction[8]);
var originX = /** @type {number} */ (instruction[9]);
@@ -683,14 +685,14 @@ ol.render.canvas.Replay.prototype.replay_ = function(
backgroundFill ? /** @type {Array.<*>} */ (lastFillInstruction) : null,
backgroundStroke ? /** @type {Array.<*>} */ (lastStrokeInstruction) : null);
}
this.renderDeclutter_(declutterGroup);
this.renderDeclutter_(declutterGroup, feature);
++i;
break;
case ol.render.canvas.Instruction.DRAW_CHARS:
var begin = /** @type {number} */ (instruction[1]);
var end = /** @type {number} */ (instruction[2]);
var baseline = /** @type {number} */ (instruction[3]);
declutterGroup = /** @type {ol.DeclutterGroup} */ (instruction[4]);
declutterGroup = featureCallback ? null : /** @type {ol.DeclutterGroup} */ (instruction[4]);
var overflow = /** @type {number} */ (instruction[5]);
var fillKey = /** @type {string} */ (instruction[6]);
var maxAngle = /** @type {number} */ (instruction[7]);
@@ -741,7 +743,7 @@ ol.render.canvas.Replay.prototype.replay_ = function(
}
}
}
this.renderDeclutter_(declutterGroup);
this.renderDeclutter_(declutterGroup, feature);
++i;
break;
case ol.render.canvas.Instruction.END_GEOMETRY:

View File

@@ -185,32 +185,20 @@ ol.render.canvas.ReplayGroup.getCircleArray_ = function(radius) {
};
/**
* @param {!Object.<string, Array.<*>>} declutterReplays Declutter replays.
* @param {CanvasRenderingContext2D} context Context.
* @param {number} rotation Rotation.
*/
ol.render.canvas.ReplayGroup.replayDeclutter = function(declutterReplays, context, rotation) {
var zs = Object.keys(declutterReplays).map(Number).sort(ol.array.numberSafeCompareFunction);
var skippedFeatureUids = {};
for (var z = 0, zz = zs.length; z < zz; ++z) {
var replayData = declutterReplays[zs[z].toString()];
for (var i = 0, ii = replayData.length; i < ii;) {
var replay = replayData[i++];
var transform = replayData[i++];
replay.replay(context, transform, rotation, {});
}
}
};
ol.render.canvas.ReplayGroup.replayDeclutterHitDetection = function(
declutterReplays, context, rotation, featureCallback, hitExtent) {
var zs = Object.keys(declutterReplays).map(Number).sort(ol.array.numberSafeCompareFunction);
for (var z = 0, zz = zs.length; z < zz; ++z) {
var replayData = declutterReplays[zs[z].toString()];
for (var i = replayData.length - 1; i >= 0;) {
var transform = replayData[i--];
var replay = replayData[i--];
var result = replay.replayHitDetection(context, transform, rotation, {},
featureCallback, hitExtent);
if (result) {
return result;
}
replay.replay(context, transform, rotation, skippedFeatureUids);
}
}
};
@@ -326,6 +314,12 @@ ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
}
var mask = ol.render.canvas.ReplayGroup.getCircleArray_(hitTolerance);
var declutteredFeatures;
if (this.declutterTree_) {
declutteredFeatures = this.declutterTree_.all().map(function(entry) {
return entry.value;
});
}
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
@@ -337,7 +331,10 @@ ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
for (var j = 0; j < contextSize; j++) {
if (mask[i][j]) {
if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
var result = callback(feature);
var result;
if (!declutteredFeatures || declutteredFeatures.indexOf(feature) !== -1) {
result = callback(feature);
}
if (result) {
return result;
} else {
@@ -350,13 +347,8 @@ ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
}
}
var result = this.replayHitDetection_(context, transform, rotation,
return this.replayHitDetection_(context, transform, rotation,
skippedFeaturesHash, hitDetectionCallback, hitExtent, declutterReplays);
if (!result && declutterReplays) {
result = ol.render.canvas.ReplayGroup.replayDeclutterHitDetection(
declutterReplays, context, rotation, hitDetectionCallback, hitExtent);
}
return result;
};

View File

@@ -138,6 +138,9 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, lay
}
var replayGroup = this.replayGroup_;
if (replayGroup && !replayGroup.isEmpty()) {
if (this.declutterTree_) {
this.declutterTree_.clear();
}
var layer = /** @type {ol.layer.Vector} */ (this.getLayer());
var drawOffsetX = 0;
var drawOffsetY = 0;
@@ -229,9 +232,6 @@ 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);
};
@@ -249,7 +249,6 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(c
var layer = /** @type {ol.layer.Vector} */ (this.getLayer());
/** @type {Object.<string, boolean>} */
var features = {};
var declutterReplays = layer.getDeclutter() ? {} : null;
var result = this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
rotation, hitTolerance, {},
/**
@@ -262,10 +261,7 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(c
features[key] = true;
return callback.call(thisArg, feature, layer);
}
}, declutterReplays);
if (this.declutterTree_) {
this.declutterTree_.clear();
}
}, null);
return result;
}
};

View File

@@ -270,7 +270,6 @@ 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 = {};
@@ -308,12 +307,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = functi
features[key] = true;
return callback.call(thisArg, feature, layer);
}
}, declutterReplays);
}, null);
}
}
if (this.declutterTree_) {
this.declutterTree_.clear();
}
return found;
};
@@ -387,6 +383,9 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
offsetY = Math.round(pixelRatio * size[1] / 2);
ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);
}
if (declutterReplays) {
this.declutterTree_.clear();
}
var tiles = this.renderedTiles;
var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
var clips = [];
@@ -443,7 +442,6 @@ ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, fra
}
if (declutterReplays) {
ol.render.canvas.ReplayGroup.replayDeclutter(declutterReplays, context, rotation);
this.declutterTree_.clear();
}
if (rotation) {
ol.render.canvas.rotateAtOffset(context, rotation,

View File

@@ -152,12 +152,13 @@ ol.source.ImageVector.prototype.canvasFunctionInternal_ = function(extent, resol
this.canvasContext_.clearRect(0, 0, size[0], size[1]);
}
this.declutterTree_.clear();
var transform = this.getTransform_(ol.extent.getCenter(extent),
resolution, pixelRatio, size);
replayGroup.replay(this.canvasContext_, transform, 0, {});
this.replayGroup_ = replayGroup;
this.declutterTree_.clear();
return this.canvasContext_.canvas;
};
@@ -186,7 +187,6 @@ ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function(
return callback(feature);
}
}, null);
this.declutterTree_.clear();
return result;
}
};