From 0a813e480ef7044663e35a6ab3a0457d55a052a7 Mon Sep 17 00:00:00 2001 From: Ponlawat W Date: Fri, 15 Dec 2023 10:49:47 +0700 Subject: [PATCH] 0.4.0 - Fixed geometry editing (#4) * Bumped * Added editing placeholder * Fixed start editing from between line segments. * Updated changeslog * Fixed autofocusing * Updated changes log --- CHANGES.md | 4 +++- package-lock.json | 4 ++-- package.json | 4 ++-- src/interaction.ts | 36 +++++++++++++++++++++--------- tests/common.ts | 2 +- tests/interaction.create.test.ts | 4 ++-- tests/interaction.edit.test.ts | 38 +++++++++++++++++++++++++++++++- tests/osmoverpass.test.ts | 2 +- 8 files changed, 74 insertions(+), 20 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c40f6a8..567055d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1 +1,3 @@ -Updated imports and exports +- Added sketch point for edit only mode. +- Fixed start editing from between line segments. +- Fixed autofocusing. diff --git a/package-lock.json b/package-lock.json index 9538345..a1fbd7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ol-osmwaysnap", - "version": "0.3.2", + "version": "0.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ol-osmwaysnap", - "version": "0.3.2", + "version": "0.4.0", "license": "ISC", "dependencies": { "ol-osmoverpass": "^0.2.3" diff --git a/package.json b/package.json index 35761a6..ee02bc7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ol-osmwaysnap", "type": "module", - "version": "0.3.2", + "version": "0.4.0", "description": "OpenLayers Interaction Extension for Snapping Ways from OSM using Overpass API", "keywords": [ "osm", @@ -14,7 +14,7 @@ "main": "dist/index.js", "scripts": { "build": "npx tsc && npx webpack", - "test": "npm run build && npx vitest run --config ./vitest.config.ts" + "test": "npx vitest run --config ./vitest.config.ts" }, "repository": { "type": "git", diff --git a/src/interaction.ts b/src/interaction.ts index 7886941..99175c6 100644 --- a/src/interaction.ts +++ b/src/interaction.ts @@ -97,8 +97,10 @@ export default class OSMWaySnap extends PointerInteraction { /** Layer of snapping ways */ private wayLayer: VectorLayer>>|undefined = undefined; - /** Snap interaction */ - private snapInteraction: Snap; + /** Snap interaction to waySource */ + private snapWayInteraction: Snap; + /** Snap interaction to source */ + private snapSourceInteraction: Snap; /** * Constructor @@ -118,7 +120,8 @@ export default class OSMWaySnap extends PointerInteraction { overpassQuery: options.overpassQuery ?? '(way["highway"];>;);', overpassEndpointURL: options.overpassEndpointURL ?? undefined }); - this.snapInteraction = new Snap({ source: this.waySource }); + this.snapWayInteraction = new Snap({ source: this.waySource }); + this.snapSourceInteraction = new Snap({ source: this.source }); if (options.createAndAddWayLayer ?? true) { this.wayLayer = new VectorLayer({ source: this.waySource, style: OSMOverpassWaySource.getDefaultStyle() }); @@ -147,7 +150,8 @@ export default class OSMWaySnap extends PointerInteraction { this.waySource.un('featuresloadend', this.waysFeaturesLoadEnded.bind(this)); this.wayLayer && this.map.removeLayer(this.wayLayer); this.map.removeLayer(this.overlayLayer); - this.map.removeInteraction(this.snapInteraction); + this.map.removeInteraction(this.snapWayInteraction); + this.map.removeInteraction(this.snapSourceInteraction); } super.setMap(map); this.map = map ?? undefined; @@ -155,7 +159,10 @@ export default class OSMWaySnap extends PointerInteraction { this.waySource.on('featuresloadend', this.waysFeaturesLoadEnded.bind(this)); this.wayLayer && this.map.getAllLayers().indexOf(this.wayLayer) < 0 && this.map.addLayer(this.wayLayer); this.map.addLayer(this.overlayLayer); - this.map.getInteractions().getArray().indexOf(this.snapInteraction) < 0 && this.map.addInteraction(this.snapInteraction); + this.map.removeInteraction(this.snapWayInteraction); + this.map.addInteraction(this.snapWayInteraction); + this.map.removeInteraction(this.snapSourceInteraction); + this.map.addInteraction(this.snapSourceInteraction); } } @@ -296,6 +303,7 @@ export default class OSMWaySnap extends PointerInteraction { * @param fromCoordinate Coordinate on feature geometry to starts altering, the original vertices after this coordinate will go to draft in overlay layer */ private enterEditMode(feature: Feature, fromCoordinate: Coordinate) { + feature.getGeometry()!.setCoordinates(LineStringUtils.split(feature.getGeometry()!, fromCoordinate).getCoordinates()); const originalCoordinates = feature.getGeometry()!.getCoordinates(); const fromCoordinateIdx = originalCoordinates.findIndex(c => c[0] === fromCoordinate[0] && c[1] === fromCoordinate[1]); this.coordinates = originalCoordinates.slice(0, fromCoordinateIdx + 1); @@ -396,10 +404,9 @@ export default class OSMWaySnap extends PointerInteraction { p => (lastCoordinate[0] === p[0] && lastCoordinate[1] === p[1]) || !this.activeFeature!.getGeometry()!.intersectsCoordinate(p) ); - if (fitCoordinates.length > 1) { - map.getView().fit(boundingExtent(fitCoordinates), { - padding: Array(4).fill(this.focusPadding) - }); + const extent = boundingExtent(fitCoordinates); + if (fitCoordinates.length > 1 && extent[0] !== extent[2] && extent[1] !== extent[3]) { + map.getView().fit(extent, { padding: Array(4).fill(this.focusPadding) }); } } } @@ -427,12 +434,21 @@ export default class OSMWaySnap extends PointerInteraction { this.createOrUpdateSketchLine(lastFeatureCoors); } + /** + * Test if the given coordinate falls on any feature geometries in the source. + * @param coordinate Coordinate + * @returns True if the given coordinate falls on any features in the source. + */ + private coordinateOnAnyFeatures(coordinate: Coordinate): boolean { + return this.source.getFeaturesAtCoordinate(coordinate).length > 0; + } + /** * Create or move the sketch point to the specified coordinate * @param coordinate Coordinate */ private createOrUpdateSketchPoint(coordinate: Coordinate) { - if (!this.allowCreate && !this.activeFeature) { + if (!this.allowCreate && this.allowEdit && !this.activeFeature && !this.coordinateOnAnyFeatures(coordinate)) { return this.removeSketchPoint(); } if (this.sketchPoint) { diff --git a/tests/common.ts b/tests/common.ts index a4cb3cc..da4a4f1 100644 --- a/tests/common.ts +++ b/tests/common.ts @@ -5,7 +5,7 @@ import EventType from 'ol/MapBrowserEventType' import { MouseEvent } from 'happy-dom'; import type { Map } from 'ol'; import type { Coordinate } from 'ol/coordinate'; -import type { OSMWaySnap } from '../dist'; +import type { OSMWaySnap } from '../src'; /** * Drawing a linestring network that looks more or less like this: diff --git a/tests/interaction.create.test.ts b/tests/interaction.create.test.ts index df0b2eb..6fae331 100644 --- a/tests/interaction.create.test.ts +++ b/tests/interaction.create.test.ts @@ -4,7 +4,7 @@ import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; import { Projection } from 'ol/proj'; import { getDefaultWaySource, mouseClick, mouseMove } from './common'; -import { OSMWaySnap, OSMWaySnapEventType } from '../dist'; +import { OSMWaySnap, OSMWaySnapEventType } from '../src'; import { Feature } from 'ol'; import { LineString, Point } from 'ol/geom'; @@ -49,7 +49,7 @@ describe('Test OSMWaySnap Interaction: Line Creation', () => { mouseMove(map, interaction, [-50, -75]); const sketchPoint = (interaction as any).sketchPoint as Feature; - expect(sketchPoint).toBeTruthy(); + expect(sketchPoint).toBeDefined(); const coor = sketchPoint.getGeometry()!.getFirstCoordinate(); expect(coor).toEqual([-50, -75]); diff --git a/tests/interaction.edit.test.ts b/tests/interaction.edit.test.ts index 5afbc52..ba17618 100644 --- a/tests/interaction.edit.test.ts +++ b/tests/interaction.edit.test.ts @@ -4,9 +4,10 @@ import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; import { Projection } from 'ol/proj'; import { getDefaultWaySource, mouseClick, mouseMove } from './common'; -import { OSMWaySnap, OSMWaySnapEventType } from '../dist'; +import { OSMWaySnap, OSMWaySnapEventType } from '../src'; import { Feature } from 'ol'; import { LineString } from 'ol/geom'; +import type { Point } from 'ol/geom'; describe('Test OSMWaySnap Interaction: Line Edition', () => { let map: Map; @@ -54,6 +55,20 @@ describe('Test OSMWaySnap Interaction: Line Edition', () => { map.addInteraction(interaction); }); + it('shows sketch point when hovering on an editable line', () => { + interaction.allowCreate = false; + interaction.allowEdit = true; + + const getSketchPoint = () => (interaction as any).sketchPoint as Feature|undefined; + + mouseMove(map, interaction, [15, 15]); + expect(getSketchPoint()).toBeUndefined(); + + mouseMove(map, interaction, [10, 10]); + expect(getSketchPoint()).toBeDefined(); + expect(getSketchPoint()!.getGeometry()!.getFirstCoordinate()).toEqual([10, 10]); + }); + it('enables edit mode by spliting selected feature and displays the remaining as draft line after user clicks on an existing feature', () => { mouseMove(map, interaction, [0, 0]); mouseClick(map, interaction, [0, 0]); @@ -74,6 +89,27 @@ describe('Test OSMWaySnap Interaction: Line Edition', () => { expect(draftLine.getGeometry()!.getCoordinates()[5]).toEqual([0, 30]); }); + it('enables edit mode by spliting the selected feature on a line segment between vertices', () => { + mouseMove(map, interaction, [0, 5]); + mouseClick(map, interaction, [0, 5]); + + const activeCoors = interaction.getActiveFeature()!.getGeometry()!.getCoordinates(); + expect(activeCoors.length).toEqual(3); + expect(activeCoors[0]).toEqual([0, -50]); + expect(activeCoors[1]).toEqual([0, 0]); + expect(activeCoors[2]).toEqual([0, 5]); + + const draftLine = (interaction as any).draftOriginalLine as Feature; + expect(draftLine).toBeDefined(); + expect(draftLine.getGeometry()!.getCoordinates().length).toEqual(6); + expect(draftLine.getGeometry()!.getCoordinates()[0]).toEqual([0, 5]); + expect(draftLine.getGeometry()!.getCoordinates()[1]).toEqual([0, 10]); + expect(draftLine.getGeometry()!.getCoordinates()[2]).toEqual([10, 10]); + expect(draftLine.getGeometry()!.getCoordinates()[3]).toEqual([10, 20]); + expect(draftLine.getGeometry()!.getCoordinates()[4]).toEqual([0, 20]); + expect(draftLine.getGeometry()!.getCoordinates()[5]).toEqual([0, 30]); + }); + it('does not enable edit mode when not allowed', () => { interaction.allowEdit = false; diff --git a/tests/osmoverpass.test.ts b/tests/osmoverpass.test.ts index ead64e3..b2c058f 100644 --- a/tests/osmoverpass.test.ts +++ b/tests/osmoverpass.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; import VectorSource from 'ol/source/Vector'; -import { OSMWaySnap } from '../dist'; +import { OSMWaySnap } from '../src'; import { OSMOverpassWaySource } from 'ol-osmoverpass'; import type Feature from 'ol/Feature'; import type LineString from 'ol/geom/LineString';