From 78039aceb8cd57c0038cc9cd7a8c77c780360e68 Mon Sep 17 00:00:00 2001 From: Antoine Abt Date: Thu, 20 Mar 2014 13:03:31 +0100 Subject: [PATCH] Use a hash to store features uids --- externs/oli.js | 4 +- src/ol/map.js | 36 +++++++++++++-- src/ol/render/canvas/canvasreplay.js | 46 +++++++++---------- .../canvas/canvasvectorlayerrenderer.js | 4 +- src/ol/source/imagevectorsource.js | 4 +- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/externs/oli.js b/externs/oli.js index d214f823f4..8ad98ea52a 100644 --- a/externs/oli.js +++ b/externs/oli.js @@ -92,8 +92,8 @@ oli.FrameState.prototype.postRenderFunctions; oli.FrameState.prototype.size; -/** @type {Array.} */ -oli.FrameState.prototype.skippedFeaturesIds_; +/** @type {Object} */ +oli.FrameState.prototype.skippedFeaturesHash_; /** @type {ol.TileQueue} */ diff --git a/src/ol/map.js b/src/ol/map.js index a179dd23af..0b5b72465b 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -366,10 +366,17 @@ ol.Map = function(options) { */ this.skippedFeatures_ = new ol.Collection(); goog.events.listen(this.skippedFeatures_, - [ol.CollectionEventType.ADD, ol.CollectionEventType.remove], - this.render, false, this); + [ol.CollectionEventType.ADD, ol.CollectionEventType.REMOVE], + this.handleSkippedFeaturesChange_, false, this); this.registerDisposable(this.skippedFeatures_); + /** + * Hash of features uid to skip drawing. + * @type {Object} + * @private + */ + this.skippedFeaturesHash_ = {}; + goog.events.listen( this, ol.Object.getChangeEventType(ol.MapProperty.LAYERGROUP), this.handleLayerGroupChanged_, false, this); @@ -818,6 +825,16 @@ ol.Map.prototype.getSkippedFeatures = function() { }; +/** + * Get the hash of features uids to be skipped. + * @return {Object} Features uids hash + * @todo stability experimental + */ +ol.Map.prototype.getSkippedFeaturesHash = function() { + return this.skippedFeaturesHash_; +}; + + /** * @param {goog.events.BrowserEvent} browserEvent Browser event. * @param {string=} opt_type Type. @@ -917,6 +934,18 @@ ol.Map.prototype.handleSizeChanged_ = function() { }; +/** + * @private + */ +ol.Map.prototype.handleSkippedFeaturesChange_ = function() { + this.skippedFeaturesHash_ = {}; + this.skippedFeatures_.forEach(function(feature) { + this.skippedFeaturesHash_[goog.getUid(feature).toString()] = true; + }, this); + this.render(); +}; + + /** * @private */ @@ -1202,8 +1231,7 @@ ol.Map.prototype.renderFrame_ = function(time) { pixelToCoordinateMatrix: this.pixelToCoordinateMatrix_, postRenderFunctions: [], size: size, - skippedFeaturesIds: goog.array.map( - this.skippedFeatures_.getArray(), goog.getUid), + skippedFeaturesHash_: this.skippedFeaturesHash_, tileQueue: this.tileQueue_, time: time, usedTiles: {}, diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index 0d2787ce55..18a15c9db5 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -209,7 +209,7 @@ ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, uid) { this.beginGeometryInstruction1_ = [ol.render.canvas.Instruction.BEGIN_GEOMETRY, geometry, 0]; this.instructions.push(this.beginGeometryInstruction1_); - this.instructionIndices_[this.instructions.length - 1] = uid; + this.instructionIndices_[this.instructions.length - 1] = uid.toString(); this.beginGeometryInstruction2_ = [ol.render.canvas.Instruction.BEGIN_GEOMETRY, geometry, 0]; this.hitDetectionInstructions.push(this.beginGeometryInstruction2_); @@ -222,7 +222,7 @@ ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, uid) { * @param {number} pixelRatio Pixel ratio. * @param {goog.vec.Mat4.Number} transform Transform. * @param {number} viewRotation View rotation. - * @param {Array.} skippedFeaturesIds Ids of features to skip. + * @param {Object} skippedFeaturesHash Ids of features to skip. * @param {Array.<*>} instructions Instructions array. * @param {function(ol.geom.Geometry, Object): T|undefined} geometryCallback * Geometry callback. @@ -230,7 +230,7 @@ ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, uid) { * @template T */ ol.render.canvas.Replay.prototype.replay_ = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesIds, + context, pixelRatio, transform, viewRotation, skippedFeaturesHash, instructions, geometryCallback) { /** @type {Array.} */ var pixelCoordinates; @@ -254,8 +254,8 @@ ol.render.canvas.Replay.prototype.replay_ = function( switch (type) { case ol.render.canvas.Instruction.BEGIN_GEOMETRY: geometry = /** @type {ol.geom.Geometry} */ (instruction[1]); - if (!goog.array.contains(skippedFeaturesIds, - this.instructionIndices_[i])) { + if (!goog.isDef(goog.object.get(skippedFeaturesHash, + this.instructionIndices_[i]))) { ++i; } else { i = /** @type {number} */ (instruction[2]); @@ -461,15 +461,15 @@ ol.render.canvas.Replay.prototype.replay_ = function( * @param {number} pixelRatio Pixel ratio. * @param {goog.vec.Mat4.Number} transform Transform. * @param {number} viewRotation View rotation. - * @param {Array.} skippedFeaturesIds Ids of features to skip + * @param {Object} skippedFeaturesHash Ids of features to skip * @return {T|undefined} Callback result. * @template T */ ol.render.canvas.Replay.prototype.replay = function( - context, pixelRatio, transform, viewRotation, skippedFeaturesIds) { + context, pixelRatio, transform, viewRotation, skippedFeaturesHash) { var instructions = this.instructions; return this.replay_(context, pixelRatio, transform, viewRotation, - skippedFeaturesIds, instructions, undefined); + skippedFeaturesHash, instructions, undefined); }; @@ -477,18 +477,18 @@ ol.render.canvas.Replay.prototype.replay = function( * @param {CanvasRenderingContext2D} context Context. * @param {goog.vec.Mat4.Number} transform Transform. * @param {number} viewRotation View rotation. - * @param {Array.} skippedFeaturesIds Ids of features to skip + * @param {Object} skippedFeaturesHash Ids of features to skip * @param {function(ol.geom.Geometry, Object): T=} opt_geometryCallback * Geometry callback. * @return {T|undefined} Callback result. * @template T */ ol.render.canvas.Replay.prototype.replayHitDetection = function( - context, transform, viewRotation, skippedFeaturesIds, + context, transform, viewRotation, skippedFeaturesHash, opt_geometryCallback) { var instructions = this.hitDetectionInstructions; return this.replay_(context, 1, transform, viewRotation, - skippedFeaturesIds, instructions, opt_geometryCallback); + skippedFeaturesHash, instructions, opt_geometryCallback); }; @@ -1850,17 +1850,17 @@ ol.render.canvas.ReplayGroup = function(tolerance, maxExtent, resolution) { * @param {number} pixelRatio Pixel ratio. * @param {goog.vec.Mat4.Number} transform Transform. * @param {number} viewRotation View rotation. - * @param {Array.} skippedFeaturesIds Ids of features to skip + * @param {Object} skippedFeaturesHash Ids of features to skip * @return {T|undefined} Callback result. * @template T */ ol.render.canvas.ReplayGroup.prototype.replay = function(context, extent, - pixelRatio, transform, viewRotation, skippedFeaturesIds) { + pixelRatio, transform, viewRotation, skippedFeaturesHash) { /** @type {Array.} */ var zs = goog.array.map(goog.object.getKeys(this.replaysByZIndex_), Number); goog.array.sort(zs); return this.replay_(zs, context, extent, pixelRatio, transform, - viewRotation, skippedFeaturesIds); + viewRotation, skippedFeaturesHash); }; @@ -1871,14 +1871,14 @@ ol.render.canvas.ReplayGroup.prototype.replay = function(context, extent, * @param {ol.Extent} extent Extent. * @param {goog.vec.Mat4.Number} transform Transform. * @param {number} viewRotation View rotation. - * @param {Array.} skippedFeaturesIds Ids of features to skip + * @param {Object} skippedFeaturesHash Ids of features to skip * @param {function(ol.geom.Geometry, Object): T} geometryCallback Geometry * callback. * @return {T|undefined} Callback result. * @template T */ ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( - zs, context, extent, transform, viewRotation, skippedFeaturesIds, + zs, context, extent, transform, viewRotation, skippedFeaturesHash, geometryCallback) { var i, ii, replays, replayType, replay, result; for (i = 0, ii = zs.length; i < ii; ++i) { @@ -1887,7 +1887,7 @@ ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( replay = replays[replayType]; if (ol.extent.intersects(extent, replay.getExtent())) { result = replay.replayHitDetection(context, transform, viewRotation, - skippedFeaturesIds, geometryCallback); + skippedFeaturesHash, geometryCallback); if (result) { return result; } @@ -1906,13 +1906,13 @@ ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function( * @param {number} pixelRatio Pixel ratio. * @param {goog.vec.Mat4.Number} transform Transform. * @param {number} viewRotation View rotation. - * @param {Array.} skippedFeaturesIds Ids of features to skip + * @param {Object} skippedFeaturesHash Ids of features to skip * @return {T|undefined} Callback result. * @template T */ ol.render.canvas.ReplayGroup.prototype.replay_ = function( zs, context, extent, pixelRatio, transform, viewRotation, - skippedFeaturesIds) { + skippedFeaturesHash) { var maxExtent = this.maxExtent_; var minX = maxExtent[0]; @@ -1938,7 +1938,7 @@ ol.render.canvas.ReplayGroup.prototype.replay_ = function( if (goog.isDef(replay) && ol.extent.intersects(extent, replay.getExtent())) { result = replay.replay(context, pixelRatio, transform, viewRotation, - skippedFeaturesIds); + skippedFeaturesHash); if (result) { return result; } @@ -1956,14 +1956,14 @@ ol.render.canvas.ReplayGroup.prototype.replay_ = function( * @param {number} resolution Resolution. * @param {number} rotation Rotation. * @param {ol.Coordinate} coordinate Coordinate. - * @param {Array.} skippedFeaturesIds Ids of features to skip + * @param {Object} skippedFeaturesHash Ids of features to skip * @param {function(ol.geom.Geometry, Object): T} callback Geometry callback. * @return {T|undefined} Callback result. * @template T */ ol.render.canvas.ReplayGroup.prototype.forEachGeometryAtPixel = function( extent, resolution, rotation, coordinate, - skippedFeaturesIds, callback) { + skippedFeaturesHash, callback) { var transform = this.hitDetectionTransform_; ol.vec.Mat4.makeTransform2D(transform, 0.5, 0.5, @@ -1978,7 +1978,7 @@ ol.render.canvas.ReplayGroup.prototype.forEachGeometryAtPixel = function( context.clearRect(0, 0, 1, 1); return this.replayHitDetection_(zs, context, extent, transform, - rotation, skippedFeaturesIds, + rotation, skippedFeaturesHash, /** * @param {ol.geom.Geometry} geometry Geometry. * @param {Object} data Opaque data object. diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js index e5131bd7a1..98cb70b2f9 100644 --- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js @@ -98,7 +98,7 @@ ol.renderer.canvas.VectorLayer.prototype.composeFrame = replayContext.globalAlpha = layerState.opacity; replayGroup.replay( replayContext, frameState.extent, frameState.pixelRatio, transform, - frameState.view2DState.rotation, frameState.skippedFeaturesIds_); + frameState.view2DState.rotation, frameState.skippedFeaturesHash_); if (replayContext != context) { this.dispatchRenderEvent(replayContext, frameState, transform); @@ -124,7 +124,7 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtPixel = var rotation = frameState.view2DState.rotation; var layer = this.getLayer(); return this.replayGroup_.forEachGeometryAtPixel(extent, resolution, - rotation, coordinate, frameState.skippedFeaturesIds_, + rotation, coordinate, frameState.skippedFeaturesHash_, /** * @param {ol.geom.Geometry} geometry Geometry. * @param {Object} data Data. diff --git a/src/ol/source/imagevectorsource.js b/src/ol/source/imagevectorsource.js index f4a436ee17..be8d85e463 100644 --- a/src/ol/source/imagevectorsource.js +++ b/src/ol/source/imagevectorsource.js @@ -141,7 +141,7 @@ ol.source.ImageVector.prototype.canvasFunctionInternal_ = var transform = this.getTransform_(ol.extent.getCenter(extent), resolution, pixelRatio, size); replayGroup.replay(this.canvasContext_, extent, pixelRatio, transform, 0, - []); + {}); this.replayGroup_ = replayGroup; @@ -158,7 +158,7 @@ ol.source.ImageVector.prototype.forEachFeatureAtPixel = return undefined; } else { return this.replayGroup_.forEachGeometryAtPixel( - extent, resolution, 0, coordinate, [], + extent, resolution, 0, coordinate, {}, /** * @param {ol.geom.Geometry} geometry Geometry. * @param {Object} data Data.