-
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.
|
|
||
| filterNodesToDisplay(node: Node): boolean { | ||
| return this.editorView.isNodeVisible(node); | ||
| return this.editorView.isNodeVisible(node) && !node.getIsCollapsed(); |
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.
Nit: isCollapsed() would be nice instead of getIsCollapsed()
| groupTrainrunSectionsIntoChains(trainrunSections: TrainrunSection[]): Array<{ | ||
| sections: TrainrunSection[]; | ||
| startNode: Node; | ||
| endNode: Node; | ||
| }> { |
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.
Nice function, very readable. I wonder if we could/should create a new type for the group object, if it will be reused elsewhere
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 the suggestion, as I simplified it thanks to @emersion it's no longer necessary
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
| // Check if this section is part of a collapsed chain | ||
| const collapsedChainPath = this.getCollapsedChainNodePath(trainrunSection); | ||
|
|
||
| if (collapsedChainPath && collapsedChainPath.length >= 2) { |
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.
Do we really need to have two codepaths? I think the collapsed codepath should work when the full chain just has a single element too?
fa9b231 to
48fd522
Compare
- Add createViewObjectForCollapsedChain() static method to handle path routing between start/end nodes - Replace standard TrainrunSectionViewObject creation with custom method for collapsed chains - Path now correctly goes from first visible node to last visible node instead of using primary section's path
48fd522 to
871f667
Compare
066c751 to
84527fb
Compare
Signed-off-by: Simon Ser <[email protected]>
…hain Signed-off-by: Simon Ser <[email protected]>
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 <[email protected]>
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 <[email protected]>
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]>
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.
Nice work, I left some small comments and some questions :) I didn't have the time to read all the files
| if (visitedSections.has(pair.trainrunSection.getId())) { | ||
| break; // Already processed this 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.
Small question, this case should never happen right ?
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.
Yes, normally this case should never happen, it's a relicat from previous development, but now we find the first section of the chain, thanks to the backward iterator.
But it can prevent infinite cycle if this iterator is changed in further development, maybe we can use this check to log an error and break to help and prevent regression in further development ?
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.
Throwing an error sounds good to me.
| return new BackwardNonStopTrainrunIterator(this.logService, node, trainrunSection); | ||
| } | ||
|
|
||
| public getExpandedIterator(node: Node, trainrunSection: TrainrunSection) { |
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'm not sure this function is used anymore
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.
True, good catch i'll remove it
| key += "_SRC_" + d.getSourceNode().getPositionX() + "_" + d.getSourceNode().getPositionY(); | ||
| key += "_TRG_" + d.getTargetNode().getPositionX() + "_" + d.getTargetNode().getPositionY(); |
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.
❓ Why do you need to add these information in the key ?
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 added thsi to the key, to refresh the path when boundaries nodes moves. Préviously when i was moving the arrival node, the TrS was in a disconnected visual state, until i also move the start node.
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.
This has been dropped in #605.
| if (connectedSections.length === 1) { | ||
| currentSection = connectedSections[0]; | ||
| } else { | ||
| break; | ||
| } |
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.
If I understand correctly, the goal here is to break if there is no connection (because we have reached the end of the chain). Then, it would be clearer to state this in the if condition:
| if (connectedSections.length === 1) { | |
| currentSection = connectedSections[0]; | |
| } else { | |
| break; | |
| } | |
| if (connectedSections.length === 0) { | |
| break; | |
| } else { | |
| currentSection = connectedSections[0]; | |
| } |
Also, is it possible to have connectedSections.length > 1 ? is it normal to break right now if it is the case ?
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.
No if you reach the end of the section there is only one connected section, the previous one, if there is 0 connectedSection is because you're not in a chain, if there is 2 you are between 2 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.
This code has been dropped in #605.
| const sourcePort = | ||
| startNode.getPortOfTrainrunSection(firstSection.getId()) ?? startNode.getPorts()[0]; |
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.
If I understand correctly, if you don't find a port with the correct section id, you take the first one ? Is it a good behavior ?
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.
Hmm yes it can end up using an already used port. I'm not sure of how to handle this one @louisgreiner ?
…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]>
| /** | ||
| * Get the value to show for collapsed chains (with corrected times) | ||
| */ | ||
| getTrainrunSectionValueToShowWithCollapsedSupport( |
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'd like to merge this function with getTrainrunSectionValueToShow: the logic is very similar, just need to use the correct TrainrunSection from there instead of always picking the first one.
| /** | ||
| * Apply basic filtering to a path | ||
| */ | ||
| private applyBasicFiltering(path: Vec2D[], ts: TrainrunSection): Vec2D[] { |
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.
Ditto: I'd like to drop this function and pick the trgNode from the last section in transformPath, instead of picking it from the first section.
| /** | ||
| * Version that works with TrainrunSectionViewObject for collapsed chains | ||
| */ | ||
| static getAdditionPositioningValueForViewObject( |
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.
Ditto: I'd like to fold this into getAdditionPositioningValue
| * Version that works with TrainrunSectionViewObject to handle custom paths for collapsed chains | ||
| * This method needs access to the view instance to get the collapsed path | ||
| */ | ||
| static translateAndRotateTextForViewObject( |
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.
Ditto for this function, as well as getTextPositionsForCollapsedChain, getAdditionPositioningValueForViewObjectWithCollapsedSupport and translateAndRotateTextForViewObjectWithCollapsedSupport. We shouldn't need to duplicate all of the logic here.
| firstSection.getNumberOfStops() + | ||
| "_" + | ||
| d.getTravelTime() + | ||
| firstSection.getTravelTime() + |
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.
Instead of picking the travel time of the first section, we should compute the total travel time of the whole chain.
We already have logic for this in getTrainrunSectionValueToShowWithCollapsedSupport, I think we can add a new TrainrunSectionViewObject.getTravelTime method to centralize it.
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)