Merge pull request #7669 from ahocevar/hit-detect-declutter

Use declutter tree only for text and image replays
This commit is contained in:
Andreas Hocevar
2018-01-09 15:56:55 +01:00
committed by GitHub
2 changed files with 53 additions and 60 deletions

View File

@@ -322,18 +322,21 @@ _ol_render_canvas_ReplayGroup_.prototype.forEachFeatureAtCoordinate = function(
});
}
var replayType;
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
* @return {?} Callback result.
*/
function hitDetectionCallback(feature) {
function featureCallback(feature) {
var imageData = context.getImageData(0, 0, contextSize, contextSize).data;
for (var i = 0; i < contextSize; i++) {
for (var j = 0; j < contextSize; j++) {
if (mask[i][j]) {
if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
var result;
if (!declutteredFeatures || declutteredFeatures.indexOf(feature) !== -1) {
if (!(declutteredFeatures && (replayType == ReplayType.IMAGE || replayType == ReplayType.TEXT)) ||
declutteredFeatures.indexOf(feature) !== -1) {
result = callback(feature);
}
if (result) {
@@ -348,8 +351,37 @@ _ol_render_canvas_ReplayGroup_.prototype.forEachFeatureAtCoordinate = function(
}
}
return this.replayHitDetection_(context, transform, rotation,
skippedFeaturesHash, hitDetectionCallback, hitExtent, declutterReplays);
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(numberSafeCompareFunction);
var i, j, replays, replay, result;
for (i = zs.length - 1; i >= 0; --i) {
var zIndexKey = zs[i].toString();
replays = this.replaysByZIndex_[zIndexKey];
for (j = _ol_render_replay_.ORDER.length - 1; j >= 0; --j) {
replayType = _ol_render_replay_.ORDER[j];
replay = replays[replayType];
if (replay !== undefined) {
if (declutterReplays &&
(replayType == ReplayType.IMAGE || replayType == ReplayType.TEXT)) {
var declutter = declutterReplays[zIndexKey];
if (!declutter) {
declutterReplays[zIndexKey] = [replay, transform.slice(0)];
} else {
declutter.push(replay, transform.slice(0));
}
} else {
result = replay.replayHitDetection(context, transform, rotation,
skippedFeaturesHash, featureCallback, hitExtent);
if (result) {
return result;
}
}
}
}
}
return undefined;
};
@@ -458,59 +490,6 @@ _ol_render_canvas_ReplayGroup_.prototype.replay = function(context,
};
/**
* @private
* @param {CanvasRenderingContext2D} context Context.
* @param {ol.Transform} transform Transform.
* @param {number} viewRotation View rotation.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T} featureCallback
* Feature callback.
* @param {ol.Extent=} opt_hitExtent Only check features that intersect this
* extent.
* @param {Object.<string, ol.DeclutterGroup>=} opt_declutterReplays Declutter
* replays.
* @return {T|undefined} Callback result.
* @template T
*/
_ol_render_canvas_ReplayGroup_.prototype.replayHitDetection_ = function(
context, transform, viewRotation, skippedFeaturesHash,
featureCallback, opt_hitExtent, opt_declutterReplays) {
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(numberSafeCompareFunction);
var i, j, replays, replay, result;
for (i = zs.length - 1; i >= 0; --i) {
var zIndexKey = zs[i].toString();
replays = this.replaysByZIndex_[zIndexKey];
for (j = _ol_render_replay_.ORDER.length - 1; j >= 0; --j) {
var replayType = _ol_render_replay_.ORDER[j];
replay = replays[replayType];
if (replay !== undefined) {
if (opt_declutterReplays &&
(replayType == ReplayType.IMAGE || replayType == ReplayType.TEXT)) {
var declutter = opt_declutterReplays[zIndexKey];
if (!declutter) {
opt_declutterReplays[zIndexKey] = [replay, transform.slice(0)];
} else {
declutter.push(replay, transform.slice(0));
}
} else {
result = replay.replayHitDetection(context, transform, viewRotation,
skippedFeaturesHash, featureCallback, opt_hitExtent);
if (result) {
return result;
}
}
}
}
}
return undefined;
};
/**
* @const
* @private

View File

@@ -3,7 +3,7 @@ import Map from '../../../src/ol/Map.js';
import MapEvent from '../../../src/ol/MapEvent.js';
import Overlay from '../../../src/ol/Overlay.js';
import _ol_View_ from '../../../src/ol/View.js';
import Point from '../../../src/ol/geom/Point.js';
import LineString from '../../../src/ol/geom/LineString.js';
import _ol_has_ from '../../../src/ol/has.js';
import {defaults as defaultInteractions} from '../../../src/ol/interaction.js';
import DoubleClickZoom from '../../../src/ol/interaction/DoubleClickZoom.js';
@@ -197,12 +197,12 @@ describe('ol.Map', function() {
target: target,
layers: [new _ol_layer_Vector_({
source: new _ol_source_Vector_({
features: [new _ol_Feature_(new Point([0, 0]))]
features: [new _ol_Feature_(new LineString([[-50, 0], [50, 0]]))]
})
})],
view: new _ol_View_({
center: [0, 0],
zoom: 2
zoom: 17
})
});
map.renderSync();
@@ -222,6 +222,20 @@ describe('ol.Map', function() {
expect(features[0]).to.be.an(_ol_Feature_);
});
it('returns an array of found features with declutter: true', function() {
var layer = map.getLayers().item(0);
map.removeLayer(layer);
var otherLayer = new _ol_layer_Vector_({
declutter: true,
source: layer.getSource()
});
map.addLayer(otherLayer);
map.renderSync();
var features = map.getFeaturesAtPixel([50, 50]);
expect(features).to.be.an(Array);
expect(features[0]).to.be.an(_ol_Feature_);
});
it('respects options', function() {
var otherLayer = new _ol_layer_Vector_({
source: new _ol_source_Vector_