Skip to content

Commit

Permalink
Minor DomainModel Showcase fixes (#200)
Browse files Browse the repository at this point in the history
* fixed nested elements and scaling

* remaned one function

* fixed a renaming problem

* Fix typo in getting-started grammar (#198)

* Fix typo in getting-started grammar

* Make code blocks vertically scrollable
To make it possible to read the docs on a phone

* Update Langium + Monaco Tutorials (#192)

* update of langium + monaco tutorial

* update generation in the web tutorial

* Update to latest monaco-editor-wrapper and monaco-editor-react (#196)

* Update to latest monaco-editor-wrapper and monaco-editor-react
* Implemented review comments

* fixed a renaming problem

---------

Co-authored-by: Vit Gottwald <[email protected]>
Co-authored-by: Benjamin Friedman Wilson <[email protected]>
Co-authored-by: Kai Salmen <[email protected]>
  • Loading branch information
4 people authored Oct 26, 2023
1 parent 6237ca9 commit dc84df4
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 37 deletions.
32 changes: 16 additions & 16 deletions hugo/assets/scripts/domainmodel/d3tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@ export default function D3Tree({ data }: TreeProps) {
useEffect(() => {
if (!svgRef.current) return;

// get the size of the tree
const getChildSize = (child: TreeNode): number => {
// get the leaf nodes of the tree
const getLeafNodes = (child: TreeNode): number => {
if (!child.children) return 1;
let amount = child.children.length;

// fastest way to iterate over an array
const length = child.children.length;
for (let i = 0; i < length; i++) {
amount += getChildSize(child.children[i]);
}
return amount;
if(child.children.length === 0) return 1;
return child.children.map(getLeafNodes).reduce((a, b) => a + b);
};

const size = getChildSize(data);
const height = size * 20;
const width = size * 18;
// get the longest path in the tree
const getLongestPath = (child: TreeNode): number => {
if (!child.children) return 1;
if(child.children.length === 0) return 1;
return 1 + Math.max(...child.children.map(getLongestPath));
};

const height = getLeafNodes(data) * 60;
const width = getLongestPath(data) * 120;

const svg = d3.select(svgRef.current);
svg.selectAll('*').remove();
Expand All @@ -51,10 +51,10 @@ export default function D3Tree({ data }: TreeProps) {
g.attr('transform', event.transform);
});

svg.call(zoom, d3.zoomIdentity.translate(50, 50));

// zoom to show the whole tree
svg.call(zoom.transform, d3.zoomIdentity.translate(width / size * 3, height / size * 2).scale(3 / (0.1 * size)));
svg.call(zoom.transform, d3.zoomIdentity.translate(width / 20, height / 30).scale(0.5));

svg.call(zoom, d3.zoomIdentity.translate(50, 50));

// draw the links
g.selectAll('.link')
Expand Down
59 changes: 40 additions & 19 deletions hugo/assets/scripts/domainmodel/domainmodel-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,8 @@ import { AstNode } from "../langium-utils/langium-ast";
import { TreeNode } from "./d3tree";


export function getTreeNode(ast: AstNode): TreeNode {
export function getMainTreeNode(ast: AstNode): TreeNode {
const astNode = getDomainModelAst(ast as DomainModelAstNode);

// create a TreeNode from all PackageDeclarations in the ast
const packageDeclarations = astNode.packageDeclarations.map(p => {
return {
...p,
children: p.elements
} as TreeNode;
});

// create a TreeNode a DataType
const getDataTypeTreeNode = (d: DataType): TreeNode => {
return {
Expand All @@ -22,6 +13,24 @@ export function getTreeNode(ast: AstNode): TreeNode {
}
}

// create a TreeNode from a PackageDeclaration
const getPackageDeclarationTreeNode = (p: PackageDeclaration): TreeNode => {
return {
...p,
children: p.elements.map(e => getTreeNode(e))
}
}

// create a TreeNode from any DomainModelElement
const getTreeNode = (e: DomainModelElement): TreeNode => {
switch(e.$type) {
case 'DataType': return getDataTypeTreeNode(e as DataType);
case 'Entity': return getEntityTreeNode(e as Entity);
case 'PackageDeclaration': return getPackageDeclarationTreeNode(e as PackageDeclaration);
default: return e as TreeNode;
}
}

// create a TreeNode from an Entity
const getEntityTreeNode = (entity: Entity): TreeNode => {

Expand Down Expand Up @@ -58,16 +67,28 @@ export function getTreeNode(ast: AstNode): TreeNode {

// create a TreeNode from all Entities in the ast
const entities = astNode.entities.flatMap(e => getEntityTreeNode(e));

// create a TreeNode from all DataTypes in the ast
const datatypes = astNode.dataTypes.map(d => getDataTypeTreeNode(d));

// combine them all to a single TreeNode
const children: TreeNode[] = [
{name: 'DataTypes', $type: 'DataType', children: datatypes},
{name: 'Entities', $type: 'Entity', children: entities},
{name: 'Packages', $type: 'PackageDeclaration', children: packageDeclarations},
];
// create a TreeNode from all PackageDeclarations in the ast
const packageDeclarations = astNode.packageDeclarations.map(p => getPackageDeclarationTreeNode(p));

const children: TreeNode[] = [];

// if datatypes exist, add them to the children
if(datatypes.length > 0) {
children.push({ name: 'DataTypes', $type: 'DataType', children: datatypes });
}

// if entities exist, add them to the children
if(entities.length > 0) {
children.push({name: 'Entities', $type: 'Entity', children: entities});
}

// if packageDeclarations exist, add them to the children
if(packageDeclarations.length > 0) {
children.push({name: 'Packages', $type: 'PackageDeclaration', children: packageDeclarations});
}


// return the root TreeNode
return {
Expand Down Expand Up @@ -103,7 +124,7 @@ export interface DomainModelAstNode extends AstNode, DomainModelElement {

export interface PackageDeclaration extends DomainModelElement {
$type: 'PackageDeclaration';
elements: DataType[];
elements: DomainModelElementType[];
}

export interface Entity extends DomainModelElement {
Expand Down
5 changes: 3 additions & 2 deletions hugo/assets/scripts/domainmodel/domainmodel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { buildWorkerDefinition } from "monaco-editor-workers";
import React from "react";
import { createRoot } from "react-dom/client";
import { Diagnostic, DocumentChangeResponse, LangiumAST } from "../langium-utils/langium-ast";
import { DomainModelAstNode, example, getTreeNode, syntaxHighlighting } from "./domainmodel-tools";
import { DomainModelAstNode, example, getMainTreeNode, syntaxHighlighting } from "./domainmodel-tools";

import D3Tree from "./d3tree";

addMonacoStyles('monaco-styles-helper');
Expand Down Expand Up @@ -85,7 +86,7 @@ class App extends React.Component<{}, AppState> {
// if there are no errors, render the tree
if (this.state.diagnostics == null || this.state.diagnostics.filter((i) => i.severity === 1).length == 0) {
return (
<D3Tree data={getTreeNode(ast)} />
<D3Tree data={getMainTreeNode(ast)} />
);
}

Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit dc84df4

Please sign in to comment.