-
Notifications
You must be signed in to change notification settings - Fork 17
feat: modify node display #554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: mrd/new-nodes-management-system
Are you sure you want to change the base?
Conversation
087bc7c to
185666b
Compare
|
Thanks you for the new feature - would it be possible to get a live demo? |
|
I haven't done a full review yet, but at first glance I don't understand why:
It seems there's no change status (generateKey) related to isCollapsed. These objects are supposed to signal that something has changed so that a visual update can be triggered (i.e., only render what has changed to improve performance). I assume that if we don't explicitly trigger the update (mark the object as changed), it won't be updated (rendered). displayNodes(inputNodes: Node[]) {
const nodes = inputNodes.filter(
(n) =>
this.editorView.doCullCheckPositionsInViewport([
new Vec2D(n.getPositionX(), n.getPositionY()),
new Vec2D(n.getPositionX() + n.getNodeWidth(), n.getPositionY()),
new Vec2D(n.getPositionX(), n.getPositionY() + n.getNodeHeight()),
new Vec2D(n.getPositionX() + n.getNodeWidth(), n.getPositionY() + n.getNodeHeight()),
]) && this.filterNodesToDisplay(n),
);
const group = this.nodeGroup
.selectAll(StaticDomTags.NODE_ROOT_CONTAINER_DOM_REF)
.data(this.createViewNodeDataObjects(nodes), (n: NodeViewObject) => n.key);
... It would be very helpful if we could add some tests to verify that changes to isCollapsed and it's functionality are functioning as intended. Even if this doesn't directly affect the visualization layer, it’s still important for the underlying service methods, especially in areas like data migration. The base functionality should be properly tested to ensure robustness and maintainability. |
|
|
||
| const node: Node = this.editorView.getNodeFromConnection(con); | ||
|
|
||
| // filter if node is collapsed - do not show connections for collapsed nodes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tiny nit: why the comment here and not in transitions.view.ts?
|
Context: This PR implements part of the 3 first sections of the implementation plan given here |
louisgreiner
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, not tested.
Maybe, instead of fully hiding the nodes when isCollapsed is true, you should display them as a "Dot", as it is shown here (mock-up from main issue). But maybe you've planned to do it in the next PR, ignore this comment if so.
emersion
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for splitting the changes into small commits! Here are a few comments.
src/app/view/editor-main-view/data-views/trainrunsections.view.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made a pass, nothing to add for now. I'll do another pass after you resolved @emersion's comments.
c4cc009 to
6145bff
Compare
Sorry for the late answer. i'm not sure to completly understand your first point. And sure, I will add some test in the next commit |
a1d2b05 to
fa9b231
Compare
emersion
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't time to read this in full yet, sorry. Here are some comments still.
As mentioned in the implementation plan, I don't think keeping a TrainrunSectionViewObject.trainrunSection is great. I think replacing it with a trainrunSections: TrainrunSection[] field would ensure we never grab information from the first trainrun when we would need to grab it from the last, or from intermediate sections. For instance the target arrival time as mentioned below in comments, but applies to others as well.
src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts
Outdated
Show resolved
Hide resolved
src/app/view/editor-main-view/data-views/trainrunSectionViewObject.ts
Outdated
Show resolved
Hide resolved
src/app/view/editor-main-view/data-views/trainrunsections.view.ts
Outdated
Show resolved
Hide resolved
fa9b231 to
48fd522
Compare
48fd522 to
871f667
Compare
Signed-off-by: Simon Ser <[email protected]>
Signed-off-by: Simon Ser <[email protected]>
The TrainrunSectionViewObject already contains the full chain, no need to re-compute it. Signed-off-by: Simon Ser <[email protected]>
…Key() We were only using the first trainrun section's path here. Expose a getPath() method to get a view object's path. We need to call it from inside generateKey() so drop the static attribute. While at it, make the generateKey() helper function private because it shouldn't be called from elsewhere. Signed-off-by: Simon Ser <[email protected]>
Target arrival was included twice, and source arrival was missing. Signed-off-by: Simon Ser <[email protected]>
We were only grabbing metadata from the first section, but we need to make the key change when the last section changes. Signed-off-by: Simon Ser <[email protected]>
Instead, grab the path from TrainrunSectionViewObject.getPath(). We need to update a few functions to take the veiw object instead of the first trainrun section. Signed-off-by: Simon Ser <[email protected]>
This function overwrites a trainrun section's path. Instead, pick the right section (first or last) when computing path-related outputs. Signed-off-by: Simon Ser <[email protected]>
Further down, these two calls return the same values:
this.getTrainrun().getTrainrunFrequency().frequency
this.getTrainrun().getTrainrunFrequency().offset
Signed-off-by: Simon Ser <[email protected]>
…ect.generateKey() Only the source matters for the first section, the target is handled by the last section of the chain. Same as this commit, but for the consecutive time: 9689208 Signed-off-by: Simon Ser <[email protected]>
…ainrunSectionViewObject
…WithCollapsed support to avoid duplication
| case TrainrunSectionText.TrainrunSectionTravelTime: | ||
| // Special case for multiple sections: calculate total time including stop times at intermediate nodes | ||
| if (viewObject.trainrunSections.length > 1) { | ||
| const totalTime = viewObject.trainrunSections.reduce((sum, section, index) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could move this into TrainrunSectionViewObject.getTravelTime(), and call it from here. That way, we fix bugs in getTravelTime() and reduce code duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure done
|
|
||
| static getTrainrunSectionValueToShow( | ||
| trainrunSection: TrainrunSection, | ||
| trainrunSectionOrViewObject: TrainrunSection | TrainrunSectionViewObject, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to accept a raw TrainrunSection here: this sounds like a footgun where some callers would just pass the first section and ignore the rest. We can always take a TrainrunSectionViewObject as input (and that object may contain a single section).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure i made a refacto of this method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see 8ea0098
| // ViewObject case: determine which section to use based on textElement | ||
| const viewObject = trainrunSectionOrViewObject; | ||
|
|
||
| switch (textElement) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be merged with the switch below. We don't need to special-case multiple trainrun sections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above see 8ea0098
| const firstSection = viewObject.trainrunSections[0]; | ||
| const lastSection = viewObject.trainrunSections.at(-1)!; | ||
|
|
||
| // Handle multi-section chains (collapsed nodes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to special-case view objects with multiple sections. We should be able to adapt the codepath below the if block and drop the if block, for instance:
const trgNode = lastSection.getTargetNode();const path = viewObject.getPath();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure changed it
| static translateAndRotateText( | ||
| trainrunSection: TrainrunSection, | ||
| trainrunSectionText: TrainrunSectionText, | ||
| viewObject?: TrainrunSectionViewObject, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we completely replace the trainrunSection argument with the viewObject argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can but, this changes would affect multiple functions and tests, and the main limitation is that createNumberOfStopsTextElement currently doesn’t have access to a viewObject.
Since this PR already includes quite a bit of refactoring, it might be cleaner to handle that work in a further PR.
WDYT?
| // Use viewObject path if provided, otherwise use trainrunSection path | ||
| const pathVec2D: Vec2D[] = viewObject | ||
| ? viewObject.trainrunSections[0].getPath() | ||
| : trainrunSection.getPath(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we use viewObject.getPath() here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, actually i think it's cleaner thanks
f01f31b to
2ae95ab
Compare
…inrunSection param -Remove TrainrunSection parameter support (accept only TrainrunSectionViewObject) -Merge duplicate switch statements into single switch -Merge Source/Target and Departure/Arrival into single case
-use complete path for collapsed nodes in text rotation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Functional review
Using this scenario (no collapsed node):
reticulaire.json
And this scenario (collapsed node in Olten):
reticulaire(1).json
Copy/paste a node selection also takes the collapsed nodes -> it should not
Enregistrement.de.l.ecran.2025-11-20.142852.mp4
In the same scenario, trainruns are drawn weirdly (ports) (but may it be caused because of import/export? should try to rebase onto Valentin's branch)
It looks like the ports assignation is mixed up
Times update works great
|
There is also a small bug in the node selection: Enregistrement.de.l.ecran.2025-11-21.135157.mp4The workflow should be:
|



Description
This PR implements the collapsed nodes functionality for the Netzgrafik editor, allowing intermediate nodes to be hidden while maintaining proper visual representation of train routes.
Features Implemented
1. Node Model Enhancement
isCollapsedfield to Node model with getter/setter methods2. Visual Filtering System
3. Intelligent Section Grouping
4. Direct Path Calculation
User Experience
collapsedbecome invisibleTechnical Implementation
Issues
Related to feature request for collapsed nodes functionality to simplify complex network display.
Checklist
documentation/(documentation to be added in follow-up)Next Steps (Future PRs)