This repository contains the prototype, experimental playground, and reference implementation for exploring generic and semantic auto-layouting concepts within web-based diagram editors.
Modern web-based modeling tools require diagram layout mechanisms that are not only aesthetically clean but also stable across edits and meaningful according to the diagram's modeling language. This project serves as a testing ground to design, implement, and evaluate solutions for two core challenges in diagram layouting within the Eclipse Graphical Language Server Platform (GLSP) ecosystem:
- Generic Layout Persistence: Creating a reusable layout pipeline in the GLSP Node.js ecosystem that automatically extracts layout coordinates computed by the Eclipse Layout Kernel (ELK) and writes them back into custom (non-GModel) source models (such as a custom JSON file format).
- Semantic Layouting: Applying modeling language domain meaning (rules, hierarchy, priorities, and constraints) to guide layout algorithms. Instead of relying purely on generic graph heuristics, this project translates domain semantics into rules, constraints, hints, and ELK-compatible options to improve readability.
This prototype demonstrates these layouting concepts using a custom Thesis Writing Process modeling tool. The elements of the diagram carry clear modeling meaning:
- Nodes:
Section(chapters),WritingTask(active work items),LiteratureSource(auxiliary references), andReviewCheckpoint(milestones). - Edges:
dependsOn(sequential prerequisites),feedbackTo(revision cycles/loops), andcites(reference associations).
The repository is structured to showcase and evaluate:
- GLSP Layout Architecture Extensions: Separating layout configurations, semantic rules, and user-defined runtime overrides using dependency-injected configurators and custom handlers.
- Layout Write-Back & Reload Persistence: Automatically syncing computed layout coordinates (positions, sizes, routing points) back to the
.thesisJSON source model (see ThesisLayoutOperationHandler and ThesisChangeBoundsHandler). - Semantic Rule Mapping: Formulating custom rules matching specific node/edge types and adding ELK options dynamically (see thesis-semantic-rules.ts).
- Interactive Option Overrides: Allowing users to customize layout settings on the fly via a sidebar panel (see LayoutPanelProvider) and feeding them into the ELK layout engine pass.
This project is configured as a multi-package Monorepo managed with Yarn Workspaces and Lerna.
graph TD
subgraph vscode_host ["VS Code Extension Host"]
EP["LayoutPanelProvider<br>Layout Controls Sidebar"]
ED["ThesisEditorProvider<br>Custom Editor .thesis"]
Conn["GlspVscodeConnector"]
end
subgraph glsp_server ["GLSP Server (NodeJS)"]
Handler["ThesisLayoutOperationHandler"]
Configurator["ThesisLayoutConfigurator"]
RuleEngine["Semantic Rule Engine"]
Store["LayoutOptionsStore"]
State["ThesisModelState"]
end
subgraph model_persistence ["Model Persistence"]
File["example.thesis JSON"]
end
EP -- SetLayoutOptionsOperation --> Conn
ED -- Opens/Edits --> File
Conn -- Socket Connection --> Handler
Handler -- Updates --> State
State -- Reads/Writes --> File
Configurator -- Reads Overrides --> Store
Configurator -- Applies Rules --> RuleEngine
thesis-glsp-server: The Node-based GLSP backend.src/layout: The core layout orchestration layer:thesis-layout-configurator.ts: Orchestrates layout request applications. Merges base ELK configurations, semantic rules, and user-defined runtime overrides.thesis-semantic-rules.ts: Declarative rule set translating domain-specific node and edge types into ELK properties.semantic-layout-rule.ts: General types and helper functions for matching and applying rules.layout-options-store.ts: Thread-safe, in-memory singleton storing active user-defined layout configurations.
src/handler: Operations handlers for diagram modifications:thesis-layout-operation-handler.ts: Intercepts the ELK layout results, maps the graphical GModel positions back onto the source node objects, and triggers source model serialization.thesis-change-bounds-handler.ts: Syncs manual drag-and-resize changes back to the source JSON coordinates.
src/model: Definition of model indices, states, and the JSON file parser/serializer.
thesis-glsp-client: Web-based graphical canvas configuring the client container, svg shapes, connection routing styles, and palette items.thesis-vscode: Integration wrapper embedding the editor into VS Code.workspace: Target directories containing sandbox diagrams, e.g.,example.thesis.
The following table summarizes the semantic rules configured in thesis-semantic-rules.ts:
| Rule ID | Type | Match Target | Applied ELK Option | Semantic Rationale / Thesis Context |
|---|---|---|---|---|
graph-algorithm |
Graph | GGraph |
'elk.algorithm': 'layered' |
Sequential thesis writing processes are best modeled using a layered layout. |
graph-direction |
Graph | GGraph |
'elk.direction': 'DOWN' |
Academic processes flow naturally top-to-bottom from introduction to conclusion. |
graph-node-placement |
Graph | GGraph |
'elk.layered.nodePlacement.strategy': 'NETWORK_SIMPLEX' |
Minimizes edge crossings and keeps node layer assignments stable. |
graph-spacing |
Graph | GGraph |
'elk.spacing.nodeNode': '40', 'elk.layered.spacing.nodeNodeBetweenLayers': '60', 'elk.padding': '[top=20,...]' |
Ensures readability at a glance. |
graph-edge-routing |
Graph | GGraph |
'elk.edgeRouting': 'ORTHOGONAL' |
Straight lines and right angles make dependency paths easy to trace. |
section-priority |
Node | Section |
'elk.priority': '10' |
Sections represent chapters and should remain visually dominant at the top of layers. |
writing-task-size |
Node | WritingTask |
'elk.nodeSize.minimum': '(160, 50)', 'elk.priority': '5' |
Active work items receive higher visual weight and minimum dimensions. |
literature-compact |
Node | LiteratureSource |
'elk.nodeSize.minimum': '(80, 36)', 'elk.priority': '1' |
Auxiliary references are kept small and de-prioritized to prevent clutter. |
checkpoint-ratio |
Node | ReviewCheckpoint |
'elk.aspectRatio': '1.0', 'elk.priority': '7' |
Milestone gates are represented as distinct 1:1 squares. |
depends-on-directed |
Edge | dependsOn |
'elk.edge.type': 'DIRECTED' |
Forces the layout engine to place the prerequisite above the dependent node. |
feedback-back-edge |
Edge | feedbackTo |
'elk.layered.feedbackEdges': 'true' |
Informs ELK that this edge represents a cycle (review loop) so it is routed backwards without altering layer structure. |
cites-cross-layer |
Edge | cites |
'elk.layered.priority.direction': '0' |
Prevents reference citation arrows from influencing main layout layers. |
- Node.js
>=20.x - Yarn
^1.17.0(Yarn Classic)
To resolve internal workspaces dependencies, fetch packages, and compile the Typescript modules, run the following command in the root folder:
yarnThis command triggers the Lerna bootstrapping process, installs node modules for all packages, and compiles the source code.
For a full debug loop, open the root workspace folder in VS Code.
Navigate to the Run and Debug view (Ctrl+Shift+D / Cmd+Shift+D) and choose one of the configurations:
- π»
Launch thesis Diagram extension with external GLSP Server(Recommended): A compound launcher that starts the node GLSP backend process with a debugger attached, and opens a secondary[Extension Development Host]VS Code window. Perfect for debugging both the client and server. - π₯οΈ
Launch thesis GLSP Server: Launches only the GLSP server backend process (port5007). Useful if you are debugging the backend code and want to attach or re-launch the client independently. - πΌοΈ
Launch thesis Diagram Extension: Launches the extension development host and starts the GLSP server internally as an embedded child process (debugger will not attach to the server). - π
Launch thesis Diagram Extension (External GLSP Server): Launches the extension development host expecting a pre-running GLSP server process on port5007.
sequenceDiagram
autonumber
actor User
User->>LayoutPanelProvider: Adjust options & click "Apply & Layout"
LayoutPanelProvider->>GlspVscodeConnector: Send SetLayoutOptionsOperation
GlspVscodeConnector->>SetLayoutOptionsHandler: Dispatch Operation
SetLayoutOptionsHandler->>LayoutOptionsStore: Update user overrides
LayoutPanelProvider->>VS Code: Execute command "thesis.layout"
VS Code->>GlspVscodeConnector: Dispatch LayoutOperation
GlspVscodeConnector->>ThesisLayoutOperationHandler: Execute LayoutOperation
ThesisLayoutOperationHandler->>ThesisLayoutConfigurator: Invoke apply(element)
ThesisLayoutConfigurator->>Semantic Rule Engine: Apply semantic rules
ThesisLayoutConfigurator->>LayoutOptionsStore: Retrieve user overrides
ThesisLayoutConfigurator->>ELK: Run ELK layout engine
ELK-->>ThesisLayoutOperationHandler: Layout results (x, y, routing)
ThesisLayoutOperationHandler->>ThesisModelState: Update source model in-memory
ThesisModelState->>example.thesis: Persist layout coordinates to disk
ThesisLayoutOperationHandler-->>LayoutPanelProvider: Done
- Select
Launch thesis Diagram extension with external GLSP Serverand press F5. - In the new
[Extension Development Host]window, open theworkspacefolder. - Double-click the file
example.thesisin the file tree. It will render inside the custom GLSP diagram canvas. - Click on the Thesis Layout tab in the VS Code sidebar. It opens the Layout Controls view showing interactive sliders for spacing and segmented controls for direction and routing.
- Change some values (e.g., set Direction to
β(LEFT/RIGHT), set Node Spacing to80px) and click Apply & Layout. - Check the Debug Console of the main VS Code window running the
Thesis GLSP Server. You will see trace logs showing the active layout pass:ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ [SemanticLayout] Layout pass #1 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ [SemanticLayout] π User overrides active: ββ {"elk.direction":"RIGHT","elk.edgeRouting":"ORTHOGONAL","elk.spacing.nodeNode":"80","elk.layered.spacing.nodeNodeBetweenLayers":"60"} [SemanticLayout] β graph-algorithm β thesis-diagram ββ {"elk.algorithm":"layered"} [SemanticLayout] β section-priority β node-section-intro ββ {"elk.priority":"10"} [SemanticLayout] β depends-on-directed β edge-1 ββ {"elk.edge.type":"DIRECTED"} - Open the
example.thesisJSON file directly in VS Code. Note how the"position"and"routingPoints"objects have updated coordinates in real-time, matching the layout output.
This project is licensed under the Eclipse Public License v2.0 or MIT. For issues and discussions on the core platform components, check the Eclipse GLSP Umbrella repository.