diff --git a/examples/edit-geographic.html b/examples/edit-geographic.html
new file mode 100644
index 0000000000..3f66d462ba
--- /dev/null
+++ b/examples/edit-geographic.html
@@ -0,0 +1,15 @@
+---
+layout: example.html
+title: Geographic Editing
+shortdesc: Editing geometries with geographic coordinates.
+docs: >
+ Calling the useGeographic function in the 'ol/proj' module
+ makes it so the map view uses geographic coordinates (even if the view projection is
+ not geographic).
+tags: "geographic"
+---
+
+
+ select a feature to modify
+ draw new features
+
diff --git a/examples/edit-geographic.js b/examples/edit-geographic.js
new file mode 100644
index 0000000000..415c780aed
--- /dev/null
+++ b/examples/edit-geographic.js
@@ -0,0 +1,63 @@
+import {Map, View} from '../src/ol/index.js';
+import GeoJSON from '../src/ol/format/GeoJSON.js';
+import {Modify, Select, Draw} from '../src/ol/interaction.js';
+import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
+import {OSM, Vector as VectorSource} from '../src/ol/source.js';
+import {useGeographic} from '../src/ol/proj.js';
+
+useGeographic();
+
+const source = new VectorSource({
+ url: 'data/geojson/countries.geojson',
+ format: new GeoJSON()
+});
+
+const map = new Map({
+ target: 'map',
+ layers: [
+ new TileLayer({
+ source: new OSM()
+ }),
+ new VectorLayer({
+ source: source
+ })
+ ],
+ view: new View({
+ center: [0, 0],
+ zoom: 2
+ })
+});
+
+const select = new Select();
+
+const modify = new Modify({
+ features: select.getFeatures()
+});
+
+const draw = new Draw({
+ type: 'Polygon',
+ source: source
+});
+
+const mode = document.getElementById('mode');
+function onChange() {
+ switch (mode.value) {
+ case 'draw': {
+ map.removeInteraction(modify);
+ map.removeInteraction(select);
+ map.addInteraction(draw);
+ break;
+ }
+ case 'modify': {
+ map.removeInteraction(draw);
+ map.addInteraction(select);
+ map.addInteraction(modify);
+ break;
+ }
+ default: {
+ // pass
+ }
+ }
+}
+mode.addEventListener('change', onChange);
+onChange();
diff --git a/src/ol/interaction/Draw.js b/src/ol/interaction/Draw.js
index 629a99dda7..49f77f0809 100644
--- a/src/ol/interaction/Draw.js
+++ b/src/ol/interaction/Draw.js
@@ -417,8 +417,7 @@ class Draw extends PointerInteraction {
useSpatialIndex: false,
wrapX: options.wrapX ? options.wrapX : false
}),
- style: options.style ? options.style :
- getDefaultStyleFunction(),
+ style: options.style ? options.style : getDefaultStyleFunction(),
updateWhileInteracting: true
});
@@ -443,8 +442,7 @@ class Draw extends PointerInteraction {
if (options.freehand) {
this.freehandCondition_ = always;
} else {
- this.freehandCondition_ = options.freehandCondition ?
- options.freehandCondition : shiftKeyOnly;
+ this.freehandCondition_ = options.freehandCondition ? options.freehandCondition : shiftKeyOnly;
}
this.addEventListener(getChangeEventType(InteractionProperty.ACTIVE), this.updateState_);
@@ -639,7 +637,7 @@ class Draw extends PointerInteraction {
const map = event.map;
for (let i = 0, ii = potentiallyFinishCoordinates.length; i < ii; i++) {
const finishCoordinate = potentiallyFinishCoordinates[i];
- const finishPixel = map.getPixelFromCoordinateInternal(finishCoordinate);
+ const finishPixel = map.getPixelFromCoordinate(finishCoordinate);
const pixel = event.pixel;
const dx = pixel[0] - finishPixel[0];
const dy = pixel[1] - finishPixel[1];
diff --git a/src/ol/interaction/Modify.js b/src/ol/interaction/Modify.js
index 5ec421e62e..f949904510 100644
--- a/src/ol/interaction/Modify.js
+++ b/src/ol/interaction/Modify.js
@@ -11,7 +11,7 @@ import {equals as coordinatesEqual, distance as coordinateDistance, squaredDista
import Event from '../events/Event.js';
import EventType from '../events/EventType.js';
import {always, primaryAction, altKeyOnly, singleClick} from '../events/condition.js';
-import {boundingExtent, buffer, createOrUpdateFromCoordinate} from '../extent.js';
+import {boundingExtent, buffer as bufferExtent, createOrUpdateFromCoordinate as createExtent} from '../extent.js';
import GeometryType from '../geom/GeometryType.js';
import Point from '../geom/Point.js';
import PointerInteraction from './Pointer.js';
@@ -20,6 +20,7 @@ import VectorSource from '../source/Vector.js';
import VectorEventType from '../source/VectorEventType.js';
import RBush from '../structs/RBush.js';
import {createEditingStyle} from '../style/Style.js';
+import {fromUserExtent, toUserExtent, fromUserCoordinate, toUserCoordinate} from '../proj.js';
/**
@@ -36,6 +37,8 @@ const CIRCLE_CENTER_INDEX = 0;
*/
const CIRCLE_CIRCUMFERENCE_INDEX = 1;
+const tempExtent = [0, 0, 0, 0];
+const tempSegment = [];
/**
* @enum {string}
@@ -652,7 +655,7 @@ class Modify extends PointerInteraction {
const featureSegments = [centerSegmentData, circumferenceSegmentData];
centerSegmentData.featureSegments = circumferenceSegmentData.featureSegments = featureSegments;
- this.rBush_.insert(createOrUpdateFromCoordinate(coordinates), centerSegmentData);
+ this.rBush_.insert(createExtent(coordinates), centerSegmentData);
this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData);
}
@@ -801,14 +804,14 @@ class Modify extends PointerInteraction {
return false;
}
this.handlePointerAtPixel_(evt.pixel, evt.map);
- const pixelCoordinate = evt.map.getCoordinateFromPixelInternal(evt.pixel);
+ const pixelCoordinate = evt.coordinate;
this.dragSegments_.length = 0;
this.modified_ = false;
const vertexFeature = this.vertexFeature_;
if (vertexFeature) {
+ const projection = evt.map.getView().getProjection();
const insertVertices = [];
- const geometry = vertexFeature.getGeometry();
- const vertex = geometry.getCoordinates();
+ const vertex = vertexFeature.getGeometry().getCoordinates();
const vertexExtent = boundingExtent([vertex]);
const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
const componentSegments = {};
@@ -824,21 +827,23 @@ class Modify extends PointerInteraction {
if (!componentSegments[uid]) {
componentSegments[uid] = new Array(2);
}
- if (segmentDataMatch.geometry.getType() === GeometryType.CIRCLE &&
- segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) {
- const closestVertex = closestOnSegmentData(pixelCoordinate, segmentDataMatch);
+ if (segmentDataMatch.geometry.getType() === GeometryType.CIRCLE && segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) {
+ const closestVertex = closestOnSegmentData(pixelCoordinate, segmentDataMatch, projection);
if (coordinatesEqual(closestVertex, vertex) && !componentSegments[uid][0]) {
this.dragSegments_.push([segmentDataMatch, 0]);
componentSegments[uid][0] = segmentDataMatch;
}
- } else if (coordinatesEqual(segment[0], vertex) &&
- !componentSegments[uid][0]) {
+ continue;
+ }
+
+ if (coordinatesEqual(segment[0], vertex) && !componentSegments[uid][0]) {
this.dragSegments_.push([segmentDataMatch, 0]);
componentSegments[uid][0] = segmentDataMatch;
- } else if (coordinatesEqual(segment[1], vertex) &&
- !componentSegments[uid][1]) {
+ continue;
+ }
+ if (coordinatesEqual(segment[1], vertex) && !componentSegments[uid][1]) {
// prevent dragging closed linestrings by the connecting node
if ((segmentDataMatch.geometry.getType() ===
GeometryType.LINE_STRING ||
@@ -851,15 +856,20 @@ class Modify extends PointerInteraction {
this.dragSegments_.push([segmentDataMatch, 1]);
componentSegments[uid][1] = segmentDataMatch;
- } else if (getUid(segment) in this.vertexSegments_ &&
+ continue;
+ }
+
+ if (getUid(segment) in this.vertexSegments_ &&
(!componentSegments[uid][0] && !componentSegments[uid][1]) &&
this.insertVertexCondition_(evt)) {
insertVertices.push([segmentDataMatch, vertex]);
}
}
+
if (insertVertices.length) {
this.willModifyFeatures_(evt);
}
+
for (let j = insertVertices.length - 1; j >= 0; --j) {
this.insertVertex_.apply(this, insertVertices[j]);
}
@@ -881,7 +891,7 @@ class Modify extends PointerInteraction {
const circumferenceSegmentData = segmentData.featureSegments[1];
centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
- this.rBush_.update(createOrUpdateFromCoordinate(coordinates), centerSegmentData);
+ this.rBush_.update(createExtent(coordinates), centerSegmentData);
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
} else {
this.rBush_.update(boundingExtent(segmentData.segment), segmentData);
@@ -909,14 +919,16 @@ class Modify extends PointerInteraction {
* @private
*/
handlePointerAtPixel_(pixel, map) {
- const pixelCoordinate = map.getCoordinateFromPixelInternal(pixel);
+ const pixelCoordinate = map.getCoordinateFromPixel(pixel);
const sortByDistance = function(a, b) {
return pointDistanceToSegmentDataSquared(pixelCoordinate, a) -
pointDistanceToSegmentDataSquared(pixelCoordinate, b);
};
- const box = buffer(createOrUpdateFromCoordinate(pixelCoordinate),
- map.getView().getResolution() * this.pixelTolerance_);
+ const projection = map.getView().getProjection();
+ const viewExtent = fromUserExtent(createExtent(pixelCoordinate, tempExtent), projection);
+ const buffer = map.getView().getResolution() * this.pixelTolerance_;
+ const box = toUserExtent(bufferExtent(viewExtent, buffer, tempExtent), projection);
const rBush = this.rBush_;
const nodes = rBush.getInExtent(box);
@@ -924,21 +936,19 @@ class Modify extends PointerInteraction {
nodes.sort(sortByDistance);
const node = nodes[0];
const closestSegment = node.segment;
- let vertex = closestOnSegmentData(pixelCoordinate, node);
- const vertexPixel = map.getPixelFromCoordinateInternal(vertex);
+ let vertex = closestOnSegmentData(pixelCoordinate, node, projection);
+ const vertexPixel = map.getPixelFromCoordinate(vertex);
let dist = coordinateDistance(pixel, vertexPixel);
if (dist <= this.pixelTolerance_) {
/** @type {Object} */
const vertexSegments = {};
- if (node.geometry.getType() === GeometryType.CIRCLE &&
- node.index === CIRCLE_CIRCUMFERENCE_INDEX) {
-
+ if (node.geometry.getType() === GeometryType.CIRCLE && node.index === CIRCLE_CIRCUMFERENCE_INDEX) {
this.snappedToVertex_ = true;
this.createOrUpdateVertexFeature_(vertex);
} else {
- const pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]);
- const pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]);
+ const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
+ const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
const squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1);
const squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2);
dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
@@ -1251,16 +1261,19 @@ function pointDistanceToSegmentDataSquared(pointCoordinates, segmentData) {
* should be found.
* @param {SegmentData} segmentData The object describing the line
* segment which should contain the closest point.
+ * @param {import("../proj/Projection.js").default} projection The view projection.
* @return {import("../coordinate.js").Coordinate} The point closest to the specified line segment.
*/
-function closestOnSegmentData(pointCoordinates, segmentData) {
+function closestOnSegmentData(pointCoordinates, segmentData, projection) {
const geometry = segmentData.geometry;
- if (geometry.getType() === GeometryType.CIRCLE &&
- segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
+ if (geometry.getType() === GeometryType.CIRCLE && segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) {
return geometry.getClosestPoint(pointCoordinates);
}
- return closestOnSegment(pointCoordinates, segmentData.segment);
+ const coordinate = fromUserCoordinate(pointCoordinates, projection);
+ tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
+ tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
+ return toUserCoordinate(closestOnSegment(coordinate, tempSegment), projection);
}