Skip to content

Commit

Permalink
[1989] Contribute an alternate rendering for diagrams
Browse files Browse the repository at this point in the history
Bug: #1989
Signed-off-by: Stéphane Bégaudeau <stephane.begaudeau@obeo.fr>
  • Loading branch information
sbegaudeau authored and gcoutable committed May 30, 2023
1 parent 682eb73 commit f44c2a1
Show file tree
Hide file tree
Showing 29 changed files with 1,476 additions and 107 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Introducing providers interfaces to help creating view programmatically.
Introducing a generator of builders aimed to help creating view programmatically, the generation makes use of emf-merge and modifications to these builders can be annotated to live during future regeneration.

- https://github.com/eclipse-sirius/sirius-components/issues/1912[#1912] [core] Add the possibility to send feedback messages to the frontend after an action.
- https://github.com/eclipse-sirius/sirius-components/issues/1989[#1979] [diagram] Contribute a new way to render diagrams to evaluate an alternate layouting strategy

=== Improvements

Expand Down
541 changes: 439 additions & 102 deletions package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"printWidth": 120,
"singleQuote": true,
"bracketSameLine": true,
"useTabs": false,
"tabWidth": 2,
"semi": true,
"overrides": [
{
"files": "*.js",
"options": {
"parser": "babel"
}
},
{
"files": "*.css",
"options": {
"parser": "css"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@eclipse-sirius/sirius-components-diagrams-reactflow",
"version": "2023.4.1",
"author": "Eclipse Sirius",
"license": "EPL-2.0",
"repository": {
"type": "git",
"url": "https://github.com/eclipse-sirius/sirius-components"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com/"
},
"main": "./dist/sirius-components-diagrams-reactflow.umd.js",
"module": "./dist/sirius-components-diagrams-reactflow.es.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"exports": {
".": {
"require": "./dist/sirius-components-diagrams-reactflow.umd.js",
"import": "./dist/sirius-components-diagrams-reactflow.es.js"
}
},
"scripts": {
"build": "vite build && tsc src/index.ts --jsx react-jsx --declaration --emitDeclarationOnly --esModuleInterop --moduleResolution node --target ES2019 --outDir dist",
"format": "prettier --write \"src/**/*.{js,ts,tsx,css}\"",
"format-lint": "prettier --list-different \"src/**/*.{js,ts,tsx,css}\"",
"publish:local": "yalc push"
},
"peerDependencies": {
"@apollo/client": "3.6.9",
"@eclipse-sirius/sirius-components-core": "~2023.4.0",
"@material-ui/core": "4.12.4",
"@material-ui/icons": "4.11.3",
"graphql": "16.5.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"reactflow": "11.7.2"
},
"devDependencies": {
"@apollo/client": "3.6.9",
"@eclipse-sirius/sirius-components-core": "~2023.4.0",
"@eclipse-sirius/sirius-components-tsconfig": "~2023.4.0",
"@material-ui/core": "4.12.4",
"@material-ui/icons": "4.11.3",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.9",
"@vitejs/plugin-react": "2.0.0",
"c8": "7.12.0",
"jsdom": "16.7.0",
"graphql": "16.5.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"prettier": "2.7.1",
"rollup-plugin-peer-deps-external": "2.2.4",
"typescript": "4.7.4",
"vite": "3.0.4",
"vitest": "0.21.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { Edge, Node } from 'reactflow';
import { GQLDiagram } from '../graphql/subscription/diagramFragment.types';
import { GQLImageNodeStyle, GQLNode, GQLRectangularNodeStyle } from '../graphql/subscription/nodeFragment.types';
import { Diagram } from '../renderer/DiagramRenderer.types';
import { ImageNodeData } from '../renderer/ImageNode.types';
import { RectangularNodeData } from '../renderer/RectangularNode.types';

const toRectangularNode = (gqlNode: GQLNode, gqlParentNode: GQLNode | null): Node<RectangularNodeData> => {
const style = gqlNode.style as GQLRectangularNodeStyle;
const { position, size } = gqlNode;
const labelStyle = gqlNode.label.style;

const data: RectangularNodeData = {
style: {
backgroundColor: style.color,
borderColor: style.borderColor,
borderRadius: style.borderRadius,
borderWidth: style.borderSize,
borderStyle: style.borderStyle,
width: `${size.width}px`,
height: `${size.height}px`,
},
label: {
text: gqlNode.label.text,
style: {
fontSize: labelStyle.fontSize,
color: labelStyle.color,
},
},
};

const node: Node<RectangularNodeData> = {
id: gqlNode.id,
type: 'rectangularNode',
data,
position,
};

if (gqlParentNode) {
node.parentNode = gqlParentNode.id;
node.extent = 'parent';
}

return node;
};

const toImageNode = (gqlNode: GQLNode, gqlParentNode: GQLNode | null): Node<ImageNodeData> => {
const style = gqlNode.style as GQLImageNodeStyle;
const { position, size } = gqlNode;

const data: ImageNodeData = {
style: {
width: `${size.width}px`,
height: `${size.height}px`,
},
imageURL: style.imageURL,
};

const node: Node<ImageNodeData> = {
id: gqlNode.id,
type: 'imageNode',
data,
position,
};

if (gqlParentNode) {
node.parentNode = gqlParentNode.id;
node.extent = 'parent';
}

return node;
};

const convertNode = (gqlNode: GQLNode, parentNode: GQLNode | null, nodes: Node[]): void => {
if (gqlNode.style.__typename === 'RectangularNodeStyle') {
nodes.push(toRectangularNode(gqlNode, parentNode));
} else if (gqlNode.style.__typename === 'ImageNodeStyle') {
nodes.push(toImageNode(gqlNode, parentNode));
}

(gqlNode.borderNodes ?? []).forEach((gqlBorderNode) => convertNode(gqlBorderNode, gqlNode, nodes));
(gqlNode.childNodes ?? []).forEach((gqlChildNode) => convertNode(gqlChildNode, gqlNode, nodes));
};

const nodeDepth = (nodeId2node: Map<string, Node>, nodeId: string): number => {
const node = nodeId2node.get(nodeId);
let depth = 0;

let parentNode = node.parentNode ? nodeId2node.get(node.parentNode) : undefined;
while (parentNode) {
depth = depth + 1;
parentNode = parentNode.parentNode ? nodeId2node.get(parentNode.parentNode) : undefined;
}

return depth;
};

export const convertDiagram = (gqlDiagram: GQLDiagram): Diagram => {
const nodes: Node[] = [];
gqlDiagram.nodes.forEach((gqlNode) => convertNode(gqlNode, null, nodes));

const nodeId2node = new Map<string, Node>();
nodes.forEach((node) => nodeId2node.set(node.id, node));

const nodeId2Depth = new Map<string, number>();
nodes.forEach((node) => nodeId2Depth.set(node.id, nodeDepth(nodeId2node, node.id)));

const edges: Edge[] = gqlDiagram.edges.map((gqlEdge) => {
const zIndex = Math.max(nodeId2Depth.get(gqlEdge.sourceId), nodeId2Depth.get(gqlEdge.targetId));

return {
id: gqlEdge.id,
type: 'step',
source: gqlEdge.sourceId,
target: gqlEdge.targetId,
zIndex,
};
});

return {
nodes,
edges,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { diagramFragment } from './diagramFragment';

export const diagramEventSubscription = `
subscription diagramEvent($input: DiagramEventInput!) {
diagramEvent(input: $input) {
... on ErrorPayload {
id
message
}
... on SubscribersUpdatedEventPayload {
id
subscribers {
username
}
}
... on DiagramRefreshedEventPayload {
id
diagram {
...diagramFragment
}
}
}
}
${diagramFragment}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { GQLDiagram } from './diagramFragment.types';

export interface GQLDiagramEventPayload {
id: string;
__typename: string;
}

export interface GQLErrorPayload extends GQLDiagramEventPayload {
message: string;
}

export interface GQLSubscribersUpdatedEventPayload extends GQLDiagramEventPayload {
subscribers: GQLSubscriber[];
}

export interface GQLSubscriber {
username: string;
}

export interface GQLDiagramRefreshedEventPayload extends GQLDiagramEventPayload {
diagram: GQLDiagram;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { edgeFragment } from './edgeFragment';
import { labelFragment } from './labelFragment';
import { nodeFragment } from './nodeFragment';

export const diagramFragment = `
fragment diagramFragment on Diagram {
id
targetObjectId
metadata {
kind
label
}
nodes {
...nodeFragment
borderNodes {
...nodeFragment
}
childNodes {
...nodeFragment
borderNodes {
...nodeFragment
}
childNodes {
...nodeFragment
borderNodes {
...nodeFragment
}
childNodes {
...nodeFragment
borderNodes {
...nodeFragment
}
childNodes {
...nodeFragment
borderNodes {
...nodeFragment
}
childNodes {
...nodeFragment
borderNodes {
...nodeFragment
}
}
}
}
}
}
}
edges {
...edgeFragment
}
}
${nodeFragment}
${edgeFragment}
${labelFragment}
`;

0 comments on commit f44c2a1

Please sign in to comment.