From 7aba9f2019d7a62a2fe12333d5f1118f9810254a Mon Sep 17 00:00:00 2001 From: Thomas Bouffard <27200110+tbouffard@users.noreply.github.com> Date: Thu, 6 Jul 2023 06:49:26 +0200 Subject: [PATCH] feat: add a project with maxGraph as a lit Web Component (#38) --- .../workflows/check-typescript-projects.yml | 10 +- README.md | 5 + projects/lit-ts/README.md | 18 ++ projects/lit-ts/favicon.svg | 13 + projects/lit-ts/index.html | 19 ++ projects/lit-ts/package-lock.json | 249 ++++++++++++++++++ projects/lit-ts/package.json | 18 ++ projects/lit-ts/src/custom-shapes.ts | 43 +++ projects/lit-ts/src/index.ts | 49 ++++ projects/lit-ts/src/style.css | 37 +++ projects/lit-ts/src/vite-env.d.ts | 1 + projects/lit-ts/tsconfig.json | 21 ++ 12 files changed, 480 insertions(+), 3 deletions(-) create mode 100644 projects/lit-ts/README.md create mode 100644 projects/lit-ts/favicon.svg create mode 100644 projects/lit-ts/index.html create mode 100644 projects/lit-ts/package-lock.json create mode 100644 projects/lit-ts/package.json create mode 100644 projects/lit-ts/src/custom-shapes.ts create mode 100644 projects/lit-ts/src/index.ts create mode 100644 projects/lit-ts/src/style.css create mode 100644 projects/lit-ts/src/vite-env.d.ts create mode 100644 projects/lit-ts/tsconfig.json diff --git a/.github/workflows/check-typescript-projects.yml b/.github/workflows/check-typescript-projects.yml index 6052b9c..23f0402 100644 --- a/.github/workflows/check-typescript-projects.yml +++ b/.github/workflows/check-typescript-projects.yml @@ -19,7 +19,7 @@ on: - 'projects/**/*' jobs: - build_maxgraph_package: + build_maxgraph_dev_package: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 @@ -43,12 +43,16 @@ jobs: build_projects: runs-on: ubuntu-22.04 - needs: [build_maxgraph_package] + needs: [build_maxgraph_dev_package] strategy: # don't cancel running jobs even if one fails fail-fast: false matrix: - project: [parcel-ts, rollup-ts, vitejs-ts] + project: + - lit-ts + - parcel-ts + - rollup-ts + - vitejs-ts npm-package: ['release', 'development'] defaults: run: diff --git a/README.md b/README.md index 939bd0e..a0f1176 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Demonstrate how to integrate [maxGraph](https://github.com/maxGraph/maxGraph/) in projects. +⏩ Find the live demo at https://maxgraph.github.io/maxgraph-integration-examples/ + ## Getting started ### Setup @@ -18,6 +20,7 @@ If the Node version is not installed, `nvm` will state how to install the requir ### Available projects +- [TypeScript with Lit](./projects/lit-ts/README.md) - [TypeScript with Parcel](./projects/parcel-ts/README.md) - [TypeScript with Rollup](./projects/rollup-ts/README.md) - [TypeScript with ViteJs](./projects/vitejs-ts/README.md) @@ -25,6 +28,8 @@ If the Node version is not installed, `nvm` will state how to install the requir ### Use the maxGraph development version +**Note**: the `maxGraph` development version is tested in a [GitHub Workflow](./.github/workflows/check-typescript-projects.yml) that uses the procedure explained below. + Build [maxGraph](https://github.com/maxGraph/maxGraph/) locally: - from the `maxGraph` project root, run: `npm install` - then, from the `packages/core` folder, run: `npm pack` diff --git a/projects/lit-ts/README.md b/projects/lit-ts/README.md new file mode 100644 index 0000000..df9257f --- /dev/null +++ b/projects/lit-ts/README.md @@ -0,0 +1,18 @@ +# lit-ts + +Demonstrate how to integrate maxGraph in a Web Component created with [lit](https://lit.dev/). + +The application is built with [Vite](https://vitejs.dev/). + +## Setup + +From the project root, run `npm install`. + +If you want to use the maxGraph development version (built locally), see the README about maxGraph integration. + +## Running the project + +Run `npm run dev` and go to http://localhost:5173/ + +If you want to bundle the application, run `npm run build` and then run `npm run preview` to access to a preview of the +bundle application. diff --git a/projects/lit-ts/favicon.svg b/projects/lit-ts/favicon.svg new file mode 100644 index 0000000..20eaec4 --- /dev/null +++ b/projects/lit-ts/favicon.svg @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/projects/lit-ts/index.html b/projects/lit-ts/index.html new file mode 100644 index 0000000..cab0f7c --- /dev/null +++ b/projects/lit-ts/index.html @@ -0,0 +1,19 @@ + + + + + + maxGraph Lit integration example + + + + +

maxGraph TypeScript example

+

Display a test graph. Activated behaviours:

+ + + + diff --git a/projects/lit-ts/package-lock.json b/projects/lit-ts/package-lock.json new file mode 100644 index 0000000..535153f --- /dev/null +++ b/projects/lit-ts/package-lock.json @@ -0,0 +1,249 @@ +{ + "name": "bpmn-visualization-lit-element-ts-vite", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bpmn-visualization-lit-element-ts-vite", + "version": "0.0.0", + "license": "Apache-2.0", + "dependencies": { + "@maxgraph/core": "0.2.1", + "lit": "~2.7.5" + }, + "devDependencies": { + "typescript": "~5.1.6", + "vite": "~4.3.9" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.1.1", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/reactive-element": { + "version": "1.6.2", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.0.0" + } + }, + "node_modules/@maxgraph/core": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@maxgraph/core/-/core-0.2.1.tgz", + "integrity": "sha512-6dBVcVwNVZr8iEn9pmvyMr66GYL7qGc1oWB1VF70kQqVKlkMSLVKKeQRmEATX5GFlywoxjQ40m8edMyNt5vsPw==" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.3", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.17.19", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/lit": { + "version": "2.7.5", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^1.6.0", + "lit-element": "^3.3.0", + "lit-html": "^2.7.0" + } + }, + "node_modules/lit-element": { + "version": "3.3.2", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.1.0", + "@lit/reactive-element": "^1.3.0", + "lit-html": "^2.7.0" + } + }, + "node_modules/lit-html": { + "version": "2.7.4", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/nanoid": { + "version": "3.3.6", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.24", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "3.24.0", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "4.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.17.5", + "postcss": "^8.4.23", + "rollup": "^3.21.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + } + } +} diff --git a/projects/lit-ts/package.json b/projects/lit-ts/package.json new file mode 100644 index 0000000..2132c24 --- /dev/null +++ b/projects/lit-ts/package.json @@ -0,0 +1,18 @@ +{ + "name": "maxgraph-ts-example-integrating-in-lit", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "tsc && vite build --base ./", + "preview": "vite preview" + }, + "dependencies": { + "@maxgraph/core": "0.2.1", + "lit": "~2.7.5" + }, + "devDependencies": { + "vite": "~4.3.9", + "typescript": "~5.1.6" + } +} diff --git a/projects/lit-ts/src/custom-shapes.ts b/projects/lit-ts/src/custom-shapes.ts new file mode 100644 index 0000000..e0fc162 --- /dev/null +++ b/projects/lit-ts/src/custom-shapes.ts @@ -0,0 +1,43 @@ +// TODO fully duplicated with other projects + +import {AbstractCanvas2D, CellRenderer, type ColorValue, EllipseShape, Rectangle, RectangleShape} from '@maxgraph/core'; + +export function registerCustomShapes(): void { + console.info('Registering custom shapes...'); + // @ts-ignore TODO fix CellRenderer. Calls to this function are also marked as 'ts-ignore' in CellRenderer + CellRenderer.registerShape('customRectangle', CustomRectangleShape); + // @ts-ignore + CellRenderer.registerShape('customEllipse', CustomEllipseShape); + console.info('Custom shapes registered'); +} + +class CustomRectangleShape extends RectangleShape { + + constructor(bounds: Rectangle, fill: ColorValue, stroke: ColorValue) { + super(bounds, fill, stroke, 3); + this.isRounded = true; // force rounded shape + } + + paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number): void { + c.setFillColor('Chartreuse'); + super.paintBackground(c, x, y, w, h); + } + + paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) { + c.setStrokeColor('Black'); + super.paintVertexShape(c, x, y, w, h); + } + +} + +class CustomEllipseShape extends EllipseShape { + constructor(bounds: Rectangle, fill: string, stroke: string) { + super(bounds, fill, stroke, 5); + } + + paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) { + c.setFillColor('Yellow'); + c.setStrokeColor('Red'); + super.paintVertexShape(c, x, y, w, h); + } +} diff --git a/projects/lit-ts/src/index.ts b/projects/lit-ts/src/index.ts new file mode 100644 index 0000000..14d9440 --- /dev/null +++ b/projects/lit-ts/src/index.ts @@ -0,0 +1,49 @@ +import './style.css'; +import {type CellStyle, Graph, InternalEvent, RubberBandHandler} from '@maxgraph/core'; +import {registerCustomShapes} from "./custom-shapes"; +import {html, LitElement} from "lit"; +import { customElement } from "lit/decorators.js"; + +// TODO mainly duplicated with other projects +const initializeGraph = (container: HTMLElement) => { + // Disables the built-in context menu + InternalEvent.disableContextMenu(container); + + const graph = new Graph(container); + graph.setPanning(true); // Use mouse right button for panning + // WARN: as the maxGraph css files are not available in the npm package (at least for now), dedicated CSS class must be defined in style.css + new RubberBandHandler(graph); // Enables rubber band selection + + // shapes and styles + registerCustomShapes(); + // @ts-ignore TODO fix TS2532: Object is possibly 'undefined'. + graph.getStylesheet().getDefaultEdgeStyle().edgeStyle = 'orthogonalEdgeStyle'; // TODO use constants.EDGESTYLE instead of 'orthogonalEdgeStyle' + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + // Adds cells to the model in a single step + graph.batchUpdate(() => { + const vertex01 = graph.insertVertex(parent, null, 'a regular rectangle', 10, 10, 100, 100); + const vertex02 = graph.insertVertex(parent, null, 'a regular ellipse', 350, 90, 50, 50, {shape: 'ellipse', fillColor: 'orange'}); + graph.insertEdge(parent, null, 'a regular edge', vertex01, vertex02); + + // insert vertices using custom shapes + // TODO type issue in CellStyle type, shape should allow string to manage custom implementation + const vertex11 = graph.insertVertex(parent, null, 'a custom rectangle', 20, 200, 100, 100, /**/{shape: 'customRectangle'}); + const vertex12 = graph.insertVertex(parent, null, 'a custom ellipse', 150, 350, 70, 70, /**/{shape: 'customEllipse'}); + graph.insertEdge(parent, null, 'another edge', vertex11, vertex12); + }); +}; + +@customElement("maxgraph-graph") +export class GraphElement extends LitElement { + firstUpdated(): void { + initializeGraph(this.renderRoot.querySelector("#graph-container")); + } + + render() { + return html`
`; + } +} diff --git a/projects/lit-ts/src/style.css b/projects/lit-ts/src/style.css new file mode 100644 index 0000000..1a5bc9e --- /dev/null +++ b/projects/lit-ts/src/style.css @@ -0,0 +1,37 @@ +/*TODO fully duplicated with other projects*/ + +body { + font-family: Avenir, Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: #2c3e50; +} + +h1 { + text-align: center; + margin-top: 3rem; +} + +footer { + position: absolute; + bottom: 1rem; + right: 1rem; + z-index: 1; + font-weight: 800; +} + +#graph-container { + border: #B0B0B0 1px solid; + height: 70vh; + overflow: hidden; +} + +/* For rubber band selection as we don't have access to the maxGraph CSS files in the project */ +div.mxRubberband { + position: absolute; + overflow: hidden; + border-style: solid; + border-width: 2px; + border-color: #b18426; + background: #db9b0b; +} diff --git a/projects/lit-ts/src/vite-env.d.ts b/projects/lit-ts/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/projects/lit-ts/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/projects/lit-ts/tsconfig.json b/projects/lit-ts/tsconfig.json new file mode 100644 index 0000000..03048da --- /dev/null +++ b/projects/lit-ts/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "esnext", + "lib": ["es2017", "dom", "dom.iterable"], + "outDir": "./build", + "rootDir": "./src", + "strict": true, + "declaration": false, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*.ts"], + "exclude": [] +}