diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f6cac5cb16..08a051d636 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,12 +57,16 @@ jobs: run: npm test -w packages/ts-support - name: Build ts-example (custom shapes) run: npm run build -w packages/ts-example + - name: Build ts-example (selected features) + run: npm run build -w packages/ts-example-selected-features - name: Build ts-example (without defaults) run: npm run build -w packages/ts-example-without-defaults - name: Build Storybook mini-site run: npm run build -w packages/html - name: Build js-example run: npm run build -w packages/js-example + - name: Build js-example (selected features) + run: npm run build -w packages/js-example-selected-features - name: Build js-example (without defaults) run: npm run build -w packages/js-example-without-defaults - name: Upload all examples as artifact @@ -71,10 +75,8 @@ jobs: name: examples-${{runner.os}}-${{github.sha}} path: | packages/html/dist/ - packages/js-example/dist/ - packages/js-example-without-defaults/dist/ - packages/ts-example/dist/ - packages/ts-example-without-defaults/dist/ + packages/js-example*/dist/ + packages/ts-example*/dist/ - name: Ensure no circular dependencies in the @maxgraph/core produced JS files run: npm run check:circular-dependencies -w packages/core - name: Ensure no lint errors diff --git a/README.md b/README.md index 538f7ef180..a7fcc24379 100644 --- a/README.md +++ b/README.md @@ -142,8 +142,10 @@ Note that they are based on `maxGraph` features, which require the use of [CSS a - The stories are currently written in `JavaScript` and will be progressively migrated to `TypeScript`. - A live instance is available on the [maxGraph website](https://maxgraph.github.io/maxGraph/demo). - the [ts-example](packages/ts-example) project/application that demonstrates how to define and use custom `Shapes` with `maxGraph`. It is a vanilla TypeScript application built by [Vite](https://vitejs.dev/). +- the [ts-example-selected-features](packages/ts-example-selected-features) project/application that demonstrates the same use case as in `ts-example` but which only loads the features and configuration required by the application for an efficient tree-shaking. It is a vanilla TypeScript application built by [Vite](https://vitejs.dev/). - the [ts-example-without-defaults](packages/ts-example-without-defaults) project/application that demonstrates how to not use defaults plugins and style defaults (shapes, perimeters, ...). It is a vanilla TypeScript application built by [Vite](https://vitejs.dev/). - the [js-example](packages/js-example) project/application that demonstrates how to import and export the `maxGraph` model with XML data. It is a vanilla JavaScript application built by [Webpack](https://webpack.js.org/). +- the [js-example-selected-features](packages/js-example-selected-features) project/application that demonstrates the same use case as in `ts-example` but which only loads the features and configuration required by the application for an efficient tree-shaking. It is a vanilla JavaScript application built by [Webpack](https://webpack.js.org/). - the [js-example-without-defaults](packages/js-example-without-defaults) project/application that demonstrates how to not use defaults plugins and style defaults (shapes, perimeters, ...). It is a vanilla JavaScript application built by [Webpack](https://webpack.js.org/). - the [maxgraph-integration-examples](https://github.com/maxGraph/maxgraph-integration-examples) repository which shows how to integrate `maxGraph` with different frameworks and build tools. diff --git a/package-lock.json b/package-lock.json index c863e0d602..f1c09283f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6374,6 +6374,10 @@ "resolved": "packages/js-example", "link": true }, + "node_modules/@maxgraph/js-example-webpack-selected-features": { + "resolved": "packages/js-example-selected-features", + "link": true + }, "node_modules/@maxgraph/js-example-webpack-without-defaults": { "resolved": "packages/js-example-without-defaults", "link": true @@ -6382,6 +6386,10 @@ "resolved": "packages/ts-example", "link": true }, + "node_modules/@maxgraph/ts-example-vite-with-selected-features": { + "resolved": "packages/ts-example-selected-features", + "link": true + }, "node_modules/@maxgraph/ts-example-vite-without-defaults": { "resolved": "packages/ts-example-without-defaults", "link": true @@ -35674,6 +35682,260 @@ "webpack-dev-server": "~5.2.1" } }, + "packages/js-example-selected-features": { + "name": "@maxgraph/js-example-webpack-selected-features", + "devDependencies": { + "copy-webpack-plugin": "~13.0.0", + "css-loader": "~7.1.2", + "html-webpack-plugin": "~5.6.3", + "http-server": "~14.1.1", + "mini-css-extract-plugin": "~2.9.2", + "style-loader": "~4.0.0", + "webpack": "~5.99.6", + "webpack-cli": "~6.0.1", + "webpack-dev-server": "~5.2.1" + } + }, + "packages/js-example-selected-features/node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true, + "license": "MIT" + }, + "packages/js-example-selected-features/node_modules/css-loader": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "packages/js-example-selected-features/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/js-example-selected-features/node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "packages/js-example-selected-features/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/js-example-selected-features/node_modules/memfs": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.0.tgz", + "integrity": "sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "packages/js-example-selected-features/node_modules/open": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.1.tgz", + "integrity": "sha512-zy1wx4+P3PfhXSEPJNtZmJXfhkkIaxU1VauWIrDZw1O7uJRDRJtKr9n3Ic4NgbA16KyOxOXO2ng9gYwCdXuSXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/js-example-selected-features/node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/js-example-selected-features/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "packages/js-example-selected-features/node_modules/webpack-dev-server": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.1.tgz", + "integrity": "sha512-ml/0HIj9NLpVKOMq+SuBPLHcmbG+TGIjXRHsYfZwocUBIqEvws8NnS/V9AFQ5FKP+tgn5adwVwRrTEpGL33QFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.21.2", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.7", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "packages/js-example-selected-features/node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.6.0", + "mime-types": "^2.1.31", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, "packages/js-example-without-defaults": { "name": "@maxgraph/js-example-webpack-without-defaults", "devDependencies": { @@ -35813,6 +36075,566 @@ "vite": "~6.2.0" } }, + "packages/ts-example-selected-features": { + "name": "@maxgraph/ts-example-vite-with-selected-features", + "license": "Apache-2.0", + "devDependencies": { + "vite": "~6.2.0" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/android-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/android-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/android-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/darwin-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-loong64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-s390x": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/linux-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/sunos-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/win32-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/win32-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/@esbuild/win32-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/ts-example-selected-features/node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" + } + }, + "packages/ts-example-selected-features/node_modules/vite": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz", + "integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "packages/ts-example-selected-features/node_modules/yaml": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", + "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "packages/ts-example-without-defaults": { "name": "@maxgraph/ts-example-vite-without-defaults", "license": "Apache-2.0", diff --git a/packages/js-example-selected-features/.gitignore b/packages/js-example-selected-features/.gitignore new file mode 100644 index 0000000000..72479eb485 --- /dev/null +++ b/packages/js-example-selected-features/.gitignore @@ -0,0 +1,4 @@ +# Build directories +/node_modules/ +/dist/ +package-lock.json diff --git a/packages/js-example-selected-features/README.md b/packages/js-example-selected-features/README.md new file mode 100644 index 0000000000..d0821898d8 --- /dev/null +++ b/packages/js-example-selected-features/README.md @@ -0,0 +1,36 @@ +# Integrate `maxGraph` in a vanilla JavaScript project built with Webpack - features selection + +This example only loads the features and configuration required by the application for an efficient tree-shaking. + +So, it demonstrates how to only register Shapes, Perimeters, EdgeMarkers and EdgeStyles used by the application. + +It also uses the following set of features: +- Cells selection by mouse click or with Rubberband +- Management of selected cells +- Fit and zoom using buttons +- Panning with mouse drag + +As in the [js-example](../js-example) example, it demonstrates how to import/decode an XML model using `Codecs`. + +Note: This example should be kept in sync with the [js-example](../js-example) example as it replicates the same use case. + +## Setup + +From the repository root, run: +```bash +npm install +cd packages/core/ +npm run build +cd ../../packages/js-example-selected-features/ +# For more details see 'Run' below +npm run dev +``` + +For more build information see: [@maxgraph/core](../../README.md#development). + + +## Run + +Run `npm run dev` from this directory and go to http://localhost:8080/ + +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/packages/js-example-selected-features/favicon.svg b/packages/js-example-selected-features/favicon.svg new file mode 100644 index 0000000000..d7b7e40b4f --- /dev/null +++ b/packages/js-example-selected-features/favicon.svg @@ -0,0 +1 @@ +icon-square-small diff --git a/packages/js-example-selected-features/index.html b/packages/js-example-selected-features/index.html new file mode 100644 index 0000000000..883753991f --- /dev/null +++ b/packages/js-example-selected-features/index.html @@ -0,0 +1,20 @@ + + + + + + + maxGraph JavaScript Integration with Webpack (selected features) + + +

maxGraph JavaScript Integration with Webpack (selected features)

+

Display a test graph loaded from an XML source. Activated behaviours:

+ +
+ + + + diff --git a/packages/js-example-selected-features/package.json b/packages/js-example-selected-features/package.json new file mode 100644 index 0000000000..a7d9499a62 --- /dev/null +++ b/packages/js-example-selected-features/package.json @@ -0,0 +1,20 @@ +{ + "name": "@maxgraph/js-example-webpack-selected-features", + "private": true, + "scripts": { + "dev": "webpack serve --open", + "build": "webpack --mode=production", + "preview": "http-server -c-1 dist" + }, + "devDependencies": { + "copy-webpack-plugin": "~13.0.0", + "css-loader": "~7.1.2", + "http-server": "~14.1.1", + "html-webpack-plugin": "~5.6.3", + "mini-css-extract-plugin": "~2.9.2", + "style-loader": "~4.0.0", + "webpack": "~5.99.6", + "webpack-cli": "~6.0.1", + "webpack-dev-server": "~5.2.1" + } +} diff --git a/packages/js-example-selected-features/src/index.js b/packages/js-example-selected-features/src/index.js new file mode 100644 index 0000000000..2e3fc8fc03 --- /dev/null +++ b/packages/js-example-selected-features/src/index.js @@ -0,0 +1,123 @@ +/* +Copyright 2025-present The maxGraph project Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import '@maxgraph/core/css/common.css'; // required by RubberBandHandler +import './style.css'; +import { + constants, + DomHelpers, + EdgeMarker, + Graph, + InternalEvent, + MarkerShape, + ModelXmlSerializer, + PanningHandler, + Perimeter, + RubberBandHandler, + SelectionCellsHandler, + SelectionHandler, + StyleRegistry, +} from '@maxgraph/core'; + +/** + * Create a custom implementation to not load all default built-in styles. This is because Graph registers them. + * + * In the future, we expect to have an implementation of Graph that does not do it. + * See https://github.com/maxGraph/maxGraph/issues/760 + */ +class CustomGraph extends Graph { + /** + * Only registers the elements required for this example. Do not let Graph load all default built-in styles. + */ + registerDefaults() { + // Register styles + StyleRegistry.putValue('rectanglePerimeter', Perimeter.RectanglePerimeter); // declared in the default vertex style, so must be registered to be used + MarkerShape.addMarker('classic', EdgeMarker.createArrow(2)); + } +} + +const xmlWithVerticesAndEdges = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; + +const initializeGraph = (container) => { + // Disables the built-in context menu + InternalEvent.disableContextMenu(container); + + const graph = new CustomGraph(container, undefined, [ + PanningHandler, // Enables panning with the mouse + RubberBandHandler, // Enables rubber band selection + SelectionCellsHandler, // Enables management of selected cells + SelectionHandler, // Enables selection with the mouse + ]); + graph.setPanning(true); // Use mouse right button for panning + + const modelXmlSerializer = new ModelXmlSerializer(graph.model); + modelXmlSerializer.import(xmlWithVerticesAndEdges); + + return graph; +}; + +// display the maxGraph version in the footer +const footer = document.querySelector('footer'); +footer.innerText = `Built with maxGraph ${constants.VERSION}`; + +// Creates the graph inside the given container +const container = document.querySelector('#graph-container'); +const graph = initializeGraph(container); + +// poor way to display the XML +const popup = (content) => { + window.alert(content); +}; + +container.parentElement.appendChild( + DomHelpers.button('View Original XML', () => { + popup(xmlWithVerticesAndEdges); + }) +); +container.parentElement.appendChild( + DomHelpers.button('Export XML', () => { + const xml = new ModelXmlSerializer(graph.model).export(); + popup(xml); + }) +); diff --git a/packages/js-example-selected-features/src/style.css b/packages/js-example-selected-features/src/style.css new file mode 100644 index 0000000000..fd077a38a1 --- /dev/null +++ b/packages/js-example-selected-features/src/style.css @@ -0,0 +1,52 @@ +/* +Copyright 2025-present The maxGraph project Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +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; +} + +button { + margin-top: 1.5rem; + margin-left: .5rem; +} + +/* For rubber band selection, override maxGraph defaults */ +div.mxRubberband { + border-color: #b18426; + background: #db9b0b; +} diff --git a/packages/js-example-selected-features/webpack.config.js b/packages/js-example-selected-features/webpack.config.js new file mode 100644 index 0000000000..30d9ddeddc --- /dev/null +++ b/packages/js-example-selected-features/webpack.config.js @@ -0,0 +1,45 @@ +// Generated using webpack-cli http://github.com/webpack-cli +const path = require('path'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +// hack to get the webpack mode +const isDevMode = !process.argv.includes('--mode=production'); + +module.exports = { + mode: 'development', + entry: './src/index.js', + output: { + filename: '[name].[contenthash].js', + path: path.resolve(__dirname, 'dist'), + clean: true, + }, + devServer: { + static: './dist', + }, + module: { + rules: [ + { + test: /\.css$/i, + use: [isDevMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader'], + }, + // @maxgraph/core is a dependency of this project but don't declare imports with js extension + // use this workaround to make webpack happy: https://github.com/webpack/webpack/issues/11467#issuecomment-691873586 + { + test: /\.m?js/, + resolve: { + fullySpecified: false, + }, + }, + ], + }, + plugins: [ + new CopyWebpackPlugin({ + patterns: [{ from: './favicon.svg', to: 'favicon.svg' }], + }), + new HtmlWebpackPlugin({ + template: 'index.html', + }), + ].concat(isDevMode ? [] : [new MiniCssExtractPlugin()]), +}; diff --git a/packages/js-example-without-defaults/README.md b/packages/js-example-without-defaults/README.md index 5690f58c63..a1027d783a 100644 --- a/packages/js-example-without-defaults/README.md +++ b/packages/js-example-without-defaults/README.md @@ -1,6 +1,6 @@ # Integrate `maxGraph` without defaults in a vanilla JavaScript project built with Webpack -Demonstrate how to integrate `maxGraph` without using defaults: +Demonstrate how to integrate `maxGraph` without loading defaults: - plugins - styles - shapes diff --git a/packages/js-example/src/index.js b/packages/js-example/src/index.js index c0e4a3e2c8..7b30ae7764 100644 --- a/packages/js-example/src/index.js +++ b/packages/js-example/src/index.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import '@maxgraph/core/css/common.css'; +import '@maxgraph/core/css/common.css'; // required by RubberBandHandler import './style.css'; import { constants, diff --git a/packages/ts-example-selected-features/README.md b/packages/ts-example-selected-features/README.md new file mode 100644 index 0000000000..3ca9487d6f --- /dev/null +++ b/packages/ts-example-selected-features/README.md @@ -0,0 +1,30 @@ +# Integrate `maxGraph` in a vanilla TypeScript project built with Vite - features selection + +This example only loads the features and configuration required by the application for an efficient tree-shaking. + +So, it demonstrates how to only register Shapes, Perimeters, EdgeMarkers and EdgeStyles used by the application. + +It also uses the following set of features: +- Cells selection by mouse click or with Rubberband +- Management of selected cells +- Fit and zoom using buttons +- Panning with mouse drag + +Note: This example should be kept in sync with the [ts-example](../ts-example) example as it replicates the same use case. + +Initialized from https://github.com/vitejs/vite/tree/v2.9.8/packages/create-vite/template-vanilla-ts + +## Setup + +Initialize all packages +> From the repository root, run `npm install`. + +Build maxgraph@core +> From the `packages/core` directory, run `npm run build`. + +## Run + +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/packages/ts-example-selected-features/favicon.svg b/packages/ts-example-selected-features/favicon.svg new file mode 100644 index 0000000000..de4aeddc12 --- /dev/null +++ b/packages/ts-example-selected-features/favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/packages/ts-example-selected-features/index.html b/packages/ts-example-selected-features/index.html new file mode 100644 index 0000000000..d5ac9e9d2c --- /dev/null +++ b/packages/ts-example-selected-features/index.html @@ -0,0 +1,28 @@ + + + + + + + maxGraph TypeScript Integration with Vite (selected features) + + + + +

maxGraph TypeScript Integration with Vite, using selected features

+

Display a test graph. Activated behaviors:

+
    +
  • Panning: use mouse right button
  • +
  • Cells selection: with Rubberband (use mouse left button), Ctrl+Click to select multiple cells
  • +
+
+
+ + +
+
+ + + diff --git a/packages/ts-example-selected-features/package.json b/packages/ts-example-selected-features/package.json new file mode 100644 index 0000000000..a78d0b5661 --- /dev/null +++ b/packages/ts-example-selected-features/package.json @@ -0,0 +1,14 @@ +{ + "name": "@maxgraph/ts-example-vite-with-selected-features", + "license": "Apache-2.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc --version && tsc && vite build --base ./", + "preview": "vite preview" + }, + "devDependencies": { + "vite": "~6.2.0" + } +} diff --git a/packages/ts-example-selected-features/src/main.ts b/packages/ts-example-selected-features/src/main.ts new file mode 100644 index 0000000000..2074e4a5bb --- /dev/null +++ b/packages/ts-example-selected-features/src/main.ts @@ -0,0 +1,158 @@ +/* +Copyright 2025-present The maxGraph project Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import '@maxgraph/core/css/common.css'; // required by RubberBandHandler +import './style.css'; +import { + CellRenderer, + constants, + EdgeMarker, + EdgeStyle, + EllipseShape, + FitPlugin, + Graph, + InternalEvent, + MarkerShape, + PanningHandler, + Perimeter, + RubberBandHandler, + SelectionCellsHandler, + SelectionHandler, + StyleRegistry, +} from '@maxgraph/core'; + +/** + * Create a custom implementation to not load all default built-in styles. This is because Graph registers them. + * + * In the future, we expect to have an implementation of Graph that does not do it. + * See https://github.com/maxGraph/maxGraph/issues/760 + */ +class CustomGraph extends Graph { + /** + * Only registers the elements required for this example. Do not let Graph load all default built-in styles. + */ + protected override registerDefaults() { + // Register shapes + // RectangleShape is not registered here because it is always available. It is the fallback shape for vertices when no shape is returned by the registry + CellRenderer.registerShape('ellipse', EllipseShape); + + // Register styles + StyleRegistry.putValue('ellipsePerimeter', Perimeter.EllipsePerimeter); + StyleRegistry.putValue('rectanglePerimeter', Perimeter.RectanglePerimeter); // declared in the default vertex style, so must be registered to be used + StyleRegistry.putValue('orthogonalEdgeStyle', EdgeStyle.OrthConnector); + + const arrowFunction = EdgeMarker.createArrow(2); + MarkerShape.addMarker('classic', arrowFunction); + MarkerShape.addMarker('block', arrowFunction); + } +} + +const initializeGraph = (container: HTMLElement) => { + // Disables the built-in context menu + InternalEvent.disableContextMenu(container); + + const graph = new CustomGraph(container, undefined, [ + FitPlugin, // Enables the fitCenter method + PanningHandler, // Enables panning with the mouse + RubberBandHandler, // Enables rubber band selection + SelectionCellsHandler, // Enables management of selected cells + SelectionHandler, // Enables selection with the mouse + ]); + graph.setPanning(true); // Use mouse right button for panning + + // create a dedicated style for "ellipse" to share properties + graph.getStylesheet().putCellStyle('myEllipse', { + perimeter: 'ellipsePerimeter', + shape: 'ellipse', + verticalAlign: 'top', + verticalLabelPosition: 'bottom', + }); + + // Adds cells to the model in a single step + graph.batchUpdate(() => { + const vertex01 = graph.insertVertex({ + value: 'a regular rectangle', + position: [10, 10], + size: [100, 100], + }); + const vertex02 = graph.insertVertex({ + value: 'a regular ellipse', + position: [350, 90], + size: [50, 50], + style: { + baseStyleNames: ['myEllipse'], + fillColor: 'orange', + }, + }); + graph.insertEdge({ + value: 'an orthogonal style edge', + source: vertex01, + target: vertex02, + style: { + edgeStyle: 'orthogonalEdgeStyle', + rounded: true, + }, + }); + + const vertex11 = graph.insertVertex({ + value: 'a custom rectangle', + position: [20, 200], + size: [100, 100], + style: { + fillColor: 'Chartreuse', + rounded: true, + strokeColor: 'Black', + strokeWidth: 3, + }, + }); + const vertex12 = graph.insertVertex({ + value: 'a custom ellipse', + x: 150, + y: 350, + width: 70, + height: 70, + style: { + baseStyleNames: ['myEllipse'], + fillColor: 'Yellow', + strokeColor: 'Red', + strokeWidth: 5, + }, + }); + graph.insertEdge({ + value: 'another edge', + source: vertex11, + target: vertex12, + style: { endArrow: 'block' }, + }); + }); + + return graph; +}; + +// display the maxGraph version in the footer +const footer = document.querySelector('footer')!; +footer.innerText = `Built with maxGraph ${constants.VERSION}`; + +// Creates the graph inside the given container +const graph = initializeGraph(document.querySelector('#graph-container')!); + +// Control buttons +document.getElementById('reset-zoom')!.addEventListener('click', () => { + graph.zoomActual(); +}); +document.getElementById('fit-center')!.addEventListener('click', () => { + graph.getPlugin('fit')?.fitCenter({ margin: 20 }); +}); diff --git a/packages/ts-example-selected-features/src/style.css b/packages/ts-example-selected-features/src/style.css new file mode 100644 index 0000000000..fd9c02e283 --- /dev/null +++ b/packages/ts-example-selected-features/src/style.css @@ -0,0 +1,51 @@ +/* +Copyright 2025-present The maxGraph project Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +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; +} + +.controls { + margin-top: .75rem; +} + +/* For rubber band selection, override maxGraph defaults */ +div.mxRubberband { + border-color: #b18426; + background: #db9b0b; +} diff --git a/packages/ts-example-selected-features/src/vite-env.d.ts b/packages/ts-example-selected-features/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/packages/ts-example-selected-features/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/packages/ts-example-selected-features/tsconfig.json b/packages/ts-example-selected-features/tsconfig.json new file mode 100644 index 0000000000..2aa41a6d7a --- /dev/null +++ b/packages/ts-example-selected-features/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "useDefineForClassFields": true, + "sourceMap": true, + "moduleResolution": "bundler", + "resolveJsonModule": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true + }, + "include": ["src/*.ts"] +} diff --git a/packages/ts-example-selected-features/vite.config.js b/packages/ts-example-selected-features/vite.config.js new file mode 100644 index 0000000000..1cf35ce529 --- /dev/null +++ b/packages/ts-example-selected-features/vite.config.js @@ -0,0 +1,33 @@ +/* +Copyright 2022-present The maxGraph project Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { defineConfig } from 'vite'; + +export default defineConfig(({ mode }) => { + return { + build: { + rollupOptions: { + output: { + manualChunks: { + // put the maxgraph code in a dedicated file. It lets know the size the produced bundle in an external application and if tree shaking works + maxgraph: ['@maxgraph/core'], + }, + }, + }, + chunkSizeWarningLimit: 440, // @maxgraph/core + }, + }; +}); diff --git a/packages/ts-example-without-defaults/README.md b/packages/ts-example-without-defaults/README.md index 2aaaf42451..24814b0ea9 100644 --- a/packages/ts-example-without-defaults/README.md +++ b/packages/ts-example-without-defaults/README.md @@ -1,6 +1,6 @@ # Integrate `maxGraph` without defaults in a vanilla TypeScript project built with Vite -Demonstrate how to integrate `maxGraph` without using defaults: +Demonstrate how to integrate `maxGraph` without loading defaults: - plugins - styles - shapes diff --git a/packages/ts-example/README.md b/packages/ts-example/README.md index 942f531912..cc946cfd6e 100644 --- a/packages/ts-example/README.md +++ b/packages/ts-example/README.md @@ -2,6 +2,13 @@ Demonstrate how to define and use custom `Shapes`. +This example uses the following set of features: +- Cells selection by mouse click or with Rubberband +- Management of selected cells +- Fit and zoom using buttons +- Panning with mouse drag + + Initialized from https://github.com/vitejs/vite/tree/v2.9.8/packages/create-vite/template-vanilla-ts ## Setup diff --git a/packages/website/docs/demo-and-examples.md b/packages/website/docs/demo-and-examples.md index 6e97c7804a..3068d3d2a4 100644 --- a/packages/website/docs/demo-and-examples.md +++ b/packages/website/docs/demo-and-examples.md @@ -26,10 +26,12 @@ Note that they are based on `maxGraph` features, which require the use of [CSS a ## TypeScript Examples - the [ts-example](https://github.com/maxGraph/maxGraph/tree/main/packages/ts-example) project/application demonstrates how to define and use custom `Shapes` with `maxGraph`. It is a vanilla TypeScript application built by [Vite](https://vitejs.dev/). +- the [ts-example-selected-features](https://github.com/maxGraph/maxGraph/tree/main/packages/ts-example-selected-features) project/application that demonstrates the same use case as in `ts-example` but which only loads the features and configuration required by the application for an efficient tree-shaking. It is a vanilla TypeScript application built by [Vite](https://vitejs.dev/). - the [ts-example-without-defaults](https://github.com/maxGraph/maxGraph/tree/main/packages/ts-example-without-defaults) project/application demonstrates how to not use defaults plugins and style defaults (shapes, perimeters, ...). It is a vanilla TypeScript application built by [Vite](https://vitejs.dev/). ## JavaScript Examples - the [js-example](https://github.com/maxGraph/maxGraph/tree/main/packages/js-example) project/application demonstrates how to import and export the `maxGraph` model with XML data. It is a vanilla JavaScript application built by [Webpack](https://webpack.js.org/). +- the [js-example-selected-features](https://github.com/maxGraph/maxGraph/tree/main/packages/js-example-selected-features) project/application that demonstrates the same use case as in `ts-example` but which only loads the features and configuration required by the application for an efficient tree-shaking. It is a vanilla JavaScript application built by [Webpack](https://webpack.js.org/). - the [js-example-without-defaults](https://github.com/maxGraph/maxGraph/tree/main/packages/js-example-without-defaults) project/application demonstrates how to not use defaults plugins and style defaults (shapes, perimeters, ...). It is a vanilla JavaScript application built by [Webpack](https://webpack.js.org/). ## Framework Integration and Bundlers