From 5b1e325336a5ae1b282857bb4da9c723e2b5a811 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 31 Oct 2025 14:49:49 +0100 Subject: [PATCH 1/7] fixup! fix start node in groupTrainrunSectionsIntoChains() Signed-off-by: Simon Ser --- src/app/services/data/trainrunsection.service.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/services/data/trainrunsection.service.ts b/src/app/services/data/trainrunsection.service.ts index 970230cf..9214ee76 100644 --- a/src/app/services/data/trainrunsection.service.ts +++ b/src/app/services/data/trainrunsection.service.ts @@ -1486,10 +1486,19 @@ export class TrainrunSectionService implements OnDestroy { return; } + const backwardIterator = this.trainrunService.getBackwardIterator( + section.getTargetNode(), + section, + ); + while (backwardIterator.hasNext() && backwardIterator.current().node.getIsCollapsed()) { + backwardIterator.next(); + } + const startNode = backwardIterator.current().node; + const startSection = backwardIterator.current().trainrunSection; + // Build chain using TrainrunIterator to leverage existing graph traversal const chain: TrainrunSection[] = []; - const startNode = section.getSourceNode(); - const iterator = this.trainrunService.getIterator(startNode, section); + const iterator = this.trainrunService.getIterator(startNode, startSection); // Traverse the trainrun and collect sections with collapsed intermediate nodes while (iterator.hasNext()) { From 65f9eb8af62b53c1fd9dee1dc9bae9d8936cd2c6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 31 Oct 2025 16:35:39 +0100 Subject: [PATCH 2/7] fixup! only create a single TrainrunSectionViewObject per collapsed chain Signed-off-by: Simon Ser --- .../data-views/trainrunsections.view.ts | 100 ++++++------------ 1 file changed, 33 insertions(+), 67 deletions(-) diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 7411195c..0ed98b95 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts @@ -126,8 +126,6 @@ export class TrainrunSectionsView { return SimpleTrainrunSectionRouter.placeTextOnTrainrunSection(collapsedChainPath, sourcePort); } - - getAdditionPositioningValueForViewObjectWithCollapsedSupport( viewObject: TrainrunSectionViewObject, textElement: TrainrunSectionText, @@ -1041,9 +1039,6 @@ export class TrainrunSectionsView { switch (textElement) { case TrainrunSectionText.SourceDeparture: case TrainrunSectionText.SourceArrival: - if (TrainrunSectionsView.getNode(trainrunSection, true).getIsCollapsed()) { - return true; - } if (!this.editorView.isFilterArrivalDepartureTimeEnabled()) { return true; } @@ -1060,9 +1055,6 @@ export class TrainrunSectionsView { return TrainrunSectionsView.getNode(trainrunSection, true).isNonStop(trainrunSection); case TrainrunSectionText.TargetDeparture: case TrainrunSectionText.TargetArrival: - if (TrainrunSectionsView.getNode(trainrunSection, false).getIsCollapsed()) { - return true; - } if (!this.editorView.isFilterArrivalDepartureTimeEnabled()) { return true; } @@ -1078,10 +1070,6 @@ export class TrainrunSectionsView { } return TrainrunSectionsView.getNode(trainrunSection, false).isNonStop(trainrunSection); case TrainrunSectionText.TrainrunSectionTravelTime: - if (TrainrunSectionsView.isExitingCollapsedChain(trainrunSection)) { - return true; - } - if (!this.editorView.isFilterTravelTimeEnabled()) { return true; } @@ -1094,10 +1082,6 @@ export class TrainrunSectionsView { ); case TrainrunSectionText.TrainrunSectionName: { - if (TrainrunSectionsView.isExitingCollapsedChain(trainrunSection)) { - return true; - } - if (!this.editorView.isFilterTrainrunNameEnabled()) { return true; } @@ -1478,22 +1462,22 @@ export class TrainrunSectionsView { .attr(StaticDomTags.EDGE_NODE_ID, (d: TrainrunSectionViewObject) => TrainrunSectionsView.getNode(d.trainrunSection, atSource).getId(), ) - .classed(StaticDomTags.TAG_HIDDEN, (d: TrainrunSectionViewObject) => { - const node = TrainrunSectionsView.getNode(d.trainrunSection, atSource); - return ( - (!this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && - !this.editorView.checkFilterNonStopNode(node)) || - node.getIsCollapsed() - ); - }) - .classed(StaticDomTags.TAG_EVENT_DISABLED, (d: TrainrunSectionViewObject) => { - const node = TrainrunSectionsView.getNode(d.trainrunSection, atSource); - return ( - (!this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && - !this.editorView.checkFilterNonStopNode(node)) || - node.getIsCollapsed() - ); - }) + .classed( + StaticDomTags.TAG_HIDDEN, + (d: TrainrunSectionViewObject) => + !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && + !this.editorView.checkFilterNonStopNode( + TrainrunSectionsView.getNode(d.trainrunSection, atSource), + ), + ) + .classed( + StaticDomTags.TAG_EVENT_DISABLED, + (d: TrainrunSectionViewObject) => + !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && + !this.editorView.checkFilterNonStopNode( + TrainrunSectionsView.getNode(d.trainrunSection, atSource), + ), + ) .classed(atSource ? StaticDomTags.EDGE_IS_SOURCE : StaticDomTags.EDGE_IS_TARGET, true) .classed(StaticDomTags.EDGE_IS_END_NODE, (d: TrainrunSectionViewObject) => { let node = d.trainrunSection.getTargetNode(); @@ -1882,27 +1866,23 @@ export class TrainrunSectionsView { this.trainrunSectionService.groupTrainrunSectionsIntoChains(inputTrainrunSections); sectionGroups.forEach((sections) => { - sections.forEach((d) => { - if (this.shouldDisplayTrainrunSection(d)) { - this.updateTrainrunSectionPathForCollapsedChain(d); - - viewTrainrunSectionDataObjects.push( - new TrainrunSectionViewObject( - editorView, - d, - TrainrunSectionsView.getNode(d, true).isNonStop(d), - TrainrunSectionsView.getNode(d, false).isNonStop(d), - TrainrunSectionsView.isMuted(d, selectedTrainrun, connectedTrainIds), - this.getHiddenTagForTime(d, TrainrunSectionText.SourceDeparture), - this.getHiddenTagForTime(d, TrainrunSectionText.TargetDeparture), - this.getHiddenTagForTime(d, TrainrunSectionText.TrainrunSectionTravelTime), - this.getHiddenTagForTime(d, TrainrunSectionText.TrainrunSectionName), - !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && - !this.editorView.isFilterDirectionArrowsEnabled(), - ), - ); - } - }); + const d = sections[0]; + this.updateTrainrunSectionPathForCollapsedChain(d); + viewTrainrunSectionDataObjects.push( + new TrainrunSectionViewObject( + editorView, + d, + TrainrunSectionsView.getNode(d, true).isNonStop(d), + TrainrunSectionsView.getNode(d, false).isNonStop(d), + TrainrunSectionsView.isMuted(d, selectedTrainrun, connectedTrainIds), + this.getHiddenTagForTime(d, TrainrunSectionText.SourceDeparture), + this.getHiddenTagForTime(d, TrainrunSectionText.TargetDeparture), + this.getHiddenTagForTime(d, TrainrunSectionText.TrainrunSectionTravelTime), + this.getHiddenTagForTime(d, TrainrunSectionText.TrainrunSectionName), + !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && + !this.editorView.isFilterDirectionArrowsEnabled(), + ), + ); }); return viewTrainrunSectionDataObjects; @@ -2486,20 +2466,6 @@ export class TrainrunSectionsView { return sections; } - /** - * Determine if a trainrun section should be displayed (not an intermediate in a collapsed chain) - */ - private shouldDisplayTrainrunSection(section: TrainrunSection): boolean { - return !section.getSourceNode().getIsCollapsed() || !section.getTargetNode().getIsCollapsed(); - } - - private static isExitingCollapsedChain(trainrunSection: TrainrunSection): boolean { - return ( - TrainrunSectionsView.getNode(trainrunSection, true).getIsCollapsed() && - !TrainrunSectionsView.getNode(trainrunSection, false).getIsCollapsed() - ); - } - /** * Apply basic filtering to a path */ From 1f46a61685922a178e7723aaf7f32cd40b42fab0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 31 Oct 2025 15:29:20 +0100 Subject: [PATCH 3/7] Add TrainrunSectionViewObject.getTrainrun() TrainrunSectionViewObject will represent multiple trainrun sections soon. Add a helper to get the parent trainrun to reduce reliance on a single trainrun. Signed-off-by: Simon Ser --- .../editor-main-view/data-views/d3.utils.ts | 6 +-- .../data-views/trainrunSectionViewObject.ts | 4 ++ .../data-views/trainrunsections.view.ts | 42 +++++++++---------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/app/view/editor-main-view/data-views/d3.utils.ts b/src/app/view/editor-main-view/data-views/d3.utils.ts index 53f36340..31bf0379 100644 --- a/src/app/view/editor-main-view/data-views/d3.utils.ts +++ b/src/app/view/editor-main-view/data-views/d3.utils.ts @@ -45,21 +45,21 @@ export class D3Utils { d3.selectAll(StaticDomTags.EDGE_LINE_ARROW_DOM_REF) .filter( (d: TrainrunSectionViewObject) => - d !== undefined && d.trainrunSection.getTrainrunId() === trainrunSection.getTrainrunId(), + d !== undefined && d.getTrainrun().getId() === trainrunSection.getTrainrunId(), ) .classed(StaticDomTags.TAG_HOVER, true); d3.selectAll(StaticDomTags.EDGE_LINE_DOM_REF) .filter( (d: TrainrunSectionViewObject) => - d !== undefined && d.trainrunSection.getTrainrunId() === trainrunSection.getTrainrunId(), + d !== undefined && d.getTrainrun().getId() === trainrunSection.getTrainrunId(), ) .classed(StaticDomTags.TAG_HOVER, true); d3.selectAll(StaticDomTags.EDGE_ROOT_CONTAINER_DOM_REF) .filter( (d: TrainrunSectionViewObject) => - d !== undefined && d.trainrunSection.getTrainrunId() === trainrunSection.getTrainrunId(), + d !== undefined && d.getTrainrun().getId() === trainrunSection.getTrainrunId(), ) .classed(StaticDomTags.TAG_HOVER, true); diff --git a/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts b/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts index 40d5bca3..db315757 100644 --- a/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts +++ b/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts @@ -30,6 +30,10 @@ export class TrainrunSectionViewObject { ); } + getTrainrun() { + return this.trainrunSection.getTrainrun(); + } + static generateKey( editorView: EditorView, d: TrainrunSection, diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 0ed98b95..85d8e8cb 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts @@ -1132,7 +1132,7 @@ export class TrainrunSectionsView { groupEnter .filter((d: TrainrunSectionViewObject) => { - const displayTextBackground = d.trainrunSection.getTrainrun().isRoundTrip() || isOneWayText; + const displayTextBackground = d.getTrainrun().isRoundTrip() || isOneWayText; return ( this.filterTrainrunsectionAtNode(d.trainrunSection, atSource) && this.filterTimeTrainrunsectionNonStop(d.trainrunSection, atSource, isArrival) && @@ -1152,7 +1152,7 @@ export class TrainrunSectionsView { ) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().getId(), + d.getTrainrun().getId(), ) .attr(StaticDomTags.EDGE_LINE_TEXT_INDEX, lineTextElement) .attr( @@ -1239,7 +1239,7 @@ export class TrainrunSectionsView { groupLinesEnter .append(StaticDomTags.EDGE_LINE_ARROW_SVG) .attr("d", (d: TrainrunSectionViewObject) => { - return d.trainrunSection.getTrainrun().isRoundTrip() ? "" : "M-4,-5L2,0L-4,5Z"; + return d.getTrainrun().isRoundTrip() ? "" : "M-4,-5L2,0L-4,5Z"; }) .attr("transform", (d: TrainrunSectionViewObject) => this.translateAndRotateArrow(d.trainrunSection, arrowType), @@ -1266,10 +1266,10 @@ export class TrainrunSectionsView { ) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().getId(), + d.getTrainrun().getId(), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_LINE_ARROW_EDITOR, true) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => @@ -1313,13 +1313,13 @@ export class TrainrunSectionsView { ) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().getId(), + d.getTrainrun().getId(), ) .attr("d", (d: TrainrunSectionViewObject) => D3Utils.getPathAsSVGString(this.transformPath(d.trainrunSection)), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_EVENT_DISABLED, !enableEvents) .classed(classRef, true); @@ -1378,7 +1378,7 @@ export class TrainrunSectionsView { ) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrunId(), + d.getTrainrun().getId(), ) .attr("d", (d: TrainrunSectionViewObject) => TrainrunSectionsView.createSemicircle( @@ -1406,7 +1406,7 @@ export class TrainrunSectionsView { TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ); } @@ -1450,7 +1450,7 @@ export class TrainrunSectionsView { .attr("class", StaticDomTags.EDGE_LINE_PIN_CLASS) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrunId(), + d.getTrainrun().getId(), ) .attr("cx", (d: TrainrunSectionViewObject) => TrainrunSectionsView.getPosition(d.trainrunSection, atSource).getX(), @@ -1502,7 +1502,7 @@ export class TrainrunSectionsView { TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .on("mouseover", (d: TrainrunSectionViewObject, i, a) => this.onTrainrunSectionMouseoverPin( @@ -1545,7 +1545,7 @@ export class TrainrunSectionsView { const renderingObjects = groupEnter .filter((d: TrainrunSectionViewObject) => { const displayTextElement = - d.trainrunSection.getTrainrun().isRoundTrip() || isDefaultText || isOneWayText; + d.getTrainrun().isRoundTrip() || isDefaultText || isOneWayText; return ( this.filterTrainrunsectionAtNode(d.trainrunSection, atSource) && @@ -1566,7 +1566,7 @@ export class TrainrunSectionsView { .attr("data-testid", StaticDomTags.EDGE_LINE_TEXT_CLASS) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrunId(), + d.getTrainrun().getId(), ) .attr(StaticDomTags.EDGE_LINE_TEXT_INDEX, textElement) .attr("x", (d: TrainrunSectionViewObject) => { @@ -1607,7 +1607,7 @@ export class TrainrunSectionsView { this.getAdditionPositioningValueForViewObjectWithCollapsedSupport(d, textElement), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), @@ -1698,7 +1698,7 @@ export class TrainrunSectionsView { ) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrunId(), + d.getTrainrun().getId(), ) .attr(StaticDomTags.EDGE_LINE_TEXT_INDEX, textElement) .attr("x", 0) @@ -1710,7 +1710,7 @@ export class TrainrunSectionsView { ), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), @@ -1919,7 +1919,7 @@ export class TrainrunSectionsView { .attr("class", StaticDomTags.EDGE_ROOT_CONTAINER) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), @@ -1929,7 +1929,7 @@ export class TrainrunSectionsView { .append(StaticDomTags.EDGE_SVG) .attr("class", StaticDomTags.EDGE_CLASS + " Lines") .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr("data-testid", `${StaticDomTags.EDGE_CLASS}-lines`); @@ -1938,7 +1938,7 @@ export class TrainrunSectionsView { .append(StaticDomTags.EDGE_SVG) .attr("class", StaticDomTags.EDGE_CLASS + " Labels") .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => - d.trainrunSection.getTrainrun().selected(), + d.getTrainrun().selected(), ) .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) .attr("data-testid", `${StaticDomTags.EDGE_CLASS}-labels`); @@ -2848,7 +2848,7 @@ export class TrainrunSectionsView { ) .attr(StaticDomTags.EDGE_ID, (t: TrainrunSectionViewObject) => t.trainrunSection.getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (t: TrainrunSectionViewObject) => - t.trainrunSection.getTrainrun().getId(), + t.getTrainrun().getId(), ) .attr("cx", position.getX()) .attr("cy", position.getY()) @@ -2859,7 +2859,7 @@ export class TrainrunSectionsView { TrainrunSectionsView.isMuted(t.trainrunSection, selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_SELECTED, (t: TrainrunSectionViewObject) => - t.trainrunSection.getTrainrun().selected(), + t.getTrainrun().selected(), ) .classed(StaticDomTags.EDGE_LINE_STOPS_FILL, () => !collapsedStops) .on("mouseover", (t: TrainrunSectionViewObject, i, a) => From e0e2fed84253285ca165060545754a89b72dc21d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 31 Oct 2025 16:10:58 +0100 Subject: [PATCH 4/7] Store full trainrun section chain in TrainrunSectionViewObject This makes it clear that there isn't a single trainrun section per TrainrunSectionViewObject: a single TrainrunSectionViewObject can hold multiple sections. The full collapsed chain is stored. For now, blindly replace trainrunSection with trainrunSections[0], to be cleaned up in future commits. Signed-off-by: Simon Ser --- .../editor-main-view/data-views/d3.utils.ts | 38 ++-- .../data-views/trainrunSectionViewObject.ts | 11 +- .../data-views/trainrunsections.view.ts | 202 +++++++++--------- 3 files changed, 125 insertions(+), 126 deletions(-) diff --git a/src/app/view/editor-main-view/data-views/d3.utils.ts b/src/app/view/editor-main-view/data-views/d3.utils.ts index 31bf0379..14432fcd 100644 --- a/src/app/view/editor-main-view/data-views/d3.utils.ts +++ b/src/app/view/editor-main-view/data-views/d3.utils.ts @@ -90,20 +90,20 @@ export class D3Utils { d3.selectAll(StaticDomTags.EDGE_LINE_ARROW_DOM_REF) .filter( (d: TrainrunSectionViewObject) => - d !== undefined && d.trainrunSection.getTrainrunId() === trainrunSection.getTrainrunId(), + d !== undefined && d.trainrunSections[0].getTrainrunId() === trainrunSection.getTrainrunId(), ) .classed(StaticDomTags.TAG_HOVER, false); d3.selectAll(StaticDomTags.EDGE_LINE_DOM_REF) .filter( (d: TrainrunSectionViewObject) => - d !== undefined && d.trainrunSection.getTrainrunId() === trainrunSection.getTrainrunId(), + d !== undefined && d.trainrunSections[0].getTrainrunId() === trainrunSection.getTrainrunId(), ) .classed(StaticDomTags.TAG_HOVER, false); d3.selectAll(StaticDomTags.EDGE_ROOT_CONTAINER_DOM_REF) .filter( (d: TrainrunSectionViewObject) => - d !== undefined && d.trainrunSection.getTrainrunId() === trainrunSection.getTrainrunId(), + d !== undefined && d.trainrunSections[0].getTrainrunId() === trainrunSection.getTrainrunId(), ) .classed(StaticDomTags.TAG_HOVER, false); @@ -347,7 +347,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.TAG_SELECTED, false) .classed(StaticDomTags.TAG_HOVER, false) @@ -359,7 +359,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.TAG_SELECTED, false) .classed(StaticDomTags.TAG_HOVER, false) @@ -371,7 +371,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.TAG_SELECTED, false) .classed(StaticDomTags.TAG_HOVER, false) @@ -383,7 +383,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.EDGE_LINE_GRAYEDOUT, true); @@ -394,8 +394,8 @@ export class D3Utils { return false; } return ( - d.trainrunSection.getId() === trainrunSection.getId() && - d.trainrunSection.getSourceNodeId() === grayoutEdgeLinePinNode.getId() + d.trainrunSections[0].getId() === trainrunSection.getId() && + d.trainrunSections[0].getSourceNodeId() === grayoutEdgeLinePinNode.getId() ); }) .classed(StaticDomTags.EDGE_LINE_GRAYEDOUT, true); @@ -405,8 +405,8 @@ export class D3Utils { return false; } return ( - d.trainrunSection.getId() === trainrunSection.getId() && - d.trainrunSection.getTargetNodeId() === grayoutEdgeLinePinNode.getId() + d.trainrunSections[0].getId() === trainrunSection.getId() && + d.trainrunSections[0].getTargetNodeId() === grayoutEdgeLinePinNode.getId() ); }) .classed(StaticDomTags.EDGE_LINE_GRAYEDOUT, true); @@ -419,7 +419,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.TAG_SELECTED, true) .classed(StaticDomTags.TAG_HOVER, false) @@ -431,7 +431,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.TAG_SELECTED, true) .classed(StaticDomTags.TAG_HOVER, false) @@ -443,7 +443,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.TAG_SELECTED, true) .classed(StaticDomTags.TAG_HOVER, false) @@ -455,7 +455,7 @@ export class D3Utils { if (d === undefined) { return false; } - return d.trainrunSection.getId() === trainrunSection.getId(); + return d.trainrunSections[0].getId() === trainrunSection.getId(); }) .classed(StaticDomTags.EDGE_LINE_GRAYEDOUT, false); @@ -466,8 +466,8 @@ export class D3Utils { return false; } return ( - d.trainrunSection.getId() === trainrunSection.getId() && - d.trainrunSection.getSourceNodeId() === grayoutEdgeLinePinNode.getId() + d.trainrunSections[0].getId() === trainrunSection.getId() && + d.trainrunSections[0].getSourceNodeId() === grayoutEdgeLinePinNode.getId() ); }) .classed(StaticDomTags.EDGE_LINE_GRAYEDOUT, false); @@ -477,8 +477,8 @@ export class D3Utils { return false; } return ( - d.trainrunSection.getId() === trainrunSection.getId() && - d.trainrunSection.getTargetNodeId() === grayoutEdgeLinePinNode.getId() + d.trainrunSections[0].getId() === trainrunSection.getId() && + d.trainrunSections[0].getTargetNodeId() === grayoutEdgeLinePinNode.getId() ); }) .classed(StaticDomTags.EDGE_LINE_GRAYEDOUT, false); diff --git a/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts b/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts index db315757..c28d31a9 100644 --- a/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts +++ b/src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts @@ -6,7 +6,7 @@ export class TrainrunSectionViewObject { constructor( private editorView: EditorView, - public trainrunSection: TrainrunSection, + public trainrunSections: TrainrunSection[], isNonStopAtSource: boolean, isNonStopAtTarget: boolean, isMuted: boolean, @@ -18,7 +18,7 @@ export class TrainrunSectionViewObject { ) { this.key = TrainrunSectionViewObject.generateKey( editorView, - trainrunSection, + trainrunSections, isNonStopAtSource, isNonStopAtTarget, isMuted, @@ -31,12 +31,12 @@ export class TrainrunSectionViewObject { } getTrainrun() { - return this.trainrunSection.getTrainrun(); + return this.trainrunSections[0].getTrainrun(); } static generateKey( editorView: EditorView, - d: TrainrunSection, + trainrunSections: TrainrunSection[], isNonStopAtSource: boolean, isNonStopAtTarget: boolean, isMuted: boolean, @@ -46,6 +46,7 @@ export class TrainrunSectionViewObject { hiddenTagTrainrunName: boolean, hiddenTagDirectionArrows: boolean, ): string { + const d = trainrunSections[0]; const cumulativeTravelTimeData = editorView.getCumulativeTravelTimeAndNodePath(d); const cumulativeTravelTime = cumulativeTravelTimeData[cumulativeTravelTimeData.length - 1].sumTravelTime; @@ -166,6 +167,4 @@ export class TrainrunSectionViewObject { return key; } - - } diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 85d8e8cb..78edc2d2 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts @@ -84,7 +84,7 @@ export class TrainrunSectionsView { viewObject: TrainrunSectionViewObject, trainrunSectionText: TrainrunSectionText, ) { - const trainrunSection = viewObject.trainrunSection; + const trainrunSection = viewObject.trainrunSections[0]; const x = trainrunSection.getTextPositionX(trainrunSectionText); const y = trainrunSection.getTextPositionY(trainrunSectionText); @@ -151,7 +151,7 @@ export class TrainrunSectionsView { viewObject: TrainrunSectionViewObject, trainrunSectionText: TrainrunSectionText, ) { - const trainrunSection = viewObject.trainrunSection; + const trainrunSection = viewObject.trainrunSections[0]; const collapsedChainPath = this.getCollapsedChainPath(trainrunSection); if (collapsedChainPath && collapsedChainPath.length >= MIN_PATH_LENGTH_FOR_ANGLE) { @@ -1134,8 +1134,8 @@ export class TrainrunSectionsView { .filter((d: TrainrunSectionViewObject) => { const displayTextBackground = d.getTrainrun().isRoundTrip() || isOneWayText; return ( - this.filterTrainrunsectionAtNode(d.trainrunSection, atSource) && - this.filterTimeTrainrunsectionNonStop(d.trainrunSection, atSource, isArrival) && + this.filterTrainrunsectionAtNode(d.trainrunSections[0], atSource) && + this.filterTimeTrainrunsectionNonStop(d.trainrunSections[0], atSource, isArrival) && displayTextBackground ); }) @@ -1145,12 +1145,12 @@ export class TrainrunSectionsView { (d: TrainrunSectionViewObject) => StaticDomTags.EDGE_LINE_TEXT_BACKGROUND_CLASS + TrainrunSectionsView.createTrainrunSectionFrequencyClassAttribute( - d.trainrunSection, + d.trainrunSections[0], selectedTrainrun, connectedTrainIds, ), ) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => d.getTrainrun().getId(), ) @@ -1158,9 +1158,9 @@ export class TrainrunSectionsView { .attr( "x", (d: TrainrunSectionViewObject) => - d.trainrunSection.getTextPositionX(lineTextElement) - + d.trainrunSections[0].getTextPositionX(lineTextElement) - TrainrunSectionsView.getTrainrunSectionValueTextWidth( - d.trainrunSection, + d.trainrunSections[0], lineTextElement, ) / 2, @@ -1168,19 +1168,19 @@ export class TrainrunSectionsView { .attr( "y", (d: TrainrunSectionViewObject) => - d.trainrunSection.getTextPositionY(lineTextElement) - + d.trainrunSections[0].getTextPositionY(lineTextElement) - TRAINRUN_SECTION_TEXT_AREA_HEIGHT / 2, ) .attr("width", (d: TrainrunSectionViewObject) => { return TrainrunSectionsView.getTrainrunSectionValueTextWidth( - d.trainrunSection, + d.trainrunSections[0], lineTextElement, ); }) .attr("height", TRAINRUN_SECTION_TEXT_AREA_HEIGHT) .classed(TrainrunSectionText[lineTextElement], true) .classed(StaticDomTags.TAG_HIDDEN, (d: TrainrunSectionViewObject) => - this.getHiddenTagForTime(d.trainrunSection, lineTextElement), + this.getHiddenTagForTime(d.trainrunSections[0], lineTextElement), ); } @@ -1242,14 +1242,14 @@ export class TrainrunSectionsView { return d.getTrainrun().isRoundTrip() ? "" : "M-4,-5L2,0L-4,5Z"; }) .attr("transform", (d: TrainrunSectionViewObject) => - this.translateAndRotateArrow(d.trainrunSection, arrowType), + this.translateAndRotateArrow(d.trainrunSections[0], arrowType), ) .attr( "class", (d: TrainrunSectionViewObject) => StaticDomTags.EDGE_LINE_ARROW_CLASS + TrainrunSectionsView.createTrainrunSectionFrequencyClassAttribute( - d.trainrunSection, + d.trainrunSections[0], selectedTrainrun, connectedTrainIds, ), @@ -1260,11 +1260,11 @@ export class TrainrunSectionsView { !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && (!this.editorView.isFilterDirectionArrowsEnabled() || !this.filterTrainrunsectionAtNode( - d.trainrunSection, + d.trainrunSections[0], arrowType === "BEGINNING_ARROW", )), ) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => d.getTrainrun().getId(), ) @@ -1273,17 +1273,17 @@ export class TrainrunSectionsView { ) .classed(StaticDomTags.TAG_LINE_ARROW_EDITOR, true) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), + TrainrunSectionsView.isMuted(d.trainrunSections[0], selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_EVENT_DISABLED, !enableEvents) .on("mouseup", (d: TrainrunSectionViewObject, i, a) => { - this.onTrainrunDirectionArrowMouseUp(d.trainrunSection, a[i]); + this.onTrainrunDirectionArrowMouseUp(d.trainrunSections[0], a[i]); }) .on("mouseover", (d: TrainrunSectionViewObject, i, a) => { - this.onTrainrunSectionMouseoverPath(d.trainrunSection, a[i]); + this.onTrainrunSectionMouseoverPath(d.trainrunSections[0], a[i]); }) .on("mouseout", (d: TrainrunSectionViewObject, i, a) => { - this.onTrainrunSectionMouseoutPath(d.trainrunSection, a[i]); + this.onTrainrunSectionMouseoutPath(d.trainrunSections[0], a[i]); }); }); } @@ -1298,7 +1298,7 @@ export class TrainrunSectionsView { ) { const trainrunSectionElements = groupEnter .filter((d: TrainrunSectionViewObject) => { - return !levelFreqFilter.includes(d.trainrunSection.getFrequencyLinePatternRef()); + return !levelFreqFilter.includes(d.trainrunSections[0].getFrequencyLinePatternRef()); }) .append(StaticDomTags.EDGE_LINE_SVG) .attr( @@ -1306,17 +1306,17 @@ export class TrainrunSectionsView { (d: TrainrunSectionViewObject) => StaticDomTags.EDGE_LINE_CLASS + TrainrunSectionsView.createTrainrunSectionFrequencyClassAttribute( - d.trainrunSection, + d.trainrunSections[0], selectedTrainrun, connectedTrainIds, ), ) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => d.getTrainrun().getId(), ) .attr("d", (d: TrainrunSectionViewObject) => - D3Utils.getPathAsSVGString(this.transformPath(d.trainrunSection)), + D3Utils.getPathAsSVGString(this.transformPath(d.trainrunSections[0])), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => d.getTrainrun().selected(), @@ -1328,17 +1328,17 @@ export class TrainrunSectionsView { trainrunSectionElements .on("mouseup", (d: TrainrunSectionViewObject, i, a) => { if (enableEvents) { - this.onTrainrunSectionMouseUp(d.trainrunSection, a[i]); + this.onTrainrunSectionMouseUp(d.trainrunSections[0], a[i]); } }) .on("mouseover", (d: TrainrunSectionViewObject, i, a) => { if (enableEvents) { - this.onTrainrunSectionMouseoverPath(d.trainrunSection, a[i]); + this.onTrainrunSectionMouseoverPath(d.trainrunSections[0], a[i]); } }) .on("mouseout", (d: TrainrunSectionViewObject, i, a) => { if (enableEvents) { - this.onTrainrunSectionMouseoutPath(d.trainrunSection, a[i]); + this.onTrainrunSectionMouseoutPath(d.trainrunSections[0], a[i]); } }); } @@ -1352,11 +1352,11 @@ export class TrainrunSectionsView { ) { groupEnter .filter((d: TrainrunSectionViewObject) => - this.filterTrainrunsectionAtNode(d.trainrunSection, atSource), + this.filterTrainrunsectionAtNode(d.trainrunSections[0], atSource), ) .filter((d: TrainrunSectionViewObject) => { - const trans = TrainrunSectionsView.getNode(d.trainrunSection, atSource).getTransition( - d.trainrunSection.getId(), + const trans = TrainrunSectionsView.getNode(d.trainrunSections[0], atSource).getTransition( + d.trainrunSections[0].getId(), ); if (trans === undefined) { return true; @@ -1371,39 +1371,39 @@ export class TrainrunSectionsView { " " + StaticDomTags.TAG_FILL + TrainrunSectionsView.createTrainrunSectionFrequencyClassAttribute( - d.trainrunSection, + d.trainrunSections[0], selectedTrainrun, connectedTrainIds, ), ) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => d.getTrainrun().getId(), ) .attr("d", (d: TrainrunSectionViewObject) => TrainrunSectionsView.createSemicircle( - d.trainrunSection, - TrainrunSectionsView.getPosition(d.trainrunSection, atSource), + d.trainrunSections[0], + TrainrunSectionsView.getPosition(d.trainrunSections[0], atSource), ), ) .attr( "transform", (d: TrainrunSectionViewObject) => "translate(" + - TrainrunSectionsView.getPosition(d.trainrunSection, atSource).getX() + + TrainrunSectionsView.getPosition(d.trainrunSections[0], atSource).getX() + "," + - TrainrunSectionsView.getPosition(d.trainrunSection, atSource).getY() + + TrainrunSectionsView.getPosition(d.trainrunSections[0], atSource).getY() + ")", ) .attr(StaticDomTags.EDGE_NODE_ID, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.getNode(d.trainrunSection, atSource).getId(), + TrainrunSectionsView.getNode(d.trainrunSections[0], atSource).getId(), ) .classed(StaticDomTags.EDGE_IS_TARGET, !atSource) .classed(StaticDomTags.TAG_HIDDEN, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.getNode(d.trainrunSection, atSource).isNonStop(d.trainrunSection), + TrainrunSectionsView.getNode(d.trainrunSections[0], atSource).isNonStop(d.trainrunSections[0]), ) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), + TrainrunSectionsView.isMuted(d.trainrunSections[0], selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => d.getTrainrun().selected(), @@ -1448,26 +1448,26 @@ export class TrainrunSectionsView { groupEnter .append(StaticDomTags.EDGE_LINE_PIN_SVG) .attr("class", StaticDomTags.EDGE_LINE_PIN_CLASS) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => d.getTrainrun().getId(), ) .attr("cx", (d: TrainrunSectionViewObject) => - TrainrunSectionsView.getPosition(d.trainrunSection, atSource).getX(), + TrainrunSectionsView.getPosition(d.trainrunSections[0], atSource).getX(), ) .attr("cy", (d: TrainrunSectionViewObject) => - TrainrunSectionsView.getPosition(d.trainrunSection, atSource).getY(), + TrainrunSectionsView.getPosition(d.trainrunSections[0], atSource).getY(), ) .attr("r", DEFAULT_PIN_RADIUS) .attr(StaticDomTags.EDGE_NODE_ID, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.getNode(d.trainrunSection, atSource).getId(), + TrainrunSectionsView.getNode(d.trainrunSections[0], atSource).getId(), ) .classed( StaticDomTags.TAG_HIDDEN, (d: TrainrunSectionViewObject) => !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && !this.editorView.checkFilterNonStopNode( - TrainrunSectionsView.getNode(d.trainrunSection, atSource), + TrainrunSectionsView.getNode(d.trainrunSections[0], atSource), ), ) .classed( @@ -1475,48 +1475,48 @@ export class TrainrunSectionsView { (d: TrainrunSectionViewObject) => !this.editorView.isTemporaryDisableFilteringOfItemsInViewEnabled() && !this.editorView.checkFilterNonStopNode( - TrainrunSectionsView.getNode(d.trainrunSection, atSource), + TrainrunSectionsView.getNode(d.trainrunSections[0], atSource), ), ) .classed(atSource ? StaticDomTags.EDGE_IS_SOURCE : StaticDomTags.EDGE_IS_TARGET, true) .classed(StaticDomTags.EDGE_IS_END_NODE, (d: TrainrunSectionViewObject) => { - let node = d.trainrunSection.getTargetNode(); + let node = d.trainrunSections[0].getTargetNode(); if (atSource) { - node = d.trainrunSection.getSourceNode(); + node = d.trainrunSections[0].getSourceNode(); } - const port = node.getPortOfTrainrunSection(d.trainrunSection.getId()); + const port = node.getPortOfTrainrunSection(d.trainrunSections[0].getId()); const trans = node.getTransitionFromPortId(port.getId()); return trans === undefined; }) .classed(StaticDomTags.EDGE_IS_NOT_END_NODE, (d: TrainrunSectionViewObject) => { - let node = d.trainrunSection.getTargetNode(); + let node = d.trainrunSections[0].getTargetNode(); if (atSource) { - node = d.trainrunSection.getSourceNode(); + node = d.trainrunSections[0].getSourceNode(); } - const port = node.getPortOfTrainrunSection(d.trainrunSection.getId()); + const port = node.getPortOfTrainrunSection(d.trainrunSections[0].getId()); const trans = node.getTransitionFromPortId(port.getId()); return trans !== undefined; }) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), + TrainrunSectionsView.isMuted(d.trainrunSections[0], selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => d.getTrainrun().selected(), ) .on("mouseover", (d: TrainrunSectionViewObject, i, a) => this.onTrainrunSectionMouseoverPin( - TrainrunSectionsView.getNode(d.trainrunSection, atSource), + TrainrunSectionsView.getNode(d.trainrunSections[0], atSource), a[i], ), ) .on("mouseout", (d: TrainrunSectionViewObject, i, a) => - this.onTrainrunSectionMouseoutPin(d.trainrunSection, a[i], atSource), + this.onTrainrunSectionMouseoutPin(d.trainrunSections[0], a[i], atSource), ) .on("mousedown", () => this.onTrainrunSectionMousedownPin()) .on("mousemove", () => this.onTrainrunSectionMousemovePin()) .on("mouseup", (d: TrainrunSectionViewObject) => - this.onTrainrunSectionMouseupPin(d.trainrunSection, atSource), + this.onTrainrunSectionMouseupPin(d.trainrunSections[0], atSource), ); } @@ -1548,58 +1548,58 @@ export class TrainrunSectionsView { d.getTrainrun().isRoundTrip() || isDefaultText || isOneWayText; return ( - this.filterTrainrunsectionAtNode(d.trainrunSection, atSource) && - this.filterTimeTrainrunsectionNonStop(d.trainrunSection, atSource, isArrival) && - TrainrunSectionsView.hasWarning(d.trainrunSection, textElement) === hasWarning && + this.filterTrainrunsectionAtNode(d.trainrunSections[0], atSource) && + this.filterTimeTrainrunsectionNonStop(d.trainrunSections[0], atSource, isArrival) && + TrainrunSectionsView.hasWarning(d.trainrunSections[0], textElement) === hasWarning && displayTextElement ); }) .append(StaticDomTags.EDGE_LINE_TEXT_SVG) .attr("class", (d: TrainrunSectionViewObject) => TrainrunSectionsView.getTrainrunSectionTimeElementClass( - d.trainrunSection, + d.trainrunSections[0], textElement, selectedTrainrun, connectedTrainIds, ), ) .attr("data-testid", StaticDomTags.EDGE_LINE_TEXT_CLASS) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => d.getTrainrun().getId(), ) .attr(StaticDomTags.EDGE_LINE_TEXT_INDEX, textElement) .attr("x", (d: TrainrunSectionViewObject) => { - const collapsedChainPath = this.getCollapsedChainPath(d.trainrunSection); + const collapsedChainPath = this.getCollapsedChainPath(d.trainrunSections[0]); if ( collapsedChainPath && collapsedChainPath.length >= 4 && (textElement === TrainrunSectionText.TargetDeparture || textElement === TrainrunSectionText.TargetArrival) ) { - const chainSections = this.getAllSectionsInCollapsedChain(d.trainrunSection); + const chainSections = this.getAllSectionsInCollapsedChain(d.trainrunSections[0]); if (chainSections.length > 1) { const lastSection = chainSections[chainSections.length - 1]; return lastSection.getTextPositionX(textElement); } } - return TrainrunSectionsView.getPositionX(d.trainrunSection, textElement); + return TrainrunSectionsView.getPositionX(d.trainrunSections[0], textElement); }) .attr("y", (d: TrainrunSectionViewObject) => { - const collapsedChainPath = this.getCollapsedChainPath(d.trainrunSection); + const collapsedChainPath = this.getCollapsedChainPath(d.trainrunSections[0]); if ( collapsedChainPath && collapsedChainPath.length >= 4 && (textElement === TrainrunSectionText.TargetDeparture || textElement === TrainrunSectionText.TargetArrival) ) { - const chainSections = this.getAllSectionsInCollapsedChain(d.trainrunSection); + const chainSections = this.getAllSectionsInCollapsedChain(d.trainrunSections[0]); if (chainSections.length > 1) { const lastSection = chainSections[chainSections.length - 1]; return lastSection.getTextPositionY(textElement); } } - return TrainrunSectionsView.getPositionY(d.trainrunSection, textElement); + return TrainrunSectionsView.getPositionY(d.trainrunSections[0], textElement); }) .attr( TrainrunSectionsView.getAdditionPositioningAttr(textElement), @@ -1610,40 +1610,40 @@ export class TrainrunSectionsView { d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), + TrainrunSectionsView.isMuted(d.trainrunSections[0], selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_WARNING, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.hasWarning(d.trainrunSection, textElement), + TrainrunSectionsView.hasWarning(d.trainrunSections[0], textElement), ) .classed(StaticDomTags.TAG_HIDDEN, (d: TrainrunSectionViewObject) => - this.getHiddenTagForTime(d.trainrunSection, textElement), + this.getHiddenTagForTime(d.trainrunSections[0], textElement), ) .classed(StaticDomTags.TAG_EVENT_DISABLED, !enableEvents) .text((d: TrainrunSectionViewObject) => this.getTrainrunSectionValueToShowWithCollapsedSupport(d, textElement, this.editorView), ) .attr("style", (d: TrainrunSectionViewObject) => - TrainrunSectionsView.getTrainrunSectionValueHtmlStyle(d.trainrunSection, textElement), + TrainrunSectionsView.getTrainrunSectionValueHtmlStyle(d.trainrunSections[0], textElement), ) .on("mouseover", (d: TrainrunSectionViewObject, i, a) => { if (enableEvents) { - this.onTrainrunSectionTextMouseover(d.trainrunSection, a[i]); + this.onTrainrunSectionTextMouseover(d.trainrunSections[0], a[i]); } }) .on("mouseout", (d: TrainrunSectionViewObject, i, a) => { if (enableEvents) { - this.onTrainrunSectionTextMouseout(d.trainrunSection, a[i]); + this.onTrainrunSectionTextMouseout(d.trainrunSections[0], a[i]); } }) .on("mouseup", (d: TrainrunSectionViewObject, i, a) => { if (enableEvents) { - this.onTrainrunSectionElementClicked(d.trainrunSection, a[i], textElement); + this.onTrainrunSectionElementClicked(d.trainrunSections[0], a[i], textElement); } }); if (hasWarning) { renderingObjects.append("svg:title").text((d: TrainrunSectionViewObject) => { - return TrainrunSectionsView.getWarning(d.trainrunSection, textElement); + return TrainrunSectionsView.getWarning(d.trainrunSections[0], textElement); }); } } @@ -1685,18 +1685,18 @@ export class TrainrunSectionsView { const textElement = TrainrunSectionText.TrainrunSectionName; groupEnter .filter((d: TrainrunSectionViewObject) => - this.filterTrainrunsectionAtNode(d.trainrunSection, atSource), + this.filterTrainrunsectionAtNode(d.trainrunSections[0], atSource), ) .append(StaticDomTags.EDGE_LINE_TEXT_SVG) .attr("class", (d: TrainrunSectionViewObject) => TrainrunSectionsView.getTrainrunSectionTimeElementClass( - d.trainrunSection, + d.trainrunSections[0], textElement, selectedTrainrun, connectedTrainIds, ), ) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (d: TrainrunSectionViewObject) => d.getTrainrun().getId(), ) @@ -1705,7 +1705,7 @@ export class TrainrunSectionsView { .attr("y", 0) .attr("transform", (d: TrainrunSectionViewObject) => TrainrunSectionsView.getAdditionTextCloseToNodePositioningValue( - d.trainrunSection, + d.trainrunSections[0], atSource, ), ) @@ -1713,18 +1713,18 @@ export class TrainrunSectionsView { d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), + TrainrunSectionsView.isMuted(d.trainrunSections[0], selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_WARNING, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.hasWarning(d.trainrunSection, textElement), + TrainrunSectionsView.hasWarning(d.trainrunSections[0], textElement), ) .classed(StaticDomTags.TAG_EVENT_DISABLED, true) .classed(StaticDomTags.TAG_START_TEXT_ANCHOR, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.enforceStartTextAnchor(d.trainrunSection, atSource), + TrainrunSectionsView.enforceStartTextAnchor(d.trainrunSections[0], atSource), ) .text((d: TrainrunSectionViewObject) => TrainrunSectionsView.getTrainrunSectionNextAndDestinationNodeToShow( - d.trainrunSection, + d.trainrunSections[0], this.editorView, atSource, ), @@ -1770,7 +1770,7 @@ export class TrainrunSectionsView { ) .classed(StaticDomTags.TAG_SELECTED, () => trainrunSection.getTrainrun().selected()) .on("mouseup", (t: TrainrunSectionViewObject, i, a) => - this.onIntermediateStopMouseUp(t.trainrunSection, a[i]), + this.onIntermediateStopMouseUp(t.trainrunSections[0], a[i]), ); } @@ -1846,7 +1846,7 @@ export class TrainrunSectionsView { .select(a[i]) .append(StaticDomTags.EDGE_LINE_STOPS_GROUP_SVG) .attr("class", StaticDomTags.EDGE_LINE_STOPS_GROUP_CLASS); - this.createIntermediateStops(grp, t.trainrunSection, selectedTrainrun, connectedTrainIds); + this.createIntermediateStops(grp, t.trainrunSections[0], selectedTrainrun, connectedTrainIds); }); } @@ -1871,7 +1871,7 @@ export class TrainrunSectionsView { viewTrainrunSectionDataObjects.push( new TrainrunSectionViewObject( editorView, - d, + sections, TrainrunSectionsView.getNode(d, true).isNonStop(d), TrainrunSectionsView.getNode(d, false).isNonStop(d), TrainrunSectionsView.isMuted(d, selectedTrainrun, connectedTrainIds), @@ -1917,12 +1917,12 @@ export class TrainrunSectionsView { .enter() .append(StaticDomTags.EDGE_SVG) .attr("class", StaticDomTags.EDGE_ROOT_CONTAINER) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => d.getTrainrun().selected(), ) .classed(StaticDomTags.TAG_MUTED, (d: TrainrunSectionViewObject) => - TrainrunSectionsView.isMuted(d.trainrunSection, selectedTrainrun, connectedTrainIds), + TrainrunSectionsView.isMuted(d.trainrunSections[0], selectedTrainrun, connectedTrainIds), ); const groupLines = edgeRootContainerEnter @@ -1931,7 +1931,7 @@ export class TrainrunSectionsView { .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => d.getTrainrun().selected(), ) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr("data-testid", `${StaticDomTags.EDGE_CLASS}-lines`); const groupLabels = edgeRootContainerEnter @@ -1940,7 +1940,7 @@ export class TrainrunSectionsView { .classed(StaticDomTags.TAG_SELECTED, (d: TrainrunSectionViewObject) => d.getTrainrun().selected(), ) - .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId()) .attr("data-testid", `${StaticDomTags.EDGE_CLASS}-labels`); // Default case: Render default trainrunSection @@ -2117,7 +2117,7 @@ export class TrainrunSectionsView { (atSource ? StaticDomTags.EDGE_IS_TARGET : StaticDomTags.EDGE_IS_SOURCE), ) .filter( - (d: TrainrunSectionViewObject) => d.trainrunSection.getId() === trainrunSection.getId(), + (d: TrainrunSectionViewObject) => d.trainrunSections[0].getId() === trainrunSection.getId(), ); const startAT: Vec2D = new Vec2D(+obj.attr("cx"), +obj.attr("cy")); this.editorView.trainrunSectionPreviewLineView.setExistingTrainrunSection(trainrunSection); @@ -2510,7 +2510,7 @@ export class TrainrunSectionsView { ) { const groupLines = inGroupLines.filter( (d: TrainrunSectionViewObject) => - !this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSection), + !this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSections[0]), ); this.make4LayerTrainrunSectionLines( @@ -2524,7 +2524,7 @@ export class TrainrunSectionsView { if (!this.editorView.isElementDragging()) { const groupLabels = inGroupLabels.filter( (d: TrainrunSectionViewObject) => - !this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSection), + !this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSections[0]), ); if (this.editorView.getLevelOfDetail() === LevelOfDetail.FULL) { @@ -2631,7 +2631,7 @@ export class TrainrunSectionsView { inGroupLabels, ) { const groupLines = inGroupLines.filter((d: TrainrunSectionViewObject) => - this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSection), + this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSections[0]), ); this.make4LayerTrainrunSectionLines( @@ -2644,7 +2644,7 @@ export class TrainrunSectionsView { if (!this.editorView.isElementDragging()) { const groupLabels = inGroupLabels.filter((d: TrainrunSectionViewObject) => - this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSection), + this.filterOutAllTrainrunSectionWithHiddenNodeConnection(d.trainrunSections[0]), ); if ( @@ -2841,12 +2841,12 @@ export class TrainrunSectionsView { (t: TrainrunSectionViewObject) => StaticDomTags.EDGE_LINE_STOPS_CLASS + TrainrunSectionsView.createTrainrunSectionFrequencyClassAttribute( - t.trainrunSection, + t.trainrunSections[0], selectedTrainrun, connectedTrainIds, ), ) - .attr(StaticDomTags.EDGE_ID, (t: TrainrunSectionViewObject) => t.trainrunSection.getId()) + .attr(StaticDomTags.EDGE_ID, (t: TrainrunSectionViewObject) => t.trainrunSections[0].getId()) .attr(StaticDomTags.EDGE_LINE_LINE_ID, (t: TrainrunSectionViewObject) => t.getTrainrun().getId(), ) @@ -2856,23 +2856,23 @@ export class TrainrunSectionsView { .attr(StaticDomTags.EDGE_LINE_STOPS_INDEX, stopIndex) .attr("numberOfStops", numberOfStops) .classed(StaticDomTags.TAG_MUTED, (t: TrainrunSectionViewObject) => - TrainrunSectionsView.isMuted(t.trainrunSection, selectedTrainrun, connectedTrainIds), + TrainrunSectionsView.isMuted(t.trainrunSections[0], selectedTrainrun, connectedTrainIds), ) .classed(StaticDomTags.TAG_SELECTED, (t: TrainrunSectionViewObject) => t.getTrainrun().selected(), ) .classed(StaticDomTags.EDGE_LINE_STOPS_FILL, () => !collapsedStops) .on("mouseover", (t: TrainrunSectionViewObject, i, a) => - this.onIntermediateStopMouseOver(t.trainrunSection, stopIndex, position, a[i]), + this.onIntermediateStopMouseOver(t.trainrunSections[0], stopIndex, position, a[i]), ) .on("mouseout", (t: TrainrunSectionViewObject, i, a) => - this.onIntermediateStopMouseOut(t.trainrunSection, stopIndex, position, a[i]), + this.onIntermediateStopMouseOut(t.trainrunSections[0], stopIndex, position, a[i]), ) .on("mousedown", (t: TrainrunSectionViewObject, i, a) => - this.onIntermediateStopMouseDown(t.trainrunSection, stopIndex, position, a[i]), + this.onIntermediateStopMouseDown(t.trainrunSections[0], stopIndex, position, a[i]), ) .on("mouseup", (t: TrainrunSectionViewObject, i, a) => - this.onIntermediateStopMouseUp(t.trainrunSection, a[i]), + this.onIntermediateStopMouseUp(t.trainrunSections[0], a[i]), ); } @@ -2945,7 +2945,7 @@ export class TrainrunSectionsView { textElement: TrainrunSectionText, editorView: EditorView, ) { - const trainrunSection = viewObject.trainrunSection; + const trainrunSection = viewObject.trainrunSections[0]; // Use unified logic for both collapsed chains and regular sections return this.getCollapsedChainValueToShow(trainrunSection, textElement, editorView); From 83cf0513428880b998a06c639801efc973c66329 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 31 Oct 2025 17:27:38 +0100 Subject: [PATCH 5/7] fixup! simplify text nodes position computation Signed-off-by: Simon Ser --- .../data-views/trainrunsections.view.ts | 59 ++++--------------- 1 file changed, 12 insertions(+), 47 deletions(-) diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 78edc2d2..90c0ee57 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts @@ -1570,36 +1570,20 @@ export class TrainrunSectionsView { ) .attr(StaticDomTags.EDGE_LINE_TEXT_INDEX, textElement) .attr("x", (d: TrainrunSectionViewObject) => { - const collapsedChainPath = this.getCollapsedChainPath(d.trainrunSections[0]); - if ( - collapsedChainPath && - collapsedChainPath.length >= 4 && - (textElement === TrainrunSectionText.TargetDeparture || - textElement === TrainrunSectionText.TargetArrival) - ) { - const chainSections = this.getAllSectionsInCollapsedChain(d.trainrunSections[0]); - if (chainSections.length > 1) { - const lastSection = chainSections[chainSections.length - 1]; - return lastSection.getTextPositionX(textElement); - } - } - return TrainrunSectionsView.getPositionX(d.trainrunSections[0], textElement); + const section = + textElement === TrainrunSectionText.TargetDeparture || + textElement === TrainrunSectionText.TargetArrival + ? d.trainrunSections.at(-1) + : d.trainrunSections[0]; + return TrainrunSectionsView.getPositionX(section, textElement); }) .attr("y", (d: TrainrunSectionViewObject) => { - const collapsedChainPath = this.getCollapsedChainPath(d.trainrunSections[0]); - if ( - collapsedChainPath && - collapsedChainPath.length >= 4 && - (textElement === TrainrunSectionText.TargetDeparture || - textElement === TrainrunSectionText.TargetArrival) - ) { - const chainSections = this.getAllSectionsInCollapsedChain(d.trainrunSections[0]); - if (chainSections.length > 1) { - const lastSection = chainSections[chainSections.length - 1]; - return lastSection.getTextPositionY(textElement); - } - } - return TrainrunSectionsView.getPositionY(d.trainrunSections[0], textElement); + const section = + textElement === TrainrunSectionText.TargetDeparture || + textElement === TrainrunSectionText.TargetArrival + ? d.trainrunSections.at(-1) + : d.trainrunSections[0]; + return TrainrunSectionsView.getPositionY(section, textElement); }) .attr( TrainrunSectionsView.getAdditionPositioningAttr(textElement), @@ -2921,25 +2905,6 @@ export class TrainrunSectionsView { /** * Get the value to show for collapsed chains (with corrected times) */ - /** - * Get the node IDs path for a collapsed chain - */ - getCollapsedChainNodePath(trainrunSection: TrainrunSection): number[] | null { - const sourceNodeId = trainrunSection.getSourceNodeId(); - const targetNodeId = trainrunSection.getTargetNodeId(); - const sourceNode = trainrunSection.getSourceNode(); - const targetNode = trainrunSection.getTargetNode(); - - // Check if this section crosses collapsed nodes by looking at the full chain - const chainSections = this.getAllSectionsInCollapsedChain(trainrunSection); - - if (chainSections.length > 1) { - return [sourceNodeId, targetNodeId]; - } - - return null; - } - getTrainrunSectionValueToShowWithCollapsedSupport( viewObject: TrainrunSectionViewObject, textElement: TrainrunSectionText, From 625dcbb679cf7f2a94dff08a9015683df5e93cf5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 31 Oct 2025 17:30:09 +0100 Subject: [PATCH 6/7] fixup! drop unnecessary getCollapsedChainValueToShow() wrapper Signed-off-by: Simon Ser --- .../data-views/trainrunsections.view.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index 90c0ee57..ba6faad6 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts @@ -2912,18 +2912,6 @@ export class TrainrunSectionsView { ) { const trainrunSection = viewObject.trainrunSections[0]; - // Use unified logic for both collapsed chains and regular sections - return this.getCollapsedChainValueToShow(trainrunSection, textElement, editorView); - } - - /** - * Calculate the correct values for collapsed chains - */ - getCollapsedChainValueToShow( - trainrunSection: TrainrunSection, - textElement: TrainrunSectionText, - editorView: EditorView, - ) { switch (textElement) { case TrainrunSectionText.SourceDeparture: case TrainrunSectionText.SourceArrival: From 2aaeb510ecb530b76432b78d6e0f2997fd892519 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 31 Oct 2025 17:33:35 +0100 Subject: [PATCH 7/7] fixup! drop getAllSectionsInCollapsedChain() The TrainrunSectionViewObject already contains the full chain, no need to re-compute it. Signed-off-by: Simon Ser --- .../data-views/trainrunsections.view.ts | 59 ++----------------- 1 file changed, 6 insertions(+), 53 deletions(-) diff --git a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts index ba6faad6..126357a5 100644 --- a/src/app/view/editor-main-view/data-views/trainrunsections.view.ts +++ b/src/app/view/editor-main-view/data-views/trainrunsections.view.ts @@ -2910,14 +2910,12 @@ export class TrainrunSectionsView { textElement: TrainrunSectionText, editorView: EditorView, ) { - const trainrunSection = viewObject.trainrunSections[0]; - switch (textElement) { case TrainrunSectionText.SourceDeparture: case TrainrunSectionText.SourceArrival: // For source times, use the original section times (should be from non-collapsed node) return TrainrunSectionsView.getTrainrunSectionValueToShow( - trainrunSection, + viewObject.trainrunSections[0], textElement, editorView, ); @@ -2925,12 +2923,9 @@ export class TrainrunSectionsView { case TrainrunSectionText.TargetDeparture: case TrainrunSectionText.TargetArrival: { // For collapsed chains, use the actual time from the last section in the chain - const chainSections = this.getAllSectionsInCollapsedChain(trainrunSection); - const lastSection = chainSections[chainSections.length - 1]; - // Use the actual time from the last section (which already includes all stops and travel times) return TrainrunSectionsView.getTrainrunSectionValueToShow( - lastSection, + viewObject.trainrunSections.at(-1)!, textElement, editorView, ); @@ -2938,12 +2933,12 @@ export class TrainrunSectionsView { case TrainrunSectionText.TrainrunSectionTravelTime: { // For collapsed chains, calculate total time including stops at collapsed nodes - const chainSections = this.getAllSectionsInCollapsedChain(trainrunSection); - const lastSection = chainSections[chainSections.length - 1]; + const firstSection = viewObject.trainrunSections[0]; + const lastSection = viewObject.trainrunSections.at(-1)!; // Calculate total time: arrival time at end - departure time at start const startTime = TrainrunSectionsView.getTime( - trainrunSection, + firstSection, TrainrunSectionText.SourceDeparture, ); const endTime = TrainrunSectionsView.getTime( @@ -2959,51 +2954,9 @@ export class TrainrunSectionsView { case TrainrunSectionText.TrainrunSectionName: // For name, use the original trainrun name - return TrainrunSectionsView.extractTrainrunName(trainrunSection); + return TrainrunSectionsView.extractTrainrunName(viewObject.trainrunSections[0]); } return undefined; } - - /** - * Get all sections that are part of the same collapsed chain - */ - getAllSectionsInCollapsedChain(currentSection: TrainrunSection): TrainrunSection[] { - const sections: TrainrunSection[] = []; - let startSection = currentSection; - - // Walk backwards to find start of chain - while (startSection.getSourceNode().getIsCollapsed()) { - const prevSections = this.getConnectedTrainrunSections( - startSection.getSourceNode(), - currentSection.getTrainrunId(), - ).filter((ts) => ts.getId() !== startSection.getId()); - - if (prevSections.length === 1) { - startSection = prevSections[0]; - } else { - break; - } - } - - // Walk forwards to find end of chain and collect all sections - let currentSectionInChain = startSection; - sections.push(currentSectionInChain); - - while (currentSectionInChain.getTargetNode().getIsCollapsed()) { - const nextSections = this.getConnectedTrainrunSections( - currentSectionInChain.getTargetNode(), - currentSection.getTrainrunId(), - ).filter((ts) => ts.getId() !== currentSectionInChain.getId()); - - if (nextSections.length === 1) { - currentSectionInChain = nextSections[0]; - sections.push(currentSectionInChain); - } else { - break; - } - } - - return sections; - } }