Merge pull request #13455 from MoonE/snap-load

Improve Snap interaction performance
This commit is contained in:
MoonE
2022-03-08 01:16:16 +01:00
committed by GitHub
3 changed files with 75 additions and 96 deletions
+6 -9
View File
@@ -16,15 +16,6 @@ tags: "draw, edit, modify, vector, snap"
<input type="radio" name="interaction" value="draw" id="draw" checked> <input type="radio" name="interaction" value="draw" id="draw" checked>
Draw &nbsp; Draw &nbsp;
</label> </label>
</div>
<div class="radio">
<label>
<input type="radio" name="interaction" value="modify">
Modify &nbsp;
</label>
</div>
<div class="form-group">
<label for="draw-type">Draw type &nbsp;</label>
<select name="draw-type" id="draw-type"> <select name="draw-type" id="draw-type">
<option value="Point">Point</option> <option value="Point">Point</option>
<option value="LineString">LineString</option> <option value="LineString">LineString</option>
@@ -32,4 +23,10 @@ tags: "draw, edit, modify, vector, snap"
<option value="Circle">Circle</option> <option value="Circle">Circle</option>
</select> </select>
</div> </div>
<div class="radio">
<label>
<input type="radio" name="interaction" value="modify">
Modify &nbsp;
</label>
</div>
</form> </form>
+14 -14
View File
@@ -94,18 +94,16 @@ const ExampleDraw = {
source: vector.getSource(), source: vector.getSource(),
type: 'Circle', type: 'Circle',
}), }),
getActive: function () { activeDraw: null,
return this.activeType ? this[this.activeType].getActive() : false;
},
setActive: function (active) { setActive: function (active) {
const type = optionsForm.elements['draw-type'].value; if (this.activeDraw) {
this.activeDraw.setActive(false);
this.activeDraw = null;
}
if (active) { if (active) {
this.activeType && this[this.activeType].setActive(false); const type = optionsForm.elements['draw-type'].value;
this[type].setActive(true); this.activeDraw = this[type];
this.activeType = type; this.activeDraw.setActive(true);
} else {
this.activeType && this[this.activeType].setActive(false);
this.activeType = null;
} }
}, },
}; };
@@ -117,14 +115,16 @@ ExampleDraw.init();
*/ */
optionsForm.onchange = function (e) { optionsForm.onchange = function (e) {
const type = e.target.getAttribute('name'); const type = e.target.getAttribute('name');
const value = e.target.value;
if (type == 'draw-type') { if (type == 'draw-type') {
ExampleDraw.getActive() && ExampleDraw.setActive(true); ExampleModify.setActive(false);
ExampleDraw.setActive(true);
optionsForm.elements['interaction'].value = 'draw';
} else if (type == 'interaction') { } else if (type == 'interaction') {
if (value == 'modify') { const interactionType = e.target.value;
if (interactionType == 'modify') {
ExampleDraw.setActive(false); ExampleDraw.setActive(false);
ExampleModify.setActive(true); ExampleModify.setActive(true);
} else if (value == 'draw') { } else if (interactionType == 'draw') {
ExampleDraw.setActive(true); ExampleDraw.setActive(true);
ExampleModify.setActive(false); ExampleModify.setActive(false);
} }
+55 -73
View File
@@ -181,18 +181,18 @@ class Snap extends PointerInteraction {
/** /**
* @const * @const
* @private * @private
* @type {Object<string, function(import("../Feature.js").default, import("../geom/Geometry.js").default): void>} * @type {Object<string, function(Array<Array<import('../coordinate.js').Coordinate>>, import("../geom/Geometry.js").default): void>}
*/ */
this.SEGMENT_WRITERS_ = { this.GEOMETRY_SEGMENTERS_ = {
'Point': this.writePointGeometry_.bind(this), 'Point': this.segmentPointGemetry_.bind(this),
'LineString': this.writeLineStringGeometry_.bind(this), 'LineString': this.segmentLineStringGemetry_.bind(this),
'LinearRing': this.writeLineStringGeometry_.bind(this), 'LinearRing': this.segmentLineStringGemetry_.bind(this),
'Polygon': this.writePolygonGeometry_.bind(this), 'Polygon': this.segmentPolygonGemetry_.bind(this),
'MultiPoint': this.writeMultiPointGeometry_.bind(this), 'MultiPoint': this.segmentMultiPointGemetry_.bind(this),
'MultiLineString': this.writeMultiLineStringGeometry_.bind(this), 'MultiLineString': this.segmentMultiLineStringGemetry_.bind(this),
'MultiPolygon': this.writeMultiPolygonGeometry_.bind(this), 'MultiPolygon': this.segmentMultiPolygonGemetry_.bind(this),
'GeometryCollection': this.writeGeometryCollectionGeometry_.bind(this), 'GeometryCollection': this.segmentGeometryCollectionGemetry_.bind(this),
'Circle': this.writeCircleGeometry_.bind(this), 'Circle': this.segmentCircleGemetry_.bind(this),
}; };
} }
@@ -208,12 +208,27 @@ class Snap extends PointerInteraction {
const feature_uid = getUid(feature); const feature_uid = getUid(feature);
const geometry = feature.getGeometry(); const geometry = feature.getGeometry();
if (geometry) { if (geometry) {
const segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()]; const segmenter = this.GEOMETRY_SEGMENTERS_[geometry.getType()];
if (segmentWriter) { if (segmenter) {
this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent( this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(
createEmpty() createEmpty()
); );
segmentWriter(feature, geometry); const segments =
/** @type {Array<Array<import('../coordinate.js').Coordinate>>} */ ([]);
segmenter(segments, geometry);
if (segments.length === 1) {
this.rBush_.insert(boundingExtent(segments[0]), {
feature: feature,
segment: segments[0],
});
} else if (segments.length > 1) {
const extents = segments.map((s) => boundingExtent(s));
const segmentsData = segments.map((segment) => ({
feature: feature,
segment: segment,
}));
this.rBush_.load(extents, segmentsData);
}
} }
} }
@@ -534,11 +549,11 @@ class Snap extends PointerInteraction {
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/Circle.js").default} geometry Geometry. * @param {import("../geom/Circle.js").default} geometry Geometry.
* @private * @private
*/ */
writeCircleGeometry_(feature, geometry) { segmentCircleGemetry_(segments, geometry) {
const projection = this.getMap().getView().getProjection(); const projection = this.getMap().getView().getProjection();
let circleGeometry = geometry; let circleGeometry = geometry;
const userProjection = getUserProjection(); const userProjection = getUserProjection();
@@ -553,134 +568,101 @@ class Snap extends PointerInteraction {
} }
const coordinates = polygon.getCoordinates()[0]; const coordinates = polygon.getCoordinates()[0];
for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
const segment = coordinates.slice(i, i + 2); segments.push(coordinates.slice(i, i + 2));
const segmentData = {
feature: feature,
segment: segment,
};
this.rBush_.insert(boundingExtent(segment), segmentData);
} }
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/GeometryCollection.js").default} geometry Geometry. * @param {import("../geom/GeometryCollection.js").default} geometry Geometry.
* @private * @private
*/ */
writeGeometryCollectionGeometry_(feature, geometry) { segmentGeometryCollectionGemetry_(segments, geometry) {
const geometries = geometry.getGeometriesArray(); const geometries = geometry.getGeometriesArray();
for (let i = 0; i < geometries.length; ++i) { for (let i = 0; i < geometries.length; ++i) {
const segmentWriter = this.SEGMENT_WRITERS_[geometries[i].getType()]; const segmenter = this.GEOMETRY_SEGMENTERS_[geometries[i].getType()];
if (segmentWriter) { if (segmenter) {
segmentWriter(feature, geometries[i]); segmenter(segments, geometries[i]);
} }
} }
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/LineString.js").default} geometry Geometry. * @param {import("../geom/LineString.js").default} geometry Geometry.
* @private * @private
*/ */
writeLineStringGeometry_(feature, geometry) { segmentLineStringGemetry_(segments, geometry) {
const coordinates = geometry.getCoordinates(); const coordinates = geometry.getCoordinates();
for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
const segment = coordinates.slice(i, i + 2); segments.push(coordinates.slice(i, i + 2));
const segmentData = {
feature: feature,
segment: segment,
};
this.rBush_.insert(boundingExtent(segment), segmentData);
} }
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/MultiLineString.js").default} geometry Geometry. * @param {import("../geom/MultiLineString.js").default} geometry Geometry.
* @private * @private
*/ */
writeMultiLineStringGeometry_(feature, geometry) { segmentMultiLineStringGemetry_(segments, geometry) {
const lines = geometry.getCoordinates(); const lines = geometry.getCoordinates();
for (let j = 0, jj = lines.length; j < jj; ++j) { for (let j = 0, jj = lines.length; j < jj; ++j) {
const coordinates = lines[j]; const coordinates = lines[j];
for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
const segment = coordinates.slice(i, i + 2); segments.push(coordinates.slice(i, i + 2));
const segmentData = {
feature: feature,
segment: segment,
};
this.rBush_.insert(boundingExtent(segment), segmentData);
} }
} }
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/MultiPoint.js").default} geometry Geometry. * @param {import("../geom/MultiPoint.js").default} geometry Geometry.
* @private * @private
*/ */
writeMultiPointGeometry_(feature, geometry) { segmentMultiPointGemetry_(segments, geometry) {
geometry.getCoordinates().forEach((point) => { geometry.getCoordinates().forEach((point) => {
const segmentData = { segments.push([point]);
feature: feature,
segment: [point],
};
this.rBush_.insert(geometry.getExtent(), segmentData);
}); });
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/MultiPolygon.js").default} geometry Geometry. * @param {import("../geom/MultiPolygon.js").default} geometry Geometry.
* @private * @private
*/ */
writeMultiPolygonGeometry_(feature, geometry) { segmentMultiPolygonGemetry_(segments, geometry) {
const polygons = geometry.getCoordinates(); const polygons = geometry.getCoordinates();
for (let k = 0, kk = polygons.length; k < kk; ++k) { for (let k = 0, kk = polygons.length; k < kk; ++k) {
const rings = polygons[k]; const rings = polygons[k];
for (let j = 0, jj = rings.length; j < jj; ++j) { for (let j = 0, jj = rings.length; j < jj; ++j) {
const coordinates = rings[j]; const coordinates = rings[j];
for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
const segment = coordinates.slice(i, i + 2); segments.push(coordinates.slice(i, i + 2));
const segmentData = {
feature: feature,
segment: segment,
};
this.rBush_.insert(boundingExtent(segment), segmentData);
} }
} }
} }
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/Point.js").default} geometry Geometry. * @param {import("../geom/Point.js").default} geometry Geometry.
* @private * @private
*/ */
writePointGeometry_(feature, geometry) { segmentPointGemetry_(segments, geometry) {
const segmentData = { segments.push([geometry.getCoordinates()]);
feature: feature,
segment: [geometry.getCoordinates()],
};
this.rBush_.insert(geometry.getExtent(), segmentData);
} }
/** /**
* @param {import("../Feature.js").default} feature Feature * @param {Array<Array<import('../coordinate.js').Coordinate>>} segments Segments
* @param {import("../geom/Polygon.js").default} geometry Geometry. * @param {import("../geom/Polygon.js").default} geometry Geometry.
* @private * @private
*/ */
writePolygonGeometry_(feature, geometry) { segmentPolygonGemetry_(segments, geometry) {
const rings = geometry.getCoordinates(); const rings = geometry.getCoordinates();
for (let j = 0, jj = rings.length; j < jj; ++j) { for (let j = 0, jj = rings.length; j < jj; ++j) {
const coordinates = rings[j]; const coordinates = rings[j];
for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
const segment = coordinates.slice(i, i + 2); segments.push(coordinates.slice(i, i + 2));
const segmentData = {
feature: feature,
segment: segment,
};
this.rBush_.insert(boundingExtent(segment), segmentData);
} }
} }
} }