MSAGLJS
repository·main·Indexed 41 days ago
https://github.com/microsoft/msagljsA JavaScript implementation of advanced graph layout algorithms for computing layouts, routing edge geometry, and rendering network visualizations via SVG or WebGL. It includes specialized algorithms like MDS and Sugiyama, as well as tools for managing geometric graph structures (GeomGraph) and spatial indexing via R-Trees.
What's inside MSAGLJS
- MSAGLJS is a JavaScript implementation of advanced graph layout algorithms. It is designed to handle complex graph structures, compute routed edge geometry, and provide visualizations for network data.
Overview of MSAGL-JS modules
mainMSAGL-JS is a JavaScript implementation of graph layout algorithms, providing graph viewers and an editor component. It is largely a port of the .NET MSAGL layout engine. The library is organized into several specialized modules:
@msagl/core: Contains core graph data structures and the layout engines.@msagl/drawing: Provides device-independent graphic support.@msagl/parser: Handles the conversion of common graph formats into MSAGL Graph instances.@msagl/renderer-webgl: A rendering component powered by WebGL, optimized for performance.@msagl/renderer-svg: A rendering component powered by SVG, suitable for smaller graphs and editing.
Benchmark file structure and endpoints
mainThe benchmark environment consists of the following components:
Server and Logging
server.js: A static HTTP+POST server running on port8765. It serves files from its directory and/graphs/*from the configured graph directory. It provides two logging endpoints:POST /log: Used by the routing-modes benchmark. Appends JSON bodies to/tmp/chrome_bench_results.log.POST /loadlog: Used by the loading benchmark. Appends JSON bodies to/tmp/chrome_load_results.log.
Benchmark Pages
- Routing Modes Benchmark: Uses
index.htmlandbench.jsto test A*, Dijkstra-tree, and Dijkstra+VC modes. Accessible athttp://127.0.0.1:8765/. - Loading Benchmark: Uses
loading.htmlandloading.jsto test full loading (parse + MDS layout with sleeve router + tile pyramid build). Accessible athttp://127.0.0.1:8765/loading.html.
Required Assets
msagl.min.js: A copy ofmodules/core/dist.min.jsthat must be placed in the benchmark directory.
Choose a MSAGL-JS workflow
mainMSAGL-JS provides different workflows depending on your end goal. Select the appropriate path based on your requirements:
- Core layout: Use this if you only need to compute node positions and routed edge curves without a visual viewer.
- Live web embedding: Use this to embed an interactive graph that renders when a web page loads.
- Browser renderers: Use this to add or configure specific SVG or WebGL rendering engines.
- Layout and routing: Use this to select specific layout algorithms or edge-routing modes.
- Document export: Use this to generate static figures in formats like SVG, PDF, PNG, EPS, or PostScript.
- Packages and inputs: Use this to understand which
@msagl/*packages to install or how to parse different graph inputs (DOT, JSON, etc.).
Choose the right MSAGLJS package for your needs
mainMSAGLJS usage is divided into three main categories depending on whether you need layout logic or visual rendering:
- Layout Only: Use
@msagl/coreif you only need to calculate the layout of a graph without rendering it. - SVG Rendering: Use
@msagl/renderer-svgif you want to render and potentially edit a graph within a web browser using SVG. - Large Graph Rendering (WebGL): Use
@msagl/renderer-webgl(Deck.gl renderer) to explore large graphs in a browser using a visualization style similar to online maps.
- Layout Only: Use
What is sleeve routing?
mainSleeve routing is a method used in MSAGL-JS to render edges in large graphs. It works by searching the dual graph of a Constrained Delaunay Triangulation to select a sequence of triangles through the free space, then applying the funnel algorithm to compute a shortest path within that selected 'sleeve'.
For more technical details, refer to the paper: Browsing Large Graphs with Tile Pyramids and Sleeve Routing in the Browser (arXiv:2605.17498).
Important MSAGL-JS invariants and best practices
mainWhen using MSAGL-JS, adhere to these technical constraints and patterns to avoid errors:
Graph Construction
- Edge Registration:
new Edge(source, target)automatically registers the edge with both endpoint nodes. Do not use a separateaddEdgecall. - Node Registration: Always add every node to its
Graphobject. - Core Layout Requirements: For direct core layout, you must provide a
GeomGraph, aGeomNodewith a boundary curve for each node, and aGeomEdgefor each edge before callinglayoutGeomGraph.
Rendering
- Synchronicity:
RendererSvg.setGraph()is synchronous. However, WebGLRenderer.setGraph()is asynchronous and must beawaited. - Environment: Browser renderers require
window,document, canvas text measurement, and a mounted container with non-zero dimensions. Do not run them during Server-Side Rendering (SSR). - Container Management: Always pass a dedicated container to a renderer. Do not rely on the
document.bodydefault in embedded applications. - Instance Lifecycle: Retain one renderer instance per mounted container. Update it using
setGraph()orsetOptions()instead of reconstructing it on every framework render.
Configuration
- Layout Types: Omit
layoutTypeto use the renderer's default. Note that the string'default'is not a validLayoutOptions.layoutType. - API Usage: Use only public package exports; avoid internal source paths.
- Exporting: When generating PDF, EPS, or PostScript, preserve the textual graph source so the binary figure is not the only editable artifact.
- Edge Registration:
Understand the core graph entities: Node, Graph, and Edge
mainThe
@msagl/corelibrary uses a minimal and efficient graph structure based on three primary classes:Node,Graph, andEdge.Node: Represents a vertex. It provides methods to access adjacent edges:outEdges(),inEdges(), andselfEdges().Edge: Represents a connection between twoNodeinstances (source and target). Creating anEdge(source, target)automatically attaches it to the source'soutEdgesand the target'sinEdges.Graph: ExtendsNodeand contains aNodeCollection(a wrapper forMap<string, Node>) to manage its nodes. You can create sub-graphs by adding aGraphinstance as a node to anotherGraph.
All these classes extend
Entity, meaning they have aparentreference to the entity they belong to (e.g., aNodeknows its parentGraph).// Iterating over edges from a node for (const e of n.outEdges()) { // process edge 'e' } // Creating a subgraph const graph = new Graph() const subgraph = new Graph('a') graph.addNode(subgraph)Understand the default layout selection logic
mainWhen calling
layoutGeomGraph(geomGraph)without predefinedlayoutSettings, the engine automatically selects a layout based on the graph's properties:- Sugiyama Scheme: Selected if the graph is directed AND:
- Number of nodes $\le$ 2000
- Number of edges $\le$ 4000
- IPSepCola: Selected for all other cases (e.g., larger graphs or undirected graphs).
A graph is considered directed if it contains at least one edge where
e.sourceArrowheadore.targetArrowheadis not null.- Sugiyama Scheme: Selected if the graph is directed AND:
Choose between SVG and WebGL renderers
mainSelect a renderer based on your graph size and interaction requirements:
RendererSvg: Best for small-to-medium graphs, SVG output, editing capabilities, and simple DOM integration.- WebGL
Renderer: Best for large graphs, semantic zoom, and smoother browsing experiences.
Manage the renderer lifecycle in frameworks
mainWhen integrating MSAGL renderers into modern web frameworks (like React or Vue), follow these lifecycle patterns to avoid performance issues and remount loops:
- Initialization: Construct the renderer only after the target container has been mounted to the DOM.
- Persistence: Store the renderer instance in a module-level variable or a framework ref (e.g.,
useRef). Do not store it in component state, as this can trigger unnecessary re-renders. - Updates: Instead of re-instantiating the renderer when data changes, reuse the existing instance by calling
setGraph()orsetOptions(). - Avoid Re-instantiation: Never instantiate a new renderer during every framework render cycle.
- Cleanup: The renderers do not currently expose a public disposal API. To prevent memory leaks or unexpected behavior, ensure you manually remove any application-owned listeners or data fetches during component unmounting. Do not attempt to access private
rendererordeck.glfields for manual disposal.
Use Attributes to separate graph structure from geometry and drawing
mainTo avoid duplicating the graph structure,
@msagl/coreuses anAttributesarray on everyEntity(Nodes, Edges, etc.).- Geometry Attributes: Required for the layout engine to function (e.g., defining the shape and size of a node).
- Drawing Attributes: Used by renderers to visualize the graph.
For example, to give a node a physical shape, you create a
GeomNode(which is a geometry attribute) and assign aboundaryCurveusing theCurveFactory.