├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ ├── feature_request.md │ └── question.md ├── dependabot.yml ├── release-drafter.yml └── workflows │ ├── ci.yml │ ├── create_release.yml │ ├── dependabot_automerge.yml │ └── release_helper.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.cjs ├── .vscode └── settings.json ├── .yarn └── releases │ └── yarn-4.5.1.cjs ├── .yarnrc.yml ├── LICENSE ├── README.md ├── eslint.config.mjs ├── package.json ├── rollup.config.mjs ├── samples ├── bubbleclusters.html ├── component.html ├── default.html ├── default_esm.html └── euler.html ├── src ├── BubbleSetPath.ts ├── BubbleSetsPlugin.ts └── index.ts ├── tsconfig.c.json ├── tsconfig.json ├── typedoc.json ├── vitest.config.ts └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | # These settings are for any web project 2 | 3 | # Handle line endings automatically for files detected as text 4 | # and leave all files detected as binary untouched. 5 | * text=auto eol=lf 6 | 7 | # 8 | # The above will handle all files NOT found below 9 | # 10 | 11 | # 12 | ## These files are text and should be normalized (Convert crlf => lf) 13 | # 14 | 15 | # source code 16 | *.php text 17 | *.css text 18 | *.sass text 19 | *.scss text 20 | *.less text 21 | *.styl text 22 | *.js text 23 | *.ts text 24 | *.coffee text 25 | *.json text 26 | *.htm text 27 | *.html text 28 | *.xml text 29 | *.txt text 30 | *.ini text 31 | *.inc text 32 | *.pl text 33 | *.rb text 34 | *.py text 35 | *.scm text 36 | *.sql text 37 | *.sh text eof=LF 38 | *.bat text 39 | 40 | # templates 41 | *.hbt text 42 | *.jade text 43 | *.haml text 44 | *.hbs text 45 | *.dot text 46 | *.tmpl text 47 | *.phtml text 48 | 49 | # server config 50 | .htaccess text 51 | 52 | # git config 53 | .gitattributes text 54 | .gitignore text 55 | 56 | # code analysis config 57 | .jshintrc text 58 | .jscsrc text 59 | .jshintignore text 60 | .csslintrc text 61 | 62 | # misc config 63 | *.yaml text 64 | *.yml text 65 | .editorconfig text 66 | 67 | # build config 68 | *.npmignore text 69 | *.bowerrc text 70 | Dockerfile text eof=LF 71 | 72 | # Heroku 73 | Procfile text 74 | .slugignore text 75 | 76 | # Documentation 77 | *.md text 78 | LICENSE text 79 | AUTHORS text 80 | 81 | 82 | # 83 | ## These files are binary and should be left untouched 84 | # 85 | 86 | # (binary is a macro for -text -diff) 87 | *.png binary 88 | *.jpg binary 89 | *.jpeg binary 90 | *.gif binary 91 | *.ico binary 92 | *.mov binary 93 | *.mp4 binary 94 | *.mp3 binary 95 | *.flv binary 96 | *.fla binary 97 | *.swf binary 98 | *.gz binary 99 | *.zip binary 100 | *.7z binary 101 | *.ttf binary 102 | *.pyc binary 103 | *.pdf binary 104 | 105 | # Source files 106 | # ============ 107 | *.pxd text 108 | *.py text 109 | *.py3 text 110 | *.pyw text 111 | *.pyx text 112 | *.sh text eol=lf 113 | *.json text 114 | 115 | # Binary files 116 | # ============ 117 | *.db binary 118 | *.p binary 119 | *.pkl binary 120 | *.pyc binary 121 | *.pyd binary 122 | *.pyo binary 123 | 124 | # Note: .db, .p, and .pkl files are associated 125 | # with the python modules ``pickle``, ``dbm.*``, 126 | # ``shelve``, ``marshal``, ``anydbm``, & ``bsddb`` 127 | # (among others). 128 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [sgratzl] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug report 3 | about: If something isn't working as expected 🤔. 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | --- 8 | 9 | 10 | 11 | When I... 12 | 13 | **To Reproduce** 14 | 15 | 17 | 18 | 1. 19 | 20 | **Expected behavior** 21 | 22 | 23 | 24 | **Screenshots** 25 | 26 | 27 | 28 | **Context** 29 | 30 | - Version: 31 | - Browser: 32 | 33 | **Additional context** 34 | 35 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | # contact_links: 3 | # - name: Samuel Gratzl 4 | # url: https://www.sgratzl.com 5 | # about: Please ask and answer questions here. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature Request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'enhancement' 6 | assignees: '' 7 | --- 8 | 9 | 10 | 11 | It would be great if ... 12 | 13 | **User story** 14 | 15 | 16 | 17 | **Additional context** 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🤗 Question 3 | about: ask question about the library (usage, features,...) 4 | title: '' 5 | labels: 'question' 6 | assignees: '' 7 | --- 8 | 9 | 13 | 14 | I'm having the following question... 15 | 16 | **Screenshots / Sketches** 17 | 18 | 19 | 20 | **Context** 21 | 22 | - Version: 23 | - Browser: 24 | 25 | **Additional context** 26 | 27 | 28 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: 'github-actions' 5 | directory: '/' 6 | schedule: 7 | interval: 'monthly' 8 | target-branch: 'dev' 9 | labels: 10 | - 'dependencies' 11 | - 'chore' 12 | - package-ecosystem: 'npm' 13 | directory: '/' 14 | schedule: 15 | interval: 'monthly' 16 | target-branch: 'dev' 17 | labels: 18 | - 'dependencies' 19 | - 'chore' 20 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$RESOLVED_VERSION' 2 | tag-template: 'v$RESOLVED_VERSION' 3 | categories: 4 | - title: '🚀 Features' 5 | labels: 6 | - 'enhancement' 7 | - 'feature' 8 | - title: '🐛 Bugs Fixes' 9 | labels: 10 | - 'bug' 11 | - title: 'Documentation' 12 | labels: 13 | - 'documentation' 14 | - title: '🧰 Development' 15 | labels: 16 | - 'chore' 17 | change-template: '- #$NUMBER $TITLE' 18 | change-title-escapes: '\<*_&`#@' 19 | template: | 20 | $CHANGES 21 | 22 | Thanks to $CONTRIBUTORS 23 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | if: github.actor != 'dependabot[bot]' 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: 20 16 | - run: npm i -g yarn 17 | - run: yarn config set checksumBehavior ignore 18 | - name: Cache Node.js modules 19 | uses: actions/cache@v4 20 | with: 21 | path: | 22 | ./.yarn/cache 23 | ./.yarn/unplugged 24 | key: ${{ runner.os }}-yarn2-v4-${{ hashFiles('**/yarn.lock') }} 25 | restore-keys: | 26 | ${{ runner.os }}-yarn2-v4 27 | - run: yarn install 28 | - run: yarn build 29 | - run: yarn lint 30 | - run: yarn test:coverage 31 | # - run: yarn docs 32 | # - name: Deploy 33 | # if: github.ref == 'refs/heads/master' && github.event_name == 'push' 34 | # uses: peaceiris/actions-gh-pages@v3 35 | # with: 36 | # github_token: ${{ secrets.GITHUB_TOKEN }} 37 | # publish_dir: ./docs 38 | # enable_jekyll: false 39 | -------------------------------------------------------------------------------- /.github/workflows/create_release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | versionName: 6 | description: 'Semantic Version Number (i.e., 5.5.0 or patch, minor, major, prepatch, preminor, premajor, prerelease)' 7 | required: true 8 | default: patch 9 | preid: 10 | description: 'Pre Release Identifier (i.e., alpha, beta)' 11 | required: true 12 | default: alpha 13 | jobs: 14 | create_release: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Check out code 18 | uses: actions/checkout@v4 19 | with: 20 | ref: main 21 | ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} 22 | - name: Reset main branch 23 | run: | 24 | git fetch origin dev:dev 25 | git reset --hard origin/dev 26 | - name: Change version number 27 | id: version 28 | run: | 29 | echo "next_tag=$(npm version --no-git-tag-version ${{ github.event.inputs.versionName }} --preid ${{ github.event.inputs.preid }})" >> $GITHUB_OUTPUT 30 | - name: Create pull request into main 31 | uses: peter-evans/create-pull-request@v7 32 | with: 33 | branch: release/${{ steps.version.outputs.next_tag }} 34 | commit-message: 'chore: release ${{ steps.version.outputs.next_tag }}' 35 | base: main 36 | title: Release ${{ steps.version.outputs.next_tag }} 37 | labels: chore 38 | assignees: sgratzl 39 | body: | 40 | Releasing ${{ steps.version.outputs.next_tag }}. 41 | -------------------------------------------------------------------------------- /.github/workflows/dependabot_automerge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: 3 | pull_request: 4 | branches: 5 | - 'dev' # only into dev 6 | 7 | permissions: 8 | contents: write 9 | pull-requests: write 10 | 11 | jobs: 12 | dependabot: 13 | runs-on: ubuntu-latest 14 | if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'sgratzl/cytoscape.js-layers' 15 | steps: 16 | - name: Dependabot metadata 17 | id: metadata 18 | uses: dependabot/fetch-metadata@v2 19 | with: 20 | github-token: '${{ secrets.GITHUB_TOKEN }}' 21 | - name: Enable auto-merge for Dependabot PRs 22 | # patch only 23 | if: steps.metadata.outputs.update-type == 'version-update:semver-patch' 24 | run: gh pr merge --auto --merge "$PR_URL" 25 | env: 26 | PR_URL: ${{github.event.pull_request.html_url}} 27 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 28 | -------------------------------------------------------------------------------- /.github/workflows/release_helper.yml: -------------------------------------------------------------------------------- 1 | name: Release Helper 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | correct_repository: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: fail on fork 12 | if: github.repository_owner != 'upsetjs' 13 | run: exit 1 14 | 15 | create_release: 16 | needs: correct_repository 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Check out code 20 | uses: actions/checkout@v4 21 | - uses: actions/setup-node@v4 22 | with: 23 | node-version: 20 24 | - name: Extract version 25 | id: extract_version 26 | run: | 27 | node -pe "'version=' + require('./package.json').version" >> $GITHUB_OUTPUT 28 | node -pe "'npm_tag=' + (require('./package.json').version.includes('-') ? 'next' : 'latest')" >> $GITHUB_OUTPUT 29 | - name: Print version 30 | run: | 31 | echo "releasing ${{ steps.extract_version.outputs.version }} with tag ${{ steps.extract_version.outputs.npm_tag }}" 32 | - name: Create Release 33 | id: create_release 34 | uses: release-drafter/release-drafter@v6 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | with: 38 | name: v${{ steps.extract_version.outputs.version }} 39 | tag: v${{ steps.extract_version.outputs.version }} 40 | version: ${{ steps.extract_version.outputs.version }} 41 | prerelease: ${{ needs.create_release.outputs.tag_name == 'next' }} 42 | publish: true 43 | outputs: 44 | version: ${{ steps.extract_version.outputs.version }} 45 | npm_tag: ${{ steps.extract_version.outputs.npm_tag }} 46 | upload_url: ${{ steps.create_release.outputs.upload_url }} 47 | tag_name: ${{ steps.create_release.outputs.tag_name }} 48 | 49 | build_assets: 50 | needs: create_release 51 | runs-on: ubuntu-latest 52 | steps: 53 | - name: Check out code 54 | uses: actions/checkout@v4 55 | - uses: actions/setup-node@v4 56 | with: 57 | node-version: 20 58 | - run: npm i -g yarn 59 | - run: yarn config set checksumBehavior ignore 60 | - name: Cache Node.js modules 61 | uses: actions/cache@v4 62 | with: 63 | path: | 64 | ./.yarn/cache 65 | ./.yarn/unplugged 66 | key: ${{ runner.os }}-yarn2-v4-${{ hashFiles('**/yarn.lock') }} 67 | restore-keys: | 68 | ${{ runner.os }}-yarn2-v4 69 | - run: yarn install 70 | - run: yarn build 71 | - run: yarn pack 72 | - name: Upload Release Asset 73 | uses: AButler/upload-release-assets@v3.0 74 | with: 75 | files: 'package.tgz' 76 | repo-token: ${{ secrets.GITHUB_TOKEN }} 77 | release-tag: ${{ needs.create_release.outputs.tag_name }} 78 | - name: Pack Publish 79 | run: | 80 | yarn config set npmAuthToken "${{ secrets.NPM_TOKEN }}" 81 | yarn pack 82 | yarn npm publish --tag "${{ needs.create_release.outputs.npm_tag }}" 83 | 84 | sync_dev: 85 | needs: correct_repository 86 | runs-on: ubuntu-latest 87 | steps: 88 | - name: Check out code 89 | uses: actions/checkout@v4 90 | with: 91 | ref: dev 92 | ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} 93 | - name: Reset dev branch 94 | run: | 95 | git fetch origin main:main 96 | git merge main 97 | git push 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | /coverage 7 | /node_modules 8 | .npm 9 | .yarn/* 10 | !.yarn/patches 11 | !.yarn/releases 12 | !.yarn/plugins 13 | !.yarn/versions 14 | .pnp.* 15 | 16 | # Build files 17 | /.tmp 18 | /build 19 | 20 | *.tgz 21 | /.vscode/extensions.json 22 | /docs 23 | samples/*.map 24 | samples/*.js 25 | *.tsbuildinfo 26 | .eslintcache 27 | /docs -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /.pnp.* 2 | /.yarnrc.yml 3 | /.yarn 4 | /build 5 | /docs 6 | /coverage 7 | /.gitattributes 8 | /.gitignore 9 | /.prettierignore 10 | /LICENSE 11 | /yarn.lock 12 | /.vscode 13 | *.tsbuildinfo 14 | *.map 15 | samples/*.js 16 | src/**/*.js -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | semi: true, 4 | singleQuote: true, 5 | trailingComma: 'es5', 6 | }; 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.formatOnType": true, 4 | "[javascript]": { 5 | "editor.defaultFormatter": "esbenp.prettier-vscode" 6 | }, 7 | "[typescript]": { 8 | "editor.defaultFormatter": "esbenp.prettier-vscode" 9 | }, 10 | "[json]": { 11 | "editor.defaultFormatter": "esbenp.prettier-vscode" 12 | }, 13 | "[yaml]": { 14 | "editor.defaultFormatter": "esbenp.prettier-vscode" 15 | }, 16 | "eslint.nodePath": ".yarn/sdks", 17 | "prettier.prettierPath": ".yarn/sdks/prettier/index.cjs", 18 | "files.eol": "\n", 19 | "editor.detectIndentation": false, 20 | "editor.tabSize": 2, 21 | "typescript.tsdk": ".yarn/sdks/typescript/lib", 22 | "typescript.enablePromptUseWorkspaceTsdk": true, 23 | "search.exclude": { 24 | "**/.yarn": true, 25 | "**/.pnp.*": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-4.5.1.cjs 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2022 Samuel Gratzl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cytoscape.js BubbleSets Plugin 2 | 3 | [![NPM Package][npm-image]][npm-url] [![Github Actions][github-actions-image]][github-actions-url] [![Cytoscape Plugin][cytoscape-image]][cytoscape-url] 4 | 5 | A [Cytoscape.js](https://js.cytoscape.org) plugin for rendering [Bubblesets](https://github.com/upsetjs/bubblesets-js). 6 | 7 |  8 | 9 | ## Install 10 | 11 | ```sh 12 | npm install cytoscape cytoscape-layers cytoscape-bubblesets 13 | ``` 14 | 15 | ## Usage 16 | 17 | see [Samples](./samples) on Github 18 | 19 | or at this [![Open in CodePen][codepen]](https://codepen.io/sgratzl/pen/RwQdBLY) 20 | 21 | ```js 22 | import cytoscape from 'cytoscape'; 23 | import BubbleSets from 'cytoscape-bubblesets'; 24 | cytoscape.use(BubbleSets); 25 | 26 | const cy = cytoscape({ 27 | container: document.getElementById('app'), 28 | elements: [ 29 | { data: { id: 'a' } }, 30 | { data: { id: 'b' } }, 31 | { 32 | data: { 33 | id: 'ab', 34 | source: 'a', 35 | target: 'b', 36 | }, 37 | }, 38 | ], 39 | }); 40 | cy.ready(() => { 41 | const bb = cy.bubbleSets(); 42 | bb.addPath(cy.nodes(), cy.edges(), null); 43 | }); 44 | ``` 45 | 46 |  47 | 48 | Alternative without registration 49 | 50 | ```js 51 | import cytoscape from 'cytoscape'; 52 | import { BubbleSetsPlugin } from 'cytoscape-bubblesets'; 53 | 54 | const cy = cytoscape({ 55 | container: document.getElementById('app'), 56 | elements: [ 57 | { data: { id: 'a' } }, 58 | { data: { id: 'b' } }, 59 | { 60 | data: { 61 | id: 'ab', 62 | source: 'a', 63 | target: 'b', 64 | }, 65 | }, 66 | ], 67 | }); 68 | cy.ready(() => { 69 | const bb = new BubbleSetsPlugin(cy); 70 | bb.addPath(cy.nodes(), cy.edges(), null); 71 | }); 72 | ``` 73 | 74 | ## API 75 | 76 | - `addPath(nodes: NodeCollection, edges?: EdgeCollection | null, avoidNodes?: NodeCollection | null, options?: IBubbleSetPathOptions): BubbleSetPath` 77 | 78 | creates a new `BubbleSetPath` instance. The `nodes` is a node collection that should be linked. `edges` an edge collection to include edges. `avoidNodes` is an optional node collection of nodes that should be avoided when generating the outline and any virtual edge between the nodes. 79 | 80 | - `removePath(path: BubbleSetPath)` 81 | 82 | removes a path again 83 | 84 | - `getPaths(): readonly BubbleSetPath[]` 85 | 86 | returns the list of active paths 87 | 88 | ## Development Environment 89 | 90 | ```sh 91 | npm i -g yarn 92 | yarn set version latest 93 | cat .yarnrc_patch.yml >> .yarnrc.yml 94 | yarn 95 | yarn pnpify --sdk vscode 96 | ``` 97 | 98 | ### Common commands 99 | 100 | ```sh 101 | yarn compile 102 | yarn test 103 | yarn lint 104 | yarn fix 105 | yarn build 106 | yarn docs 107 | yarn release 108 | yarn release:pre 109 | ``` 110 | 111 | [npm-image]: https://badge.fury.io/js/cytoscape-bubblesets.svg 112 | [npm-url]: https://npmjs.org/package/cytoscape-bubblesets 113 | [github-actions-image]: https://github.com/upsetjs/cytoscape.js-bubblesets/workflows/ci/badge.svg 114 | [github-actions-url]: https://github.com/upsetjs/cytoscape.js-bubblesets/actions 115 | [cytoscape-image]: https://img.shields.io/badge/Cytoscape-plugin-yellow 116 | [cytoscape-url]: https://js.cytoscape.org/#extensions/ui-extensions 117 | [codepen]: https://img.shields.io/badge/CodePen-open-blue?logo=codepen 118 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | import eslint from '@eslint/js'; 4 | import tseslint from 'typescript-eslint'; 5 | import prettier from 'eslint-plugin-prettier'; 6 | 7 | export default tseslint.config(eslint.configs.recommended, ...tseslint.configs.recommended, { 8 | plugins: { prettier }, 9 | rules: { 10 | '@typescript-eslint/no-explicit-any': 'off', 11 | 'max-classes-per-file': 'off', 12 | 'no-underscore-dangle': 'off', 13 | 'import/extensions': 'off', 14 | }, 15 | }); 16 | 17 | // import path from "node:path"; 18 | // import { fileURLToPath } from "node:url"; 19 | // import js from "@eslint/js"; 20 | // import { FlatCompat } from "@eslint/eslintrc"; 21 | 22 | // const __filename = fileURLToPath(import.meta.url); 23 | // const __dirname = path.dirname(__filename); 24 | // const compat = new FlatCompat({ 25 | // baseDirectory: __dirname, 26 | // recommendedConfig: js.configs.recommended, 27 | // allConfig: js.configs.all 28 | // }); 29 | 30 | // export default [...fixupConfigRules(compat.extends( 31 | // "airbnb-typescript", 32 | // "react-app", 33 | // "plugin:prettier/recommended", 34 | // "prettier", 35 | // )), { 36 | // plugins: { 37 | // prettier: fixupPluginRules(prettier), 38 | // }, 39 | 40 | // languageOptions: { 41 | // ecmaVersion: 5, 42 | // sourceType: "script", 43 | 44 | // parserOptions: { 45 | // project: "./tsconfig.eslint.json", 46 | // }, 47 | // }, 48 | 49 | // settings: { 50 | // react: { 51 | // version: "99.99.99", 52 | // }, 53 | // }, 54 | 55 | // rules: { 56 | // "@typescript-eslint/no-explicit-any": "off", 57 | // "max-classes-per-file": "off", 58 | // "no-underscore-dangle": "off", 59 | // "import/extensions": "off", 60 | // }, 61 | // }]; 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cytoscape-bubblesets", 3 | "description": "Cytoscape.js plugin for rendering bubblesets", 4 | "version": "4.0.0", 5 | "author": { 6 | "name": "Samuel Gratzl", 7 | "email": "sam@sgratzl.com", 8 | "url": "https://www.sgratzl.com" 9 | }, 10 | "license": "MIT", 11 | "homepage": "https://github.com/upsetjs/cytoscape.js-bubblesets", 12 | "bugs": { 13 | "url": "https://github.com/upsetjs/cytoscape.js-bubblesets/issues" 14 | }, 15 | "keywords": [ 16 | "cytoscape", 17 | "bubblesets" 18 | ], 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/upsetjs/cytoscape.js-bubblesets.git" 22 | }, 23 | "global": "CytoscapeBubbleSets", 24 | "dependencies": { 25 | "@types/cytoscape": "^3.21.8", 26 | "@types/lodash.throttle": "^4.1.9", 27 | "bubblesets-js": "^3.0.0", 28 | "lodash.throttle": "^4.1.1" 29 | }, 30 | "peerDependencies": { 31 | "cytoscape": "^3.23.0", 32 | "cytoscape-layers": "^3.0.0" 33 | }, 34 | "browserslist": [ 35 | "Firefox ESR", 36 | "last 2 Chrome versions", 37 | "last 2 Firefox versions" 38 | ], 39 | "type": "module", 40 | "main": "build/index.js", 41 | "module": "build/index.js", 42 | "require": "build/index.cjs", 43 | "umd": "build/index.umd.js", 44 | "unpkg": "build/index.umd.min.js", 45 | "jsdelivr": "build/index.umd.min.js", 46 | "types": "build/index.d.ts", 47 | "exports": { 48 | ".": { 49 | "import": "./build/index.js", 50 | "require": "./build/index.cjs", 51 | "scripts": "./build/index.umd.min.js", 52 | "types": "./build/index.d.ts" 53 | } 54 | }, 55 | "sideEffects": false, 56 | "files": [ 57 | "build", 58 | "src/**/*.ts", 59 | "src/**/*.tsx" 60 | ], 61 | "devDependencies": { 62 | "@babel/core": "^7.26.0", 63 | "@babel/preset-env": "^7.26.0", 64 | "@eslint/js": "~9.15.0", 65 | "@rollup/plugin-babel": "^6.0.4", 66 | "@rollup/plugin-commonjs": "^28.0.1", 67 | "@rollup/plugin-node-resolve": "^15.3.0", 68 | "@rollup/plugin-replace": "^6.0.1", 69 | "@rollup/plugin-typescript": "^12.1.1", 70 | "@vitest/coverage-v8": "^2.1.5", 71 | "@yarnpkg/sdks": "^3.2.0", 72 | "cytoscape": "^3.30.3", 73 | "cytoscape-layers": "^3.0.0", 74 | "eslint": "~9.14.0", 75 | "eslint-plugin-prettier": "^5.2.1", 76 | "jsdom": "^25.0.1", 77 | "prettier": "^3.3.3", 78 | "rimraf": "^6.0.1", 79 | "rollup": "^4.27.2", 80 | "rollup-plugin-dts": "^6.1.1", 81 | "rollup-plugin-terser": "^7.0.2", 82 | "tslib": "^2.8.1", 83 | "typedoc": "^0.26.11", 84 | "typescript": "^5.6.3", 85 | "typescript-eslint": "^8.14.0", 86 | "vite": "^5.4.11", 87 | "vitest": "^2.1.5" 88 | }, 89 | "scripts": { 90 | "clean": "rimraf --glob build node_modules \"*.tgz\" \"*.tsbuildinfo\"", 91 | "compile": "tsc -b tsconfig.c.json", 92 | "start": "yarn run watch", 93 | "watch": "rollup -c -w", 94 | "build": "rollup -c", 95 | "test": "vitest --passWithNoTests", 96 | "test:watch": "yarn run test --watch", 97 | "test:coverage": "yarn run test --coverage", 98 | "lint": "yarn run eslint && yarn run prettier", 99 | "fix": "yarn run eslint:fix && yarn run prettier:write", 100 | "prettier:write": "prettier \"*\" \"*/**\" --write", 101 | "prettier": "prettier \"*\" \"*/**\" --check", 102 | "eslint": "eslint src --cache", 103 | "eslint:fix": "yarn run eslint --fix", 104 | "docs": "typedoc --options typedoc.json", 105 | "prepare": "yarn run build" 106 | }, 107 | "packageManager": "yarn@4.5.1" 108 | } 109 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | import dts from 'rollup-plugin-dts'; 4 | import typescript from '@rollup/plugin-typescript'; 5 | import { terser } from 'rollup-plugin-terser'; 6 | import replace from '@rollup/plugin-replace'; 7 | import babel from '@rollup/plugin-babel'; 8 | 9 | import fs from 'fs'; 10 | 11 | const pkg = JSON.parse(fs.readFileSync('./package.json')); 12 | 13 | function resolveYear() { 14 | // Extract copyrights from the LICENSE. 15 | const license = fs.readFileSync('./LICENSE', 'utf-8').toString(); 16 | const matches = Array.from(license.matchAll(/\(c\) (\d+-\d+)/gm)); 17 | if (!matches || matches.length === 0) { 18 | return 2021; 19 | } 20 | return matches[matches.length - 1][1]; 21 | } 22 | const year = resolveYear(); 23 | 24 | const banner = `/** 25 | * ${pkg.name} 26 | * ${pkg.homepage} 27 | * 28 | * Copyright (c) ${year} ${pkg.author.name} <${pkg.author.email}> 29 | */ 30 | `; 31 | 32 | /** 33 | * defines which formats (umd, esm, cjs, types) should be built when watching 34 | */ 35 | const watchOnly = ['umd']; 36 | 37 | const isDependency = (v) => Object.keys(pkg.dependencies || {}).some((e) => e === v || v.startsWith(e + '/')); 38 | const isPeerDependency = (v) => Object.keys(pkg.peerDependencies || {}).some((e) => e === v || v.startsWith(e + '/')); 39 | 40 | // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types 41 | export default function Config(options) { 42 | const buildFormat = (format) => !options.watch || watchOnly.includes(format); 43 | 44 | const base = { 45 | input: './src/index.ts', 46 | output: { 47 | sourcemap: true, 48 | banner, 49 | exports: 'named', 50 | globals: { 51 | cytoscape: 'cytoscape', 52 | 'cytoscape-layers': 'CytoscapeLayers', 53 | crypto: 'NodeCrypto', 54 | }, 55 | }, 56 | external: (v) => isDependency(v) || isPeerDependency(v), 57 | plugins: [ 58 | typescript(), 59 | resolve(), 60 | commonjs(), 61 | replace({ 62 | preventAssignment: true, 63 | values: { 64 | // eslint-disable-next-line no-undef 65 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) || 'production', 66 | __VERSION__: JSON.stringify(pkg.version), 67 | }, 68 | }), 69 | ], 70 | }; 71 | return [ 72 | (buildFormat('esm') || buildFormat('cjs')) && { 73 | ...base, 74 | output: [ 75 | buildFormat('esm') && { 76 | ...base.output, 77 | file: pkg.module, 78 | format: 'esm', 79 | }, 80 | buildFormat('cjs') && { 81 | ...base.output, 82 | file: pkg.require, 83 | format: 'cjs', 84 | }, 85 | ].filter(Boolean), 86 | }, 87 | ((buildFormat('umd') && pkg.umd) || (buildFormat('umd-min') && pkg.unpkg)) && { 88 | ...base, 89 | input: fs.existsSync(base.input.replace('.ts', '.umd.ts')) ? base.input.replace('.ts', '.umd.ts') : base.input, 90 | output: [ 91 | buildFormat('umd') && 92 | pkg.umd && { 93 | ...base.output, 94 | file: pkg.umd, 95 | format: 'umd', 96 | name: pkg.global, 97 | }, 98 | buildFormat('umd-min') && 99 | pkg.unpkg && { 100 | ...base.output, 101 | file: pkg.unpkg, 102 | format: 'umd', 103 | name: pkg.global, 104 | plugins: [terser()], 105 | }, 106 | ].filter(Boolean), 107 | external: (v) => isPeerDependency(v), 108 | plugins: [...base.plugins, babel({ presets: ['@babel/env'], babelHelpers: 'bundled' })], 109 | }, 110 | buildFormat('types') && { 111 | ...base, 112 | output: { 113 | ...base.output, 114 | file: pkg.types, 115 | format: 'es', 116 | }, 117 | plugins: [ 118 | dts({ 119 | compilerOptions: { 120 | removeComments: false, 121 | }, 122 | respectExternal: true, 123 | }), 124 | ], 125 | }, 126 | ].filter(Boolean); 127 | } 128 | -------------------------------------------------------------------------------- /samples/bubbleclusters.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |