Check hits for wrapped around geometries
This commit is contained in:
@@ -75,6 +75,8 @@ import {toUserCoordinate, fromUserCoordinate} from './proj.js';
|
|||||||
* will be tested for features. By default, all visible layers will be tested.
|
* will be tested for features. By default, all visible layers will be tested.
|
||||||
* @property {number} [hitTolerance=0] Hit-detection tolerance in pixels. Pixels
|
* @property {number} [hitTolerance=0] Hit-detection tolerance in pixels. Pixels
|
||||||
* inside the radius around the given position will be checked for features.
|
* inside the radius around the given position will be checked for features.
|
||||||
|
* @property {boolean} [checkWrapped=true] Check-Wrapped Will check for for wrapped geometries inside the range of
|
||||||
|
* +/- 1 world width. Works only if a projection is used that can be wrapped.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -553,8 +555,9 @@ class PluggableMap extends BaseObject {
|
|||||||
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
|
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
|
||||||
const layerFilter = opt_options.layerFilter !== undefined ?
|
const layerFilter = opt_options.layerFilter !== undefined ?
|
||||||
opt_options.layerFilter : TRUE;
|
opt_options.layerFilter : TRUE;
|
||||||
|
const checkWrapped = opt_options.checkWrapped !== false;
|
||||||
return this.renderer_.forEachFeatureAtCoordinate(
|
return this.renderer_.forEachFeatureAtCoordinate(
|
||||||
coordinate, this.frameState_, hitTolerance, callback, null,
|
coordinate, this.frameState_, hitTolerance, checkWrapped, callback, null,
|
||||||
layerFilter, null);
|
layerFilter, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,8 +627,9 @@ class PluggableMap extends BaseObject {
|
|||||||
const layerFilter = opt_options.layerFilter !== undefined ? opt_options.layerFilter : TRUE;
|
const layerFilter = opt_options.layerFilter !== undefined ? opt_options.layerFilter : TRUE;
|
||||||
const hitTolerance = opt_options.hitTolerance !== undefined ?
|
const hitTolerance = opt_options.hitTolerance !== undefined ?
|
||||||
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
|
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
|
||||||
|
const checkWrapped = opt_options.checkWrapped !== false;
|
||||||
return this.renderer_.hasFeatureAtCoordinate(
|
return this.renderer_.hasFeatureAtCoordinate(
|
||||||
coordinate, this.frameState_, hitTolerance, layerFilter, null);
|
coordinate, this.frameState_, hitTolerance, checkWrapped, layerFilter, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ class LayerRenderer extends Observable {
|
|||||||
}
|
}
|
||||||
).bind(this);
|
).bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {inView} from '../layer/Layer.js';
|
|||||||
import {shared as iconImageCache} from '../style/IconImageCache.js';
|
import {shared as iconImageCache} from '../style/IconImageCache.js';
|
||||||
import {compose as composeTransform, makeInverse} from '../transform.js';
|
import {compose as composeTransform, makeInverse} from '../transform.js';
|
||||||
import {renderDeclutterItems} from '../render.js';
|
import {renderDeclutterItems} from '../render.js';
|
||||||
|
import {add} from '../coordinate.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract
|
* @abstract
|
||||||
@@ -65,6 +66,7 @@ class MapRenderer extends Disposable {
|
|||||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||||
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
|
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
|
||||||
* @param {number} hitTolerance Hit tolerance in pixels.
|
* @param {number} hitTolerance Hit tolerance in pixels.
|
||||||
|
* @param {boolean} checkWrapped Check for wrapped geometries.
|
||||||
* @param {function(this: S, import("../Feature.js").FeatureLike,
|
* @param {function(this: S, import("../Feature.js").FeatureLike,
|
||||||
* import("../layer/Layer.js").default): T} callback Feature callback.
|
* import("../layer/Layer.js").default): T} callback Feature callback.
|
||||||
* @param {S} thisArg Value to use as `this` when executing `callback`.
|
* @param {S} thisArg Value to use as `this` when executing `callback`.
|
||||||
@@ -80,6 +82,7 @@ class MapRenderer extends Disposable {
|
|||||||
coordinate,
|
coordinate,
|
||||||
frameState,
|
frameState,
|
||||||
hitTolerance,
|
hitTolerance,
|
||||||
|
checkWrapped,
|
||||||
callback,
|
callback,
|
||||||
thisArg,
|
thisArg,
|
||||||
layerFilter,
|
layerFilter,
|
||||||
@@ -103,6 +106,7 @@ class MapRenderer extends Disposable {
|
|||||||
const projection = viewState.projection;
|
const projection = viewState.projection;
|
||||||
|
|
||||||
let translatedCoordinate = coordinate;
|
let translatedCoordinate = coordinate;
|
||||||
|
const offsets = [[0, 0]];
|
||||||
if (projection.canWrapX()) {
|
if (projection.canWrapX()) {
|
||||||
const projectionExtent = projection.getExtent();
|
const projectionExtent = projection.getExtent();
|
||||||
const worldWidth = getWidth(projectionExtent);
|
const worldWidth = getWidth(projectionExtent);
|
||||||
@@ -111,6 +115,9 @@ class MapRenderer extends Disposable {
|
|||||||
const worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
|
const worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
|
||||||
translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]];
|
translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]];
|
||||||
}
|
}
|
||||||
|
if (checkWrapped) {
|
||||||
|
offsets.push([-worldWidth, 0], [worldWidth, 0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const layerStates = frameState.layerStatesArray;
|
const layerStates = frameState.layerStatesArray;
|
||||||
@@ -121,21 +128,22 @@ class MapRenderer extends Disposable {
|
|||||||
return entry.value;
|
return entry.value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let i;
|
for (let i = 0; i < offsets.length; i++) {
|
||||||
for (i = numLayers - 1; i >= 0; --i) {
|
for (let j = numLayers - 1; j >= 0; --j) {
|
||||||
const layerState = layerStates[i];
|
const layerState = layerStates[j];
|
||||||
const layer = /** @type {import("../layer/Layer.js").default} */ (layerState.layer);
|
const layer = /** @type {import("../layer/Layer.js").default} */ (layerState.layer);
|
||||||
if (layer.hasRenderer() && inView(layerState, viewState) && layerFilter.call(thisArg2, layer)) {
|
if (layer.hasRenderer() && inView(layerState, viewState) && layerFilter.call(thisArg2, layer)) {
|
||||||
const layerRenderer = layer.getRenderer();
|
const layerRenderer = layer.getRenderer();
|
||||||
const source = layer.getSource();
|
const source = layer.getSource();
|
||||||
if (layerRenderer && source) {
|
if (layerRenderer && source) {
|
||||||
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
|
const callback = forEachFeatureAtCoordinate.bind(null, layerState.managed);
|
||||||
result = layerRenderer.forEachFeatureAtCoordinate(
|
result = layerRenderer.forEachFeatureAtCoordinate(
|
||||||
source.getWrapX() ? translatedCoordinate : coordinate,
|
add(source.getWrapX() ? translatedCoordinate : coordinate, offsets[i]),
|
||||||
frameState, hitTolerance, callback, declutteredFeatures);
|
frameState, hitTolerance, callback, declutteredFeatures);
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,6 +172,7 @@ class MapRenderer extends Disposable {
|
|||||||
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
* @param {import("../coordinate.js").Coordinate} coordinate Coordinate.
|
||||||
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
|
* @param {import("../PluggableMap.js").FrameState} frameState FrameState.
|
||||||
* @param {number} hitTolerance Hit tolerance in pixels.
|
* @param {number} hitTolerance Hit tolerance in pixels.
|
||||||
|
* @param {boolean} checkWrapped Check for wrapped geometries.
|
||||||
* @param {function(this: U, import("../layer/Layer.js").default): boolean} layerFilter Layer filter
|
* @param {function(this: U, import("../layer/Layer.js").default): boolean} layerFilter Layer filter
|
||||||
* function, only layers which are visible and for which this function
|
* function, only layers which are visible and for which this function
|
||||||
* returns `true` will be tested for features. By default, all visible
|
* returns `true` will be tested for features. By default, all visible
|
||||||
@@ -172,9 +181,9 @@ class MapRenderer extends Disposable {
|
|||||||
* @return {boolean} Is there a feature at the given coordinate?
|
* @return {boolean} Is there a feature at the given coordinate?
|
||||||
* @template U
|
* @template U
|
||||||
*/
|
*/
|
||||||
hasFeatureAtCoordinate(coordinate, frameState, hitTolerance, layerFilter, thisArg) {
|
hasFeatureAtCoordinate(coordinate, frameState, hitTolerance, checkWrapped, layerFilter, thisArg) {
|
||||||
const hasFeature = this.forEachFeatureAtCoordinate(
|
const hasFeature = this.forEachFeatureAtCoordinate(
|
||||||
coordinate, frameState, hitTolerance, TRUE, this, layerFilter, thisArg);
|
coordinate, frameState, hitTolerance, checkWrapped, TRUE, this, layerFilter, thisArg);
|
||||||
|
|
||||||
return hasFeature !== undefined;
|
return hasFeature !== undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
const layer = this.getLayer();
|
const layer = this.getLayer();
|
||||||
/** @type {!Object<string, boolean>} */
|
/** @type {!Object<string, boolean>} */
|
||||||
const features = {};
|
const features = {};
|
||||||
|
|
||||||
const result = this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, rotation, hitTolerance,
|
const result = this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, rotation, hitTolerance,
|
||||||
/**
|
/**
|
||||||
* @param {import("../../Feature.js").FeatureLike} feature Feature.
|
* @param {import("../../Feature.js").FeatureLike} feature Feature.
|
||||||
@@ -214,6 +215,7 @@ class CanvasVectorLayerRenderer extends CanvasLayerRenderer {
|
|||||||
return callback(feature, layer);
|
return callback(feature, layer);
|
||||||
}
|
}
|
||||||
}, layer.getDeclutter() ? declutteredFeatures : null);
|
}, layer.getDeclutter() ? declutteredFeatures : null);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user