Skip to content

Conversation

@aiAdrian
Copy link
Contributor

@aiAdrian aiAdrian commented Oct 22, 2025

Description

Rendering of the origin/destination matrix was a major performance bottleneck. To address this, the SVG-based rendering of the O/D matrix has been replaced with a Canvas-based implementation.

image Final Version.

To discuss - but it looks very promising

Please compare the rendering outcome: Pixel graphics (new) vs Vector graphics (old). If we like to have high quality support (vector graphic / svg) we might have to implement an automatic switch from (old) to new if the matrix gets to big.

I strongly recommend using canvas -> just using this canvas based rendering for such matrix based rendering otherwise we will run into big issue with the performance. I am aware that it's not so cool having pixel graphics but is looks quite good. And as well it make againt the interactive tool more complex du of having svg ( d3.js) and canvas in one product. But for interactive real - time application the life is hard:)

What changed

  • Replaced SVG rendering of the O/D matrix with a Canvas renderer.
  • Result: rendering is now fast and responsive, especially for large matrices.

Known issues / TODOs

  • Export to PNG/SVG currently does not work. Export functionality needs to be restored for the new Canvas renderer. image Issue fixed - png can directly exported - svg must be simulated with an image layer but it works.

  • Small visual issue: some "button" elements render without a background. It appears the rendering area for those elements is too large, causing their backgrounds not to be drawn correctly.

Before After
image image

Checklist

  • This PR contains a description of the changes I'm making
  • I've read the Contribution Guidelines
  • I've added tests for changes or features I've introduced
  • I documented any high-level concepts I'm introducing in documentation/
  • CI is currently green and this is ready for review

Fixed known issue

Issue with ambiguous node names fixed:

test json (case 1) test json (case 2)
netzgrafik (1).json netzgrafik (2).json
image image
image image

Final result

chrome-capture-2025-10-22.webm

@aiAdrian
Copy link
Contributor Author

aiAdrian commented Oct 22, 2025

It would be great if the user manual were updated when this improvement is implemented. I could help by recording some nice demonstration videos.

"that looks like a commit message rather than documentation" -> indeed it was just for my own
Make more clear why we check for existance
`That's confusing to me, since filtering trains should trigger computation` - comment was not aligned with the functionality (copy & paste issue)
@aiAdrian aiAdrian requested a review from louisgreiner October 23, 2025 11:38
@aiAdrian
Copy link
Contributor Author

aiAdrian commented Oct 24, 2025

Some benchmarks (all tests have finished : without error)

51 Nodes - standalone demo

Browser main (bdcc0d2) aeg/od_improve_rendering_performance_switching_svg_to_canvas Speed Up
Google Chrome image image 1.25
337ms 267ms 1.25
Microsoft Edge image image 1.25
703ms 615ms 1.25

204 nodes - 3x duplicated - 4x standalone demo

Browser main (bdcc0d2) aeg/od_improve_rendering_performance_switching_svg_to_canvas Speed Up
Google Chrome image image 1.65
2716ms 1612ms 1.65
Microsoft Edge image image 1.55
4201ms 2713ms 1.55

408 Nodes

Browser main (bdcc0d2) aeg/od_improve_rendering_performance_switching_svg_to_canvas Speed Up
chrome 9271ms 4073ms 2.27
Edge 17981ms 8790ms 2.04

816 Nodes

Browser main (bdcc0d2) aeg/od_improve_rendering_performance_switching_svg_to_canvas Speed Up
chrome image image image image 2.7
43s 16s 2.7

Big, real Netzgrafik test

I tested with an internal really big Netzgrafik (851 unique named nodes) - can not share the file/data!

main branch (bdcc0d2)

image

aeg/od_improve_rendering_performance_switching_svg_to_canvas

After very long waiting - time manuel measured (clock): 5min 38s = 338s)
Only rendering :

  • drawMatrix : 3.8s
  • drawCellText : 1.9s
image

just mouse over : real-time (near)

High memory usage : 911MB

Further idea to improve: Next steps

=> Thus the reloadData cost are massiv ! -> might we can reduce it with open draft pull request (Dijkstra, ... )
performance_computeShortestPaths_ai_Dijkstra

#578

--- other idea
#573
#568

Copy link
Contributor

@louisgreiner louisgreiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments, could not get into the PNG/SVG export

Also did not challenged the new structure of the component, but except for the ".style" noise, it's quite easy to follow actually

Note: origin-destination.component.html -> move the style outside of this file and set it in the .scss file

Comment on lines 83 to 90
style="
display: flex;
align-items: center;
gap: 1rem;
width: 100%;
height: 57px;
flex-wrap: nowrap;
"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only related to this styling, but can we keep style in the .scss corresponding files? Otherwise, it makes the code way more difficult to navigate into

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style is still html hard coded, can it be moved to scss file?

Comment on lines 160 to 167
.attr("class", "tooltip")
.style("opacity", 0)
.style("position", "absolute")
.style("border", "solid 1px")
.style("border-radius", "4px")
.style("padding", "6px")
.style("user-select", "none")
.style("pointer-events", "none");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add this style as we do for other Netzgrafik-Editor objects? what is done with static.dom.tags.ts for instance; to reduce the code's length

-> same for other .style occurrences of this file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-)

Copy link
Contributor

@louisgreiner louisgreiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more minor comments

<div id="main-origin-destination-container-root"></div>

<div class="palette-buttons">
<div class="palette-buttons" style="transform: translateX(-64px)">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as other style parameters, can we move them to scss file?

Suggested change
<div class="palette-buttons" style="transform: translateX(-64px)">
<div class="palette-buttons">

Comment on lines 83 to 90
style="
display: flex;
align-items: center;
gap: 1rem;
width: 100%;
height: 57px;
flex-wrap: nowrap;
"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style is still html hard coded, can it be moved to scss file?

<sbb-radio-group
class="sbb-checkbox-group-horizontal"
[(ngModel)]="displayBy"
style="display: flex; flex-direction: row; gap: 0.5rem; transform: translateX(-16px)"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same issue, style must go to scss file

Suggested change
style="display: flex; flex-direction: row; gap: 0.5rem; transform: translateX(-16px)"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

// -------------------------
// Initialization helpers
// -------------------------

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return this.getStreckengrafikEditingContainerToExport();
case EditorMode.OriginDestination:
return this.getOriginDestinationContainerToExport();
return undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not test this part, but this gives me bad feeling; could we gather all the exports at the same place?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is, that we have a complete different export behavior when using canvas ... but i will refactor it, try to fix the problem

@louisgreiner
Copy link
Contributor

Also, if doable I think it is better to let the reviewer press "Resolve conversation", to ensure the comment has been treated and there is no more discussion.

Also, if the conversation are closed, I cannot see them on the "Files changed" page to review another time

Copy link
Contributor

@louisgreiner louisgreiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with the current code (except the few remarks), however the zoom feature is a bit bugged. You can try zoom on the edges of this network graphic for instance:
reticulaire(2).json

Also, when zoomed out a lot (30%), the panning feature is very slow, very different of the previous behaviour

Enregistrement.de.l.ecran.2025-10-30.163511.mp4

// canvas Data-URL (PNG)
const dataUrl = canvas.toDataURL("image/png");

// Erzeuge SVG string mit eingebettetem Bild
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you translate this in english please 😆

"text-anchor",
"dominant-baseline",
];
// quality only used for image/jpeg
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of jpeg since we use png?

@aiAdrian aiAdrian marked this pull request as draft November 7, 2025 11:19
@aiAdrian
Copy link
Contributor Author

aiAdrian commented Nov 7, 2025

The current version is really fast. But pan/zoom doesn't work smooth and acceptable

@aiAdrian
Copy link
Contributor Author

aiAdrian commented Nov 7, 2025

I experimented extensively with this pull request (PR), but unfortunately, I couldn't cleanly implement the transformation/scaling logic for panning and zooming. I also have to admit that while Canvas has its strengths, SVG offers significantly higher rendering quality—and the entire mesh graphics editor is based on SVG. Therefore, using Canvas for the o/d matrix is ​​problematic.

Performance optimizations for large matrices are possible, but would likely require techniques like frustum culling (as used in the mesh graphics editor's editor mode) and possibly other rendering strategies like level-of-detail (LOD).

Furthermore, Canvas introduces considerable complexity once we consider HiDPI and Retina displays.

Conclusion

In conclusion, this was a valuable experiment, and I learned a lot. While Canvas can significantly improve performance, it also introduces greater complexity and doesn't fit well with the SVG-based architecture of the mesh graphics editor.

Decision (suggestion)

Therefore, I propose closing this PR without merging it. Should Canvas become relevant again in the future, we can revisit this code and the discussion as a reference point.

Thanks to

Many thanks to everyone involved, including the reviewers!

@aiAdrian aiAdrian added the wontfix This will not be worked on label Nov 7, 2025
@aiAdrian aiAdrian closed this Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants