Fix: Change layout engine logic - #108
Conversation
tonilastre
left a comment
There was a problem hiding this comment.
This is great! The structure or layouts and engines are well done, and easy to extend in the future. And the performance, 🚀 !
I also like the graph interaction part because it was always hard to maintain those states from internal node/edge functions.
I've added some comments, mostly nitpicking.
| setSettings(settings: ID3SimulatorEngineSettingsUpdate): void; | ||
| setSettings(settings: DeepPartial<ILayoutSettings>): void; | ||
|
|
||
| getIsSimulationRunning(): boolean; |
There was a problem hiding this comment.
Nitpicking, but can this be isSimulationRunning()?
| this.emitToWorker({ | ||
| type: WorkerInputType.SetSettings, | ||
| data: settings, | ||
| } as IWorkerInputPayload); |
There was a problem hiding this comment.
If we have new typescript in this project, you can use satisfies here instead of as.
| unhoverAll(): number; | ||
| } | ||
|
|
||
| export class GraphInteraction<N extends INodeBase, E extends IEdgeBase> implements IGraphInteraction { |
| } | ||
|
|
||
| if (data.edges) { | ||
| this._edges = this._edges.concat(data.edges); |
There was a problem hiding this comment.
Why edges are not being merged by id?
| ); | ||
|
|
||
| let lastProgress = -1; | ||
| let i = 0; |
There was a problem hiding this comment.
Nitpicking, but does it make sense to call this step instead of i because i is usually used a blocked locally variable, this i is all around in runChunk.
| ) { | ||
| const angleStep = (2 * Math.PI) / nodes.length; | ||
| let lastProgress = -1; | ||
| let i = 0; |
There was a problem hiding this comment.
Same comment as before for i
| const rows = Math.ceil(Math.sqrt(nodes.length)); | ||
| const cols = Math.ceil(nodes.length / rows); | ||
| let lastProgress = -1; | ||
| let i = 0; |
There was a problem hiding this comment.
And here :), and probably on other engines
| isPhysicsEnabled: false, | ||
| alpha: { | ||
| alpha: 1, | ||
| alphaMin: 0.05, // default alphaMin is 0.001, which results in 285 ticks to converge. Using 0.05 converges to similar stable results in 106 ticks |
| const layout = this._settings.layout; | ||
| const isHorizontal = | ||
| layout.type === 'hierarchical' && (layout.options as IHierarchicalLayoutOptions).orientation === 'horizontal'; | ||
| const isVertical = | ||
| layout.type === 'hierarchical' && (layout.options as IHierarchicalLayoutOptions).orientation === 'vertical'; | ||
| const reversed = (layout.options as IHierarchicalLayoutOptions).reversed; | ||
| const recenterOptions: IFitZoomTransformOptions = { | ||
| anchorX: isHorizontal ? (reversed ? 'end' : 'start') : 'center', | ||
| anchorY: isVertical ? (reversed ? 'end' : 'start') : 'center', | ||
| }; |
There was a problem hiding this comment.
Does it make sense to get these anchor variables from the recenter itself? We could have defaults for each layout, but user can override it through the argument of this function, e.g.
recenter({ anchorX, anchorY }, onRendered?);
recenter(onRendered?);
...
There was a problem hiding this comment.
Maybe we could also save these defaults for layouts in layout settings too. I find it odd to have these checks here.
There was a problem hiding this comment.
Yeah, I was skeptical about these checks too - it gets complicated because it depends both on the layout type and the layout options (it's different for horizontal/vertical tree, for example). I've added them to the layout settings, but I also extracted the logic for the default anchoring depending on the current layout; I believe this is the cleanest solution for now
… tooling * Fix: Fix multiple maps issue (#33) * Chore: Update package.json version * New: Change the API to handle OrbView and OrbMapView (#34) * New: Change the API to handle OrbView and OrbMapView * New: Change the API for select/hover strategies * Chore: Release/1.0.0 * New: Add support to get selected/hovered nodes and edges (#61) * New: Added support to get selected nodes and edges * New: Added support to get hovered nodes and edges --------- Co-authored-by: Abhinav Singh Parmar <abhinavparmar147@gmail.com> * New: Add support for enabling and disabling dragging of nodes (fixes #62) (#69) * New: Add feature to enable/disable node dragging (fixes #62) * New: Added support to modify interaction from setSettings * New: Updated documentation for interaction property * New: Add feature to enable/disable zoom (fixes #62) * NEW: Updated documentation for interaction property * NEW: Updated documentation to include isDragEnabled * New: Add support for custom edge line style (#77) * New Added support for custom edges * Refactor: Streamline edge rendering code and optimize line style handling * New: Add support for handling device pixel ratio (#45) * Chore: Move container and canvas creation from the view to the renderer * New: Add devicePixelRatio render property and handler * Fix: Add default DPR for older browsers * Chore: Remove useless check for automatic DPR * New: Add new simulator (#56) (#57) * New: Add new simulator (#56) * New: Add simulator scenarios for manual testing * New: Refactor simulator (WIP) * New: Add progress overlay, Update descriptions * Fix: Introduce new simulator event, Fix main-thread behavior * Fix: Rearrange class methods based on visibility * Fix: Improve naming * Chore(release): 0.2.0 * Fix: Tweak simulator, adjust API slightly * Fix: Temporarily patch some physics behavior * Fix: Adjust re-heating parameters * Fix: tweak physics behavior -> immediately stop sim when disabling * Chore: Remove the beta from release branches --------- Co-authored-by: dlozic <davidlozic@gmail.com> * New: Add zoom and recenter functions (#74) * New: Add zoom and recenter functions * Fix: Reduce excessive recentering (#75) * Fix: Remove excessive recenterings * Fix: Remove unused code * Fix: New simulator (#92) * Chore: Refactor naming * New: Add new events * Chore: Refactor code styling * Docs: Remove unused flags * Chore: Remove unused simulation functions * Chore: Refactor view render function calls * Chore: Add missing tests * New: Add removal functions (#96) * New: Add removal functions * Fix: Add missing callback data * Chore: Refactor remove return values * Chore: Refactor remove function type usage * Fix: Default settings for node placement (#98) * New: Add properties setters and getters (#93) * New: Add node properties setters * New: Add edge properties setters * New: Add properties getters * New: Add patch for nodes and edges * Fix: Make getters return copies * Fix: Edge factory listeners copying * Fix: Jest outdated tests * Fix: Github actions node version * Chore: Refactor observer interface * Chore: Refactor node/edge constructor settings * Chore: Refactor node/edge function grouping * Chore: Refactor node/edge function grouping * Fix: Listeners behaviour * Chore: Refactor property copying * Chore: Refactor subject implementation * Fix: Set position behaviour on node drag * Chore: Upgrade node version * Chore: Refactor function type check * Fix: Remove listener behaviour * Chore: Refactor util naming * Chore: Remove unused type assertion * Chore: Refactor position setter options * Chore: Refactor property patch function * Fix: Set map node position behaviour * Chore: Refactor simulator data patching * Chore: Change observers to callbacks * New: Add state setters with options (#95) * New: Add state setters with options * Chore: Remove leftover comments * Chore: Refactor state setter logic * Chore: Refactor state types * Fix: Rename merged function usage * Fix: Merged variable naming * Chore: Fix tests --------- Co-authored-by: dlozic <davidlozic@gmail.com> Co-authored-by: Oleksandr Ichenskyi <55350107+AlexIchenskiy@users.noreply.github.com> Co-authored-by: AlexIchenskiy <aichenskiy@gmail.com> * New: Add zoom in and out functions (#100) * Fix: Skip unnecessary listener notify on set style * Fix: remove unnecessary rerender on state change * Chore: Update documentation * Fix: Node/edge getter performance issue * Chore: Add data change docs example * Fix: Docs typos * Fix: Disable source map generation (#105) * New: Add tree layout (#107) * New: Add new layouts * New: Add layout options * Chore: Make layout dynamically changeable * Chore: Update docs * Fix: Naming typo * Chore: Refactor layouts * New: Enable layout node add/remove * Chore: Improve behavior for recurrent nodes * Chore: Move some simulator settings to layout * Chore: Refactor code quality and performance * Fix: Layout behavior on change * Chore: Add recenter on layout change * Fix: Layout change behavior * Fix: Simulation behavior on data deletion * Chore: Add recenter on layout change * Fix: Change layout engine logic (#108) * Fix: Change layout engine logic * New: Add simulation cancellation logic * Chore: Remove leftover code * Fix: Hierarchical layout recenter logic * Chore: Refactor package versions and code logic * Fix: Refactor function types * New: Add multiselect (#110) * New: Add multiselect * Chore: Simplify logic * Chore: Update package.json * New: Add SVG export (#111) * New: Add SVG export * Chore: Refactor code quality * New: Add WebGL renderer (#109) * New: Add WebGL renderer * New: Add naive WebGL force layout computation * New: Add WebGL improved node/shape geometry options * New: Add labels and node images * Fix: GPU drag behavior * Chore: Remove leftover comments * Fix: WebGL renderer style invalidating * Chore: Refactor code quality * Chore: Add WebGL example and docs * New: Add docs page (#112) * New: Add docs page * New: Add more docs examples * Update .github/workflows/docs.yml --------- Co-authored-by: Toni <toni.lastre@memgraph.io> * Chore: Finish up the release process * Chore: Fix sync between package.json files * Chore: Add new package-lock.json --------- Co-authored-by: David <davidlozic@gmail.com> Co-authored-by: Abhinv Singh Parmar <abhi171b010@gmail.com> Co-authored-by: Abhinav Singh Parmar <abhinavparmar147@gmail.com> Co-authored-by: Abhinv Singh Parmar <abhinav.parmar@infosys.com> Co-authored-by: Oleksandr Ichenskyi <55350107+AlexIchenskiy@users.noreply.github.com> Co-authored-by: AlexIchenskiy <aichenskiy@gmail.com>
This PR aims to refactor the core simulation and position calculation logic, fix some long-standing bugs - such as issues with render and recenter callback functionality - and add long-awaited features like simulation cancellation.
List of the most important changes:
Restructured layout engines into
engines/dynamic/andengines/static/subdirectories with a sharedBaseLayoutEngineabstract class that consolidates common fields (_nodes,_edges,_nodeIndexByNodeId), cancellation support (_cancelSimulation), and aMessageChannel-based scheduler (_scheduleNext) for non-blocking chunked executionAdded chunked asynchronous execution to static layout engines (circular, grid, hierarchical) with cancellation support,
_pendingRecalculationqueuing to prevent batch operations from being silently dropped, and_emitProgressfor progress trackingAdded chunked asynchronous execution to the force layout engine's
_runSimulation, replacing the synchronous blocking loop that froze the main thread during simulationChanged the
alphaparameter to drop number of iterations per simulation from ~300 to ~100, improving performanceRemoved the separate
SimulatorSettingsabstraction (IForceLayoutSettings) and folded its options intoIForceLayoutOptions, collapsingsetSettings()andsetLayoutEngine()into a singlesetSettings(ILayoutSettings)call - establishing layout settings as the single abstraction layer for all position-recalculation configurationFixed render callback timing -
render(onRendered)now fires the callback afterSIMULATION_END+RENDER_ENDinstead of synchronously before the simulation completes.Fixed transition callbacks -
recenter(),zoomIn(), andzoomOut()now use.on('end', ...)instead of.call()for post-transition callbacksFixed the throttle function - rewrote it with proper time-based gating to prevent stale closures and frozen renders
Cleaned up the D3 simulation lifecycle -
_resetSimulationnow properly stops and detaches listeners before creating a new simulationSimplified and improved the web worker - replaced the verbose switch/case with a handler map, removed the
SetLayoutEnginemessage type, created the engine lazily on the firstSetSettings, and enabled real-time engine switching using theSetSettingsmessageDesigned an
IGraphInteractioninterface to cleanly separate entity interaction concerns (select/unselect, hover/unhover by ID) from the core graph data model, exposed viaview.interaction.*- consistent with the existingview.data.*patternFixed the
recenter()logic to accept options so that it recenters correctly for edge cases such as unbalanced tree views