From d1af18ab7c54389c57438a03b4a9e21f668e9570 Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Tue, 20 Feb 2024 15:39:40 +0100 Subject: [PATCH] wip: add multi line support --- demos/simple/demo.js | 4 +++ demos/simple/simple.html | 2 ++ src/interaction/TrackData.ts | 6 ++++ src/interaction/TrackInteraction.ts | 7 ++--- src/interaction/TrackInteractionModify.ts | 9 ++---- src/interaction/TrackManager.ts | 34 +++++++++++++++++------ src/interaction/TrackUpdater.ts | 20 ++++++------- 7 files changed, 52 insertions(+), 30 deletions(-) diff --git a/demos/simple/demo.js b/demos/simple/demo.js index 085ee470..167f3e21 100644 --- a/demos/simple/demo.js +++ b/demos/simple/demo.js @@ -124,6 +124,10 @@ function main() { } trackManager.addPOI(poiOverlay, onAddListener) }); + + document.querySelector('#createNewPart').addEventListener('click', () => { + trackManager.createNewPart(); + }); } main(); diff --git a/demos/simple/simple.html b/demos/simple/simple.html index e691f898..e23ecbce 100644 --- a/demos/simple/simple.html +++ b/demos/simple/simple.html @@ -56,6 +56,8 @@ +
+ Add a new line string
diff --git a/src/interaction/TrackData.ts b/src/interaction/TrackData.ts index 253b84a0..d029606b 100644 --- a/src/interaction/TrackData.ts +++ b/src/interaction/TrackData.ts @@ -119,6 +119,7 @@ export default class TrackData { point.set('type', 'controlPoint'); console.assert(index >= 0 && index <= this.controlPoints.length); // add new control point + point.set('trackData', this); this.controlPoints.splice(index, 0, point); // remove segment @@ -368,3 +369,8 @@ function createStraightSegment(featureFrom: Feature, featureTo: Feature

): TrackData { + return controlPoint.get('trackData') as TrackData; +} diff --git a/src/interaction/TrackInteraction.ts b/src/interaction/TrackInteraction.ts index a380dd39..5f5e3dc9 100644 --- a/src/interaction/TrackInteraction.ts +++ b/src/interaction/TrackInteraction.ts @@ -8,7 +8,6 @@ import {FALSE} from 'ol/functions'; import type {Feature, Map, MapBrowserEvent} from 'ol'; import VectorLayer from 'ol/layer/Vector'; import VectorSource from 'ol/source/Vector'; -import TrackData from './TrackData'; import type {StyleLike} from 'ol/style/Style'; import type {FlatStyleLike} from 'ol/style/flat'; import type {Pixel} from 'ol/pixel'; @@ -18,7 +17,6 @@ import {Point} from 'ol/geom'; export interface Options { map: Map; trackLayer: VectorLayer - trackData: TrackData style: StyleLike | FlatStyleLike /** @@ -86,9 +84,8 @@ export default class TrackInteraction extends Interaction { return draw; } - createModifyInteraction(trackData: TrackData, source: VectorSource, style: StyleLike | FlatStyleLike, hitTolerance: number): Modify { + createModifyInteraction(source: VectorSource, style: StyleLike | FlatStyleLike, hitTolerance: number): Modify { const modify = new Modify({ - trackData: trackData, source: source, style: style, condition: (event) => !this.deleteCondition_(event), @@ -146,7 +143,7 @@ export default class TrackInteraction extends Interaction { source.on('removefeature', () => requestAnimationFrame(() => this.modifyTrack_.updateSketchFeature())); this.drawTrack_ = this.createDrawInteraction(source); - this.modifyTrack_ = this.createModifyInteraction(options.trackData, source, options.style, options.hitTolerance); + this.modifyTrack_ = this.createModifyInteraction(source, options.style, options.hitTolerance); this.deletePoint_ = this.createSelectInteraction(options.trackLayer); this.setActive(false); diff --git a/src/interaction/TrackInteractionModify.ts b/src/interaction/TrackInteractionModify.ts index 68e424bd..02e666cf 100644 --- a/src/interaction/TrackInteractionModify.ts +++ b/src/interaction/TrackInteractionModify.ts @@ -6,12 +6,11 @@ import LineString from 'ol/geom/LineString.js'; import Point from 'ol/geom/Point.js'; import Event from 'ol/events/Event.js'; import {Geometry} from 'ol/geom'; -import TrackData from './TrackData'; import {Map, MapBrowserEvent} from 'ol'; import type {StyleLike} from 'ol/style/Style.js'; import type {FlatStyleLike} from 'ol/style/flat.js'; import type {Pixel} from 'ol/pixel.js'; -import type {FeatureType} from './TrackData.js'; +import {trackData, type FeatureType} from './TrackData.js'; export class ModifyEvent extends Event { @@ -32,7 +31,6 @@ export class ModifyEvent extends Event { export interface Options { source: VectorSource; - trackData: TrackData; style: StyleLike | FlatStyleLike; condition: (mbe: MapBrowserEvent) => boolean; addControlPointCondition: (mbe: MapBrowserEvent) => boolean; @@ -65,7 +63,6 @@ export default class Modify extends PointerInteraction { }); private overlay_: VectorLayer>; private lastPixel_ = [0, 0]; - private trackData_: Options['trackData']; /** * @type {Feature} */ @@ -106,8 +103,6 @@ export default class Modify extends PointerInteraction { updateWhileAnimating: true, updateWhileInteracting: true }); - - this.trackData_ = options.trackData; } @@ -231,7 +226,7 @@ export default class Modify extends PointerInteraction { // we create a 3 points linestring, doubled if end points clicked console.assert(this.feature_.getGeometry().getType() === 'Point', this.feature_.getProperties()); const f = this.feature_ as Feature; - const {before, after} = this.trackData_.getAdjacentSegments(f); + const {before, after} = trackData(f).getAdjacentSegments(f); if (!before && !after) { // single point case this.involvedFeatures_ = [this.feature_]; diff --git a/src/interaction/TrackManager.ts b/src/interaction/TrackManager.ts index d7d2fc4b..7c1086e3 100644 --- a/src/interaction/TrackManager.ts +++ b/src/interaction/TrackManager.ts @@ -1,7 +1,7 @@ import Feature from 'ol/Feature.js'; import Point from 'ol/geom/Point.js'; -import TrackData from './TrackData'; +import TrackData, { trackData } from './TrackData'; import TrackUpdater from './TrackUpdater'; import TrackInteraction from './TrackInteraction'; import HistoryManager from './HistoryManager'; @@ -73,7 +73,8 @@ export default class TrackManager { private trackChangeEventListeners_: Function[] = []; // eslint-disable-next-line @typescript-eslint/ban-types private trackHoverEventListeners_: Function[] = []; - private trackData_ = new TrackData(); + // the data for the current line + private trackData_: TrackData; private router_: Router; get router(): Router { return this.router_; @@ -85,6 +86,7 @@ export default class TrackManager { private updater_: TrackUpdater; private interaction_: TrackInteraction; private historyManager_ = new HistoryManager[]>(); + parts: TrackData[] = []; constructor(options: Options) { this.map_ = options.map; @@ -96,15 +98,16 @@ export default class TrackManager { this.router_ = options.router; this.profiler_ = options.profiler; + + this.createNewPart(); + this.updater_ = new TrackUpdater({ profiler: this.profiler_, router: this.router_, - trackData: this.trackData_ }); this.interaction_ = new TrackInteraction({ style: options.style, - trackData: this.trackData_, trackLayer: this.trackLayer_, map: this.map_, deleteCondition: options.deleteCondition, @@ -131,6 +134,7 @@ export default class TrackManager { if (!this.snapping) { feature.set('snapped', false); } + // this is what we want: the new point is added to the current line const {pointFrom, pointTo, segment} = this.trackData_.pushControlPoint(feature); if (segment) { this.source_.addFeature(segment); @@ -142,7 +146,7 @@ export default class TrackManager { } }); - + // FIXME: check this const debouncedMapToProfileUpdater = debounce( (coordinate: Coordinate, hover: boolean) => { if (hover && this.trackData_.getSegments().length > 0) { @@ -175,6 +179,7 @@ export default class TrackManager { const type = event.feature.get('type') as FeatureType; if (type === 'POI') { + // FIXME: check this this.trackData_.updatePOIIndexes(); this.onTrackChanged_(); } else if (type === 'controlPoint') { @@ -182,10 +187,12 @@ export default class TrackManager { await this.updater_.updateAdjacentSegmentsGeometries(feature, this.snapping); this.updater_.changeAdjacentSegmentsStyling(feature, ''); await this.updater_.computeAdjacentSegmentsProfile(feature); + // FIXME: check this this.trackData_.updatePOIIndexes(); this.onTrackChanged_(); } else if (type === 'segment') { const feature = event.feature as Feature; + // FIXME: check this const indexOfSegment = this.trackData_.getSegments().indexOf(feature); console.assert(indexOfSegment >= 0); @@ -218,12 +225,12 @@ export default class TrackManager { console.assert(selected.getGeometry().getType() === 'Point'); const type = selected.get('type') as FeatureType; if (type === 'POI') { - this.trackData_.deletePOI(selected); + trackData(selected).deletePOI(selected); this.source_.removeFeature(selected); this.onTrackChanged_(); } else { // control point - const {deleted, pointBefore, pointAfter, newSegment} = this.trackData_.deleteControlPoint(selected); + const {deleted, pointBefore, pointAfter, newSegment} = trackData(selected).deleteControlPoint(selected); // remove deleted features from source deleted.forEach(f => this.source_.removeFeature(f)); @@ -362,11 +369,13 @@ export default class TrackManager { private clearInternal_() { this.source_.clear(); this.trackData_.clear(); + // FIXME: remove all parts ? } /** */ clear() { + // FIXME: check this if (this.trackData_.hasData()) { this.clearInternal_() this.onTrackChanged_(); @@ -386,6 +395,7 @@ export default class TrackManager { } async restoreFeatures(features: Feature[]): Promise { + // FIXME: check this this.clearInternal_(); await this.restoreFeaturesInternal_(features); this.onTrackChanged_(); @@ -444,6 +454,7 @@ export default class TrackManager { * Delete a POI and notify track change listeners. */ deletePOI(index: number) { + // FIXME: check this const poi = this.trackData_.getPOIs().find(feature => feature.get('index') === index); const feature = this.source_.getFeatures().find(feature => feature.get('type') === 'POI' && feature.get('index') === index); this.source_.removeFeature(feature); @@ -568,4 +579,11 @@ export default class TrackManager { this.source_.changed(); this.shadowTrackLayer_.getSource().changed(); } -} \ No newline at end of file + + // Add a new line string and set it add the "current" line string + createNewPart() { + this.trackData_ = new TrackData(); + + this.parts.push(this.trackData_); + } +} diff --git a/src/interaction/TrackUpdater.ts b/src/interaction/TrackUpdater.ts index 2263eea7..7ab9b2e6 100644 --- a/src/interaction/TrackUpdater.ts +++ b/src/interaction/TrackUpdater.ts @@ -1,12 +1,11 @@ import type Point from 'ol/geom/Point.js'; import type Feature from 'ol/Feature.js'; -import type TrackData from './TrackData'; import type {Router} from '../router/index'; import type {Profiler} from '../profiler/index'; import {equals} from 'ol/coordinate'; +import { trackData } from './TrackData'; type TrackUpdaterOptions = { - trackData: TrackData; router: Router; profiler: Profiler; }; @@ -16,12 +15,10 @@ type TrackUpdaterOptions = { * Drive the chosen router to update the segment geometries. */ export default class TrackUpdater { - private trackData: TrackData; private profiler: Profiler; private router: Router; constructor(options: TrackUpdaterOptions) { - this.trackData = options.trackData; this.profiler = options.profiler; this.router = options.router; } @@ -29,7 +26,7 @@ export default class TrackUpdater { computeAdjacentSegmentsProfile(modifiedControlPoint: Feature): Promise { const promises = []; if (modifiedControlPoint) { - const {before, after} = this.trackData.getAdjacentSegments(modifiedControlPoint); + const {before, after} = trackData(modifiedControlPoint).getAdjacentSegments(modifiedControlPoint); if (before) { promises.push(this.profiler.computeProfile(before)); } @@ -42,7 +39,7 @@ export default class TrackUpdater { changeAdjacentSegmentsStyling(modifiedControlPoint: Feature, subtype: string) { if (modifiedControlPoint) { - const {before, after} = this.trackData.getAdjacentSegments(modifiedControlPoint); + const {before, after} = trackData(modifiedControlPoint).getAdjacentSegments(modifiedControlPoint); if (before) { before.set('subtype', subtype); } @@ -54,9 +51,9 @@ export default class TrackUpdater { async updateAdjacentSegmentsGeometries(modifiedControlPoint: Feature, snapping: boolean): Promise { if (modifiedControlPoint) { - const {before, after} = this.trackData.getAdjacentSegments(modifiedControlPoint); - const pointFrom = this.trackData.getControlPointBefore(modifiedControlPoint); - const pointTo = this.trackData.getControlPointAfter(modifiedControlPoint); + const {before, after} = trackData(modifiedControlPoint).getAdjacentSegments(modifiedControlPoint); + const pointFrom = trackData(modifiedControlPoint).getControlPointBefore(modifiedControlPoint); + const pointTo = trackData(modifiedControlPoint).getControlPointAfter(modifiedControlPoint); modifiedControlPoint.set('snapped', snapping ? undefined : false); const geometryUpdates = []; if (before) { @@ -83,7 +80,10 @@ export default class TrackUpdater { // If needed, equalize the control point, the segment before and after to all share the same coordinate. equalizeCoordinates(controlPoint: Feature) { - const {before, after} = this.trackData.getAdjacentSegments(controlPoint); + if (!controlPoint) { + return; + } + const {before, after} = trackData(controlPoint).getAdjacentSegments(controlPoint); if (before && after) { const firstCoordinate = before.getGeometry().getLastCoordinate(); const lastCoordinate = after.getGeometry().getFirstCoordinate();