Simplify API and code
This commit is contained in:
@@ -120,8 +120,10 @@ const ModifyEventType = {
|
|||||||
* features to modify. If a vector source is not provided, a layer or feature collection
|
* features to modify. If a vector source is not provided, a layer or feature collection
|
||||||
* must be provided with the `layer` or `features` option.
|
* must be provided with the `layer` or `features` option.
|
||||||
* @property {import("../layer/BaseVector").default} [layer] The layer with
|
* @property {import("../layer/BaseVector").default} [layer] The layer with
|
||||||
* features to modify. If a layer is not provided, a vector source or feature collection
|
* features to modify. When provided, point features will considered for modification based on
|
||||||
* must be provided with the `source` or `features` option.
|
* their visual appearance on this layer, instead of being within the `pixelTolerance` from the
|
||||||
|
* pointer location. When no `source` or `features` are configured, this layer's source will
|
||||||
|
* be used as source for modification candidates.
|
||||||
* @property {Collection<Feature>} [features]
|
* @property {Collection<Feature>} [features]
|
||||||
* The features the interaction works on. If a feature collection is not
|
* The features the interaction works on. If a feature collection is not
|
||||||
* provided, a layer or vector source must be provided with the `layer` or `source` option.
|
* provided, a layer or vector source must be provided with the `layer` or `source` option.
|
||||||
@@ -170,15 +172,12 @@ export class ModifyEvent extends Event {
|
|||||||
* the `features` option. The interaction must be constructed with either a
|
* the `features` option. The interaction must be constructed with either a
|
||||||
* `source`, `features` or `layer` option.
|
* `source`, `features` or `layer` option.
|
||||||
*
|
*
|
||||||
* When configured with a `source` or `features`, Cartesian distance from the
|
* Cartesian distance from the pointer is used to determine the features that
|
||||||
* pointer is used to determine all features that will be modified. This is the
|
* will be modified. This means that geometries will only be considered for
|
||||||
* preferred mode for modifying polygons or linestrings with shared edges or
|
* modification when they are within the configured `pixelTolerane`. For point
|
||||||
* vertices that have to be modified together to maintain topology.
|
* geometries, hit detection can be used to match their visual appearance. To
|
||||||
*
|
* enable hit detection, the interaction has to be configured with the `layer`
|
||||||
* When configured with a `layer`, pointer hit detection is used to determine the
|
* that contains the points.
|
||||||
* topmost feature that will be modified. This is the preferred mode for modifying
|
|
||||||
* points when the visual representation is much different from
|
|
||||||
* their geometry (e.g. large icons or icons with an offset).
|
|
||||||
*
|
*
|
||||||
* By default, the interaction will allow deletion of vertices when the `alt`
|
* By default, the interaction will allow deletion of vertices when the `alt`
|
||||||
* key is pressed. To configure the interaction with a different condition
|
* key is pressed. To configure the interaction with a different condition
|
||||||
@@ -339,21 +338,28 @@ class Modify extends PointerInteraction {
|
|||||||
this.layer_ = null;
|
this.layer_ = null;
|
||||||
|
|
||||||
let features;
|
let features;
|
||||||
if (options.source) {
|
if (options.features) {
|
||||||
this.source_ = options.source;
|
|
||||||
features = new Collection(this.source_.getFeatures());
|
|
||||||
this.source_.addEventListener(
|
|
||||||
VectorEventType.ADDFEATURE,
|
|
||||||
this.handleSourceAdd_.bind(this)
|
|
||||||
);
|
|
||||||
this.source_.addEventListener(
|
|
||||||
VectorEventType.REMOVEFEATURE,
|
|
||||||
this.handleSourceRemove_.bind(this)
|
|
||||||
);
|
|
||||||
} else if (options.features) {
|
|
||||||
features = options.features;
|
features = options.features;
|
||||||
} else if (options.layer) {
|
} else {
|
||||||
features = new Collection();
|
const source = options.source
|
||||||
|
? options.source
|
||||||
|
: options.layer
|
||||||
|
? options.layer.getSource()
|
||||||
|
: undefined;
|
||||||
|
if (source) {
|
||||||
|
this.source_ = source;
|
||||||
|
features = new Collection(this.source_.getFeatures());
|
||||||
|
this.source_.addEventListener(
|
||||||
|
VectorEventType.ADDFEATURE,
|
||||||
|
this.handleSourceAdd_.bind(this)
|
||||||
|
);
|
||||||
|
this.source_.addEventListener(
|
||||||
|
VectorEventType.REMOVEFEATURE,
|
||||||
|
this.handleSourceRemove_.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.layer) {
|
||||||
this.layer_ = options.layer;
|
this.layer_ = options.layer;
|
||||||
}
|
}
|
||||||
if (!features) {
|
if (!features) {
|
||||||
@@ -1116,68 +1122,51 @@ class Modify extends PointerInteraction {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const rBush = this.rBush_;
|
let box, hitPointGeometry;
|
||||||
/** @type {import("../geom/SimpleGeometry").default} */
|
|
||||||
let geometry;
|
|
||||||
let point = false;
|
|
||||||
let nodes;
|
|
||||||
if (this.layer_) {
|
if (this.layer_) {
|
||||||
const feature = map.forEachFeatureAtPixel(
|
map.forEachFeatureAtPixel(
|
||||||
pixel,
|
pixel,
|
||||||
(feature, layer, geom) => {
|
(feature, layer, geometry) => {
|
||||||
geometry = geom || feature.getGeometry();
|
geometry = geometry || feature.getGeometry();
|
||||||
return feature;
|
if (geometry.getType() === GeometryType.POINT) {
|
||||||
|
hitPointGeometry = geometry;
|
||||||
|
box = hitPointGeometry.getExtent();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
layerFilter: (layer) => layer === this.layer_,
|
layerFilter: (layer) => layer === this.layer_,
|
||||||
hitTolerance: this.pixelTolerance_,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (feature && feature !== this.features_.item(0)) {
|
}
|
||||||
this.features_.setAt(0, feature);
|
if (!box) {
|
||||||
}
|
|
||||||
if (!feature) {
|
|
||||||
this.features_.clear();
|
|
||||||
}
|
|
||||||
if (geometry) {
|
|
||||||
nodes = rBush.getInExtent(geometry.getExtent());
|
|
||||||
const type = geometry.getType();
|
|
||||||
if (type === GeometryType.POINT || type === GeometryType.MULTI_POINT) {
|
|
||||||
point = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const viewExtent = fromUserExtent(
|
const viewExtent = fromUserExtent(
|
||||||
createExtent(pixelCoordinate, tempExtent),
|
createExtent(pixelCoordinate, tempExtent),
|
||||||
projection
|
projection
|
||||||
);
|
);
|
||||||
const buffer = map.getView().getResolution() * this.pixelTolerance_;
|
const buffer = map.getView().getResolution() * this.pixelTolerance_;
|
||||||
const box = toUserExtent(
|
box = toUserExtent(
|
||||||
bufferExtent(viewExtent, buffer, tempExtent),
|
bufferExtent(viewExtent, buffer, tempExtent),
|
||||||
projection
|
projection
|
||||||
);
|
);
|
||||||
nodes = rBush.getInExtent(box);
|
|
||||||
}
|
}
|
||||||
|
const nodes = this.rBush_.getInExtent(box);
|
||||||
|
|
||||||
if (nodes && nodes.length > 0) {
|
if (nodes && nodes.length > 0) {
|
||||||
nodes.sort(sortByDistance);
|
const node = nodes.sort(sortByDistance)[0];
|
||||||
const node = nodes[0];
|
|
||||||
if (!geometry) {
|
|
||||||
geometry = node.geometry;
|
|
||||||
}
|
|
||||||
const closestSegment = node.segment;
|
const closestSegment = node.segment;
|
||||||
let vertex = closestOnSegmentData(pixelCoordinate, node, projection);
|
let vertex = closestOnSegmentData(pixelCoordinate, node, projection);
|
||||||
const vertexPixel = map.getPixelFromCoordinate(vertex);
|
const vertexPixel = map.getPixelFromCoordinate(vertex);
|
||||||
let dist = coordinateDistance(pixel, vertexPixel);
|
let dist = coordinateDistance(pixel, vertexPixel);
|
||||||
if (point || dist <= this.pixelTolerance_) {
|
if (hitPointGeometry || dist <= this.pixelTolerance_) {
|
||||||
/** @type {Object<string, boolean>} */
|
/** @type {Object<string, boolean>} */
|
||||||
const vertexSegments = {};
|
const vertexSegments = {};
|
||||||
vertexSegments[getUid(closestSegment)] = true;
|
vertexSegments[getUid(closestSegment)] = true;
|
||||||
|
|
||||||
this.delta_[0] = point ? vertex[0] - pixelCoordinate[0] : 0;
|
this.delta_[0] = hitPointGeometry ? vertex[0] - pixelCoordinate[0] : 0;
|
||||||
this.delta_[1] = point ? vertex[1] - pixelCoordinate[1] : 0;
|
this.delta_[1] = hitPointGeometry ? vertex[1] - pixelCoordinate[1] : 0;
|
||||||
if (
|
if (
|
||||||
geometry.getType() === GeometryType.CIRCLE &&
|
node.geometry.getType() === GeometryType.CIRCLE &&
|
||||||
node.index === CIRCLE_CIRCUMFERENCE_INDEX
|
node.index === CIRCLE_CIRCUMFERENCE_INDEX
|
||||||
) {
|
) {
|
||||||
this.snappedToVertex_ = true;
|
this.snappedToVertex_ = true;
|
||||||
@@ -1205,7 +1194,7 @@ class Modify extends PointerInteraction {
|
|||||||
[node.geometry]
|
[node.geometry]
|
||||||
);
|
);
|
||||||
const geometries = {};
|
const geometries = {};
|
||||||
geometries[getUid(geometry)] = true;
|
geometries[getUid(node.geometry)] = true;
|
||||||
for (let i = 1, ii = nodes.length; i < ii; ++i) {
|
for (let i = 1, ii = nodes.length; i < ii; ++i) {
|
||||||
const segment = nodes[i].segment;
|
const segment = nodes[i].segment;
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -195,6 +195,55 @@ describe('ol.interaction.Modify', function () {
|
|||||||
expect(rbushEntries.length).to.be(1);
|
expect(rbushEntries.length).to.be(1);
|
||||||
expect(rbushEntries[0].feature).to.be(feature);
|
expect(rbushEntries[0].feature).to.be(feature);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('accepts a layer for modification features', function () {
|
||||||
|
const feature = new Feature(new Point([0, 0]));
|
||||||
|
const source = new VectorSource({features: [feature]});
|
||||||
|
const layer = new VectorLayer({source: source});
|
||||||
|
const modify = new Modify({layer: layer});
|
||||||
|
const rbushEntries = modify.rBush_.getAll();
|
||||||
|
expect(rbushEntries.length).to.be(1);
|
||||||
|
expect(rbushEntries[0].feature).to.be(feature);
|
||||||
|
expect(modify.layer_).to.be(layer);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts a layer in addition to a features collection', function () {
|
||||||
|
const feature = new Feature(new Point([0, 0]));
|
||||||
|
const source = new VectorSource({features: [feature]});
|
||||||
|
const layer = new VectorLayer({source: source});
|
||||||
|
const features = new Collection([new Feature(new Point([1, 1]))]);
|
||||||
|
const modify = new Modify({layer: layer, features: features});
|
||||||
|
const rbushEntries = modify.rBush_.getAll();
|
||||||
|
expect(rbushEntries.length).to.be(1);
|
||||||
|
expect(rbushEntries[0].feature).to.be(features.item(0));
|
||||||
|
expect(modify.layer_).to.be(layer);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts a layer in addition to a features collection', function () {
|
||||||
|
const feature = new Feature(new Point([0, 0]));
|
||||||
|
const source = new VectorSource({features: [feature]});
|
||||||
|
const layer = new VectorLayer({source: source});
|
||||||
|
const features = new Collection([new Feature(new Point([1, 1]))]);
|
||||||
|
const modify = new Modify({layer: layer, features: features});
|
||||||
|
const rbushEntries = modify.rBush_.getAll();
|
||||||
|
expect(rbushEntries.length).to.be(1);
|
||||||
|
expect(rbushEntries[0].feature).to.be(features.item(0));
|
||||||
|
expect(modify.layer_).to.be(layer);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts a layer in addition to a source', function () {
|
||||||
|
const feature = new Feature(new Point([0, 0]));
|
||||||
|
const source = new VectorSource({features: [feature]});
|
||||||
|
const layer = new VectorLayer({source: source});
|
||||||
|
const candidateSource = new VectorSource({
|
||||||
|
features: [new Feature(new Point([1, 1]))],
|
||||||
|
});
|
||||||
|
const modify = new Modify({layer: layer, source: candidateSource});
|
||||||
|
const rbushEntries = modify.rBush_.getAll();
|
||||||
|
expect(rbushEntries.length).to.be(1);
|
||||||
|
expect(rbushEntries[0].feature).to.be(candidateSource.getFeatures()[0]);
|
||||||
|
expect(modify.layer_).to.be(layer);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('vertex deletion', function () {
|
describe('vertex deletion', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user