Skip to content

Commit

Permalink
commented code and increased efficency
Browse files Browse the repository at this point in the history
  • Loading branch information
emilkrebs committed Aug 22, 2023
1 parent fc06ce5 commit 29eb260
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 47 deletions.
43 changes: 18 additions & 25 deletions hugo/assets/scripts/domainmodel/d3tree.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useRef, useEffect } from 'react';
import * as d3 from 'd3';
import tailwindConfig from '../../../../tailwind/tailwind.config';
import { DomainModelElementTypeNames } from './domainmodel-tools';

export interface TreeNode {
Expand All @@ -12,19 +11,19 @@ export interface TreeNode {
}

export type TreeNodeTag = 'supertype' | 'many';

interface TreeProps {
data: TreeNode;
}


const D3Tree: React.FC<TreeProps> = ({ data }) => {
export default function D3Tree({ data }: TreeProps) {
const svgRef = useRef<SVGSVGElement | null>(null);

useEffect(() => {
if (!svgRef.current) return;


// base height and width on the size tree
// get the size of the tree
const getChildSize = (child: TreeNode): number => {
if (!child.children) return 1;
let amount = child.children.length;
Expand All @@ -36,57 +35,55 @@ const D3Tree: React.FC<TreeProps> = ({ data }) => {
}
return amount;
};
const size = getChildSize(data);

const size = getChildSize(data);
const height = size * 20;
const width = size * 18;

const svg = d3.select(svgRef.current);
svg.selectAll('*').remove();
svg.attr('width', '100%').attr('height', '100%')

const hierarchy = d3.hierarchy(data);
const treeLayout = d3.tree<TreeNode>().size([height, width]);
const treeData = treeLayout(hierarchy);
const g = svg.append('g');

const zoom = d3.zoom<SVGSVGElement, unknown>().on('zoom', (event) => {
g.attr('transform', event.transform);
});

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


const hierarchy = d3.hierarchy(data);
const treeLayout = d3.tree<TreeNode>().size([height, width]);

const treeData = treeLayout(hierarchy);
const g = svg.append('g');

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


const link = g.selectAll('.link')
// draw the links
g.selectAll('.link')
.data(treeData.links())
.enter().append('path')
.attr('class', 'link')
.attr('d', d => {
// connect parent node to child node with a bezier curve (quadratic)
// connect parent node to child node
return `M${d.source.y},${d.source.x}C${d.source.y + 100},${d.source.x} ${d.target.y - 100},${d.target.x} ${d.target.y},${d.target.x}`;
})
.style('fill', 'none')
.style('stroke', 'white')
.style('stroke-width', '1px')
.style('stroke-dasharray', function (d) {
if(d.target.data.tags?.includes('supertype')) return '10,5';
if(d.source.data.tags?.includes('many')) return '5,5';
if (d.target.data.tags?.includes('supertype')) return '10,5';
if (d.source.data.tags?.includes('many')) return '5,5';
return 'none';
})
.style('stroke-opacity', '0.4');


const node = g.selectAll('.node')
.data(treeData.descendants())
.enter().append('g')
.attr('class', 'node')
.attr('transform', d => `translate(${d.y},${d.x})`);


// draw circle for nodes
node.append('circle')
.attr('r', 5)
.style('fill', function (d) {
Expand All @@ -104,6 +101,7 @@ const D3Tree: React.FC<TreeProps> = ({ data }) => {
}
});

// draw text for nodes
node.append('text')
.attr('dy', '0.31em')
.attr('x', d => d.children ? -6 : 6)
Expand Down Expand Up @@ -132,15 +130,10 @@ const D3Tree: React.FC<TreeProps> = ({ data }) => {
}
});



}, [data]);

return (
<svg ref={svgRef} width="100%" height="100%" >
{/* SVG content will be rendered here */}
</svg>
<svg ref={svgRef} width="100%" height="100%" />
);
};

export default D3Tree;
45 changes: 27 additions & 18 deletions hugo/assets/scripts/domainmodel/domainmodel-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,84 +6,93 @@ import { TreeNode } from "./d3tree";
export function getTreeNode(ast: AstNode): TreeNode {
const astNode = getDomainModelAst(ast as DomainModelAstNode);

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

// create a TreeNode a DataType
const getDataTypeTreeNode = (d: DataType): TreeNode => {
const result: TreeNode = {
return {
...d,
children: []
}
return result;
}


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

// create a TreeNode from a Feature
const getFeatureTreeNode = (feature: Feature): TreeNode => {
const result: TreeNode = {
return {
name: `${feature.name}${feature.many ? '[]' : ''}`,
$type: feature.$type,
tags: feature.many ? ['many'] : [],
children: [getDataTypeTreeNode(feature.type.ref)]
}
return result;
}

// get all children of an Entity (including the supertype)
const getCildren = (e: Entity): TreeNode[] => {
const superType = astNode.entities.find(entity => entity.name === e.superType?.ref.name);
const features = e.features.map(f => { return getFeatureTreeNode(f) });
const features = e.features.map(f => getFeatureTreeNode(f));

const children: TreeNode[] = superType ? [...features, {
name: superType.name,
$type: superType.$type,
tags: ['supertype'],
children: superType?.features.map(f => { return getFeatureTreeNode(f) })
children: superType?.features.map(f => getFeatureTreeNode(f) )
}] : features;

return children;
}
const result: TreeNode = {

return {
...entity,
children: getCildren(entity)
}
return result;
}

const entities = astNode.entities.map(e => { return getEntityTreeNode(e); });
const datatypes = astNode.dataTypes.map(d => { return getDataTypeTreeNode(d); });
// 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},
];

const result: TreeNode = {
// return the root TreeNode
return {
name: astNode.$type,
$type: astNode.$type,
children: children
}
return result;
}


/**
* Returns a DomainModelAstNode from a given ast.
*/
export function getDomainModelAst(ast: DomainModelAstNode ): DomainModelAstNode {
const result: DomainModelAstNode = {
return {
name: ast.name,
$type: 'Domainmodel',
elements: ast.elements,
packageDeclarations: (ast.elements as DomainModelElement[]).filter(e => e.$type === 'PackageDeclaration') as PackageDeclaration[],
entities: (ast.elements as DomainModelElement[]).filter(e => e.$type === 'Entity') as Entity[],
dataTypes: (ast.elements as DomainModelElement[]).filter(e => e.$type === 'DataType') as DataType[],
}
return result;
}

// a more accessible representation of the DomainModel Ast
export interface DomainModelAstNode extends AstNode, DomainModelElement {
$type: 'Domainmodel';
elements: DomainModelElementType[];
Expand Down
6 changes: 2 additions & 4 deletions hugo/assets/scripts/domainmodel/domainmodel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ class App extends React.Component<{}, AppState> {
* @param resp Response data
*/
onDocumentChange(resp: DocumentChangeResponse) {
// decode the received Asts
// update the state

// get the AST from the response and deserialize it
const ast = new LangiumAST().deserializeAST(resp.content) as DomainModelAstNode;

this.setState({
Expand Down Expand Up @@ -142,13 +140,13 @@ class App extends React.Component<{}, AppState> {
}
}


userConfig = createUserConfig({
languageId: 'domainmodel',
code: example,
htmlElement: document.getElementById('root')!,
worker: '/showcase/libs/worker/domainmodelServerWorker.js',
monarchGrammar: syntaxHighlighting
});

const root = createRoot(document.getElementById("root") as HTMLElement);
root.render(<App />);

0 comments on commit 29eb260

Please sign in to comment.