diff --git a/src/ol/render/canvas/replay.js b/src/ol/render/canvas/replay.js index 81e168e410..38923817d8 100644 --- a/src/ol/render/canvas/replay.js +++ b/src/ol/render/canvas/replay.js @@ -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: diff --git a/src/ol/render/canvas/replaygroup.js b/src/ol/render/canvas/replaygroup.js index c3ec7b4666..f37e7a3851 100644 --- a/src/ol/render/canvas/replaygroup.js +++ b/src/ol/render/canvas/replaygroup.js @@ -185,32 +185,20 @@ ol.render.canvas.ReplayGroup.getCircleArray_ = function(radius) { }; +/** + * @param {!Object.>} 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; }; diff --git a/src/ol/renderer/canvas/vectorlayer.js b/src/ol/renderer/canvas/vectorlayer.js index d1fca8eb10..173bef5b37 100644 --- a/src/ol/renderer/canvas/vectorlayer.js +++ b/src/ol/renderer/canvas/vectorlayer.js @@ -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.} */ 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; } }; diff --git a/src/ol/renderer/canvas/vectortilelayer.js b/src/ol/renderer/canvas/vectortilelayer.js index cbbe208c85..d77e440028 100644 --- a/src/ol/renderer/canvas/vectortilelayer.js +++ b/src/ol/renderer/canvas/vectortilelayer.js @@ -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.} */ 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, diff --git a/src/ol/source/imagevector.js b/src/ol/source/imagevector.js index 78352056d7..50e690a583 100644 --- a/src/ol/source/imagevector.js +++ b/src/ol/source/imagevector.js @@ -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; } };