diff --git a/common/changes/@visactor/vchart/feat-issue-3868_2025-04-14-06-37.json b/common/changes/@visactor/vchart/feat-issue-3868_2025-04-14-06-37.json new file mode 100644 index 0000000000..99a4c67af5 --- /dev/null +++ b/common/changes/@visactor/vchart/feat-issue-3868_2025-04-14-06-37.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "feat: markLine and markArea supports render multiple labels", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/common/changes/@visactor/vchart/refactor-brush_2025-04-14-09-40.json b/common/changes/@visactor/vchart/refactor-brush_2025-04-14-09-40.json new file mode 100644 index 0000000000..63e25d6469 --- /dev/null +++ b/common/changes/@visactor/vchart/refactor-brush_2025-04-14-09-40.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vchart", + "comment": "refactor: brush interactive. close#3765 & #3262 & #2802 & #3885", + "type": "none" + } + ], + "packageName": "@visactor/vchart" +} \ No newline at end of file diff --git a/common/config/rush/pnpm-config.json b/common/config/rush/pnpm-config.json index 1ab89a9366..39db9e6211 100644 --- a/common/config/rush/pnpm-config.json +++ b/common/config/rush/pnpm-config.json @@ -83,9 +83,9 @@ * PNPM documentation: https://pnpm.io/package_json#pnpmoverrides */ "globalOverrides": { - // "@visactor/vrender-core": "0.22.3", - // "@visactor/vrender-kits": "0.22.3", - // "@visactor/vrender-components": "0.22.3" + // "@visactor/vrender-core": "0.22.8", + // "@visactor/vrender-kits": "0.22.8", + // "@visactor/vrender-components": "0.22.8" }, /** * The `globalPeerDependencyRules` setting provides various settings for suppressing validation errors @@ -190,4 +190,4 @@ // }, // "pnpm": { "futurePnpmFeature": true } } -} +} \ No newline at end of file diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 9523e10817..20397ecfaa 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -21,15 +21,15 @@ importers: '@visactor/vchart': workspace:1.13.8 '@visactor/vchart-extension': workspace:1.13.8 '@visactor/vchart-theme': ~1.6.6 - '@visactor/vgrammar': 0.16.3 + '@visactor/vgrammar': 0.16.4 '@visactor/vmind': 1.2.4-alpha.5 - '@visactor/vrender': 0.22.6 - '@visactor/vrender-kits': 0.22.6 + '@visactor/vrender': 0.22.8 + '@visactor/vrender-kits': 0.22.8 '@visactor/vtable': 1.12.0 '@visactor/vtable-calendar': 1.12.0 '@visactor/vtable-editors': 1.12.0 '@visactor/vtable-gantt': 1.12.0 - '@visactor/vutils': ~0.19.4 + '@visactor/vutils': ~0.19.5 '@vitejs/plugin-react': 3.1.0 axios: ^1.4.0 buble: ^0.20.0 @@ -59,15 +59,15 @@ importers: '@visactor/vchart': link:../packages/vchart '@visactor/vchart-extension': link:../packages/vchart-extension '@visactor/vchart-theme': 1.6.9 - '@visactor/vgrammar': 0.16.3 + '@visactor/vgrammar': 0.16.4 '@visactor/vmind': 1.2.4-alpha.5 - '@visactor/vrender': 0.22.6 - '@visactor/vrender-kits': 0.22.6 + '@visactor/vrender': 0.22.8 + '@visactor/vrender-kits': 0.22.8 '@visactor/vtable': 1.12.0 '@visactor/vtable-calendar': 1.12.0 '@visactor/vtable-editors': 1.12.0 '@visactor/vtable-gantt': 1.12.0 - '@visactor/vutils': 0.19.4 + '@visactor/vutils': 0.19.5 axios: 1.7.9 buble: 0.20.0 highlight.js: 11.11.1 @@ -146,10 +146,10 @@ importers: '@types/offscreencanvas': 2019.6.4 '@types/react-is': ^17.0.3 '@visactor/vchart': workspace:1.13.8 - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': ~0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': ~0.19.5 '@vitejs/plugin-react': 3.1.0 eslint: ~8.18.0 eslint-config-prettier: 8.5.0 @@ -167,10 +167,10 @@ importers: vite: 3.2.6 dependencies: '@visactor/vchart': link:../vchart - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 react-is: 18.3.1 devDependencies: '@internal/bundler': link:../../tools/bundler @@ -211,10 +211,10 @@ importers: '@types/react-dom': ^18.0.0 '@types/react-is': ^17.0.3 '@visactor/vchart': workspace:1.13.8 - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': ~0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': ~0.19.5 '@vitejs/plugin-react': 3.1.0 eslint: ~8.18.0 eslint-config-prettier: 8.5.0 @@ -233,10 +233,10 @@ importers: vite: 3.2.6 dependencies: '@visactor/vchart': link:../vchart - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 react-is: 18.3.1 devDependencies: '@internal/bundler': link:../../tools/bundler @@ -371,20 +371,20 @@ importers: '@types/jest': ^26.0.0 '@types/node': '*' '@types/offscreencanvas': 2019.6.4 - '@visactor/vdataset': ~0.19.4 - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-hierarchy': 0.16.3 - '@visactor/vgrammar-projection': 0.16.3 - '@visactor/vgrammar-sankey': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vgrammar-venn': 0.16.3 - '@visactor/vgrammar-wordcloud': 0.16.3 - '@visactor/vgrammar-wordcloud-shape': 0.16.3 - '@visactor/vrender-components': 0.22.6 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vscale': ~0.19.4 - '@visactor/vutils': ~0.19.4 + '@visactor/vdataset': ~0.19.5 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-hierarchy': 0.16.4 + '@visactor/vgrammar-projection': 0.16.4 + '@visactor/vgrammar-sankey': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vgrammar-venn': 0.16.4 + '@visactor/vgrammar-wordcloud': 0.16.4 + '@visactor/vgrammar-wordcloud-shape': 0.16.4 + '@visactor/vrender-components': 0.22.8 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vscale': ~0.19.5 + '@visactor/vutils': ~0.19.5 '@visactor/vutils-extension': workspace:1.13.8 canvas: 2.11.2 cross-env: ^7.0.3 @@ -419,20 +419,20 @@ importers: typescript: 4.9.5 vite: 3.2.6 dependencies: - '@visactor/vdataset': 0.19.4 - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-hierarchy': 0.16.3 - '@visactor/vgrammar-projection': 0.16.3 - '@visactor/vgrammar-sankey': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vgrammar-venn': 0.16.3 - '@visactor/vgrammar-wordcloud': 0.16.3 - '@visactor/vgrammar-wordcloud-shape': 0.16.3 - '@visactor/vrender-components': 0.22.6 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vscale': 0.19.4 - '@visactor/vutils': 0.19.4 + '@visactor/vdataset': 0.19.5 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-hierarchy': 0.16.4 + '@visactor/vgrammar-projection': 0.16.4 + '@visactor/vgrammar-sankey': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vgrammar-venn': 0.16.4 + '@visactor/vgrammar-wordcloud': 0.16.4 + '@visactor/vgrammar-wordcloud-shape': 0.16.4 + '@visactor/vrender-components': 0.22.8 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vscale': 0.19.5 + '@visactor/vutils': 0.19.5 '@visactor/vutils-extension': link:../vutils-extension devDependencies: '@esbuild-plugins/node-globals-polyfill': 0.1.1 @@ -490,12 +490,12 @@ importers: '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 '@visactor/vchart': workspace:1.13.8 - '@visactor/vdataset': ~0.19.4 - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vrender-components': 0.22.6 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': ~0.19.4 + '@visactor/vdataset': ~0.19.5 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vrender-components': 0.22.8 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': ~0.19.5 '@vitejs/plugin-react': 3.1.0 canvas: 2.11.2 eslint: ~8.18.0 @@ -514,12 +514,12 @@ importers: vite: 3.2.6 dependencies: '@visactor/vchart': link:../vchart - '@visactor/vdataset': 0.19.4 - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vrender-components': 0.22.6 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vdataset': 0.19.5 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vrender-components': 0.22.8 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 devDependencies: '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -593,8 +593,8 @@ importers: '@types/jest': ^26.0.0 '@types/node': '*' '@types/offscreencanvas': 2019.6.4 - '@visactor/vdataset': ~0.19.4 - '@visactor/vutils': ~0.19.4 + '@visactor/vdataset': ~0.19.5 + '@visactor/vutils': ~0.19.5 eslint: ~8.18.0 husky: 7.0.4 jest: ^26.0.0 @@ -611,8 +611,8 @@ importers: typescript: 4.9.5 vite: 3.2.6 dependencies: - '@visactor/vdataset': 0.19.4 - '@visactor/vutils': 0.19.4 + '@visactor/vdataset': 0.19.5 + '@visactor/vutils': 0.19.5 devDependencies: '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -890,10 +890,10 @@ importers: '@typescript-eslint/eslint-plugin': 5.30.0 '@typescript-eslint/parser': 5.30.0 '@visactor/vchart': workspace:1.13.8 - '@visactor/vrender': 0.22.6 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': ~0.19.4 + '@visactor/vrender': 0.22.8 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': ~0.19.5 cross-env: ^7.0.3 eslint: ~8.18.0 jest: ^26.0.0 @@ -905,10 +905,10 @@ importers: vite: 3.2.6 dependencies: '@visactor/vchart': link:../../packages/vchart - '@visactor/vrender': 0.22.6 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vrender': 0.22.8 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 devDependencies: '@internal/bundler': link:../bundler '@internal/eslint-config': link:../../share/eslint-config @@ -4839,13 +4839,13 @@ packages: topojson-client: 3.1.0 dev: false - /@visactor/vdataset/0.19.4: - resolution: {integrity: sha512-xxglcFtvho5jWiQPKwTolKXbNOG8f77CrK7TJhfiqNlzoe27qO8B+A6lUKlLMt1kZaCH7ZNrFFkHyPjnnZ/gng==} + /@visactor/vdataset/0.19.5: + resolution: {integrity: sha512-8sOzJKHRLTdjmCDGemroxo3t3iWYrw4aDgPaCUbV1GiKuttC4CdTJlVsfq/JLdSldvMgNDTAmovAchVgjBNH6Q==} dependencies: '@turf/flatten': 6.5.0 '@turf/helpers': 6.5.0 '@turf/rewind': 6.5.0 - '@visactor/vutils': 0.19.4 + '@visactor/vutils': 0.19.5 d3-dsv: 2.0.0 d3-geo: 1.12.1 d3-hexbin: 0.2.2 @@ -4861,97 +4861,97 @@ packages: topojson-client: 3.1.0 dev: false - /@visactor/vgrammar-coordinate/0.16.3: - resolution: {integrity: sha512-tfDSi3WgY/GWDvbf67eus4a7jR74y7OMod3JrTqyDVzSNZUOgUtS3ieEM71f9yipxjY8gxo53GPDpH/advxUZw==} + /@visactor/vgrammar-coordinate/0.16.4: + resolution: {integrity: sha512-R4c+LjuM7QARv+X47zuJk2hOb6PlkV7CrvQB1pdlq+WUZuGQv5Nv7jRuRPrX9ENzIrlf0S+luH1efm84NR9dSw==} dependencies: - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar-core/0.16.3: - resolution: {integrity: sha512-cd7hmh9JobbCDUJPOshmQB5V0KVM0GLTPBe/ZySJDi1cUSWpukAgRrLozEk/M5XgDbVIT+4pjqe6siacCad8dg==} + /@visactor/vgrammar-core/0.16.4: + resolution: {integrity: sha512-eKHDqWDY76ddrkHCJJFJZ3xfVyp0YsGEd8mFPXq9Z8p4gderASmK7hHoWgG+AJ+JVDXwDzMRE1d2b3XXOa8twA==} dependencies: - '@visactor/vdataset': 0.19.4 - '@visactor/vgrammar-coordinate': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vrender-components': 0.22.6 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vscale': 0.19.4 - '@visactor/vutils': 0.19.4 + '@visactor/vdataset': 0.19.5 + '@visactor/vgrammar-coordinate': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vrender-components': 0.22.8 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vscale': 0.19.5 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar-hierarchy/0.16.3: - resolution: {integrity: sha512-qnfSWRt1PErkVPTtet8DVc4MY+WwmgJoNNW2FALFht1qUfPdglTqT96drPbkurwiZMzSk+Xfr7+IPUA8ZQwWag==} + /@visactor/vgrammar-hierarchy/0.16.4: + resolution: {integrity: sha512-vwDHAdHgJG/bKfMAsROSDcQh4QWc0kWx0r8vAQ70po0xlJKFwoc07GW52PfRBbZAs82MY4KGYtUB7YZXyIVjGQ==} dependencies: - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar-projection/0.16.3: - resolution: {integrity: sha512-c+MJ3qgtsNQHwZCDBVT7fNahNxe0g827IiytQWvrtMxavLIrtJqeul5H+6BYrGvYk8d81ByxNZdoVNn/mfNtDw==} + /@visactor/vgrammar-projection/0.16.4: + resolution: {integrity: sha512-5tluO34qgF8U3fvaSbASrouiwIlRm9lHfghMw/wLnLLLhQMDNOkf9+J3+MwzOSeC9xpxEvj4mL5GJm1DrBdLgQ==} dependencies: - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vutils': 0.19.5 d3-geo: 1.12.1 dev: false - /@visactor/vgrammar-sankey/0.16.3: - resolution: {integrity: sha512-7j0xx77Yn2KzY4EcZ27qFF6R1KTcmy3BtQQewOHA1uoUX8ZRsfe57eziYRiBhyVrzdFWoa0IJqzH7Yk/zITvuQ==} + /@visactor/vgrammar-sankey/0.16.4: + resolution: {integrity: sha512-pQBLvRfsQJOLlTRps7V1bYPrITqTC/DTRZ3uBZ2vY9vtGn8ZHHaWozTsRDQqc9+rsNbuPe9y0t3SdMFhQyQv7g==} dependencies: - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar-util/0.16.3: - resolution: {integrity: sha512-aF9MqjTR7YvBAVDtp1A/CDVcXFGlO+TxkHVPEQVrn7cVu2DGRXCZnu/iQ+AUhttVYaWlSRflZj4cnQrKS4zy4g==} + /@visactor/vgrammar-util/0.16.4: + resolution: {integrity: sha512-T40YzizF0B69GwxSqIqQTIX52CqqjedGJphmkd5pVha9yFiPaftO17u8lYhro9/m/zu+RDFc/Z5Vj9Grqwpqgw==} dependencies: - '@visactor/vrender-core': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar-venn/0.16.3: - resolution: {integrity: sha512-M6mtCrpOcPrD6nkQFZ3Fl0Z2zPaKFTyRIPeO235vDwB/ZzefN5BObh85UGsv0swK46L5yu3daBxW0VtrGMBZRA==} + /@visactor/vgrammar-venn/0.16.4: + resolution: {integrity: sha512-Qw5SsdtXFQLHGKmXP14/4QEx2oNEI3Ikj7c9b+Y13ir7aiiqApkNptrUQ9fFi9jKVYR3eDXkKUW10StSOgfCxQ==} dependencies: - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar-wordcloud-shape/0.16.3: - resolution: {integrity: sha512-ZWRHbec4WM2W3v2t57gRaX1IUGy+nDRjumcctgzSvmCpmR3nORgLKmMhxXYEA0VwcpY+umM0lVcd42iqPH8c7g==} + /@visactor/vgrammar-wordcloud-shape/0.16.4: + resolution: {integrity: sha512-XpD+e7OE/mkHKiHEows5nKJtu+mB9C+c5o5n27ZWQF4CjNPiDh2gkv+64W/VqcUpzQommXrGQIVaDxtLlffAdw==} dependencies: - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vscale': 0.19.4 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vscale': 0.19.5 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar-wordcloud/0.16.3: - resolution: {integrity: sha512-uIHUJ3CGir+IjDjv4SpJR5SZvWSIYU2VoBdoCvFdhP9j8t15wadGYfe0/br9d6xOM3laiSCFYvPdhy0Ke5sP4w==} + /@visactor/vgrammar-wordcloud/0.16.4: + resolution: {integrity: sha512-sT+ntTnJHFrqQ80KhQQ41RQ0MTUmfnB0qCPby+jI83OL7fRTShBUcDMkUrHiPyKSKkAdTErnzFrxf3TbnuXD+Q==} dependencies: - '@visactor/vgrammar-core': 0.16.3 - '@visactor/vgrammar-util': 0.16.3 - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vgrammar-core': 0.16.4 + '@visactor/vgrammar-util': 0.16.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vutils': 0.19.5 dev: false - /@visactor/vgrammar/0.16.3: - resolution: {integrity: sha512-hUeJliljIPQVHos1WgEwY64VHrc47dd2avKhhGiNgKg66er5CLaapMAKC2S1su4V2+BmdfzKGLM6J93raqbjeA==} + /@visactor/vgrammar/0.16.4: + resolution: {integrity: sha512-1+HQ9DMq7S7AM5ettNVv9B23BV4hUnlipW6DM6DKlpw27UbvISgKpTxesPVddSaOOSOIEz8Ovk4NoSa2Ra4JZw==} dependencies: - '@visactor/vgrammar-core': 0.16.3 + '@visactor/vgrammar-core': 0.16.4 dev: false /@visactor/vmind/1.2.4-alpha.5: @@ -4982,13 +4982,13 @@ packages: gifuct-js: 2.1.2 dev: false - /@visactor/vrender-components/0.22.6: - resolution: {integrity: sha512-YHLjA2GzP5LQxAAgzo2iniBxDldy9GtEzjm/sCXrrOGzzwMFlyhAeXCbUVEIMhTTfpRdK5LocAP1PSJsv4BObA==} + /@visactor/vrender-components/0.22.8: + resolution: {integrity: sha512-DqJ4oEcCvlPkfgoCCk0tqa0N9hJd13EeuVzQTB4n30OUp4uSkws2CML+6Xv+Th0m5xzGOsZLXdMZsyXjxrwBaQ==} dependencies: - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 - '@visactor/vscale': 0.19.4 - '@visactor/vutils': 0.19.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 + '@visactor/vscale': 0.19.5 + '@visactor/vutils': 0.19.5 dev: false /@visactor/vrender-core/0.21.0-alpha.4: @@ -4998,10 +4998,10 @@ packages: color-convert: 2.0.1 dev: false - /@visactor/vrender-core/0.22.6: - resolution: {integrity: sha512-R/MPjAuF9vT5atn7tAqhA5K1FMqYzv2SOhREsJpgP6QbJSnGR2uMTrNENRFvrM81ikR6yeh7WeTx6Fh2av+M4A==} + /@visactor/vrender-core/0.22.8: + resolution: {integrity: sha512-sQmZ+uTJ0M6s6Jhkhkz0/uiYiBTiFnLyDxIhZvPNADEMsjkPLj3hFHrhnxe1LrDHfz+IMoLMASD4IxzCGdjNpw==} dependencies: - '@visactor/vutils': 0.19.4 + '@visactor/vutils': 0.19.5 color-convert: 2.0.1 dev: false @@ -5014,22 +5014,22 @@ packages: roughjs: 4.5.2 dev: false - /@visactor/vrender-kits/0.22.6: - resolution: {integrity: sha512-0yRvhMhnT3JeFKCOi8riubkuKjNMIlzcW1FQV+kIyOGGV6nCSjvFL4+XDuEGalHlHt76BSlM1/cmxnmRNTHCRQ==} + /@visactor/vrender-kits/0.22.8: + resolution: {integrity: sha512-k5QiOoFVBr88XMKVNHigBKGPWF63D8pUsUwi74hJNph+Gxy1ML9373eGgUkTEed/LUK/FvJxFwHO0oN23ZWJtg==} dependencies: '@resvg/resvg-js': 2.4.1 - '@visactor/vrender-core': 0.22.6 - '@visactor/vutils': 0.19.4 + '@visactor/vrender-core': 0.22.8 + '@visactor/vutils': 0.19.5 gifuct-js: 2.1.2 lottie-web: 5.12.2 roughjs: 4.5.2 dev: false - /@visactor/vrender/0.22.6: - resolution: {integrity: sha512-hcLE3jGJxACBQXwiw4xjOEE2fcLuwTpGQn5m5wDULhgMGG7VuNJoXZNHjcRw2zHiw0J/PRIqAAU7pdamxYw6uA==} + /@visactor/vrender/0.22.8: + resolution: {integrity: sha512-XievbxN4oy57m5GrmPZSGhOzrt3ae6cgwplzWo+YiC0bmpgppQwb8PxvbnIeO93lqg7IhuUGGMQDuBfTj5W3dw==} dependencies: - '@visactor/vrender-core': 0.22.6 - '@visactor/vrender-kits': 0.22.6 + '@visactor/vrender-core': 0.22.8 + '@visactor/vrender-kits': 0.22.8 dev: false /@visactor/vscale/0.18.18: @@ -5038,10 +5038,10 @@ packages: '@visactor/vutils': 0.18.18 dev: false - /@visactor/vscale/0.19.4: - resolution: {integrity: sha512-kp69hPMof3GBKRuUiXSR9+9K+Z8ZXsTlOAwcnknXmiiZDhdcDkPlv27/d+Xx1Wi/iqw+BS2S7YIjHmfzdiVQ/Q==} + /@visactor/vscale/0.19.5: + resolution: {integrity: sha512-KiXrn184Fh5aJBl/IcOK5irkJr0jwrpNjLPJ/0wfepYSycyEF5z7lDdfnvoJFEcMoljYjDQVg6Fxg9Adozc6vg==} dependencies: - '@visactor/vutils': 0.19.4 + '@visactor/vutils': 0.19.5 dev: false /@visactor/vtable-calendar/1.12.0: @@ -5105,8 +5105,8 @@ packages: eventemitter3: 4.0.7 dev: false - /@visactor/vutils/0.19.4: - resolution: {integrity: sha512-kLbcsTe1/3HSSvEJvJikzGD0plY0gdHbpxt98oo7W6OrianfYd97nm/w7rFXcq/S49e6C5d1SdU4MZk/PYxhEQ==} + /@visactor/vutils/0.19.5: + resolution: {integrity: sha512-sSU9Gnmnej7LgkENKkdmVqx1I3ZYVugDbGP0KEzgo8j+txAwrthEQTSeFwZcVS0iYrAvSzpmAVuN0/NRo6+vpg==} dependencies: '@turf/helpers': 6.5.0 '@turf/invariant': 6.5.0 diff --git a/docs/assets/option/en/component/mark-area.md b/docs/assets/option/en/component/mark-area.md index f67164a03b..93590763bb 100644 --- a/docs/assets/option/en/component/mark-area.md +++ b/docs/assets/option/en/component/mark-area.md @@ -137,9 +137,10 @@ The area style for the label area. prefix = '####' ) }} -### label(Object) +### label(Array|Object) Label style for dimension lines. +Since `1.13.9`, configuring multiple labels is supported. #### position(Object) diff --git a/docs/assets/option/en/component/mark-line.md b/docs/assets/option/en/component/mark-line.md index 3af3a85c6c..c0b6ed00e3 100644 --- a/docs/assets/option/en/component/mark-line.md +++ b/docs/assets/option/en/component/mark-line.md @@ -219,9 +219,10 @@ The line style of the dimension line. When performing multi-section configuratio prefix = '####' ) }} -### label(Object) +### label(Array|Object) Label style for dimension lines. +Since `1.13.9`, configuring multiple labels is supported. #### position(Object) diff --git a/docs/assets/option/zh/component/mark-area.md b/docs/assets/option/zh/component/mark-area.md index bbf1b0a826..0e59ae94f9 100644 --- a/docs/assets/option/zh/component/mark-area.md +++ b/docs/assets/option/zh/component/mark-area.md @@ -137,9 +137,10 @@ y 轴上的标注区域边界,与 markArea.y 共同构造标注区域。可以 prefix = '####' ) }} -### label(Object) +### label(Array|Object) 标注线的标签样式。 +自 `1.13.9` 版本开始,支持配置多个标签。 #### position(Object) diff --git a/docs/assets/option/zh/component/mark-line.md b/docs/assets/option/zh/component/mark-line.md index 94a31d7cbc..719b7a4812 100644 --- a/docs/assets/option/zh/component/mark-line.md +++ b/docs/assets/option/zh/component/mark-line.md @@ -219,9 +219,10 @@ x 轴上的参考线。可以配置参考线在 x 轴上的值,或者聚合计 prefix = '####' ) }} -### label(Object) +### label(Array|Object) 标注线的标签样式。 +自 `1.13.9` 版本开始,支持配置多个标签。 #### position(Object) diff --git a/docs/package.json b/docs/package.json index d595435d03..0975864cbe 100644 --- a/docs/package.json +++ b/docs/package.json @@ -18,10 +18,10 @@ "@visactor/vchart-extension": "workspace:1.13.8", "@visactor/vchart-theme": "~1.6.6", "@visactor/vmind": "1.2.4-alpha.5", - "@visactor/vutils": "~0.19.4", - "@visactor/vrender": "0.22.6", - "@visactor/vrender-kits": "0.22.6", - "@visactor/vgrammar": "0.16.3", + "@visactor/vutils": "~0.19.5", + "@visactor/vrender": "0.22.8", + "@visactor/vrender-kits": "0.22.8", + "@visactor/vgrammar": "0.16.4", "@visactor/vtable": "1.12.0", "@visactor/vtable-editors": "1.12.0", "@visactor/vtable-gantt": "1.12.0", @@ -59,4 +59,4 @@ "react-device-detect": "^2.2.2", "minimist": "1.2.8" } -} +} \ No newline at end of file diff --git a/packages/openinula-vchart/package.json b/packages/openinula-vchart/package.json index 621c0b43ee..473b054eba 100644 --- a/packages/openinula-vchart/package.json +++ b/packages/openinula-vchart/package.json @@ -29,10 +29,10 @@ }, "dependencies": { "@visactor/vchart": "workspace:1.13.8", - "@visactor/vutils": "~0.19.4", - "@visactor/vrender-core": "0.22.6", - "@visactor/vrender-kits": "0.22.6", - "@visactor/vgrammar-core": "0.16.3", + "@visactor/vutils": "~0.19.5", + "@visactor/vrender-core": "0.22.8", + "@visactor/vrender-kits": "0.22.8", + "@visactor/vgrammar-core": "0.16.4", "react-is": "^18.2.0" }, "devDependencies": { @@ -79,4 +79,4 @@ "access": "public", "registry": "https://registry.npmjs.org/" } -} +} \ No newline at end of file diff --git a/packages/react-vchart/package.json b/packages/react-vchart/package.json index bd4703bf06..db337e67f1 100644 --- a/packages/react-vchart/package.json +++ b/packages/react-vchart/package.json @@ -29,10 +29,10 @@ }, "dependencies": { "@visactor/vchart": "workspace:1.13.8", - "@visactor/vutils": "~0.19.4", - "@visactor/vrender-core": "0.22.6", - "@visactor/vrender-kits": "0.22.6", - "@visactor/vgrammar-core": "0.16.3", + "@visactor/vutils": "~0.19.5", + "@visactor/vrender-core": "0.22.8", + "@visactor/vrender-kits": "0.22.8", + "@visactor/vgrammar-core": "0.16.4", "react-is": "^18.2.0" }, "devDependencies": { @@ -83,4 +83,4 @@ "access": "public", "registry": "https://registry.npmjs.org/" } -} +} \ No newline at end of file diff --git a/packages/vchart-extension/package.json b/packages/vchart-extension/package.json index a8aed0ca94..dca06f26a7 100644 --- a/packages/vchart-extension/package.json +++ b/packages/vchart-extension/package.json @@ -21,12 +21,12 @@ "start": "ts-node __tests__/runtime/browser/scripts/initVite.ts && vite serve __tests__/runtime/browser" }, "dependencies": { - "@visactor/vrender-core": "0.22.6", - "@visactor/vrender-kits": "0.22.6", - "@visactor/vrender-components": "0.22.6", - "@visactor/vgrammar-core": "0.16.3", - "@visactor/vutils": "~0.19.4", - "@visactor/vdataset": "~0.19.4", + "@visactor/vrender-core": "0.22.8", + "@visactor/vrender-kits": "0.22.8", + "@visactor/vrender-components": "0.22.8", + "@visactor/vgrammar-core": "0.16.4", + "@visactor/vutils": "~0.19.5", + "@visactor/vdataset": "~0.19.5", "@visactor/vchart": "workspace:1.13.8" }, "devDependencies": { @@ -60,4 +60,4 @@ "registry": "https://registry.npmjs.org/" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/packages/vchart/__tests__/runtime/browser/test-page/brush-summary.ts b/packages/vchart/__tests__/runtime/browser/test-page/brush-summary.ts new file mode 100644 index 0000000000..9f9c1eb216 --- /dev/null +++ b/packages/vchart/__tests__/runtime/browser/test-page/brush-summary.ts @@ -0,0 +1,1531 @@ +import { isMobile } from 'react-device-detect'; +import { default as VChart } from '../../../../src/index'; +import { DataSet, DataView, csvParser } from '@visactor/vdataset'; + +const run = async () => { + const dataSet = new DataSet(); + dataSet.registerParser('csv', csvParser); + const dataView = new DataView(dataSet); + const type1 = ['A', 'B']; + const type2 = ['A', 'B']; + const color = { + A: { + A: 'A', + B: 'B' + }, + B: { + A: 'C', + B: 'D' + } + }; + + let data = 'y,x,y2,type,type2,color'; + type2.forEach(t2 => { + type1.forEach(t => { + for (let i = 0; i < 10; i++) { + data += `\n${Math.floor(Math.random() * 300) + 600},${i},0,${t},${t2},${color[t][t2]}`; + } + }); + }); + + dataView.parse(data, { + type: 'csv' + }); + const spec = { + type: 'line', + xField: ['250109111947088'], + yField: ['10002'], + direction: 'vertical', + seriesField: '20001', + padding: 0, + labelLayout: 'region', + data: [ + { + id: 'data', + values: [ + { + '10001': 'sales', + '10002': '572.88', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-01', + '250109111947091': '572.88' + }, + { + '10001': 'sales', + '10002': '3599.9880000000003', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-03', + '250109111947091': '3599.9880000000003' + }, + { + '10001': 'sales', + '10002': '15928.248', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-04', + '250109111947091': '15928.248' + }, + { + '10001': 'sales', + '10002': '3593.9680000000003', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-05', + '250109111947091': '3593.9680000000003' + }, + { + '10001': 'sales', + '10002': '9932.328000000001', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-06', + '250109111947091': '9932.328000000001' + }, + { + '10001': 'sales', + '10002': '186.396', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-08', + '250109111947091': '186.396' + }, + { + '10001': 'sales', + '10002': '541.8', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-09', + '250109111947091': '541.8' + }, + { + '10001': 'sales', + '10002': '7029.958', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-10', + '250109111947091': '7029.958' + }, + { + '10001': 'sales', + '10002': '56.448', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-11', + '250109111947091': '56.448' + }, + { + '10001': 'sales', + '10002': '3004.6800000000003', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-12', + '250109111947091': '3004.6800000000003' + }, + { + '10001': 'sales', + '10002': '4945.756', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-14', + '250109111947091': '4945.756' + }, + { + '10001': 'sales', + '10002': '12221', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-16', + '250109111947091': '12221' + }, + { + '10001': 'sales', + '10002': '9317.868', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-17', + '250109111947091': '9317.868' + }, + { + '10001': 'sales', + '10002': '7425.824', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-18', + '250109111947091': '7425.824' + }, + { + '10001': 'sales', + '10002': '2919.2799999999997', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-20', + '250109111947091': '2919.2799999999997' + }, + { + '10001': 'sales', + '10002': '600.908', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-21', + '250109111947091': '600.908' + }, + { + '10001': 'sales', + '10002': '25273.829999999998', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-23', + '250109111947091': '25273.829999999998' + }, + { + '10001': 'sales', + '10002': '6008.099999999999', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-24', + '250109111947091': '6008.099999999999' + }, + { + '10001': 'sales', + '10002': '2753.46', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-25', + '250109111947091': '2753.46' + }, + { + '10001': 'sales', + '10002': '24794.174', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-26', + '250109111947091': '24794.174' + }, + { + '10001': 'sales', + '10002': '17047.379999999997', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-27', + '250109111947091': '17047.379999999997' + }, + { + '10001': 'sales', + '10002': '711.48', + '10003': '250109111947091', + '20001': 'sales', + '250109111947088': '2017-01-29', + '250109111947091': '711.48' + } + ], + fields: { + '10001': { + alias: '指标名称 ' + }, + '10002': { + alias: '指标值 ' + }, + '20001': { + alias: '图例项 ', + domain: ['sales'], + sortIndex: 0, + lockStatisticsByDomain: true + }, + '250109111947088': { + alias: 'order_date', + domain: [ + '2017-01-01', + '2017-01-03', + '2017-01-04', + '2017-01-05', + '2017-01-06', + '2017-01-08', + '2017-01-09', + '2017-01-10', + '2017-01-11', + '2017-01-12', + '2017-01-14', + '2017-01-16', + '2017-01-17', + '2017-01-18', + '2017-01-20', + '2017-01-21', + '2017-01-23', + '2017-01-24', + '2017-01-25', + '2017-01-26', + '2017-01-27', + '2017-01-29' + ], + sortIndex: 0, + lockStatisticsByDomain: true + }, + '250109111947091': { + alias: 'sales' + } + } + } + ], + stackInverse: true, + axes: [ + { + type: 'band', + tick: { + visible: false + }, + grid: { + visible: false, + style: { + zIndex: 150, + stroke: '#DADCDD', + lineWidth: 1, + lineDash: [4, 2] + } + }, + orient: 'bottom', + visible: true, + domainLine: { + visible: true, + style: { + lineWidth: 1, + stroke: '#989999' + } + }, + title: { + visible: false, + space: 5, + text: 'order_date', + style: { + fontSize: 12, + fill: '#363839', + fontWeight: 'normal' + } + }, + maxHeight: null, + autoIndent: false, + sampling: false, + zIndex: 200, + label: { + visible: true, + space: 4, + style: { + fontSize: 12, + fill: '#6F6F6F', + angle: 0, + fontWeight: 'normal', + direction: 'horizontal', + maxLineWidth: 174 + }, + autoHide: true, + autoHideMethod: 'greedy', + flush: true, + lastVisible: true + }, + hover: true, + background: { + visible: true, + state: { + hover: { + fillOpacity: 0.08, + fill: '#141414' + }, + hover_reverse: { + fillOpacity: 0.08, + fill: '#141414' + } + } + }, + paddingInner: 0.36249999999999993, + paddingOuter: 0.175 + }, + { + type: 'linear', + tick: { + visible: false, + style: { + stroke: 'rgba(255, 255, 255, 0)' + } + }, + niceType: 'accurateFirst', + zIndex: 200, + grid: { + visible: true, + style: { + zIndex: 150, + stroke: '#DADCDD', + lineWidth: 1, + lineDash: [4, 2] + } + }, + orient: 'left', + visible: true, + domainLine: { + visible: true, + style: { + lineWidth: 1, + stroke: 'rgba(255, 255, 255, 0)' + } + }, + title: { + visible: false, + text: 'sales', + space: 8, + style: { + fontSize: 12, + fill: '#363839', + fontWeight: 'normal' + } + }, + autoIndent: false, + sampling: false, + label: { + visible: true, + space: 6, + flush: true, + padding: 0, + style: { + fontSize: 12, + maxLineWidth: 174, + fill: '#6F6F6F', + angle: 0, + fontWeight: 'normal', + dy: 0, + direction: 'horizontal' + }, + autoHide: true, + autoHideMethod: 'greedy' + }, + background: { + visible: true, + state: { + hover: { + fillOpacity: 0.08, + fill: '#141414' + }, + hover_reverse: { + fillOpacity: 0.08, + fill: '#141414' + } + } + }, + innerOffset: { + top: 4.4311346272637895 + }, + zero: true, + nice: true + } + ], + color: { + field: '20001', + type: 'ordinal', + range: ['#2E62F1'], + specified: {}, + domain: ['sales'] + }, + legends: [ + { + type: 'discrete', + visible: true, + id: 'legend-discrete', + orient: 'right', + position: 'start', + layoutType: 'normal', + maxCol: 1, + title: { + textStyle: { + fontSize: 12, + fill: '#6F6F6F' + } + }, + layoutLevel: 60, + item: { + focus: true, + focusIconStyle: { + size: 14 + }, + maxWidth: 398, + spaceRow: 0, + spaceCol: 0, + padding: { + top: 1, + bottom: 2, + left: 3, + right: 2 + }, + background: { + visible: false, + style: { + fillOpacity: 0.001 + } + }, + label: { + style: { + fontSize: 12, + fill: '#6F6F6F' + } + }, + shape: { + style: { + lineWidth: 0, + symbolType: 'circle', + fillOpacity: 1, + size: 10 + } + } + }, + pager: { + type: 'default', + layout: 'horizontal', + padding: { + left: -18 + }, + textStyle: {}, + space: 0, + handler: { + preShape: 'triangleLeft', + nextShape: 'triangleRight', + style: {}, + state: { + disable: {} + } + } + }, + alignSelf: 'end', + padding: { + top: 0, + bottom: 12, + left: 16, + right: 0 + } + } + ], + label: { + visible: false, + offset: 3, + overlap: { + hideOnHit: true, + avoidBaseMark: false, + strategy: [ + { + type: 'position', + position: ['top', 'bottom'] + } + ], + clampForce: true + }, + style: { + fontSize: 12, + fontWeight: 'normal', + zIndex: 400, + lineHeight: '100%', + boundsPadding: [1, 0, 0, 0], + fill: '#363839', + stroke: 'rgba(255, 255, 255, 0.8)', + lineWidth: 2, + strokeOpacity: 1 + }, + position: 'top', + smartInvert: false + }, + tooltip: { + handler: {} + }, + point: { + style: { + shape: { + type: 'ordinal', + field: '20001', + range: ['circle'], + domain: ['sales'] + }, + size: { + type: 'ordinal', + field: '20001', + range: [7.0898154036220635], + domain: ['sales'] + }, + fill: { + field: '20001', + type: 'ordinal', + range: ['#2E62F1'], + specified: {}, + domain: ['sales'] + }, + stroke: { + field: '20001', + type: 'ordinal', + range: ['#2E62F1'], + specified: {}, + domain: ['sales'] + }, + strokeOpacity: { + type: 'ordinal', + field: '20001', + range: [1], + domain: ['sales'] + }, + fillOpacity: { + type: 'ordinal', + field: '20001', + range: [1], + domain: ['sales'] + } + }, + state: { + hover: { + lineWidth: 2, + fillOpacity: 1, + strokeOpacity: 1, + scaleX: 1.5, + scaleY: 1.5, + cursor: 'pointer' + }, + dimension_hover: { + visible: true + } + } + }, + line: { + style: { + curveType: { + type: 'ordinal', + field: '20001', + range: ['linear'], + domain: ['sales'] + }, + lineWidth: { + type: 'ordinal', + field: '20001', + range: [3], + domain: ['sales'] + }, + lineDash: { + type: 'ordinal', + field: '20001', + range: [[0, 0]], + domain: ['sales'] + } + } + }, + seriesMark: 'line', + markOverlap: true, + region: [ + { + clip: true + } + ], + background: 'rgba(255, 255, 255, 0)', + area: { + style: { + curveType: { + type: 'ordinal', + field: '20001', + range: ['linear'], + domain: ['sales'] + } + } + }, + invalidType: 'break', + animation: false, + brush: { + onBrushEnd: () => { + console.log('onBrushEnd'); + return true; + }, + // markTypeFilter: ['line'], + endTrigger: ['pointerup', 'pointerupoutside'], + sizeThreshold: 50, + inBrush: { + fillOpacity: 1, + strokeOpacity: 1, + colorAlpha: 1 + }, + outOfBrush: { + colorAlpha: 0.2, + fillOpacity: 0.3 + } + }, + crosshair: { + xField: { + visible: true, + line: { + type: 'rect', + style: { + fillOpacity: 0.2, + fill: '#b2bacf' + } + } + }, + gridZIndex: 100 + }, + hash: '3d3f5254de2551eaf32c946dd44bb42e' + }; + + const cs = new VChart(spec, { + dataSet, + dom: document.getElementById('chart'), + mode: isMobile ? 'mobile-browser' : 'desktop-browser' + }); + console.time('renderTime'); + cs.renderAsync().then(() => { + console.timeEnd('renderTime'); + cs.on('brushStart', (...e) => console.log('brushStart', e)); + cs.on('brushEnd', (...e) => console.log('brushEnd', e)); + cs.on('brushClear', (...e) => console.log('brushClear', e)); + cs.on('brushActive', (...e) => console.log('brushActive', e)); + }); + + const response = await fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/brush-data.json'); + const dataBrush = await response.json(); + + const row = 4; + const col = 4; + const region = []; + const layoutElements = []; + const series = []; + const axes = []; + const rowHeight = []; + for (let k = 0; k < row * col; k++) { + region.push({ + id: `${k}_Region` + }); + + const seriesRow = Math.floor(k / col) + Math.floor(k / col); + const seriesCol = k - Math.floor(k / col) * col; + + // 系列行 + layoutElements.push({ + row: seriesRow, + col: seriesCol + seriesCol + 1, + modelId: `${k}_Region` + }); + + series.push({ + id: `${k}_Region`, + type: 'scatter', + xField: 'x', + yField: 'y', + seriesField: 'type', + data: { id: `${k}_Data`, values: dataBrush[k] }, + regionId: `${k}_Region`, + size: 5 + }); + + axes.push({ + id: `${k}_Left`, + orient: 'left', + regionId: `${k}_Region`, + seriesId: [`${k}_Region`], + zero: false + }); + + layoutElements.push({ + row: seriesRow, + col: seriesCol + seriesCol, + modelId: `${k}_Left` + }); + + axes.push({ + id: `${k}_Bottom`, + orient: 'bottom', + regionId: `${k}_Region`, + seriesId: [`${k}_Region`], + type: 'linear', + zero: false + }); + + layoutElements.push({ + row: seriesRow + 1, + col: seriesCol + seriesCol + 1, + modelId: `${k}_Bottom` + }); + + if (seriesCol === 0) { + rowHeight.push({ + index: seriesRow + 1, + size: 30 + }); + } + } + + const spec2 = { + type: 'common', + padding: 30, + region, + layout: { + type: 'grid', + col: col * 2, + row: row * 2, + elements: layoutElements, + rowHeight + }, + axes, + tooltip: false, + series, + brush: { + seriesIndex: Array.from({ length: 16 }, (v, k) => k), + brushType: 'rect', + brushLinkSeriesIndex: Array.from({ length: 16 }, (v, k) => k), + inBrush: { + colorAlpha: 1 + }, + outOfBrush: { + colorAlpha: 0.2 + } + } + }; + + const cs2 = new VChart(spec2, { + dataSet, + dom: document.getElementById('chart'), + mode: isMobile ? 'mobile-browser' : 'desktop-browser' + }); + console.time('renderTime'); + cs2.renderAsync().then(() => { + console.timeEnd('renderTime'); + cs2.on('brushStart', (...e) => console.log('brushStart-2', e)); + cs2.on('brushEnd', (...e) => console.log('brushEnd-2', e)); + cs2.on('brushClear', (...e) => console.log('brushClear-2', e)); + cs2.on('brushActive', (...e) => console.log('brushActive-2', e)); + }); + window['vchart2'] = cs; + console.log(cs); + + const spec3 = { + type: 'scatter', + data: [ + { + values: [ + { x: 936196, size: 83431, y: 1371, type: 'Technology', area: 'Northeast' }, + { x: 1270911, size: 219815, y: 5590, type: 'office supplies', area: 'Zhongnan' }, + { x: 453898, size: 19061, y: 727, type: 'Technology', area: 'Southwest' }, + { x: 919743, size: 148800, y: 1199, type: 'furniture', area: 'North China' }, + { x: 1676224, size: 163453, y: 2517, type: 'furniture', area: 'East China' }, + { x: 1466575, size: 251487, y: 2087, type: 'Technology', area: 'Zhongnan' }, + { x: 824673, size: 86067, y: 3622, type: 'office supplies', area: 'Northeast' }, + { x: 230956, size: 24016, y: 347, type: 'Technology', area: 'Northwest' }, + { x: 1599653, size: 228179, y: 2183, type: 'Technology', area: 'East China' }, + { x: 745813, size: 137265, y: 3020, type: 'office supplies', area: 'North China' }, + { x: 267870, size: 49633, y: 970, type: 'office supplies', area: 'Northwest' }, + { x: 1408628, size: 215585, y: 6341, type: 'office supplies', area: 'East China' }, + { x: 781743, size: 144986, y: 927, type: 'Technology', area: 'North China' }, + { x: 501533, size: 29303, y: 814, type: 'furniture', area: 'Southwest' }, + { x: 920698, size: 72692, y: 1470, type: 'furniture', area: 'Northeast' }, + { x: 316212, size: 24903, y: 468, type: 'furniture', area: 'Northwest' }, + { x: 1399928, size: 199582, y: 2023, type: 'furniture', area: 'Zhongnan' }, + { x: 347692, size: 49272, y: 1858, type: 'office supplies', area: 'Southwest' } + ] + } + ], + xField: 'x', + yField: 'y', + seriesField: 'type', + sizeField: 'size', + size: [10, 25], + shapeField: 'type', + shape: ['circle', 'triangle'], + axes: [ + { orient: 'left', range: { min: 0 }, type: 'linear' }, + { orient: 'bottom', label: { visible: true }, type: 'linear' } + ], + legends: [ + { + visible: true, + orient: 'left', + position: 'start', + title: { + visible: true, + style: { + text: 'title' + } + }, + item: { + visible: true + } + } + ], + direction: 'horizontal', + brush: { + brushMode: 'multiple', + brushType: 'rect', + inBrush: { + colorAlpha: 1 + }, + outOfBrush: { + colorAlpha: 0.2 + } + } + }; + const cs3 = new VChart(spec3, { + dataSet, + dom: document.getElementById('chart'), + mode: isMobile ? 'mobile-browser' : 'desktop-browser' + }); + console.time('renderTime'); + cs3.renderAsync().then(() => { + console.timeEnd('renderTime'); + cs3.on('brushStart', (...e) => console.log('brushStart-3', e)); + cs3.on('brushEnd', (...e) => console.log('brushEnd-3', e)); + cs3.on('brushClear', (...e) => console.log('brushClear-3', e)); + cs3.on('brushActive', (...e) => console.log('brushActive-3', e)); + }); + window['vchart3'] = cs3; + + const spec4 = { + type: 'bar', + xField: ['10002'], + yField: ['241216184524145', '20001'], + direction: 'horizontal', + seriesField: '20001', + padding: 0, + labelLayout: 'region', + data: [ + { + id: 'data', + values: [ + { + '10001': '销售额', + '10002': '710386.2080000001', + '10003': '241216184524139', + '20001': '公司-销售额', + '241216184524139': '710386.2080000001', + '241216184524145': '2019', + '241216184524148': '公司' + }, + { + '10001': '利润', + '10002': '96740.72800000002', + '10003': '241216184524142', + '20001': '公司-利润', + '241216184524142': '96740.72800000002', + '241216184524145': '2019', + '241216184524148': '公司' + }, + { + '10001': '销售额', + '10002': '401978.82199999975', + '10003': '241216184524139', + '20001': '小型企业-销售额', + '241216184524139': '401978.82199999975', + '241216184524145': '2019', + '241216184524148': '小型企业' + }, + { + '10001': '利润', + '10002': '70445.662', + '10003': '241216184524142', + '20001': '小型企业-利润', + '241216184524142': '70445.662', + '241216184524145': '2019', + '241216184524148': '小型企业' + }, + { + '10001': '销售额', + '10002': '1209267.4509999994', + '10003': '241216184524139', + '20001': '消费者-销售额', + '241216184524139': '1209267.4509999994', + '241216184524145': '2019', + '241216184524148': '消费者' + }, + { + '10001': '利润', + '10002': '130523.21100000004', + '10003': '241216184524142', + '20001': '消费者-利润', + '241216184524142': '130523.21100000004', + '241216184524145': '2019', + '241216184524148': '消费者' + }, + { + '10001': '销售额', + '10002': '1194097.982', + '10003': '241216184524139', + '20001': '公司-销售额', + '241216184524139': '1194097.982', + '241216184524145': '2020', + '241216184524148': '公司' + }, + { + '10001': '利润', + '10002': '156066.722', + '10003': '241216184524142', + '20001': '公司-利润', + '241216184524142': '156066.722', + '241216184524145': '2020', + '241216184524148': '公司' + }, + { + '10001': '销售额', + '10002': '612662.176', + '10003': '241216184524139', + '20001': '小型企业-销售额', + '241216184524139': '612662.176', + '241216184524145': '2020', + '241216184524148': '小型企业' + }, + { + '10001': '利润', + '10002': '70031.83600000002', + '10003': '241216184524142', + '20001': '小型企业-利润', + '241216184524142': '70031.83600000002', + '241216184524145': '2020', + '241216184524148': '小型企业' + }, + { + '10001': '销售额', + '10002': '1547854.518', + '10003': '241216184524139', + '20001': '消费者-销售额', + '241216184524139': '1547854.518', + '241216184524145': '2020', + '241216184524148': '消费者' + }, + { + '10001': '利润', + '10002': '224529.71799999976', + '10003': '241216184524142', + '20001': '消费者-利润', + '241216184524142': '224529.71799999976', + '241216184524145': '2020', + '241216184524148': '消费者' + }, + { + '10001': '销售额', + '10002': '751827.4890000003', + '10003': '241216184524139', + '20001': '小型企业-销售额', + '241216184524139': '751827.4890000003', + '241216184524145': '2021', + '241216184524148': '小型企业' + }, + { + '10001': '利润', + '10002': '104185.24900000016', + '10003': '241216184524142', + '20001': '小型企业-利润', + '241216184524142': '104185.24900000016', + '241216184524145': '2021', + '241216184524148': '小型企业' + }, + { + '10001': '销售额', + '10002': '1232049.7069999985', + '10003': '241216184524139', + '20001': '公司-销售额', + '241216184524139': '1232049.7069999985', + '241216184524145': '2021', + '241216184524148': '公司' + }, + { + '10001': '利润', + '10002': '170255.82699999984', + '10003': '241216184524142', + '20001': '公司-利润', + '241216184524142': '170255.82699999984', + '241216184524145': '2021', + '241216184524148': '公司' + }, + { + '10001': '销售额', + '10002': '2009897.834', + '10003': '241216184524139', + '20001': '消费者-销售额', + '241216184524139': '2009897.834', + '241216184524145': '2021', + '241216184524148': '消费者' + }, + { + '10001': '利润', + '10002': '297288.05400000047', + '10003': '241216184524142', + '20001': '消费者-利润', + '241216184524142': '297288.05400000047', + '241216184524145': '2021', + '241216184524148': '消费者' + }, + { + '10001': '销售额', + '10002': '1707242.6979999992', + '10003': '241216184524139', + '20001': '公司-销售额', + '241216184524139': '1707242.6979999992', + '241216184524145': '2022', + '241216184524148': '公司' + }, + { + '10001': '利润', + '10002': '198663.45799999998', + '10003': '241216184524142', + '20001': '公司-利润', + '241216184524142': '198663.45799999998', + '241216184524145': '2022', + '241216184524148': '公司' + }, + { + '10001': '销售额', + '10002': '2849279.1179999993', + '10003': '241216184524139', + '20001': '消费者-销售额', + '241216184524139': '2849279.1179999993', + '241216184524145': '2022', + '241216184524148': '消费者' + }, + { + '10001': '利润', + '10002': '378567.09799999924', + '10003': '241216184524142', + '20001': '消费者-利润', + '241216184524142': '378567.09799999924', + '241216184524145': '2022', + '241216184524148': '消费者' + }, + { + '10001': '销售额', + '10002': '972806.0580000003', + '10003': '241216184524139', + '20001': '小型企业-销售额', + '241216184524139': '972806.0580000003', + '241216184524145': '2022', + '241216184524148': '小型企业' + }, + { + '10001': '利润', + '10002': '146603.898', + '10003': '241216184524142', + '20001': '小型企业-利润', + '241216184524142': '146603.898', + '241216184524145': '2022', + '241216184524148': '小型企业' + }, + { + '10001': '销售额', + '10002': '309016.701', + '10003': '241216184524139', + '20001': '公司-销售额', + '241216184524139': '309016.701', + '241216184524145': '2023', + '241216184524148': '公司' + }, + { + '10001': '利润', + '10002': '60240.901000000005', + '10003': '241216184524142', + '20001': '公司-利润', + '241216184524142': '60240.901000000005', + '241216184524145': '2023', + '241216184524148': '公司' + }, + { + '10001': '销售额', + '10002': '151814.09599999996', + '10003': '241216184524139', + '20001': '小型企业-销售额', + '241216184524139': '151814.09599999996', + '241216184524145': '2023', + '241216184524148': '小型企业' + }, + { + '10001': '利润', + '10002': '21212.016', + '10003': '241216184524142', + '20001': '小型企业-利润', + '241216184524142': '21212.016', + '241216184524145': '2023', + '241216184524148': '小型企业' + }, + { + '10001': '销售额', + '10002': '408773.2670000001', + '10003': '241216184524139', + '20001': '消费者-销售额', + '241216184524139': '408773.2670000001', + '241216184524145': '2023', + '241216184524148': '消费者' + }, + { + '10001': '利润', + '10002': '22184.54699999999', + '10003': '241216184524142', + '20001': '消费者-利润', + '241216184524142': '22184.54699999999', + '241216184524145': '2023', + '241216184524148': '消费者' + } + ], + fields: { + '10001': { + alias: '指标名称 ' + }, + '10002': { + alias: '指标值 ' + }, + '20001': { + alias: '图例项 ', + domain: ['公司-销售额', '小型企业-销售额', '消费者-销售额', '公司-利润', '小型企业-利润', '消费者-利润'], + sortIndex: 0, + lockStatisticsByDomain: true + }, + '241216184524139': { + alias: '销售额' + }, + '241216184524142': { + alias: '利润' + }, + '241216184524145': { + alias: '订单日期', + domain: ['2019', '2020', '2021', '2022', '2023'], + sortIndex: 0, + lockStatisticsByDomain: true + }, + '241216184524148': { + alias: '细分' + } + } + } + ], + stackInverse: true, + axes: [ + { + type: 'band', + tick: { + visible: false + }, + grid: { + visible: false, + style: { + zIndex: 150, + stroke: '#DADCDD', + lineWidth: 1, + lineDash: [4, 2] + } + }, + orient: 'left', + visible: true, + domainLine: { + visible: true, + style: { + lineWidth: 1, + stroke: '#989999' + } + }, + title: { + visible: false, + space: 5, + text: '订单日期', + style: { + fontSize: 12, + fill: '#363839', + fontWeight: 'normal' + } + }, + maxHeight: null, + autoIndent: false, + sampling: false, + zIndex: 200, + label: { + visible: true, + space: 8, + style: { + fontSize: 12, + fill: '#6F6F6F', + angle: 0, + fontWeight: 'normal', + direction: 'horizontal', + maxLineWidth: 174 + }, + autoHide: true, + autoHideMethod: 'greedy', + flush: true, + lastVisible: true + }, + hover: true, + background: { + visible: true, + state: { + hover: { + fillOpacity: 0.08, + fill: '#141414' + }, + hover_reverse: { + fillOpacity: 0.08, + fill: '#141414' + } + } + }, + paddingInner: [0.15, 0.1], + paddingOuter: [0.075, 0.1] + }, + { + type: 'linear', + tick: { + visible: false, + style: { + stroke: 'rgba(255, 255, 255, 0)' + } + }, + niceType: 'accurateFirst', + zIndex: 200, + grid: { + visible: true, + style: { + zIndex: 150, + stroke: '#DADCDD', + lineWidth: 1, + lineDash: [4, 2] + } + }, + orient: 'bottom', + visible: true, + domainLine: { + visible: true, + style: { + lineWidth: 1, + stroke: 'rgba(255, 255, 255, 0)' + } + }, + title: { + visible: false, + text: '销售额', + space: 8, + style: { + fontSize: 12, + fill: '#363839', + fontWeight: 'normal' + } + }, + autoIndent: false, + sampling: false, + label: { + visible: true, + space: 4, + flush: true, + padding: 0, + style: { + fontSize: 12, + maxLineWidth: 174, + fill: '#6F6F6F', + angle: 0, + fontWeight: 'normal', + dy: 0, + direction: 'horizontal' + }, + autoHide: true, + autoHideMethod: 'greedy' + }, + background: { + visible: true, + state: { + hover: { + fillOpacity: 0.08, + fill: '#141414' + }, + hover_reverse: { + fillOpacity: 0.08, + fill: '#141414' + } + } + }, + zero: true, + nice: true + } + ], + color: { + field: '20001', + type: 'ordinal', + range: ['#2E62F1', '#4DC36A', '#FF8406', '#FFCC00', '#4F44CF', '#5AC8FA'], + specified: {}, + domain: ['公司-销售额', '小型企业-销售额', '消费者-销售额', '公司-利润', '小型企业-利润', '消费者-利润'] + }, + legends: [ + { + type: 'discrete', + visible: true, + id: 'legend-discrete', + orient: 'bottom', + position: 'middle', + layoutType: 'normal', + maxRow: 1, + title: { + textStyle: { + fontSize: 12, + fill: '#6F6F6F' + } + }, + layoutLevel: 30, + item: { + focus: true, + focusIconStyle: { + size: 14 + }, + maxWidth: 400, + spaceRow: 0, + spaceCol: 0, + padding: { + top: 1, + bottom: 1, + left: 1, + right: 1 + }, + background: { + visible: false, + style: { + fillOpacity: 0.001 + } + }, + label: { + style: { + fontSize: 12, + fill: '#6F6F6F' + } + }, + shape: { + style: { + lineWidth: 0, + symbolType: 'square', + size: 10, + fillOpacity: 1 + } + } + }, + pager: { + type: 'default', + layout: 'horizontal', + padding: 0, + textStyle: {}, + space: 0, + handler: { + preShape: 'triangleLeft', + nextShape: 'triangleRight', + style: {}, + state: { + disable: {} + } + } + }, + alignSelf: 'start', + padding: { + top: 16, + bottom: 0, + left: 0, + right: 0 + } + } + ], + label: { + visible: false, + offset: 3, + overlap: { + hideOnHit: true, + avoidBaseMark: false, + strategy: [ + { + type: 'position', + position: [] + } + ], + clampForce: true + }, + style: { + fontSize: 12, + fontWeight: 'normal', + zIndex: 400, + lineHeight: '100%', + boundsPadding: [1, 0, 0, 0], + fill: '#363839', + stroke: 'rgba(255, 255, 255, 0.8)', + lineWidth: 2, + strokeOpacity: 1 + }, + position: 'outside', + smartInvert: false + }, + tooltip: { + handler: {} + }, + hover: { + enable: true + }, + select: { + enable: true + }, + bar: { + state: { + hover: { + cursor: 'pointer', + fillOpacity: 0.8, + stroke: '#58595B', + lineWidth: 1, + zIndex: 500 + }, + selected: { + cursor: 'pointer', + fillOpacity: 1, + stroke: '#58595B', + lineWidth: 1 + }, + selected_reverse: { + fillOpacity: 0.3, + lineWidth: 0.3 + } + }, + style: { + cornerRadius: 0 + } + }, + region: [ + { + clip: true + } + ], + background: 'rgba(255, 255, 255, 0)', + animation: false, + brush: { + inBrush: { + fillOpacity: 1, + stroke: '#58595B', + lineWidth: 1, + strokeOpacity: 1, + colorAlpha: 1 + }, + outOfBrush: { + colorAlpha: 0.2, + fillOpacity: 0.3, + lineWidth: 0.3 + }, + endTrigger: ['pointerup', 'pointerupoutside'] + }, + crosshair: { + yField: { + visible: true, + line: { + type: 'rect', + style: { + fillOpacity: 0.2, + fill: '#b2bacf' + } + } + }, + gridZIndex: 100 + }, + hash: 'a1fc9f11b63b517f25ee509322421bb5' + }; + + const cs4 = new VChart(spec4, { + dataSet, + dom: document.getElementById('chart'), + mode: isMobile ? 'mobile-browser' : 'desktop-browser' + }); + console.time('renderTime'); + cs4.renderAsync().then(() => { + console.timeEnd('renderTime'); + cs4.on('brushStart', (...e) => console.log('brushStart-4', e)); + cs4.on('brushEnd', (...e) => console.log('brushEnd-4', e)); + cs4.on('brushClear', (...e) => console.log('brushClear-4', e)); + cs4.on('brushActive', (...e) => console.log('brushActive-4', e)); + }); +}; +run(); diff --git a/packages/vchart/__tests__/runtime/browser/test-page/debug.ts b/packages/vchart/__tests__/runtime/browser/test-page/debug.ts index 5c8edf8cf8..34662bdbb4 100644 --- a/packages/vchart/__tests__/runtime/browser/test-page/debug.ts +++ b/packages/vchart/__tests__/runtime/browser/test-page/debug.ts @@ -2,312 +2,15 @@ import { default as VChart } from '../../../../src/index'; const CONTAINER_ID = 'chart'; const run = async () => { - // const spec = { - // direction: 'vertical', - // type: 'common', - // color: ['#00295C', '#2568BD', '#9F9F9F', '#C5C5C5', '#00B0F0', '#4BCFFF', '#C2C2C2', '#D7D7D7'], - // series: [ - // { - // type: 'bar', - // stack: true, - // direction: 'vertical', - // bar: { - // style: { - // stroke: '', - // lineWidth: 1 - // }, - // state: { - // hover: { - // stroke: '#000', - // lineWidth: 1 - // } - // } - // }, - // barBackground: { - // style: { - // stroke: '', - // lineWidth: 1 - // } - // }, - // label: { - // visible: true, - // position: 'inside', - // style: { - // lineHeight: '100%', - // fontSize: 16, - // fontWeight: 'bold' - // }, - // overlap: { - // strategy: [] - // }, - // smartInvert: true, - // formatConfig: {}, - // interactive: true - // }, - // totalLabel: { - // visible: true, - // position: 'top', - // overlap: false, - // clampForce: false, - // formatConfig: { - // fixed: 0, - // content: 'value' - // }, - // style: { - // lineHeight: '100%', - // lineWidth: 1, - // fill: '#1F2329', - // stroke: '#ffffff', - // fontSize: 16, - // fontWeight: 'bold' - // }, - // interactive: true - // }, - // seriesLabel: { - // visible: true, - // position: 'end', - // label: { - // style: { - // lineHeight: '100%', - // lineWidth: 1, - // stroke: '#ffffff', - // fontSize: 16, - // fontWeight: 'bold' - // }, - // space: 10 - // } - // }, - // xField: '_editor_dimension_field', - // yField: '_editor_value_field', - // dataId: '0', - // id: 'series-0', - // EDITOR_SERIES_DATA_KEY: '销量', - // seriesField: '_editor_type_field' - // } - // ], - // legends: { - // id: 'legend-discrete', - // visible: false, - // autoPage: false, - // position: 'start', - // interactive: false, - // item: { - // label: { - // style: { - // fill: '#1F2329', - // fontSize: 16 - // } - // } - // }, - // _originalVisible: false - // }, - // region: [ - // { - // id: 'region-0' - // } - // ], - // tooltip: { - // visible: true, - // mark: { - // content: [{}], - // title: {} - // }, - // dimension: { - // content: [{}], - // title: {} - // } - // }, - // axes: [ - // { - // orient: 'left', - // id: 'axis-left', - // type: 'linear', - // label: { - // autoLimit: false, - // style: { - // fill: '#1F2329', - // fontSize: 16 - // }, - // formatConfig: {} - // }, - // domainLine: { - // visible: true, - // style: { - // stroke: '#000000' - // } - // }, - // tick: { - // visible: true, - // style: { - // stroke: '#000000' - // } - // }, - // grid: { - // visible: false, - // style: { - // stroke: '#bbbfc4' - // } - // }, - // autoIndent: false, - // maxWidth: null, - // maxHeight: null, - // inverse: true - // }, - // { - // orient: 'bottom', - // id: 'axis-bottom', - // type: 'band', - // label: { - // autoLimit: false, - // style: { - // fill: '#1F2329', - // fontSize: 16 - // }, - // formatConfig: {} - // }, - // domainLine: { - // visible: true, - // style: { - // stroke: '#000000' - // }, - // onZero: true - // }, - // tick: { - // visible: true, - // style: { - // stroke: '#000000' - // } - // }, - // grid: { - // visible: false, - // style: { - // stroke: '#bbbfc4' - // } - // }, - // autoIndent: false, - // maxWidth: null, - // maxHeight: null, - // trimPadding: false, - // paddingInner: [0.2, 0], - // paddingOuter: [0.2, 0] - // } - // ], - // data: [ - // { - // id: '0', - // sourceKey: '销量', - // values: [ - // { - // _editor_dimension_field: '1 月', - // _editor_value_field: 2354, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '2 月', - // _editor_value_field: 1902, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '3 月', - // _editor_value_field: 3524, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '4 月', - // _editor_value_field: 2698, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '5 月', - // _editor_value_field: 2896, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '6 月', - // _editor_value_field: 2563, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '7 月', - // _editor_value_field: 3156, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '8 月', - // _editor_value_field: 2896, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '9 月', - // _editor_value_field: 3621, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '10 月', - // _editor_value_field: 2635, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '11 月', - // _editor_value_field: 2963, - // _editor_type_field: '销量' - // }, - // { - // _editor_dimension_field: '12 月', - // _editor_value_field: 2789, - // _editor_type_field: '销量' - // } - // ], - // specField: { - // _editor_dimension_field: { - // type: 'dimension', - // order: 0 - // }, - // _editor_type_field: { - // type: 'series', - // order: 0 - // }, - // _editor_value_field: { - // type: 'value', - // order: 0 - // } - // } - // } - // ], - // labelLayout: 'region', - // customMark: [ - // { - // type: 'component', - // componentType: 'seriesLabel', - // interactive: false, - // style: { - // id: 'a4fdf1eb-5315-48e7-b601-58e095324da6', - // position: 'end', - // label: { - // space: 10, - // style: { - // lineHeight: '100%', - // lineWidth: 1, - // stroke: '#ffffff', - // fontSize: 16, - // fontWeight: 'bold' - // } - // } - // } - // } - // ], - // background: 'transparent' - // }; const spec = { - // direction: 'horizontal', + direction: 'vertical', type: 'common', - // padding: [24, 400, 24, 24], color: ['#00295C', '#2568BD', '#9F9F9F', '#C5C5C5', '#00B0F0', '#4BCFFF', '#C2C2C2', '#D7D7D7'], series: [ { type: 'bar', stack: true, - direction: 'horizontal', + direction: 'vertical', bar: { style: { stroke: '', @@ -332,7 +35,8 @@ const run = async () => { style: { lineHeight: '100%', fontSize: 16, - fontWeight: 'bold' + fontWeight: 'bold', + pickMode: 'imprecise' }, overlap: { strategy: [] @@ -356,13 +60,14 @@ const run = async () => { fill: '#1F2329', stroke: '#ffffff', fontSize: 16, - fontWeight: 'bold' + fontWeight: 'bold', + pickMode: 'imprecise' }, interactive: true }, seriesLabel: { visible: true, - position: 'start', + position: 'end', label: { style: { lineHeight: '100%', @@ -374,11 +79,90 @@ const run = async () => { space: 10 } }, - xField: '_editor_value_field', - yField: '_editor_dimension_field', + xField: '_editor_dimension_field', + yField: '_editor_value_field', dataId: '0', id: 'series-0', - EDITOR_SERIES_DATA_KEY: '2023年库存数量', + EDITOR_SERIES_DATA_KEY: 'a', + seriesField: '_editor_type_field' + }, + { + type: 'bar', + stack: true, + direction: 'vertical', + bar: { + style: { + stroke: '', + lineWidth: 1 + }, + state: { + hover: { + stroke: '#000', + lineWidth: 1 + } + } + }, + barBackground: { + style: { + stroke: '', + lineWidth: 1 + } + }, + label: { + visible: true, + position: 'inside', + style: { + lineHeight: '100%', + fontSize: 16, + fontWeight: 'bold', + pickMode: 'imprecise' + }, + overlap: { + strategy: [] + }, + smartInvert: true, + formatConfig: {}, + interactive: true + }, + totalLabel: { + visible: true, + position: 'top', + overlap: false, + clampForce: false, + formatConfig: { + fixed: 0, + content: 'value' + }, + style: { + lineHeight: '100%', + lineWidth: 1, + fill: '#1F2329', + stroke: '#ffffff', + fontSize: 16, + fontWeight: 'bold', + pickMode: 'imprecise' + }, + interactive: true + }, + seriesLabel: { + visible: true, + position: 'end', + label: { + style: { + lineHeight: '100%', + lineWidth: 1, + stroke: '#ffffff', + fontSize: 16, + fontWeight: 'bold' + }, + space: 10 + } + }, + xField: '_editor_dimension_field', + yField: '_editor_value_field', + dataId: '1', + id: 'series-1', + EDITOR_SERIES_DATA_KEY: 'b', seriesField: '_editor_type_field' } ], @@ -392,7 +176,8 @@ const run = async () => { label: { style: { fill: '#1F2329', - fontSize: 16 + fontSize: 16, + lineWidth: 1 } } }, @@ -400,7 +185,8 @@ const run = async () => { }, region: [ { - id: 'region-0' + id: 'region-0', + stackInverse: true } ], tooltip: { @@ -412,28 +198,37 @@ const run = async () => { dimension: { content: [{}], title: {} + }, + enterable: true, + showDelay: 0, + style: { + maxContentHeight: '95%' } }, axes: [ { - orient: 'right', + orient: 'left', id: 'axis-left', - type: 'band', - trimPadding: false, + type: 'linear', label: { autoLimit: false, style: { fill: '#1F2329', - fontSize: 16 + fontSize: 16, + lineWidth: 1 }, - formatConfig: {} + formatConfig: {}, + _originStyle: { + fill: '#1F2329', + fontSize: 16, + lineWidth: 1 + } }, domainLine: { visible: true, style: { stroke: '#000000' - }, - onZero: true + } }, tick: { visible: true, @@ -454,20 +249,27 @@ const run = async () => { { orient: 'bottom', id: 'axis-bottom', - type: 'linear', + type: 'band', label: { autoLimit: false, style: { fill: '#1F2329', - fontSize: 16 + fontSize: 16, + lineWidth: 1 }, - formatConfig: {} + formatConfig: {}, + _originStyle: { + fill: '#1F2329', + fontSize: 16, + lineWidth: 1 + } }, domainLine: { visible: true, style: { stroke: '#000000' - } + }, + onZero: true }, tick: { visible: true, @@ -484,68 +286,65 @@ const run = async () => { autoIndent: false, maxWidth: null, maxHeight: null, - inverse: true + trimPadding: false, + paddingInner: [0.2, 0], + paddingOuter: [0.2, 0] } ], data: [ { id: '0', - sourceKey: '2023年库存数量', + sourceKey: 'a', values: [ { - _editor_dimension_field: '0-3', - _editor_value_field: 210, - _editor_type_field: '2023年库存数量' - }, - { - _editor_dimension_field: '4-6', - _editor_value_field: 350, - _editor_type_field: '2023年库存数量' + _editor_value_field: 20, + _editor_type_field: 'a', + _editor_dimension_field: 'x1' }, { - _editor_dimension_field: '7-9', - _editor_value_field: 500, - _editor_type_field: '2023年库存数量' + _editor_value_field: 23, + _editor_type_field: 'a', + _editor_dimension_field: 'x2' }, { - _editor_dimension_field: '10-12', - _editor_value_field: 850, - _editor_type_field: '2023年库存数量' - }, - { - _editor_dimension_field: '13-15', - _editor_value_field: 1180, - _editor_type_field: '2023年库存数量' - }, - { - _editor_dimension_field: '16-18', - _editor_value_field: 1450, - _editor_type_field: '2023年库存数量' - }, - { - _editor_dimension_field: '19-21', - _editor_value_field: 1190, - _editor_type_field: '2023年库存数量' + _editor_value_field: 26, + _editor_type_field: 'a', + _editor_dimension_field: 'x3' + } + ], + specField: { + _editor_dimension_field: { + type: 'dimension', + order: 0 }, - { - _editor_dimension_field: '22-24', - _editor_value_field: 950, - _editor_type_field: '2023年库存数量' + _editor_type_field: { + type: 'series', + order: 0 }, + _editor_value_field: { + type: 'value', + order: 0 + } + } + }, + { + id: '1', + sourceKey: 'b', + values: [ { - _editor_dimension_field: '25-27', - _editor_value_field: 700, - _editor_type_field: '2023年库存数量' + _editor_value_field: 20, + _editor_type_field: 'b', + _editor_dimension_field: 'x1' }, { - _editor_dimension_field: '28-30', - _editor_value_field: 400, - _editor_type_field: '2023年库存数量' + _editor_value_field: 24, + _editor_type_field: 'b', + _editor_dimension_field: 'x2' }, { - _editor_dimension_field: '31-33', - _editor_value_field: 300, - _editor_type_field: '2023年库存数量' + _editor_value_field: 29, + _editor_type_field: 'b', + _editor_dimension_field: 'x3' } ], specField: { @@ -564,9 +363,94 @@ const run = async () => { } } ], + markArea: [ + { + id: '17bd0d32-3070-4679-bc39-b0ce3426add8', + name: 'v-area', + interactive: true, + x: '0%', + x1: '50%', + area: { + style: { + fill: '#005DFF', + fillOpacity: '0.1' + } + }, + label: [ + { + position: 'top', + text: 'x1 - x2', + labelBackground: { + visible: true, + style: { + fill: '#fff', + fillOpacity: 1, + stroke: '#000', + lineWidth: 1, + cornerRadius: 4 + } + }, + style: { + fill: '#1F2329', + fontSize: 16, + fontWeight: 'bold' + }, + dy: -6, + pickable: true, + childrenPickable: false + }, + { + position: 'left', + text: 'x1 - x2', + labelBackground: { + visible: true, + style: { + fill: '#fff', + fillOpacity: 1, + stroke: '#000', + lineWidth: 1, + cornerRadius: 4 + } + }, + style: { + fill: '#1F2329', + fontSize: 16, + fontWeight: 'bold' + }, + dx: -6, + pickable: true, + childrenPickable: false + } + ], + _originValue_: ['x1', 'x2'], + _editor_marker_label_: 'x1 - x2', + zIndex: 500 + } + ], + markLine: [], + markPoint: [], labelLayout: 'region', - - background: 'transparent' + customMark: [ + { + type: 'component', + componentType: 'seriesLabel', + interactive: false, + style: { + id: '13643b25-e719-4de6-874c-a4587015f1aa', + position: 'end', + label: { + space: 10, + style: { + lineHeight: '100%', + lineWidth: 1, + stroke: '#ffffff', + fontSize: 16, + fontWeight: 'bold' + } + } + } + } + ] }; const vchart = new VChart(spec, { dom: CONTAINER_ID }); vchart.renderSync(); diff --git a/packages/vchart/package.json b/packages/vchart/package.json index 33d8232e0e..568c43a193 100644 --- a/packages/vchart/package.json +++ b/packages/vchart/package.json @@ -118,24 +118,24 @@ "cross-env": "^7.0.3" }, "dependencies": { - "@visactor/vutils": "~0.19.4", - "@visactor/vdataset": "~0.19.4", - "@visactor/vscale": "~0.19.4", - "@visactor/vrender-core": "0.22.6", - "@visactor/vrender-kits": "0.22.6", - "@visactor/vrender-components": "0.22.6", - "@visactor/vgrammar-core": "0.16.3", - "@visactor/vgrammar-projection": "0.16.3", - "@visactor/vgrammar-wordcloud": "0.16.3", - "@visactor/vgrammar-wordcloud-shape": "0.16.3", - "@visactor/vgrammar-hierarchy": "0.16.3", - "@visactor/vgrammar-sankey": "0.16.3", - "@visactor/vgrammar-venn": "0.16.3", - "@visactor/vgrammar-util": "0.16.3", + "@visactor/vutils": "~0.19.5", + "@visactor/vdataset": "~0.19.5", + "@visactor/vscale": "~0.19.5", + "@visactor/vrender-core": "0.22.8", + "@visactor/vrender-kits": "0.22.8", + "@visactor/vrender-components": "0.22.8", + "@visactor/vgrammar-core": "0.16.4", + "@visactor/vgrammar-projection": "0.16.4", + "@visactor/vgrammar-wordcloud": "0.16.4", + "@visactor/vgrammar-wordcloud-shape": "0.16.4", + "@visactor/vgrammar-hierarchy": "0.16.4", + "@visactor/vgrammar-sankey": "0.16.4", + "@visactor/vgrammar-venn": "0.16.4", + "@visactor/vgrammar-util": "0.16.4", "@visactor/vutils-extension": "workspace:1.13.8" }, "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" } -} +} \ No newline at end of file diff --git a/packages/vchart/src/component/brush/brush.ts b/packages/vchart/src/component/brush/brush.ts index fa08de8541..1216ea8ae6 100644 --- a/packages/vchart/src/component/brush/brush.ts +++ b/packages/vchart/src/component/brush/brush.ts @@ -5,12 +5,12 @@ import { BaseComponent } from '../base/base-component'; // eslint-disable-next-line no-duplicate-imports import { ComponentTypeEnum } from '../interface/type'; import { Brush as BrushComponent, IOperateType as BrushEvent } from '@visactor/vrender-components'; -import type { IPointLike, Maybe } from '@visactor/vutils'; +import type { IBounds, IPointLike, Maybe } from '@visactor/vutils'; // eslint-disable-next-line no-duplicate-imports -import { array, polygonIntersectPolygon, isValid, last } from '@visactor/vutils'; +import { array, polygonIntersectPolygon, isValid, last, cloneDeep } from '@visactor/vutils'; import type { IModelRenderOption, IModelSpecInfo } from '../../model/interface'; import type { IRegion } from '../../region/interface'; -import type { IGraphic, IGroup, INode, IPolygon, ISymbolGraphicAttribute } from '@visactor/vrender-core'; +import type { IGraphic, IGroup, INode, IPolygon } from '@visactor/vrender-core'; import { transformToGraphic } from '../../util/style'; import type { ISeries } from '../../series/interface'; import type { IMark } from '../../mark/interface'; @@ -53,7 +53,6 @@ export class Brush extends BaseComponent i protected _linkedInBrushElementsMap: { [brushName: string]: { [elementKey: string]: IElement } } = {}; protected _linkedOutOfBrushElementsMap: { [elementKey: string]: IElement } = {}; - private _needInitOutState: boolean = true; private _cacheInteractiveRangeAttrs: BrushInteractiveRangeAttr[] = []; private _needDisablePickable: boolean = false; @@ -73,10 +72,17 @@ export class Brush extends BaseComponent i endValue: number | string; }[] = []; + static getSpecInfo(chartSpec: any): Maybe { + return getSpecInfo(chartSpec, this.specKey, this.type, (s: IBrushSpec) => { + return s.visible !== false; + }); + } + + /*** start: abstract pipe ***/ init() { const inBrushMarkAttr = this._transformBrushedMarkAttr(this._spec.inBrush); const outOfBrushMarkAttr = this._transformBrushedMarkAttr(this._spec.outOfBrush); - // 写入mark state, 便于后续state管理 + // 注册mark state, 便于后续state管理 this._option.getAllSeries().forEach((s: ISeries) => { s.getActiveMarks().forEach((m: IMark) => { if (m) { @@ -100,17 +106,31 @@ export class Brush extends BaseComponent i }); }); } + private _initNeedOperatedItem() { + const seriesUserId = this._spec.seriesId; + const seriesIndex = this._spec.seriesIndex; + this._relativeRegions.forEach(r => { + const allMarks: IMark[] = []; + r.getSeries().forEach((s: ISeries) => { + if ( + (seriesUserId && array(seriesUserId).includes(s.userId.toString())) || + (seriesIndex && array(seriesIndex).includes(s.getSpecIndex())) || + (!seriesIndex && !seriesUserId) + ) { + allMarks.push(...s.getMarksWithoutRoot()); + } + this._itemMap[r.id] = allMarks; + }); + }); - static getSpecInfo(chartSpec: any): Maybe { - return getSpecInfo(chartSpec, this.specKey, this.type, (s: IBrushSpec) => { - return s.visible !== false; + this._linkedSeries.forEach(s => { + this._linkedItemMap[s.id] = s.getMarksWithoutRoot(); }); } created() { super.created(); - // event this.initEvent(); this._bindRegions(); this._bindLinkedSeries(); @@ -119,62 +139,117 @@ export class Brush extends BaseComponent i this._initNeedOperatedItem(); } - protected _extendDataInBrush(elementsMap: { [brushName: string]: { [elementKey: string]: IElement } }) { - const data = []; - for (const brushName in elementsMap) { - for (const elementKey in elementsMap[brushName]) { - data.push({ - ...elementsMap[brushName][elementKey]?.data?.[0] - }); - } + protected _bindRegions() { + if (isValid(this._spec.regionId) && isValid(this._spec.regionIndex)) { + this._relativeRegions = this._option.getAllRegions(); } - return data; + this._relativeRegions = this._option.getRegionsInUserIdOrIndex( + array(this._spec.regionId), + array(this._spec.regionIndex) + ); } - protected _extendDatumOutOfBrush(elementsMap: { [elementKey: string]: IElement }) { - const data = []; - for (const elementKey in elementsMap) { - // 图例筛选后, elementKey未更新, 导致data可能为null - // FIXME: brush透出的map维护逻辑有待优化 - data.push(elementsMap[elementKey].data?.[0]); + protected _bindLinkedSeries() { + if (!isValid(this._spec.brushLinkSeriesId) && !isValid(this._spec.brushLinkSeriesIndex)) { + return; } - return data; + this._linkedSeries = this._option.getSeriesInUserIdOrIndex( + array(this._spec.brushLinkSeriesId), + array(this._spec.brushLinkSeriesIndex) + ); } - protected _getBrushInteractiveAttr(region: IRegion) { - const regionLayoutPosition = region.getLayoutStartPoint(); - const regionLayoutRect = region.getLayoutRect(); - const seriesRegionStartX = regionLayoutPosition.x; - const seriesRegionEndX = seriesRegionStartX + regionLayoutRect.width; - const seriesRegionStartY = regionLayoutPosition.y; - const seriesRegionEndY = seriesRegionStartY + regionLayoutRect.height; - return { - interactiveRange: { - minY: seriesRegionStartY, - maxY: seriesRegionEndY, - minX: seriesRegionStartX, - maxX: seriesRegionEndX - }, - xRange: [seriesRegionStartX, seriesRegionEndX], - yRange: [seriesRegionStartY, seriesRegionEndY] - } as BrushInteractiveRangeAttr; + private _initRegionAxisMap() { + // 如果配置了axis,则按配置 + // 如果没有配置axis,则默认所有axis + if (isValid(this._spec.axisId)) { + array(this._spec.axisId).forEach((axisId: string) => { + this._releatedAxes.push(this._option.getComponentByUserId(axisId) as AxisComponent); + }); + } else if (isValid(this._spec.axisIndex)) { + array(this._spec.axisIndex).forEach((axisIndex: number) => { + this._releatedAxes.push(this._option.getComponentByIndex('axes', axisIndex) as AxisComponent); + }); + } else { + this._releatedAxes = this._option.getComponentsByKey('axes') as AxisComponent[]; + } + + // 按照region进行分组,便于brush找到关联axis (brush -> region -> axis) + this._releatedAxes.forEach((axis: AxisComponent) => { + axis?.getRegions().forEach((region: IRegion) => { + if (this._regionAxisMap['region_' + region.id]) { + this._regionAxisMap['region_' + region.id].push(axis); + } else { + this._regionAxisMap['region_' + region.id] = [axis]; + } + }); + }); + } + + private _initAxisDataZoomMap() { + (this._option.getComponentsByKey('dataZoom') as DataZoom[]).forEach((dz: DataZoom) => { + if (dz.relatedAxisComponent) { + this._axisDataZoomMap[(dz.relatedAxisComponent as AxisComponent).id] = dz; + } + }); + } + + protected initEvent() { + // do nothing + } + onRender(ctx: IModelRenderOption): void { + // do nothing + } + changeRegions(regions: IRegion[]): void { + // do nothing + } + + _compareSpec(spec: T, prevSpec: T) { + if (this._brushComponents) { + // FIXME: 这个逻辑放在这个方法里不太妥当? + this._relativeRegions.forEach((region: IRegion, index: number) => { + this._updateBrushComponent(region, index); + }); + } + const result = super._compareSpec(spec, prevSpec); + if (!isEqual(prevSpec, spec)) { + result.reRender = true; + result.reMake = true; + } + return result; } + onLayoutEnd(ctx: any): void { + super.onLayoutEnd(ctx); + if (this._option.disableTriggerEvent) { + return; + } + const brushVisible = this._spec.visible ?? true; + if (brushVisible) { + if (!this._brushComponents) { + this._brushComponents = []; + this._relativeRegions.forEach((region: IRegion, index: number) => { + this._createBrushComponent(region, index); + }); + } else { + this._relativeRegions.forEach((region: IRegion, index: number) => { + this._updateBrushComponent(region, index); + }); + } + } + } + /*** end: abstract pipe ***/ + + /*** start: brush component ***/ protected _updateBrushComponent(region: IRegion, componentIndex: number) { const interactiveAttr = this._getBrushInteractiveAttr(region); // 布局变化后, 更新可交互范围 const brushComponent = this._brushComponents[componentIndex]; brushComponent.setAttributes(interactiveAttr as any); - // 布局变化后, 更新brush 和 图元状态 - // 方案一: - // TODO: 更新mask位置(保持选框在画布中的相对位置) - // TODO: 是否更新mask大小有待商榷(保持选框位置和图元高亮区域一致) - - // 方案二: 清空brushMask 和 图元高亮状态 + // 布局变化后,清空brushMask 和 重置图元高亮状态 this._initMarkBrushState(componentIndex, ''); brushComponent.children[0].removeAllChild(); - this._needInitOutState = true; } protected _createBrushComponent(region: IRegion, componentIndex: number) { @@ -188,11 +263,15 @@ export class Brush extends BaseComponent i }); brush.id = this._spec.id ?? `brush-${this.id}`; this.getContainer().add(brush as unknown as INode); - const { brushMode = 'single' } = this._spec; this._brushComponents.push(brush); this._cacheInteractiveRangeAttrs.push(interactiveAttr); - brush.addEventListener(BrushEvent.drawStart, (e: any) => { + brush.addEventListener(BrushEvent.brushActive, (e: any) => { + this._initMarkBrushState(componentIndex, OUT_BRUSH_STATE); + this._emitEvent(ChartEvent.brushActive, region); + }); + + brush.addEventListener(BrushEvent.brushStart, (e: any) => { this._emitEvent(ChartEvent.brushStart, region); }); @@ -201,48 +280,47 @@ export class Brush extends BaseComponent i }); brush.addEventListener(BrushEvent.drawing, (e: any) => { - // 需要重置out状态的情况: - // _needInitOutState:框选模式为'single' 且 开始后的第一次drawing时(这里不选择drawStart而选择第一次触发drawing的时机是因为点击空白处也会触发drawStart), 需要重置图元状态 - if (this._needInitOutState && brushMode === 'single') { - this._initMarkBrushState(componentIndex, OUT_BRUSH_STATE); - } - this._needInitOutState = false; this._needDisablePickable = true; - - this._handleBrushChange(ChartEvent.brushChange, region, e); + this._handleBrushChange(region, e); this._emitEvent(ChartEvent.brushChange, region); }); brush.addEventListener(BrushEvent.moving, (e: any) => { - this._handleBrushChange(ChartEvent.brushChange, region, e); + this._handleBrushChange(region, e); this._emitEvent(ChartEvent.brushChange, region); }); brush.addEventListener(BrushEvent.brushClear, (e: any) => { this._initMarkBrushState(componentIndex, ''); - this._needInitOutState = true; this._needDisablePickable = false; - this._handleBrushChange(ChartEvent.brushChange, region, e); - this._handleBrushChange(ChartEvent.brushClear, region, e); - this._emitEvent(ChartEvent.brushChange, region); this._emitEvent(ChartEvent.brushClear, region); }); brush.addEventListener(BrushEvent.drawEnd, (e: any) => { - this._needInitOutState = true; this._needDisablePickable = false; const { operateMask } = e.detail as any; - this._handleBrushChange(ChartEvent.brushEnd, region, e); - const inBrushData = this._extendDataInBrush(this._inBrushElementsMap); - if (!this._spec.zoomWhenEmpty && inBrushData.length > 0) { - this._setAxisAndDataZoom(operateMask, region); + if (this._spec?.onBrushEnd) { + // 如果onBrushEnd返回true,则清空brush, 并抛出clear事件 + if (this._spec.onBrushEnd(e) === true) { + this.clearGraphic(); + this._initMarkBrushState(componentIndex, ''); + this._needDisablePickable = false; + this._emitEvent(ChartEvent.brushClear, region); + } else { + this._spec.onBrushEnd(e); + this._emitEvent(ChartEvent.brushEnd, region); + } + } else { + const inBrushData = this._extendDataInBrush(this._inBrushElementsMap); + if (!this._spec.zoomWhenEmpty && inBrushData.length > 0) { + this._setAxisAndDataZoom(operateMask, region); + } + this._emitEvent(ChartEvent.brushEnd, region); } - this._emitEvent(ChartEvent.brushEnd, region); }); brush.addEventListener(BrushEvent.moveEnd, (e: any) => { const { operateMask } = e.detail as any; - this._handleBrushChange(ChartEvent.brushEnd, region, e); const inBrushData = this._extendDataInBrush(this._inBrushElementsMap); if (!this._spec.zoomWhenEmpty && inBrushData.length > 0) { this._setAxisAndDataZoom(operateMask, region); @@ -251,12 +329,75 @@ export class Brush extends BaseComponent i }); } - private _handleBrushChange(eventType: string, region: IRegion, e: any) { + protected _getBrushInteractiveAttr(region: IRegion) { + const regionLayoutPosition = region.getLayoutStartPoint(); + const regionLayoutRect = region.getLayoutRect(); + const seriesRegionStartX = regionLayoutPosition.x; + const seriesRegionEndX = seriesRegionStartX + regionLayoutRect.width; + const seriesRegionStartY = regionLayoutPosition.y; + const seriesRegionEndY = seriesRegionStartY + regionLayoutRect.height; + return { + interactiveRange: { + minY: seriesRegionStartY, + maxY: seriesRegionEndY, + minX: seriesRegionStartX, + maxX: seriesRegionEndX + }, + xRange: [seriesRegionStartX, seriesRegionEndX], + yRange: [seriesRegionStartY, seriesRegionEndY] + } as BrushInteractiveRangeAttr; + } + + private _transformBrushedMarkAttr(brushedStyle: selectedItemStyle) { + const styleResult: any = {}; + if (brushedStyle?.symbol) { + styleResult.symbolType = brushedStyle.symbol; + } + if (brushedStyle?.symbolSize) { + styleResult.size = brushedStyle.symbolSize; + } + if (brushedStyle?.color) { + styleResult.fill = brushedStyle.color; + } + if (brushedStyle?.colorAlpha) { + styleResult.fillOpacity = brushedStyle.colorAlpha; + } + return { + ...transformToGraphic(brushedStyle), + ...styleResult + }; + } + /*** end: brush component ***/ + + /*** start: event dispatch ***/ + private _handleBrushChange(region: IRegion, e: any) { const { operateMask } = e.detail as any; this._reconfigItem(operateMask, region); this._reconfigLinkedItem(operateMask, region); } + protected _extendDataInBrush(elementsMap: { [brushName: string]: { [elementKey: string]: IElement } }) { + const data = []; + for (const brushName in elementsMap) { + for (const elementKey in elementsMap[brushName]) { + data.push({ + ...elementsMap[brushName][elementKey]?.data?.[0] + }); + } + } + return data; + } + + protected _extendDatumOutOfBrush(elementsMap: { [elementKey: string]: IElement }) { + const data = []; + for (const elementKey in elementsMap) { + // 图例筛选后, elementKey未更新, 导致data可能为null + // FIXME: brush透出的map维护逻辑有待优化 + data.push(elementsMap[elementKey].data?.[0]); + } + return data; + } + private _emitEvent(eventType: string, region: IRegion) { this.event.emit(eventType, { model: this, @@ -283,40 +424,44 @@ export class Brush extends BaseComponent i linkedOutOfBrushElementsMap: this._linkedOutOfBrushElementsMap, // 缩放记录 zoomRecord: this._zoomRecord - } + }, + vchart: this._option?.globalInstance }); } + /*** end: event dispatch ***/ - private _transformBrushedMarkAttr(brushedStyle: selectedItemStyle) { - const styleResult: any = {}; - if (brushedStyle?.symbol) { - styleResult.symbolType = brushedStyle.symbol; - } - if (brushedStyle?.symbolSize) { - styleResult.size = brushedStyle.symbolSize; - } - if (brushedStyle?.color) { - styleResult.fill = brushedStyle.color; - } - if (brushedStyle?.colorAlpha) { - styleResult.fillOpacity = brushedStyle.colorAlpha; + /** start: set mark state ***/ + private _reconfigItem(operateMask: IPolygon, region: IRegion) { + if (!operateMask?.globalTransMatrix || !operateMask?.attribute?.points) { + return; } - return { - ...transformToGraphic(brushedStyle), - ...styleResult - }; - } - private _reconfigItem(operateMask: IPolygon, region: IRegion) { + // 根据变换矩阵得到brushMask的实际坐标 + const points = operateMask?.attribute?.points ?? []; + const { a, b, c, d, e, f } = operateMask.globalTransMatrix; + const pointsCoord = points.map((p: IPointLike) => { + return { + x: a * p.x + c * p.y + e, + y: b * p.x + d * p.y + f + }; + }); + const { markTypeFilter = [] } = this._spec; + // 遍历图元, 更新状态 this._itemMap[region.id].forEach((mark: IMark) => { + if (markTypeFilter.includes(mark.type)) { + return; + } const grammarMark = mark.getProduct(); + if (!grammarMark || !grammarMark.elements || !grammarMark.elements.length) { return; } + const elements = grammarMark.elements; elements.forEach((el: IElement) => { const graphicItem = el.getGraphicItem(); + const elementKey = mark.id + '_' + el.key; // 判断逻辑: // 应该被置为inBrush状态的图元: @@ -326,17 +471,15 @@ export class Brush extends BaseComponent i // 应该被置为outOfBrush状态的图元: // before: 在当前brush 的 in brush element map中, 即在当前brush中 // now: 不在当前brush中 - if (this._outOfBrushElementsMap?.[elementKey] && this._isBrushContainItem(operateMask, graphicItem)) { + const isBrushContainItem = this._isBrushContainItem(operateMask.globalAABBBounds, pointsCoord, graphicItem); + if (this._outOfBrushElementsMap?.[elementKey] && isBrushContainItem) { el.addState(IN_BRUSH_STATE); if (!this._inBrushElementsMap[operateMask?.name]) { this._inBrushElementsMap[operateMask?.name] = {}; } this._inBrushElementsMap[operateMask?.name][elementKey] = el; delete this._outOfBrushElementsMap[elementKey]; - } else if ( - this._inBrushElementsMap?.[operateMask?.name]?.[elementKey] && - !this._isBrushContainItem(operateMask, graphicItem) - ) { + } else if (this._inBrushElementsMap?.[operateMask?.name]?.[elementKey] && !isBrushContainItem) { el.removeState(IN_BRUSH_STATE); el.addState(OUT_BRUSH_STATE); this._outOfBrushElementsMap[elementKey] = el; @@ -348,6 +491,10 @@ export class Brush extends BaseComponent i } private _reconfigLinkedItem(operateMask: IPolygon, region: IRegion) { + if (!operateMask?.globalTransMatrix || !operateMask?.attribute?.points) { + return; + } + const regionLayoutPos = region.getLayoutStartPoint(); const seriesId = region.getSeries().map(s => s.id); this._linkedSeries.forEach((s: ISeries) => { @@ -357,7 +504,34 @@ export class Brush extends BaseComponent i const regionOffsetX = sRegionLayoutPos.x - regionLayoutPos.x; const regionOffsetY = sRegionLayoutPos.y - regionLayoutPos.y; + // 根据变换矩阵得到brushMask的实际坐标 + const points = operateMask?.attribute?.points ?? []; + const { a, b, c, d, e, f } = operateMask.globalTransMatrix; + + const dx = regionOffsetX || 0; + const dy = regionOffsetY || 0; + + const pointsCoord = points.map((p: IPointLike) => { + return { + x: a * p.x + c * p.y + e + dx, + y: b * p.x + d * p.y + f + dy + }; + }); + + operateMask.globalAABBBounds + .clone() + .set( + operateMask.globalAABBBounds.x1 + dx, + operateMask.globalAABBBounds.y1 + dy, + operateMask.globalAABBBounds.x2 + dx, + operateMask.globalAABBBounds.y2 + dy + ); + + const { markTypeFilter = [] } = this._spec; this._linkedItemMap[s.id].forEach((mark: IMark) => { + if (markTypeFilter.includes(mark.type)) { + return; + } const grammarMark = mark.getProduct(); if (!grammarMark || !grammarMark.elements || !grammarMark.elements.length) { return; @@ -376,7 +550,7 @@ export class Brush extends BaseComponent i // now: 不在当前brush中 if ( this._linkedOutOfBrushElementsMap?.[elementKey] && - this._isBrushContainItem(operateMask, graphicItem, { dx: regionOffsetX, dy: regionOffsetY }) + this._isBrushContainItem(operateMask.globalAABBBounds, pointsCoord, graphicItem) ) { el.addState(IN_BRUSH_STATE); if (!this._linkedInBrushElementsMap[operateMask?.name]) { @@ -386,7 +560,7 @@ export class Brush extends BaseComponent i delete this._linkedOutOfBrushElementsMap[elementKey]; } else if ( this._linkedInBrushElementsMap?.[operateMask?.name]?.[elementKey] && - !this._isBrushContainItem(operateMask, graphicItem, { dx: regionOffsetX, dy: regionOffsetY }) + !this._isBrushContainItem(operateMask.globalAABBBounds, pointsCoord, graphicItem) ) { el.removeState(IN_BRUSH_STATE); el.addState(OUT_BRUSH_STATE); @@ -399,89 +573,89 @@ export class Brush extends BaseComponent i }); } - private _isBrushContainItem(brushMask: IPolygon, item: IGraphic, linkedOffset?: { dx: number; dy: number }) { - if (!brushMask?.globalTransMatrix || !brushMask?.attribute?.points) { - return false; - } - - // 根据变换矩阵得到brushMask的实际坐标 - const points = brushMask?.attribute?.points ?? []; - const { a, b, c, d, e, f } = brushMask.globalTransMatrix; - - const dx = linkedOffset?.dx || 0; - const dy = linkedOffset?.dy || 0; - - const pointsCoord = points.map((p: IPointLike) => { - return { - x: a * p.x + c * p.y + e + dx, - y: b * p.x + d * p.y + f + dy - }; - }); - - brushMask.globalAABBBounds - .clone() - .set( - brushMask.globalAABBBounds.x1 + dx, - brushMask.globalAABBBounds.y1 + dy, - brushMask.globalAABBBounds.x2 + dx, - brushMask.globalAABBBounds.y2 + dy - ); - - // 根据变换矩阵得到item的实际坐标 - const x = item.globalTransMatrix.e; - const y = item.globalTransMatrix.f; - + private _isBrushContainItem(brushMaskAABBBounds: IBounds, brushMaskPointsCoord: IPointLike[], item: IGraphic) { // brush与图表图元进行相交 或 包含判断 let itemBounds: { x: number; y: number }[] = []; - if (item.type === 'symbol') { - const { size: itemSize = 0 } = item?.attribute as ISymbolGraphicAttribute; - const size = array(itemSize)[0] / 2; + if (['symbol', 'rect'].includes(item.type)) { + const { x1, x2, y1, y2 } = item?.globalAABBBounds; itemBounds = [ { - x: x - size, - y: y - size + x: x1, + y: y1 }, { - x: x + size, - y: y - size + x: x2, + y: y1 }, { - x: x + size, - y: y + size + x: x2, + y: y2 }, { - x: x - size, - y: y + size + x: x1, + y: y2 } ]; - return polygonIntersectPolygon(pointsCoord, itemBounds); - } else if (item.type === 'rect') { - const { x1, x2, y1, y2 } = item?.AABBBounds; - const width = Math.abs(x1 - x2); - const height = Math.abs(y1 - y2); - itemBounds = [ - { - x: x, - y: y - }, - { - x: x + width, - y: y - }, - { - x: x + width, - y: y + height - }, - { - x: x, - y: y + height - } - ]; - return polygonIntersectPolygon(pointsCoord, itemBounds); + return polygonIntersectPolygon(brushMaskPointsCoord, itemBounds); } - return brushMask.globalAABBBounds.intersects(item.globalAABBBounds); + return brushMaskAABBBounds.intersects(item.globalAABBBounds); } + protected _initMarkBrushState(componentIndex: number, stateName: string) { + this._brushComponents.forEach((brush, index) => { + if (index !== componentIndex) { + brush.children[0].removeAllChild(); + } + }); + + this._inBrushElementsMap = {}; + this._outOfBrushElementsMap = {}; + this._linkedInBrushElementsMap = {}; + this._linkedOutOfBrushElementsMap = {}; + const { markTypeFilter = [] } = this._spec; + + Object.entries(this._itemMap).forEach(([regionId, marks]) => { + marks.forEach((mark: IMark) => { + if (markTypeFilter.includes(mark.type)) { + return; + } + const grammarMark = mark.getProduct(); + if (!grammarMark || !grammarMark.elements || !grammarMark.elements.length) { + return; + } + const elements = grammarMark.elements; + elements.forEach((el: IElement) => { + const elementKey = mark.id + '_' + el.key; + el.removeState(IN_BRUSH_STATE); + el.removeState(OUT_BRUSH_STATE); + el.addState(stateName); + this._outOfBrushElementsMap[elementKey] = el; + }); + }); + }); + Object.entries(this._linkedItemMap).forEach(([seriesId, marks]) => { + marks.forEach((mark: IMark) => { + if (markTypeFilter.includes(mark.type)) { + return; + } + const grammarMark = mark.getProduct(); + if (!grammarMark || !grammarMark.elements || !grammarMark.elements.length) { + return; + } + const elements = grammarMark.elements; + elements.forEach((el: IElement) => { + const elementKey = mark.id + '_' + el.key; + el.removeState(IN_BRUSH_STATE); + el.removeState(OUT_BRUSH_STATE); + el.addState(stateName); + this._linkedOutOfBrushElementsMap[elementKey] = el; + }); + }); + }); + } + /** end: set mark state ***/ + + /** start: control data zoom ***/ private _stateClamp(state: number) { return Math.min(Math.max(0, state), 1); } @@ -559,167 +733,12 @@ export class Brush extends BaseComponent i } } - protected _bindRegions() { - if (isValid(this._spec.regionId) && isValid(this._spec.regionIndex)) { - this._relativeRegions = this._option.getAllRegions(); - } - this._relativeRegions = this._option.getRegionsInUserIdOrIndex( - array(this._spec.regionId), - array(this._spec.regionIndex) - ); - } - - protected _bindLinkedSeries() { - if (isValid(this._spec.brushLinkSeriesId) && isValid(this._spec.brushLinkSeriesIndex)) { - return; - } - this._linkedSeries = this._option.getSeriesInUserIdOrIndex( - array(this._spec.brushLinkSeriesId), - array(this._spec.brushLinkSeriesIndex) - ); - } - - private _initRegionAxisMap() { - // 如果配置了axis,则按配置 - // 如果没有配置axis,则默认所有axis - if (isValid(this._spec.axisId)) { - array(this._spec.axisId).forEach((axisId: string) => { - this._releatedAxes.push(this._option.getComponentByUserId(axisId) as AxisComponent); - }); - } else if (isValid(this._spec.axisIndex)) { - array(this._spec.axisIndex).forEach((axisIndex: number) => { - this._releatedAxes.push(this._option.getComponentByIndex('axes', axisIndex) as AxisComponent); - }); - } else { - this._releatedAxes = this._option.getComponentsByKey('axes') as AxisComponent[]; - } - - // 按照region进行分组,便于brush找到关联axis (brush -> region -> axis) - this._releatedAxes.forEach((axis: AxisComponent) => { - axis?.getRegions().forEach((region: IRegion) => { - if (this._regionAxisMap['region_' + region.id]) { - this._regionAxisMap['region_' + region.id].push(axis); - } else { - this._regionAxisMap['region_' + region.id] = [axis]; - } - }); - }); - } - - private _initAxisDataZoomMap() { - (this._option.getComponentsByKey('dataZoom') as DataZoom[]).forEach((dz: DataZoom) => { - if (dz.relatedAxisComponent) { - this._axisDataZoomMap[(dz.relatedAxisComponent as AxisComponent).id] = dz; - } - }); - } - - private _initNeedOperatedItem() { - const seriesUserId = this._spec.seriesId; - const seriesIndex = this._spec.seriesIndex; - this._relativeRegions.forEach(r => { - const allMarks: IMark[] = []; - r.getSeries().forEach((s: ISeries) => { - if ( - (seriesUserId && array(seriesUserId).includes(s.userId.toString())) || - (seriesIndex && array(seriesIndex).includes(s.getSpecIndex())) || - (!seriesIndex && !seriesUserId) - ) { - allMarks.push(...s.getMarksWithoutRoot()); - } - this._itemMap[r.id] = allMarks; - }); - }); - - this._linkedSeries.forEach(s => { - this._linkedItemMap[s.id] = s.getMarksWithoutRoot(); - }); - } - - protected _initMarkBrushState(componentIndex: number, stateName: string) { - this._brushComponents.forEach((brush, index) => { - if (index !== componentIndex) { - brush.children[0].removeAllChild(); - } - }); - - this._inBrushElementsMap = {}; - this._outOfBrushElementsMap = {}; - this._linkedInBrushElementsMap = {}; - this._linkedOutOfBrushElementsMap = {}; - - this._option.getAllSeries().forEach((s: ISeries) => { - s.getMarksWithoutRoot().forEach((mark: IMark) => { - const grammarMark = mark.getProduct(); - if (!grammarMark || !grammarMark.elements || !grammarMark.elements.length) { - return; - } - const elements = grammarMark.elements; - elements.forEach((el: IElement) => { - const elementKey = mark.id + '_' + el.key; - el.removeState(IN_BRUSH_STATE); - el.removeState(OUT_BRUSH_STATE); - el.addState(stateName); - this._outOfBrushElementsMap[elementKey] = el; - this._linkedOutOfBrushElementsMap[elementKey] = el; - }); - }); - }); - } - - protected initEvent() { - // do nothing - } - onRender(ctx: IModelRenderOption): void { - // do nothing - } - changeRegions(regions: IRegion[]): void { - // do nothing - } + /** end: control data zoom ***/ protected _getNeedClearVRenderComponents(): IGraphic[] { return this._brushComponents as unknown as IGroup[]; } - /** - * updateSpec - */ - _compareSpec(spec: T, prevSpec: T) { - if (this._brushComponents) { - // FIXME: 这个逻辑放在这个方法里不太妥当? - this._relativeRegions.forEach((region: IRegion, index: number) => { - this._updateBrushComponent(region, index); - }); - } - const result = super._compareSpec(spec, prevSpec); - if (!isEqual(prevSpec, spec)) { - result.reRender = true; - result.reMake = true; - } - return result; - } - - onLayoutEnd(ctx: any): void { - super.onLayoutEnd(ctx); - if (this._option.disableTriggerEvent) { - return; - } - const brushVisible = this._spec.visible ?? true; - if (brushVisible) { - // 创建或更新marker组件 - if (!this._brushComponents) { - this._brushComponents = []; - this._relativeRegions.forEach((region: IRegion, index: number) => { - this._createBrushComponent(region, index); - }); - } else { - this._relativeRegions.forEach((region: IRegion, index: number) => { - this._updateBrushComponent(region, index); - }); - } - } - } - clearGraphic(): void { if (this._brushComponents) { this._brushComponents.forEach(brush => { @@ -731,7 +750,11 @@ export class Brush extends BaseComponent i clear(): void { if (this._brushComponents) { const container = this.getContainer(); - this._brushComponents.forEach(brush => { + this._brushComponents.forEach((brush, index) => { + // 清空元素状态 + this._initMarkBrushState(index, ''); + this._needDisablePickable = false; + brush.removeAllChild(); brush.releaseBrushEvents(); diff --git a/packages/vchart/src/component/brush/interface.ts b/packages/vchart/src/component/brush/interface.ts index c261a364e1..b20255f73f 100644 --- a/packages/vchart/src/component/brush/interface.ts +++ b/packages/vchart/src/component/brush/interface.ts @@ -15,11 +15,11 @@ interface IBrushDataBindSpec { */ regionId?: string | string[]; // 默认为所有region /** - * 可刷取的seriesIndex + * 可刷取的seriesIndex(在可刷取的region范围内) */ seriesIndex?: number | number[]; // 默认为所有系列 /** - * 可刷取的seriesId + * 可刷取的seriesId(在可刷取的region范围内) */ seriesId?: string | string[]; // 默认为所有系列 /** @@ -117,6 +117,17 @@ export interface IBrushTheme { * @since 1.2.0 */ sizeThreshold?: number; + /** + * 不需要被brush操作的mark类型 + * @since 1.13.9 + */ + markTypeFilter?: string[]; + /** + * 自定义brush事件, 触发时机: 框选结束 + * 返回true, 则清空brush + * @since 1.13.9 + */ + onBrushEnd: (e: any) => boolean; } export interface IBrushSpec extends IBrushTheme, IBrushDataBindSpec { diff --git a/packages/vchart/src/component/marker/mark-area/base-mark-area.ts b/packages/vchart/src/component/marker/mark-area/base-mark-area.ts index b7e99c906f..44a9a4ae7b 100644 --- a/packages/vchart/src/component/marker/mark-area/base-mark-area.ts +++ b/packages/vchart/src/component/marker/mark-area/base-mark-area.ts @@ -13,6 +13,7 @@ import { transformToGraphic } from '../../../util/style'; import { BaseMarker } from '../base-marker'; import { LayoutZIndex } from '../../../constant/layout'; import type { IGroup } from '@visactor/vrender-core'; +import { array } from '@visactor/vutils'; export abstract class BaseMarkArea extends BaseMarker implements IMarkArea { static specKey = 'markArea'; specKey = 'markArea'; @@ -35,7 +36,7 @@ export abstract class BaseMarkArea extends BaseMarker implements } protected _createMarkerComponent() { - const label = this._spec.label ?? {}; + const label = array(this._spec.label ?? {}); const markAreaAttrs: MarkAreaAttrs | MarkArcAreaAttrs = { zIndex: this.layoutZIndex, interactive: this._spec.interactive ?? true, @@ -61,15 +62,17 @@ export abstract class BaseMarkArea extends BaseMarker implements this._markAttributeContext ), clipInRange: this._spec.clip ?? false, - label: transformLabelAttributes(label, this._markerData, this._markAttributeContext), + label: label.map((labelItem: any) => { + return transformLabelAttributes(labelItem, this._markerData, this._markAttributeContext); + }), state: { area: transformState(this._spec.area?.state, this._markerData, this._markAttributeContext), - label: transformState(this._spec.label?.state, this._markerData, this._markAttributeContext), - labelBackground: transformState( - this._spec?.label?.labelBackground?.state, - this._markerData, - this._markAttributeContext - ) + label: label.map((labelItem: any) => { + return transformState(labelItem.state, this._markerData, this._markAttributeContext); + }), + labelBackground: label.map((labelItem: any) => { + return transformState(labelItem.labelBackground?.state, this._markerData, this._markAttributeContext); + }) }, animation: this._spec.animation ?? false, animationEnter: this._spec.animationEnter, @@ -98,7 +101,7 @@ export abstract class BaseMarkArea extends BaseMarker implements : seriesData; let limitRect; - if (spec.clip || spec.label?.confine) { + if (spec.clip || array(spec.label).some(labelCfg => labelCfg?.confine)) { const { minX, maxX, minY, maxY } = computeClipRange([ startRelativeSeries.getRegion(), endRelativeSeries.getRegion(), @@ -113,15 +116,21 @@ export abstract class BaseMarkArea extends BaseMarker implements } if (this._markerComponent) { + const prevLabelAttrs = array(this._markerComponent.attribute?.label); + const specLabels = array(this._spec.label); + this._markerComponent.setAttributes({ ...pointsAttr, - label: { - ...this._markerComponent.attribute?.label, - text: this._spec.label.formatMethod - ? // type error here will be fixed in components - (this._spec.label.formatMethod(dataPoints, seriesData) as any) - : this._markerComponent.attribute?.label?.text - }, + label: prevLabelAttrs.map((prevLabel, index) => { + const specLabel = specLabels[index] || {}; + return { + ...prevLabel, + text: specLabel.formatMethod + ? // type error here will be fixed in components + (specLabel.formatMethod(dataPoints, seriesData) as any) + : prevLabel?.text + }; + }), limitRect, dx: this._layoutOffsetX, dy: this._layoutOffsetY diff --git a/packages/vchart/src/component/marker/mark-area/interface/theme.ts b/packages/vchart/src/component/marker/mark-area/interface/theme.ts index 07987497d7..c61c81874c 100644 --- a/packages/vchart/src/component/marker/mark-area/interface/theme.ts +++ b/packages/vchart/src/component/marker/mark-area/interface/theme.ts @@ -2,18 +2,21 @@ import type { IMarkAreaLabelPosition, IMarkCommonArcLabelPosition } from '@visac import type { IArcMarkSpec, IPolygonMarkSpec } from '../../../../typings'; import type { IMarkerLabelWithoutRefSpec, IMarkerState } from '../../interface'; +export type IMarkAreaLabel = { + /** + * label整体 - 相对line的位置 + */ + position?: keyof typeof IMarkAreaLabelPosition | IMarkCommonArcLabelPosition; +} & IMarkerLabelWithoutRefSpec; + export interface IMarkAreaTheme { /** * 标记区域的样式 */ area?: Partial>; /** - * 标记区域的标签样式配置 + * 标记区域的标签样式配置。 + * 自 1.13.9 版本开始,支持创建多个标签 */ - label?: { - /** - * label整体 - 相对line的位置 - */ - position?: keyof typeof IMarkAreaLabelPosition | IMarkCommonArcLabelPosition; - } & IMarkerLabelWithoutRefSpec; + label?: IMarkAreaLabel | IMarkAreaLabel[]; } diff --git a/packages/vchart/src/component/marker/mark-line/base-mark-line.ts b/packages/vchart/src/component/marker/mark-line/base-mark-line.ts index 8312250c81..be268c5a25 100644 --- a/packages/vchart/src/component/marker/mark-line/base-mark-line.ts +++ b/packages/vchart/src/component/marker/mark-line/base-mark-line.ts @@ -19,6 +19,7 @@ import type { IMarkerSymbol } from '../interface'; import { markerRegression } from '../../../data/transforms/regression'; import { LayoutZIndex } from '../../../constant/layout'; import { markerFilter } from '../../../data/transforms/marker-filter'; +import { array } from '@visactor/vutils'; export abstract class BaseMarkLine extends BaseMarker implements IMarkLine { static specKey = 'markLine'; @@ -49,11 +50,8 @@ export abstract class BaseMarkLine extends BaseMarker implements } protected _createMarkerComponent() { - const { - label = {}, - startSymbol = {} as IMarkerSymbol, - endSymbol = {} as IMarkerSymbol - } = this._spec as IMarkLineSpec; + const { startSymbol = {} as IMarkerSymbol, endSymbol = {} as IMarkerSymbol } = this._spec as IMarkLineSpec; + const label = array(this._spec.label ?? {}); const markLineAttrs: MarkLineAttrs | MarkArcLineAttrs = { zIndex: this.layoutZIndex, @@ -77,7 +75,9 @@ export abstract class BaseMarkLine extends BaseMarker implements this._markAttributeContext ), clipInRange: this._spec.clip ?? false, - label: transformLabelAttributes(label, this._markerData, this._markAttributeContext), + label: label.map(labelItem => { + return transformLabelAttributes(labelItem, this._markerData, this._markAttributeContext); + }), state: { line: transformState(this._spec.line?.state ?? {}, this._markerData, this._markAttributeContext), lineStartSymbol: transformState( @@ -86,12 +86,12 @@ export abstract class BaseMarkLine extends BaseMarker implements this._markAttributeContext ), lineEndSymbol: transformState(this._spec.endSymbol?.state ?? {}, this._markerData, this._markAttributeContext), - label: transformState(this._spec?.label?.state ?? {}, this._markerData, this._markAttributeContext), - labelBackground: transformState( - this._spec?.label?.labelBackground?.state ?? {}, - this._markerData, - this._markAttributeContext - ) + label: label.map(labelItem => { + return transformState(labelItem.state ?? {}, this._markerData, this._markAttributeContext); + }), + labelBackground: label.map(labelItem => { + return transformState(labelItem.labelBackground?.state ?? {}, this._markerData, this._markAttributeContext); + }) }, animation: this._spec.animation ?? false, animationEnter: this._spec.animationEnter, @@ -140,7 +140,7 @@ export abstract class BaseMarkLine extends BaseMarker implements data.latestData[0] && data.latestData[0].latestData ? data.latestData[0].latestData : data.latestData; let limitRect; - if (spec.clip || spec.label?.confine) { + if (spec.clip || array(spec.label).some(labelCfg => labelCfg?.confine)) { const { minX, maxX, minY, maxY } = computeClipRange([ startRelativeSeries.getRegion(), endRelativeSeries.getRegion(), @@ -154,13 +154,16 @@ export abstract class BaseMarkLine extends BaseMarker implements }; } const markerComponentAttr = this._markerComponent?.attribute ?? {}; - const labelAttrs = { - ...markerComponentAttr.label, - text: this._spec.label.formatMethod - ? this._spec.label.formatMethod(dataPoints, seriesData) - : markerComponentAttr.label?.text - }; - + const prevLabelAttrs = array(markerComponentAttr.label); + const specLabels = array(this._spec.label); + + const labelAttrs = prevLabelAttrs.map((prevLabel, index) => { + const specLabel = specLabels[index] || {}; + return { + ...prevLabel, + text: specLabel.formatMethod ? (specLabel.formatMethod(dataPoints, seriesData) as any) : prevLabel?.text + }; + }); return { ...pointsAttr, label: labelAttrs as MarkLineComponent['attribute']['label'], diff --git a/packages/vchart/src/component/marker/mark-line/cartesian-mark-line.ts b/packages/vchart/src/component/marker/mark-line/cartesian-mark-line.ts index e6a500784d..94d7c17457 100644 --- a/packages/vchart/src/component/marker/mark-line/cartesian-mark-line.ts +++ b/packages/vchart/src/component/marker/mark-line/cartesian-mark-line.ts @@ -8,7 +8,7 @@ import { MarkLine as MarkLineComponent, registerMarkLineAnimate } from '@visactor/vrender-components'; -import { isValid, isValidNumber } from '@visactor/vutils'; +import { array, isValid, isValidNumber } from '@visactor/vutils'; import type { IDataPos, IMarkProcessOptions } from '../interface'; import { getInsertPoints, getTextOffset } from './util'; import { Factory } from '../../../core/factory'; @@ -105,7 +105,7 @@ export class CartesianMarkLine extends BaseMarkLine { } else { expandDistanceValue = expandDistance as number; } - const { points, label, limitRect } = updateAttrs; + const { points, limitRect } = updateAttrs; const joinPoints = getInsertPoints( (points as IPoint[])[0], @@ -119,33 +119,20 @@ export class CartesianMarkLine extends BaseMarkLine { // 如果用户配置了主线段,则不进行 label 的偏移处理,直接显示在主线段中间 labelPositionAttrs = { position: 'middle', - autoRotate: false, - refX: 0, - refY: 0 + autoRotate: false }; } else { labelPositionAttrs = { position: 'start', autoRotate: false, - ...getTextOffset((points as IPoint[])[0], (points as IPoint[])[1], connectDirection, expandDistanceValue), - refX: 0, - refY: 0 + ...getTextOffset((points as IPoint[])[0], (points as IPoint[])[1], connectDirection, expandDistanceValue) }; } - if (isValidNumber(this._spec.label?.refX)) { - labelPositionAttrs.refX += this._spec.label.refX; - } - if (isValidNumber(this._spec.label?.refY)) { - labelPositionAttrs.refY += this._spec.label.refY; - } - if (isValidNumber(this._spec.label?.dx)) { - labelPositionAttrs.dx = (labelPositionAttrs.dx || 0) + this._spec.label.dx; - } - if (isValidNumber(this._spec.label?.dy)) { - labelPositionAttrs.dy = (labelPositionAttrs.dy || 0) + this._spec.label.dy; - } const markerComponentAttr = this._markerComponent?.attribute ?? {}; + const prevLabelAttrs = array(markerComponentAttr.label); + const updateLabels = array(updateAttrs.label); + const labelsInSpec = array(this._spec.label); this._markerComponent?.setAttributes({ points: multiSegment ? [ @@ -154,15 +141,38 @@ export class CartesianMarkLine extends BaseMarkLine { [joinPoints[2], joinPoints[3]] ] : joinPoints, - label: { - ...label, - ...labelPositionAttrs, - textStyle: { - ...markerComponentAttr.label.textStyle, - textAlign: 'center', - textBaseline: 'middle' + label: updateLabels.map((labelItem, index) => { + let refX = 0; + let refY = 0; + let dx = labelPositionAttrs.dx ?? 0; + let dy = labelPositionAttrs.dy ?? 0; + const labelSpec = labelsInSpec[index] ?? labelsInSpec[0]; + if (isValidNumber(labelSpec?.refX)) { + refX += labelSpec.refX; + } + if (isValidNumber(labelSpec?.refY)) { + refY += labelSpec.refY; + } + if (isValidNumber(labelSpec?.dx)) { + dx += labelSpec.dx; + } + if (isValidNumber(labelSpec?.dy)) { + dy += labelSpec.dy; } - }, + return { + ...labelItem, + ...labelPositionAttrs, + refX, + refY, + dx, + dy, + textStyle: { + ...prevLabelAttrs[index]?.textStyle, + textAlign: 'center', + textBaseline: 'middle' + } + }; + }), limitRect, multiSegment, mainSegmentIndex, diff --git a/packages/vchart/src/component/marker/mark-line/interface/theme.ts b/packages/vchart/src/component/marker/mark-line/interface/theme.ts index 54688f2e1e..34c5aedfef 100644 --- a/packages/vchart/src/component/marker/mark-line/interface/theme.ts +++ b/packages/vchart/src/component/marker/mark-line/interface/theme.ts @@ -2,20 +2,23 @@ import type { IMarkCommonArcLabelPosition, IMarkLineLabelPosition } from '@visac import type { IArcMarkSpec, ILineMarkSpec } from '../../../../typings'; import type { IMarkerLabelSpec, IMarkerState, IMarkerSymbol } from '../../interface'; +export type IMarkLineLabel = { + /** + * label整体 - 相对line的位置 + */ + position?: keyof typeof IMarkLineLabelPosition | IMarkCommonArcLabelPosition; +} & IMarkerLabelSpec; + export interface IMarkLineTheme { /** * 标注线的线样式 */ line?: Partial>; /** - * 标注线的标签样式 + * 标注线的标签样式。 + * 自 1.13.9 版本开始,支持创建多个标签。 */ - label?: { - /** - * label整体 - 相对line的位置 - */ - position?: keyof typeof IMarkLineLabelPosition | IMarkCommonArcLabelPosition; - } & IMarkerLabelSpec; + label?: IMarkLineLabel | IMarkLineLabel[]; /** * 线标注起点symbol样式 diff --git a/packages/vchart/src/constant/event.ts b/packages/vchart/src/constant/event.ts index c5d3673507..b8511c417c 100644 --- a/packages/vchart/src/constant/event.ts +++ b/packages/vchart/src/constant/event.ts @@ -96,6 +96,7 @@ export enum ChartEvent { brushStart = 'brushStart', brushChange = 'brushChange', brushEnd = 'brushEnd', + brushActive = 'brushActive', brushClear = 'brushClear', // legend legendSelectedDataChange = 'legendSelectedDataChange', diff --git a/packages/vstory/package.json b/packages/vstory/package.json index c843ef3885..aedd7acd35 100644 --- a/packages/vstory/package.json +++ b/packages/vstory/package.json @@ -21,10 +21,10 @@ }, "dependencies": { "@visactor/vchart": "workspace:1.11.0", - "@visactor/vrender-core": "0.22.6", - "@visactor/vrender-kits": "0.22.6", - "@visactor/vrender-components": "0.22.6", - "@visactor/vutils": "~0.19.4" + "@visactor/vrender-core": "0.22.8", + "@visactor/vrender-kits": "0.22.8", + "@visactor/vrender-components": "0.22.8", + "@visactor/vutils": "~0.19.5" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vutils-extension/package.json b/packages/vutils-extension/package.json index bbe4003203..6f1b3c7540 100644 --- a/packages/vutils-extension/package.json +++ b/packages/vutils-extension/package.json @@ -25,8 +25,8 @@ "test-watch": "DEBUG_MODE=1 jest --watch" }, "dependencies": { - "@visactor/vutils": "~0.19.4", - "@visactor/vdataset": "~0.19.4" + "@visactor/vutils": "~0.19.5", + "@visactor/vdataset": "~0.19.5" }, "devDependencies": { "@internal/bundler": "workspace:*", @@ -67,4 +67,4 @@ "url": "https://www.visactor.io/" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/tools/story-player/package.json b/tools/story-player/package.json index 6be0042412..ecc35fc205 100644 --- a/tools/story-player/package.json +++ b/tools/story-player/package.json @@ -56,10 +56,10 @@ "vite": "3.2.6" }, "dependencies": { - "@visactor/vrender-core": "0.22.6", - "@visactor/vrender-kits": "0.22.6", + "@visactor/vrender-core": "0.22.8", + "@visactor/vrender-kits": "0.22.8", "@visactor/vchart": "workspace:1.13.8", - "@visactor/vrender": "0.22.6", - "@visactor/vutils": "~0.19.4" + "@visactor/vrender": "0.22.8", + "@visactor/vutils": "~0.19.5" } -} +} \ No newline at end of file