diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..5c7247b40 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 275ed7a8b..abb3a6bdd 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -22,7 +22,7 @@ importers: specifier: ~0.5.7 version: 0.5.7 '@visactor/vrender': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../packages/vrender '@visactor/vutils': specifier: 1.0.6 @@ -95,7 +95,7 @@ importers: ../../packages/react-vrender: dependencies: '@visactor/vrender': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender '@visactor/vutils': specifier: 1.0.6 @@ -153,10 +153,10 @@ importers: ../../packages/react-vrender-utils: dependencies: '@visactor/react-vrender': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../react-vrender '@visactor/vrender': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender '@visactor/vutils': specifier: 1.0.6 @@ -211,13 +211,13 @@ importers: ../../packages/vrender: dependencies: '@visactor/vrender-animate': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-animate '@visactor/vrender-core': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-core '@visactor/vrender-kits': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-kits devDependencies: '@internal/bundler': @@ -284,7 +284,7 @@ importers: ../../packages/vrender-animate: dependencies: '@visactor/vrender-core': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-core '@visactor/vutils': specifier: 1.0.6 @@ -342,13 +342,13 @@ importers: ../../packages/vrender-components: dependencies: '@visactor/vrender-animate': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-animate '@visactor/vrender-core': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-core '@visactor/vrender-kits': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-kits '@visactor/vscale': specifier: 1.0.6 @@ -467,7 +467,7 @@ importers: specifier: 2.4.1 version: 2.4.1 '@visactor/vrender-core': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../vrender-core '@visactor/vutils': specifier: 1.0.6 @@ -583,19 +583,19 @@ importers: ../../tools/bugserver-trigger: dependencies: '@visactor/vrender': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../../packages/vrender '@visactor/vrender-animate': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../../packages/vrender-animate '@visactor/vrender-components': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../../packages/vrender-components '@visactor/vrender-core': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../../packages/vrender-core '@visactor/vrender-kits': - specifier: workspace:1.0.13 + specifier: workspace:1.0.14 version: link:../../packages/vrender-kits devDependencies: '@internal/bundler': diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 12f6b8ddf..ec39e3ab2 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -1 +1 @@ -[{"definitionName":"lockStepVersion","policyName":"vrenderMain","version":"1.0.13","nextBump":"patch"}] +[{"definitionName":"lockStepVersion","policyName":"vrenderMain","version":"1.0.14","nextBump":"patch"}] diff --git a/docs/assets/changelog/en/changelog.md b/docs/assets/changelog/en/changelog.md index 90490b1e6..5068e4c93 100644 --- a/docs/assets/changelog/en/changelog.md +++ b/docs/assets/changelog/en/changelog.md @@ -1,3 +1,20 @@ +# v1.0.13 + +2025-08-26 + + +**🆕 New feature** + +- **@visactor/vrender-core**: linear-gradient support ignore percent, closed [#1926](https://github.com/VisActor/VRender/issues/1926) + +**🐛 Bug fix** + +- **@visactor/vrender-core**: fix issue with scaled shadowBounds and editLine in richtext-edit-plugin, closed [#1911](https://github.com/VisActor/VRender/issues/1911) + + + +[more detail about v1.0.13](https://github.com/VisActor/VRender/releases/tag/v1.0.13) + # v1.0.12 2025-08-20 diff --git a/docs/assets/changelog/zh/changelog.md b/docs/assets/changelog/zh/changelog.md index 23a1a4f38..3d12afd8c 100644 --- a/docs/assets/changelog/zh/changelog.md +++ b/docs/assets/changelog/zh/changelog.md @@ -1,3 +1,20 @@ +# v1.0.13 + +2025-08-26 + + +**🆕 新增功能** + +- **@visactor/vrender-core**: linear-gradient support ignore percent, closed [#1926](https://github.com/VisActor/VRender/issues/1926) + +**🐛 功能修复** + +- **@visactor/vrender-core**: fix issue with scaled shadowBounds and editLine in richtext-edit-plugin, closed [#1911](https://github.com/VisActor/VRender/issues/1911) + + + +[更多详情请查看 v1.0.13](https://github.com/VisActor/VRender/releases/tag/v1.0.13) + # v1.0.12 2025-08-20 diff --git a/docs/package.json b/docs/package.json index b40e8996e..d07ed0e73 100644 --- a/docs/package.json +++ b/docs/package.json @@ -13,7 +13,7 @@ "@visactor/vchart": "1.3.0", "@visactor/vutils": "1.0.6", "@visactor/vgrammar": "~0.5.7", - "@visactor/vrender": "workspace:1.0.13", + "@visactor/vrender": "workspace:1.0.14", "markdown-it": "^13.0.0", "highlight.js": "^11.8.0", "axios": "^1.4.0", diff --git a/packages/react-vrender-utils/CHANGELOG.json b/packages/react-vrender-utils/CHANGELOG.json index 201089dc4..71d8929d2 100644 --- a/packages/react-vrender-utils/CHANGELOG.json +++ b/packages/react-vrender-utils/CHANGELOG.json @@ -1,6 +1,12 @@ { "name": "@visactor/react-vrender-utils", "entries": [ + { + "version": "1.0.14", + "tag": "@visactor/react-vrender-utils_v1.0.14", + "date": "Fri, 29 Aug 2025 09:17:17 GMT", + "comments": {} + }, { "version": "1.0.13", "tag": "@visactor/react-vrender-utils_v1.0.13", diff --git a/packages/react-vrender-utils/CHANGELOG.md b/packages/react-vrender-utils/CHANGELOG.md index a8eb322dc..3dc9070ba 100644 --- a/packages/react-vrender-utils/CHANGELOG.md +++ b/packages/react-vrender-utils/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log - @visactor/react-vrender-utils -This log was last generated on Tue, 26 Aug 2025 11:35:34 GMT and should not be manually modified. +This log was last generated on Fri, 29 Aug 2025 09:17:17 GMT and should not be manually modified. + +## 1.0.14 +Fri, 29 Aug 2025 09:17:17 GMT + +_Version update only_ ## 1.0.13 Tue, 26 Aug 2025 11:35:34 GMT diff --git a/packages/react-vrender-utils/package.json b/packages/react-vrender-utils/package.json index a484df8a1..860b84a21 100644 --- a/packages/react-vrender-utils/package.json +++ b/packages/react-vrender-utils/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/react-vrender-utils", - "version": "1.0.13", + "version": "1.0.14", "description": "", "sideEffects": false, "main": "cjs/index.js", @@ -24,8 +24,8 @@ "react-dom": "^18.2.0" }, "dependencies": { - "@visactor/vrender": "workspace:1.0.13", - "@visactor/react-vrender": "workspace:1.0.13", + "@visactor/vrender": "workspace:1.0.14", + "@visactor/react-vrender": "workspace:1.0.14", "@visactor/vutils": "1.0.6", "react-reconciler": "^0.29.0", "tslib": "^2.3.1" diff --git a/packages/react-vrender/CHANGELOG.json b/packages/react-vrender/CHANGELOG.json index a27f07cd8..33fe767a9 100644 --- a/packages/react-vrender/CHANGELOG.json +++ b/packages/react-vrender/CHANGELOG.json @@ -1,6 +1,12 @@ { "name": "@visactor/react-vrender", "entries": [ + { + "version": "1.0.14", + "tag": "@visactor/react-vrender_v1.0.14", + "date": "Fri, 29 Aug 2025 09:17:17 GMT", + "comments": {} + }, { "version": "1.0.13", "tag": "@visactor/react-vrender_v1.0.13", diff --git a/packages/react-vrender/CHANGELOG.md b/packages/react-vrender/CHANGELOG.md index 51e807a1b..98184afcd 100644 --- a/packages/react-vrender/CHANGELOG.md +++ b/packages/react-vrender/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log - @visactor/react-vrender -This log was last generated on Tue, 26 Aug 2025 11:35:34 GMT and should not be manually modified. +This log was last generated on Fri, 29 Aug 2025 09:17:17 GMT and should not be manually modified. + +## 1.0.14 +Fri, 29 Aug 2025 09:17:17 GMT + +_Version update only_ ## 1.0.13 Tue, 26 Aug 2025 11:35:34 GMT diff --git a/packages/react-vrender/package.json b/packages/react-vrender/package.json index 7b5fdb843..191bc8f20 100644 --- a/packages/react-vrender/package.json +++ b/packages/react-vrender/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/react-vrender", - "version": "1.0.13", + "version": "1.0.14", "description": "", "sideEffects": false, "main": "cjs/index.js", @@ -23,7 +23,7 @@ "react": "^18.2.0" }, "dependencies": { - "@visactor/vrender": "workspace:1.0.13", + "@visactor/vrender": "workspace:1.0.14", "@visactor/vutils": "1.0.6", "react-reconciler": "^0.29.0", "tslib": "^2.3.1" diff --git a/packages/vrender-animate/CHANGELOG.json b/packages/vrender-animate/CHANGELOG.json index 8ec668ee7..ce72bc94e 100644 --- a/packages/vrender-animate/CHANGELOG.json +++ b/packages/vrender-animate/CHANGELOG.json @@ -1,6 +1,12 @@ { "name": "@visactor/vrender-animate", "entries": [ + { + "version": "1.0.14", + "tag": "@visactor/vrender-animate_v1.0.14", + "date": "Fri, 29 Aug 2025 09:17:17 GMT", + "comments": {} + }, { "version": "1.0.13", "tag": "@visactor/vrender-animate_v1.0.13", diff --git a/packages/vrender-animate/CHANGELOG.md b/packages/vrender-animate/CHANGELOG.md index ff334e6e8..3ddb2fab1 100644 --- a/packages/vrender-animate/CHANGELOG.md +++ b/packages/vrender-animate/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log - @visactor/vrender-animate -This log was last generated on Tue, 26 Aug 2025 11:35:34 GMT and should not be manually modified. +This log was last generated on Fri, 29 Aug 2025 09:17:17 GMT and should not be manually modified. + +## 1.0.14 +Fri, 29 Aug 2025 09:17:17 GMT + +_Version update only_ ## 1.0.13 Tue, 26 Aug 2025 11:35:34 GMT diff --git a/packages/vrender-animate/package.json b/packages/vrender-animate/package.json index 974c14270..ef4b77232 100644 --- a/packages/vrender-animate/package.json +++ b/packages/vrender-animate/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender-animate", - "version": "1.0.13", + "version": "1.0.14", "description": "", "sideEffects": false, "main": "cjs/index.js", @@ -21,7 +21,7 @@ }, "dependencies": { "@visactor/vutils": "1.0.6", - "@visactor/vrender-core": "workspace:1.0.13" + "@visactor/vrender-core": "workspace:1.0.14" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vrender-components/CHANGELOG.json b/packages/vrender-components/CHANGELOG.json index 484090329..91c0f8f07 100644 --- a/packages/vrender-components/CHANGELOG.json +++ b/packages/vrender-components/CHANGELOG.json @@ -1,6 +1,18 @@ { "name": "@visactor/vrender-components", "entries": [ + { + "version": "1.0.14", + "tag": "@visactor/vrender-components_v1.0.14", + "date": "Fri, 29 Aug 2025 09:17:17 GMT", + "comments": { + "none": [ + { + "comment": "feat: add table series number component \n\n" + } + ] + } + }, { "version": "1.0.13", "tag": "@visactor/vrender-components_v1.0.13", diff --git a/packages/vrender-components/CHANGELOG.md b/packages/vrender-components/CHANGELOG.md index d77c0cfa9..5ff799b05 100644 --- a/packages/vrender-components/CHANGELOG.md +++ b/packages/vrender-components/CHANGELOG.md @@ -1,6 +1,15 @@ # Change Log - @visactor/vrender-components -This log was last generated on Tue, 26 Aug 2025 11:35:34 GMT and should not be manually modified. +This log was last generated on Fri, 29 Aug 2025 09:17:17 GMT and should not be manually modified. + +## 1.0.14 +Fri, 29 Aug 2025 09:17:17 GMT + +### Updates + +- feat: add table series number component + + ## 1.0.13 Tue, 26 Aug 2025 11:35:34 GMT diff --git a/packages/vrender-components/__tests__/browser/examples/table-series-number.ts b/packages/vrender-components/__tests__/browser/examples/table-series-number.ts new file mode 100644 index 000000000..e1643e94e --- /dev/null +++ b/packages/vrender-components/__tests__/browser/examples/table-series-number.ts @@ -0,0 +1,25 @@ +import '@visactor/vrender'; +import { IPointLike } from '@visactor/vutils'; +import render from '../../util/render'; +import { EmptyTip, SeriesNumberEvent, TableSeriesNumber } from '../../../src'; + +export function run() { + const tableSeriesNumber: TableSeriesNumber = new TableSeriesNumber( + { + rowCount: 100, + colCount: 100 + }, + { initRenderAll: true } + ); + window.tableSeriesNumber = tableSeriesNumber; + const stage = render(tableSeriesNumber, 'main'); + tableSeriesNumber.on(SeriesNumberEvent.seriesNumberCellClick, e => { + console.log(SeriesNumberEvent.seriesNumberCellClick, e); + }); + tableSeriesNumber.on(SeriesNumberEvent.seriesNumberCellHover, e => { + console.log(SeriesNumberEvent.seriesNumberCellHover, e); + }); + tableSeriesNumber.on(SeriesNumberEvent.seriesNumberCellUnHover, e => { + console.log(SeriesNumberEvent.seriesNumberCellUnHover, e); + }); +} diff --git a/packages/vrender-components/__tests__/browser/main.ts b/packages/vrender-components/__tests__/browser/main.ts index 44d5ab92d..545648b86 100644 --- a/packages/vrender-components/__tests__/browser/main.ts +++ b/packages/vrender-components/__tests__/browser/main.ts @@ -2,6 +2,10 @@ import './style.css'; const LOCAL_STORAGE_KEY = 'VRENDER_COMPONENTS_DEMOS'; const specs = [ + { + path: 'table-series-number', + name: '表格序号' + }, { path: 'axis-break', name: '轴截断' diff --git a/packages/vrender-components/package.json b/packages/vrender-components/package.json index 63565ad4d..d02bbb094 100644 --- a/packages/vrender-components/package.json +++ b/packages/vrender-components/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender-components", - "version": "1.0.13", + "version": "1.0.14", "description": "components library for dp visualization", "sideEffects": false, "main": "cjs/index.js", @@ -27,9 +27,9 @@ "dependencies": { "@visactor/vutils": "1.0.6", "@visactor/vscale": "1.0.6", - "@visactor/vrender-core": "workspace:1.0.13", - "@visactor/vrender-kits": "workspace:1.0.13", - "@visactor/vrender-animate": "workspace:1.0.13" + "@visactor/vrender-core": "workspace:1.0.14", + "@visactor/vrender-kits": "workspace:1.0.14", + "@visactor/vrender-animate": "workspace:1.0.14" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vrender-components/src/index.ts b/packages/vrender-components/src/index.ts index 49db22017..10d532b4f 100644 --- a/packages/vrender-components/src/index.ts +++ b/packages/vrender-components/src/index.ts @@ -32,3 +32,4 @@ export * from './weather'; export * from './util'; export * from './switch'; export * from './label-item'; +export * from './table-series-number'; diff --git a/packages/vrender-components/src/table-series-number/event-manager.ts b/packages/vrender-components/src/table-series-number/event-manager.ts new file mode 100644 index 000000000..eb432c738 --- /dev/null +++ b/packages/vrender-components/src/table-series-number/event-manager.ts @@ -0,0 +1,335 @@ +import type { TableSeriesNumber } from './table-series-number'; +import { vglobal, type FederatedPointerEvent, type Group, type IGroup, type IText } from '@visactor/vrender-core'; +import { SeriesNumberCellStateValue, SeriesNumberEvent } from './type'; + +export class TableSeriesNumberEventManager { + private _tableSeriesNumber: TableSeriesNumber; + isPointerDownStartSelect: boolean = false; + constructor(tableSeriesNumber: TableSeriesNumber) { + this._tableSeriesNumber = tableSeriesNumber; + } + + bindEvents() { + //ff + const { hover = true, select = true } = this._tableSeriesNumber.attribute; + + if (hover) { + this._tableSeriesNumber._rowSeriesNumberGroup.addEventListener( + 'pointermove', + this._onPointermove as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._rowSeriesNumberGroup.addEventListener( + 'pointerleave', + this._onPointerleave as EventListenerOrEventListenerObject + ); + + this._tableSeriesNumber._colSeriesNumberGroup.addEventListener( + 'pointermove', + this._onPointermove as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._colSeriesNumberGroup.addEventListener( + 'pointerleave', + this._onPointerleave as EventListenerOrEventListenerObject + ); + + this._tableSeriesNumber._cornerGroup.addEventListener( + 'pointermove', + this._onPointermove as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._cornerGroup.addEventListener( + 'pointerleave', + this._onPointerleave as EventListenerOrEventListenerObject + ); + + this._tableSeriesNumber._frozenTopRowSeriesNumberGroup.addEventListener( + 'pointermove', + this._onPointermove as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._frozenTopRowSeriesNumberGroup.addEventListener( + 'pointerleave', + this._onPointerleave as EventListenerOrEventListenerObject + ); + + this._tableSeriesNumber._frozenLeftColSeriesNumberGroup.addEventListener( + 'pointermove', + this._onPointermove as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._frozenLeftColSeriesNumberGroup.addEventListener( + 'pointerleave', + this._onPointerleave as EventListenerOrEventListenerObject + ); + } + + if (select) { + this._tableSeriesNumber._rowSeriesNumberGroup.addEventListener( + 'pointerdown', + this._onPointerdown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._colSeriesNumberGroup.addEventListener( + 'pointerdown', + this._onPointerdown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._cornerGroup.addEventListener( + 'pointerdown', + this._onPointerdown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._frozenTopRowSeriesNumberGroup.addEventListener( + 'pointerdown', + this._onPointerdown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._frozenLeftColSeriesNumberGroup.addEventListener( + 'pointerdown', + this._onPointerdown as EventListenerOrEventListenerObject + ); + + vglobal.addEventListener('pointerup', this._onPointerup as EventListenerOrEventListenerObject); + } + this._tableSeriesNumber._rowSeriesNumberGroup.addEventListener( + 'rightdown', + this._onRightDown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._colSeriesNumberGroup.addEventListener( + 'rightdown', + this._onRightDown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._cornerGroup.addEventListener( + 'rightdown', + this._onRightDown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._frozenTopRowSeriesNumberGroup.addEventListener( + 'rightdown', + this._onRightDown as EventListenerOrEventListenerObject + ); + this._tableSeriesNumber._frozenLeftColSeriesNumberGroup.addEventListener( + 'rightdown', + this._onRightDown as EventListenerOrEventListenerObject + ); + } + private _onRightDown = (e: FederatedPointerEvent) => { + const target = e.target as unknown as IGroup; + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellRightClick, { + seriesNumberCell: target, + event: e + }); + }; + private _onPointermove = (e: FederatedPointerEvent) => { + //ff + const target = e.target as unknown as IGroup; + if (this.isPointerDownStartSelect) { + if (!this._tableSeriesNumber.interactionState.selectIndexs.has(target.name)) { + this._tableSeriesNumber.interactionState.selectIndexs.add(target.name); + this._tableSeriesNumber.renderSelectedIndexsState(); + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellClick, { + seriesNumberCell: target, + event: e, + isDragSelect: true + }); + } else { + if ( + this._tableSeriesNumber.interactionState._lastClickItem && + this._tableSeriesNumber.interactionState._lastClickItem.id === target.id + ) { + return; + } + this._tableSeriesNumber.renderSelectedIndexsState(); + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellClick, { + seriesNumberCell: target, + event: e, + isDragSelect: true + }); + } + this._tableSeriesNumber.interactionState._lastClickItem = target; + return; + } + + if (target.name.startsWith('col')) { + //判断鼠标是否位于列间隔线附近,如果是则设置cursor为col-resize + const colIndex = Number(target.name.split('-')[1]); + const canvasPointXY = target.stage.window.pointTransform(e.canvasX, e.canvasY); + const XYtoTarget = { x: 0, y: 0 }; + + target.globalTransMatrix.transformPoint(canvasPointXY, XYtoTarget); + if ( + XYtoTarget.x <= 4 || + (XYtoTarget.x <= target.getAttributes().width && XYtoTarget.x >= target.getAttributes().width - 4) + ) { + target.setAttribute('cursor', 'col-resize'); + } else { + target.setAttribute('cursor', 'default'); + } + } else if (target.name.startsWith('row')) { + //判断鼠标是否位于行间隔线附近,如果是则设置cursor为row-resize + const rowIndex = Number(target.name.split('-')[1]); + const canvasPointXY = target.stage.window.pointTransform(e.canvasX, e.canvasY); + const XYtoTarget = { x: 0, y: 0 }; + + target.globalTransMatrix.transformPoint(canvasPointXY, XYtoTarget); + if ( + XYtoTarget.y <= 4 || + (XYtoTarget.y <= target.getAttributes().height && XYtoTarget.y >= target.getAttributes().height - 4) + ) { + target.setAttribute('cursor', 'row-resize'); + } else { + target.setAttribute('cursor', 'default'); + } + } + // // 如果上个激活元素存在,则判断当前元素是否和上个激活元素相同,相同则不做处理,不相同则触发 unhover + if (this._tableSeriesNumber.interactionState._lastHoverItem) { + if (this._tableSeriesNumber.interactionState._lastHoverItem.id === target.id) { + return; + } + this._unHoverHandler(this._tableSeriesNumber.interactionState._lastHoverItem, e); + } + if ((this._tableSeriesNumber.getAttributes() as any).hover) { + this._hoverHandler(target, e); + } + }; + private _onPointerleave = (e: FederatedPointerEvent) => { + //ff + if (this._tableSeriesNumber.interactionState._lastHoverItem) { + this._unHoverHandler(this._tableSeriesNumber.interactionState._lastHoverItem, e); + this._tableSeriesNumber.interactionState._lastHoverItem = null; + } + }; + private _onPointerdown = (e: FederatedPointerEvent) => { + //验证是否右键点击 + if (e.button === 2) { + return; + } + const target = e.target as unknown as IGroup; + + if (target.name.startsWith('col')) { + //判断鼠标是否位于列间隔线附近,如果是则触发resizeColWidthStart事件 + const colIndex = Number(target.name.split('-')[1]); + const canvasPointXY = target.stage.window.pointTransform(e.canvasX, e.canvasY); + const XYtoTarget = { x: 0, y: 0 }; + + target.globalTransMatrix.transformPoint(canvasPointXY, XYtoTarget); + if ( + XYtoTarget.x <= 4 || + (XYtoTarget.x <= target.getAttributes().width && XYtoTarget.x >= target.getAttributes().width - 4) + ) { + let resizeTargetColIndex = colIndex; + if (XYtoTarget.x <= 4) { + resizeTargetColIndex = colIndex - 1; + } + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.resizeColWidthStart, { + colIndex: resizeTargetColIndex, + event: e + }); + return; + } + } else if (target.name.startsWith('row')) { + //判断鼠标是否位于行间隔线附近,如果是则触发resizeRowHeightStart事件 + const rowIndex = Number(target.name.split('-')[1]); + const canvasPointXY = target.stage.window.pointTransform(e.canvasX, e.canvasY); + const XYtoTarget = { x: 0, y: 0 }; + + target.globalTransMatrix.transformPoint(canvasPointXY, XYtoTarget); + if ( + XYtoTarget.y <= 4 || + (XYtoTarget.y <= target.getAttributes().height && XYtoTarget.y >= target.getAttributes().height - 4) + ) { + let resizeTargetRowIndex = rowIndex; + if (XYtoTarget.y <= 4) { + resizeTargetRowIndex = rowIndex - 1; + } + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.resizeRowHeightStart, { + rowIndex: resizeTargetRowIndex, + event: e + }); + return; + } + } + this.isPointerDownStartSelect = true; + if (this._tableSeriesNumber.interactionState.selectIndexs?.size) { + if (this._tableSeriesNumber.interactionState.selectIndexs.has(target.name)) { + if (e.nativeEvent.ctrlKey || e.nativeEvent.metaKey) { + this._tableSeriesNumber.removeOneGroupSelected(target); + this._unClickHandler(target.name, e); + } else { + this._tableSeriesNumber.removeAllSelectedIndexs(); + for (const name of this._tableSeriesNumber.interactionState.selectIndexs) { + this._unClickHandler(name, e); + } + } + } else { + if (e.nativeEvent.ctrlKey || e.nativeEvent.metaKey) { + // nothing + } else { + this._tableSeriesNumber.removeAllSelectedIndexs(); + for (const name of this._tableSeriesNumber.interactionState.selectIndexs) { + if ( + (target.name.startsWith('row') && name.startsWith('row')) || + (target.name.startsWith('col') && name.startsWith('col')) + ) { + this._unClickHandler(name, e); + } + } + } + } + } + this._clickHandler(target, e); + }; + private _onPointerup = (e: FederatedPointerEvent) => { + //ff + const target = e.target as unknown as IGroup; + if (this.isPointerDownStartSelect) { + this.isPointerDownStartSelect = false; + this._tableSeriesNumber.interactionState._lastClickItem = null; + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellClickUp, { + seriesNumberCell: target, + event: e + }); + } + }; + + private _hoverHandler(seriesNumberCell: IGroup, e: FederatedPointerEvent) { + this._tableSeriesNumber.interactionState._lastHoverItem = seriesNumberCell; + //需兼顾select状态 + if (seriesNumberCell.hasState(SeriesNumberCellStateValue.select)) { + seriesNumberCell.useStates([SeriesNumberCellStateValue.select, SeriesNumberCellStateValue.hover]); + } else { + seriesNumberCell.useStates([SeriesNumberCellStateValue.hover]); + } + + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellHover, { + seriesNumberCell, + event: e + }); + } + + private _unHoverHandler(seriesNumberCell: IGroup, e: FederatedPointerEvent) { + seriesNumberCell.removeState(SeriesNumberCellStateValue.hover); + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellUnHover, { + seriesNumberCell, + event: e + }); + } + + private _clickHandler(seriesNumberCell: IGroup, e: FederatedPointerEvent) { + // this._tableSeriesNumber.interactionState.selectIndexs.add(seriesNumberCell.name); + // seriesNumberCell.useStates([SeriesNumberCellStateValue.select]); + this._tableSeriesNumber.addOneGroupSelected(seriesNumberCell); + this._tableSeriesNumber.interactionState._lastClickItem = seriesNumberCell; + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellClick, { + seriesNumberCell, + event: e + }); + } + private _unClickHandler(seriesNumberIndex: string, e: FederatedPointerEvent) { + const isRow = seriesNumberIndex.startsWith('row'); + // const isCol = seriesNumberIndex.startsWith('col'); + + // this._tableSeriesNumber.interactionState.selectIndexs.delete(seriesNumberIndex); + // this._tableSeriesNumber.removeOneGroupSelected(seriesNumberIndex); + const seriesNumberCell = isRow + ? this._tableSeriesNumber.getRowSeriesNumberCellGroup(Number(seriesNumberIndex.split('-')[1])) + : this._tableSeriesNumber.getColSeriesNumberCellGroup(Number(seriesNumberIndex.split('-')[1])); + seriesNumberCell?.removeState(SeriesNumberCellStateValue.select); + this._tableSeriesNumber.dispatchTableSeriesNumberEvent(SeriesNumberEvent.seriesNumberCellCancelClick, { + index: seriesNumberIndex, + event: e + }); + } +} diff --git a/packages/vrender-components/src/table-series-number/index.ts b/packages/vrender-components/src/table-series-number/index.ts new file mode 100644 index 000000000..bf16e5242 --- /dev/null +++ b/packages/vrender-components/src/table-series-number/index.ts @@ -0,0 +1,2 @@ +export * from './table-series-number'; +export * from './type'; diff --git a/packages/vrender-components/src/table-series-number/register.ts b/packages/vrender-components/src/table-series-number/register.ts new file mode 100644 index 000000000..4b690a0d7 --- /dev/null +++ b/packages/vrender-components/src/table-series-number/register.ts @@ -0,0 +1,8 @@ +import { registerGroup, registerImage, registerRect, registerText } from '@visactor/vrender-kits'; + +export function loadTableSeriesNumberComponent() { + registerGroup(); + // registerRect(); + registerText(); + registerImage(); +} diff --git a/packages/vrender-components/src/table-series-number/table-series-number.ts b/packages/vrender-components/src/table-series-number/table-series-number.ts new file mode 100644 index 000000000..3edb12d11 --- /dev/null +++ b/packages/vrender-components/src/table-series-number/table-series-number.ts @@ -0,0 +1,1065 @@ +import { generateColField } from './tools'; +import { isValid, merge, normalizePadding } from '@visactor/vutils'; +import { AbstractComponent } from '../core/base'; +import { SeriesNumberCellStateValue, SeriesNumberEvent } from './type'; +import type { TableSeriesNumberAttributes } from './type'; +import { TableSeriesNumberEventManager } from './event-manager'; +import type { FederatedPointerEvent, Group, IGroup, IText } from '@visactor/vrender-core'; +import { parsePadding } from '@visactor/vrender-core'; +import type { ComponentOptions } from '../interface'; +import { loadTableSeriesNumberComponent } from './register'; + +const cornerSvg = + ''; + +loadTableSeriesNumberComponent(); +export class TableSeriesNumber extends AbstractComponent> { + static defaultAttributes: Partial = { + frozenRowCount: 0, + frozenColCount: 0, + rightFrozenColCount: 0, + bottomFrozenRowCount: 0, + pickable: false, + rowCount: 100, + colCount: 100, + rowHeight: 20, + colWidth: 50, + rowSeriesNumberWidth: 30, + colSeriesNumberHeight: 30, + rowSeriesNumberCellStyle: { + text: { + fontSize: 14, + fill: '#7A7A7A', + pickable: false, + textAlign: 'left', + textBaseline: 'middle', + padding: [2, 4, 2, 4] + }, + borderLine: { + stroke: '#D9D9D9', + lineWidth: 1, + pickable: false + }, + bgColor: '#F9F9F9', + states: { + hover: { + fill: '#98C8A5', + opacity: 0.7 + }, + select: { + fill: 'yellow', + opacity: 0.7 + } + } + }, + colSeriesNumberCellStyle: { + text: { + fontSize: 14, + fill: '#7A7A7A', + pickable: false, + textAlign: 'left', + textBaseline: 'middle', + padding: [2, 4, 2, 4] + }, + borderLine: { + stroke: '#D9D9D9', + lineWidth: 1, + pickable: false + }, + bgColor: '#F9F9F9', + states: { + hover: { + fill: '#98C8A5', + opacity: 0.7 + }, + select: { + fill: 'orange', + opacity: 0.7 + } + } + }, + cornerCellStyle: { + borderLine: { + stroke: '#D9D9D9', + lineWidth: 1, + pickable: false + }, + bgColor: '#F9F9F9', + states: { + hover: { + fill: '#98C8A5', + opacity: 0.7 + }, + select: { + fill: '#98C8A5', + opacity: 0.7 + } + } + }, + hover: true, + select: true + }; + name = 'tableSeriesNumber'; + protected _tableSeriesNumberContainer: IGroup; + // protected _title: Tag | null = null; + _cornerGroup: IGroup; + _rowSeriesNumberGroup: IGroup; + _colSeriesNumberGroup: IGroup; + _frozenTopRowSeriesNumberGroup: IGroup; + _frozenLeftColSeriesNumberGroup: IGroup; + _frozenRightColSeriesNumberGroup: IGroup; + _frozenBottomRowSeriesNumberGroup: IGroup; + + // _lastClickItem: IGroup; + // 记录rowSeriesNumberGroup中第一个元素的索引 + _firstRowSeriesNumberIndex: number = 0; + // 记录colSeriesNumberGroup中第一个元素的索引 + _firstColSeriesNumberIndex: number = 0; + // 文字最大宽度 + _maxTextWidth: number = 0; + _changeRowSeriesNumberWidthTimer: number = null; + interactionState: { + _lastHoverItem: IGroup; + _lastClickItem: IGroup; + selectIndexs?: Set; //记录选中的行号或列号 cellGroup的name + // selectColIndexs?:number[], + } = { selectIndexs: new Set(), _lastHoverItem: null, _lastClickItem: null }; + _parsedRowSeriesNumberCellPadding: number[] = [0, 0, 0, 0]; + _parsedColSeriesNumberCellPadding: number[] = [0, 0, 0, 0]; + initRenderAll: boolean = false; + _eventManager: TableSeriesNumberEventManager; + constructor(attributes: TableSeriesNumberAttributes, options?: ComponentOptions & { initRenderAll?: boolean }) { + super(options?.skipDefault ? attributes : merge({}, TableSeriesNumber.defaultAttributes, attributes)); + this.initRenderAll = options?.initRenderAll || false; + this._skipRenderAttributes.push('frozenTopRow'); + this._skipRenderAttributes.push('frozenLeftCol'); + this._skipRenderAttributes.push('frozenRightCol'); + this._skipRenderAttributes.push('frozenBottomRow'); + this._skipRenderAttributes.push('rowCount'); + this._skipRenderAttributes.push('colCount'); + this._skipRenderAttributes.push('hover'); + this._skipRenderAttributes.push('select'); + if (this.attribute.rowSeriesNumberCellStyle.text.padding) { + const padding = parsePadding(this.attribute.rowSeriesNumberCellStyle.text.padding); + if (typeof padding === 'number') { + this._parsedRowSeriesNumberCellPadding = [padding, padding, padding, padding]; + } else { + this._parsedRowSeriesNumberCellPadding = padding; + } + } + if (this.attribute.colSeriesNumberCellStyle.text.padding) { + const padding = parsePadding(this.attribute.colSeriesNumberCellStyle.text.padding); + if (typeof padding === 'number') { + this._parsedColSeriesNumberCellPadding = [padding, padding, padding, padding]; + } else { + this._parsedColSeriesNumberCellPadding = padding; + } + } + this._eventManager = new TableSeriesNumberEventManager(this); + // this.render(); + } + + get rowSeriesNumberWidth() { + const { rowSeriesNumberWidth } = this.attribute; + if (this._maxTextWidth) { + return Math.max( + this._maxTextWidth + this._parsedRowSeriesNumberCellPadding[3] + this._parsedRowSeriesNumberCellPadding[1], + typeof rowSeriesNumberWidth === 'number' ? rowSeriesNumberWidth : 40 + ); + } + return typeof rowSeriesNumberWidth === 'number' ? rowSeriesNumberWidth : 40; + } + get colSeriesNumberHeight() { + const { colSeriesNumberHeight } = this.attribute; + return typeof colSeriesNumberHeight === 'number' ? colSeriesNumberHeight : 20; + } + get rowCount() { + const { rowCount } = this.attribute; + return rowCount; + } + get colCount() { + const { colCount } = this.attribute; + return colCount; + } + protected bindEvents(): void { + this._eventManager.bindEvents(); + } + dispatchTableSeriesNumberEvent(event: any, ...args: any) { + this._dispatchEvent(event, ...args); + } + render() { + // this.removeAllChild(true); + const { + rowCount, + colCount, + rowSeriesNumberWidth, + colSeriesNumberHeight, + rowSeriesNumberCellStyle, + colSeriesNumberCellStyle, + rowHeight, + colWidth + } = this.attribute; + // 创建一个内部的 container 用于存储所有的元素 + const innerView = this.createOrUpdateChild( + 'tableSeriesNumberContainer', + { + x: 0, + y: 0, + fill: 'rgba(1,1,1,0)', + width: this.rowSeriesNumberWidth + colCount * (typeof colWidth === 'number' ? colWidth : 20), + height: this.colSeriesNumberHeight + rowCount * (typeof rowHeight === 'number' ? rowHeight : 20), + pickable: false, + childrenPickable: true + }, + 'group' + ) as IGroup; + // innerView.name = LEGEND_ELEMENT_NAME.innerView; + // this.add(innerView); + this._tableSeriesNumberContainer = innerView; + + this._renderContent(); + + // this._bindEvents(); + } + _renderContent() { + this._renderRowSeriesNumber(); + this._renderColSeriesNumber(); + // this.refreshRowSeriesNumberGroup(0,100); + + this._renderFrozenTopRowSeriesNumber(); + this._renderFrozenLeftColSeriesNumber(); + this._renderCorner(); + if (this.initRenderAll) { + this.recreateCellsToRowSeriesNumberGroup(0, this.attribute.rowCount - 1); + this.recreateCellsToColSeriesNumberGroup(0, this.attribute.colCount - 1); + let y = 0; + for (let i = 0; i < this.attribute.rowCount; i++) { + this.setRowSeriesNumberCellAttributes(i, { + y, + height: typeof this.attribute.rowHeight === 'number' ? this.attribute.rowHeight : 20 + }); + y += typeof this.attribute.rowHeight === 'number' ? this.attribute.rowHeight : 20; + } + let x = 0; + for (let i = 0; i < this.attribute.colCount; i++) { + this.setColSeriesNumberCellAttributes(i, { + x, + width: typeof this.attribute.colWidth === 'number' ? this.attribute.colWidth : 20 + }); + x += typeof this.attribute.colWidth === 'number' ? this.attribute.colWidth : 20; + } + } + // this._renderFrozenRightSeriesNumber(); + // this._renderFrozenBottomSeriesNumber(); + } + _renderCorner() { + const { + rowCount, + colCount, + cornerCellStyle: cornerSeriesNumberCellStyle, + rowSeriesNumberWidth, + colSeriesNumberHeight, + rowSeriesNumberCellStyle, + colSeriesNumberCellStyle, + rowHeight, + colWidth + } = this.attribute; + // 组织角头 + const cornerGroup = this._tableSeriesNumberContainer.createOrUpdateChild( + 'cornerSeriesNumberCell', + { + x: 0, + y: 0, + fill: cornerSeriesNumberCellStyle.bgColor, + stroke: cornerSeriesNumberCellStyle.borderLine.stroke, + lineWidth: cornerSeriesNumberCellStyle.borderLine.lineWidth, + pickable: true, + width: this.rowSeriesNumberWidth, + height: this.colSeriesNumberHeight + }, + 'group' + ) as IGroup; + // cornerGroup.name = `conerSeriesNumberCell`; + cornerGroup.id = '0,0'; + cornerGroup.states = cornerSeriesNumberCellStyle.states; + // this._tableSeriesNumberContainer.add(cornerGroup); + this._cornerGroup = cornerGroup; + } + _renderRowSeriesNumber() { + const { + frozenRowCount, + rowCount, + colCount, + rowSeriesNumberWidth, + colSeriesNumberHeight, + rowSeriesNumberCellStyle, + colSeriesNumberCellStyle, + rowHeight, + colWidth + } = this.attribute; + + //组织行号Group + const rowSeriesNumberGroup = this._tableSeriesNumberContainer.createOrUpdateChild( + 'rowSeriesNumberCellGroup', + { + x: 0, + y: this.colSeriesNumberHeight, //后续setFrozenRowCount会重新设置y + pickable: true, + fill: rowSeriesNumberCellStyle.bgColor, + width: this.rowSeriesNumberWidth, + height: rowCount * (typeof rowHeight === 'number' ? rowHeight : 20) + }, + 'group' + ) as IGroup; + // this._tableSeriesNumberContainer.add(rowSeriesNumberGroup); + this._rowSeriesNumberGroup = rowSeriesNumberGroup; + // //组织每个行号单元格 + // for (let i = 0; i < rowCount - frozenRowCount; i++) { + // const cellGroup = this._rowSeriesNumberGroup.createOrUpdateChild(`rowSeriesNumberCell-${i}`,{ + // x: 0, + // y: i * (typeof rowHeight === 'number' ? rowHeight : 20), + // pickable: true, + // fill: rowSeriesNumberCellStyle.bgColor, + // stroke: rowSeriesNumberCellStyle.borderLine.stroke, + // lineWidth: rowSeriesNumberCellStyle.borderLine.lineWidth, + // width: this.rowSeriesNumberWidth, + // height: typeof rowHeight === 'number' ? rowHeight : 20 + // },'group') as IGroup; + // // cellGroup.name = `rowSeriesNumberCell-${i}`; + // cellGroup.id = i; + // cellGroup.states = rowSeriesNumberCellStyle.states; + // // rowSeriesNumberGroup.add(cellGroup); + + // const text = cellGroup.createOrUpdateChild(`rowSeriesNumberCellText-${i}`,{ + // x: 0, + // y: typeof rowHeight === 'number' ? rowHeight : 20, + // text: `${i + 1 + frozenRowCount}`, + // pickable: false, + // ...rowSeriesNumberCellStyle.text + // },'text'); + // // cellGroup.add(text); + // } + } + _renderColSeriesNumber() { + const { + frozenColCount, + rowCount, + colCount, + rowSeriesNumberWidth, + colSeriesNumberHeight, + rowSeriesNumberCellStyle, + colSeriesNumberCellStyle, + rowHeight, + colWidth + } = this.attribute; + //组织列号Group + const colSeriesNumberGroup = this._tableSeriesNumberContainer.createOrUpdateChild( + 'colSeriesNumberCellGroup', + { + x: this.rowSeriesNumberWidth + frozenColCount * (typeof colWidth === 'number' ? colWidth : 20), + y: 0, + pickable: true, + fill: colSeriesNumberCellStyle.bgColor, + width: colCount * (typeof colWidth === 'number' ? colWidth : 20), + height: this.colSeriesNumberHeight + }, + 'group' + ) as IGroup; + // this._tableSeriesNumberContainer.add(colSeriesNumberGroup); + this._colSeriesNumberGroup = colSeriesNumberGroup; + // //组织每个列号单元格 + // for (let i = 0; i < colCount - frozenColCount; i++) { + // const cellGroup = this._colSeriesNumberGroup.createOrUpdateChild(`colSeriesNumberCell-${i}`,{ + // x: i * (typeof colWidth === 'number' ? colWidth : 20), + // y: 0, + // pickable: true, + // fill: colSeriesNumberCellStyle.bgColor, + // stroke: colSeriesNumberCellStyle.borderLine.stroke, + // width: typeof colWidth === 'number' ? colWidth : 20, + // height: this.colSeriesNumberHeight + // },'group') as IGroup; + // // cellGroup.name = `colSeriesNumberCell-${i}`; + // cellGroup.id = i; + // // colSeriesNumberGroup.add(cellGroup); + // const text = cellGroup.createOrUpdateChild(`colSeriesNumberCellText-${i}`,{ + // x: 0, + // y: this.colSeriesNumberHeight, + // text: generateColField(i + frozenColCount), + // pickable: false, + // ...colSeriesNumberCellStyle.text + // },'text'); + // // cellGroup.add(text); + // cellGroup.states = colSeriesNumberCellStyle.states; + // } + } + _renderFrozenTopRowSeriesNumber() { + const { + frozenRowCount, + colCount, + rowSeriesNumberWidth, + colSeriesNumberHeight, + rowSeriesNumberCellStyle, + colSeriesNumberCellStyle, + rowHeight, + colWidth + } = this.attribute; + const frozenTopSeriesNumberGroup = this._tableSeriesNumberContainer.createOrUpdateChild( + 'frozenTopSeriesNumberGroup', + { + x: 0, + y: this.colSeriesNumberHeight, + width: this.rowSeriesNumberWidth, + height: frozenRowCount * (typeof rowHeight === 'number' ? rowHeight : 20) + }, + 'group' + ) as IGroup; + this._frozenTopRowSeriesNumberGroup = frozenTopSeriesNumberGroup; + // for (let i = 0; i < frozenRowCount; i++) { + // const cellGroup = this._frozenTopRowSeriesNumberGroup.createOrUpdateChild(`rowSeriesNumberCell-${i}`,{ + // x: 0, + // y: i * (typeof rowHeight === 'number' ? rowHeight : 20), + // pickable: true, + // // display: 'flex', + // fill: rowSeriesNumberCellStyle.bgColor, + // stroke: rowSeriesNumberCellStyle.borderLine.stroke, + // lineWidth: rowSeriesNumberCellStyle.borderLine.lineWidth, + // width: this.rowSeriesNumberWidth, + // height: typeof rowHeight === 'number' ? rowHeight : 20 + // },'group') as IGroup; + // cellGroup.id = i; + // cellGroup.states = rowSeriesNumberCellStyle.states; + // const text = cellGroup.createOrUpdateChild(`rowSeriesNumberCellText-${i}`,{ + // x: 0, + // y: typeof rowHeight === 'number' ? rowHeight : 20, + // text: `${i + 1}`, + // pickable: false, + // ...rowSeriesNumberCellStyle.text + // },'text'); + // } + } + _renderFrozenLeftColSeriesNumber() { + const { + frozenColCount, + rowCount, + rowSeriesNumberWidth, + colSeriesNumberHeight, + rowSeriesNumberCellStyle, + colSeriesNumberCellStyle, + rowHeight, + colWidth + } = this.attribute; + const frozenLeftSeriesNumberGroup = this._tableSeriesNumberContainer.createOrUpdateChild( + 'frozenLeftSeriesNumberGroup', + { + x: this.rowSeriesNumberWidth, + y: 0, + height: this.colSeriesNumberHeight, + width: frozenColCount * (typeof colWidth === 'number' ? colWidth : 20) + }, + 'group' + ) as IGroup; + this._frozenLeftColSeriesNumberGroup = frozenLeftSeriesNumberGroup; + // for (let i = 0; i < frozenColCount; i++) { + // const cellGroup = this._frozenLeftColSeriesNumberGroup.createOrUpdateChild(`colSeriesNumberCell-${i}`,{ + // x: i * (typeof colWidth === 'number' ? colWidth : 20), + // y: 0, + // pickable: true, + // fill: colSeriesNumberCellStyle.bgColor, + // stroke: colSeriesNumberCellStyle.borderLine.stroke, + // lineWidth: colSeriesNumberCellStyle.borderLine.lineWidth, + // width: typeof colWidth === 'number' ? colWidth : 20, + // height: this.colSeriesNumberHeight + // },'group') as IGroup; + // cellGroup.id = i; + // cellGroup.states = colSeriesNumberCellStyle.states; + // const text = cellGroup.createOrUpdateChild(`colSeriesNumberCellText-${i}`,{ + // x: 0, + // y: this.colSeriesNumberHeight, + // text: generateColField(i), + // pickable: false, + // ...colSeriesNumberCellStyle.text + // },'text'); + // } + } + + recreateCellsToRowSeriesNumberGroup(startIndex: number, endIndex: number) { + const { + frozenRowCount, + rowCount, + colCount, + rowSeriesNumberWidth, + colSeriesNumberHeight, + rowSeriesNumberCellStyle, + colSeriesNumberCellStyle, + rowHeight, + colWidth + } = this.attribute; + this._frozenTopRowSeriesNumberGroup.removeAllChild(); + this._rowSeriesNumberGroup.removeAllChild(); + + //#region根据textBaseline 计算每个cell中text的y坐标 + let y = 0; + const height = + (typeof rowHeight === 'number' ? rowHeight : 20) - + this._parsedRowSeriesNumberCellPadding[0] - + this._parsedRowSeriesNumberCellPadding[2]; + if (rowSeriesNumberCellStyle.text.textBaseline === 'middle') { + y = this._parsedRowSeriesNumberCellPadding[0] + (height - rowSeriesNumberCellStyle.text.fontSize) / 2; + } else if (rowSeriesNumberCellStyle.text.textBaseline === 'bottom') { + y = this._parsedRowSeriesNumberCellPadding[0] + height - rowSeriesNumberCellStyle.text.fontSize; + } else { + y = this._parsedRowSeriesNumberCellPadding[0]; + } + //#endregion + + //#region 根据textAlign 计算子元素Text的x坐标 + let x; + const width = + this.rowSeriesNumberWidth - this._parsedRowSeriesNumberCellPadding[3] - this._parsedRowSeriesNumberCellPadding[1]; + const textAlign = this.attribute.rowSeriesNumberCellStyle.text.textAlign; + const padding = this._parsedRowSeriesNumberCellPadding; + if (textAlign === 'center') { + x = padding[3] + +width / 2; + } else if (textAlign === 'right') { + x = padding[3] + width; + } else { + x = padding[3]; + } + //#endregion + + // #region 冻结行序号 + for (let i = 0; i < frozenRowCount; i++) { + const cellGroup = this._frozenTopRowSeriesNumberGroup.createOrUpdateChild( + `rowSeriesNumberCell-${i}`, + { + x: 0, + y: 0, + pickable: true, + fill: rowSeriesNumberCellStyle.bgColor, + stroke: rowSeriesNumberCellStyle.borderLine.stroke, + lineWidth: rowSeriesNumberCellStyle.borderLine.lineWidth, + width: this.rowSeriesNumberWidth, + height: typeof rowHeight === 'number' ? rowHeight : 20 + }, + 'group' + ) as IGroup; + cellGroup.id = i; + cellGroup.states = rowSeriesNumberCellStyle.states; + if (this.interactionState.selectIndexs?.has(cellGroup.name)) { + cellGroup.useStates([SeriesNumberCellStateValue.select]); + } + + const text = cellGroup.createOrUpdateChild( + `rowSeriesNumberCellText-${i}`, + { + x, + y, + text: `${i + 1}`, + pickable: false, + dx: 0, + ...rowSeriesNumberCellStyle.text, + textBaseline: 'top' + }, + 'text' + ); + } + // #endregion + this._firstRowSeriesNumberIndex = Math.max(startIndex, frozenRowCount) - frozenRowCount; + let thisTextMaxWidth: number = 0; + for (let i = this._firstRowSeriesNumberIndex; i <= endIndex - frozenRowCount; i++) { + const cellGroup = this._rowSeriesNumberGroup.createOrUpdateChild( + `rowSeriesNumberCell-${i + frozenRowCount}`, + { + x: 0, + y: 0, + pickable: true, + fill: rowSeriesNumberCellStyle.bgColor, + stroke: rowSeriesNumberCellStyle.borderLine.stroke, + lineWidth: rowSeriesNumberCellStyle.borderLine.lineWidth, + width: this.rowSeriesNumberWidth, + height: typeof rowHeight === 'number' ? rowHeight : 20 + }, + 'group' + ) as IGroup; + + cellGroup.id = i + frozenRowCount; + cellGroup.states = rowSeriesNumberCellStyle.states; + //判断是否是当前选中的行号 + if (this.interactionState.selectIndexs?.has(cellGroup.name)) { + cellGroup.useStates([SeriesNumberCellStateValue.select]); + } + const text = cellGroup.createOrUpdateChild( + `rowSeriesNumberCellText-${i + frozenRowCount}`, + { + x, + y, + text: `${i + 1 + frozenRowCount}`, + pickable: false, + dx: 0, + ...rowSeriesNumberCellStyle.text, + textBaseline: 'top' + }, + 'text' + ); + if (i === endIndex - frozenRowCount) { + thisTextMaxWidth = (text as IText).clipedWidth; + } + } + //对比新的宽和原来宽度差别大于1 则赋新值,并通知事件 + // 节流,防止频繁触发。频繁触发时,只取最后一次的值。 + clearTimeout(this._changeRowSeriesNumberWidthTimer); + this._changeRowSeriesNumberWidthTimer = setTimeout(() => { + if (Math.abs(thisTextMaxWidth - this._maxTextWidth) >= 6) { + const oldWidth = this._maxTextWidth; + this._maxTextWidth = thisTextMaxWidth; + this.changeRowSeriesNumberWidth(Math.max(this.rowSeriesNumberWidth, 20)); + this._dispatchEvent(SeriesNumberEvent.rowSeriesNumberWidthChange, { + newWidth: this.rowSeriesNumberWidth, + oldWidth + }); + } + }, 100); + } + + recreateCellsToColSeriesNumberGroup(startIndex: number, endIndex: number) { + const { colCount, colSeriesNumberCellStyle, frozenColCount, colWidth } = this + .attribute as TableSeriesNumberAttributes; + const oldFrozenLeftColSeriesNumberGroupCellsWidth = new Map(); + this._frozenLeftColSeriesNumberGroup?.forEachChildren?.((child: IGroup, index: number) => { + oldFrozenLeftColSeriesNumberGroupCellsWidth.set(index, child.getAttributes().width); + }); + this._frozenLeftColSeriesNumberGroup.removeAllChild(); + this._colSeriesNumberGroup.removeAllChild(); + + //#region 根据textBaseline 计算每个cell中text的y坐标 + let y = 0; + const height = + this.colSeriesNumberHeight - + this._parsedColSeriesNumberCellPadding[0] - + this._parsedColSeriesNumberCellPadding[2]; + if (colSeriesNumberCellStyle.text.textBaseline === 'middle') { + y = this._parsedColSeriesNumberCellPadding[0] + (height - colSeriesNumberCellStyle.text.fontSize) / 2; + } else if (colSeriesNumberCellStyle.text.textBaseline === 'bottom') { + y = this._parsedColSeriesNumberCellPadding[0] + height - colSeriesNumberCellStyle.text.fontSize; + } else { + y = this._parsedColSeriesNumberCellPadding[0]; + } + //#endregion + + //#region 根据textAlign 计算子元素Text的x坐标 + let x; + const width = + (typeof colWidth === 'number' ? colWidth : 20) - + this._parsedColSeriesNumberCellPadding[3] - + this._parsedColSeriesNumberCellPadding[1]; + const textAlign = this.attribute.colSeriesNumberCellStyle.text.textAlign; + const padding = this._parsedColSeriesNumberCellPadding; + if (textAlign === 'center') { + x = padding[3] + +width / 2; + } else if (textAlign === 'right') { + x = padding[3] + width; + } else { + x = padding[3]; + } + //#endregion + + // #region 冻结列序号 + for (let i = 0; i < frozenColCount; i++) { + const cellGroup = this._frozenLeftColSeriesNumberGroup.createOrUpdateChild( + `colSeriesNumberCell-${i}`, + { + x: 0, + y: 0, + pickable: true, + fill: colSeriesNumberCellStyle.bgColor, + stroke: colSeriesNumberCellStyle.borderLine.stroke, + lineWidth: colSeriesNumberCellStyle.borderLine.lineWidth, + width: oldFrozenLeftColSeriesNumberGroupCellsWidth.get(i) || (typeof colWidth === 'number' ? colWidth : 20), + height: this.colSeriesNumberHeight + }, + 'group' + ) as IGroup; + cellGroup.id = i; + cellGroup.states = colSeriesNumberCellStyle.states; + if (this.interactionState.selectIndexs?.has(cellGroup.name)) { + cellGroup.useStates([SeriesNumberCellStateValue.select]); + } + const text = cellGroup.createOrUpdateChild( + `colSeriesNumberCellText-${i}`, + { + x, + y, + dx: 0, + text: generateColField(i), + pickable: false, + ...colSeriesNumberCellStyle.text, + textBaseline: 'top' + }, + 'text' + ); + } + // #endregion + + this._firstColSeriesNumberIndex = Math.max(startIndex, frozenColCount) - frozenColCount; + for (let i = this._firstColSeriesNumberIndex; i <= endIndex - frozenColCount; i++) { + const cellGroup = this._colSeriesNumberGroup.createOrUpdateChild( + `colSeriesNumberCell-${i + frozenColCount}`, + { + x: 0, + y: 0, + pickable: true, + fill: colSeriesNumberCellStyle.bgColor, + stroke: colSeriesNumberCellStyle.borderLine.stroke, + lineWidth: colSeriesNumberCellStyle.borderLine.lineWidth, + width: typeof colWidth === 'number' ? colWidth : 20, + height: this.colSeriesNumberHeight + }, + 'group' + ) as IGroup; + cellGroup.id = i + frozenColCount; + cellGroup.states = colSeriesNumberCellStyle.states; + //判断是否是当前选中的列号 + if (this.interactionState.selectIndexs?.has(cellGroup.name)) { + cellGroup.useStates([SeriesNumberCellStateValue.select]); + } + const text = cellGroup.createOrUpdateChild( + `colSeriesNumberCellText-${i + frozenColCount}`, + { + x, + y, + dx: 0, + text: generateColField(i + frozenColCount), + pickable: false, + ...colSeriesNumberCellStyle.text, + textBaseline: 'top' + }, + 'text' + ); + } + } + + changeRowSeriesNumberWidth(newWidth: number) { + const { + rowHeight, + rowCount: oldRowCount, + frozenRowCount, + frozenColCount: frozenLeftCol, + rowSeriesNumberCellStyle + } = this.attribute as TableSeriesNumberAttributes; + // 修改角头宽度 + this._cornerGroup.setAttributes({ + width: newWidth + }); + + //修改行序号冻结部分宽度 + this._frozenTopRowSeriesNumberGroup.setAttributes({ + width: newWidth + }); + for (let i = 0; i < this._frozenTopRowSeriesNumberGroup.children.length; i++) { + this.setRowSeriesNumberCellAttributes(i, { + width: newWidth + }); + } + + //修改行序号整体宽度 + this._rowSeriesNumberGroup.setAttributes({ + width: newWidth + }); + for (let i = 0; i < this._rowSeriesNumberGroup.children.length; i++) { + this.setRowSeriesNumberCellAttributes(i + this._firstRowSeriesNumberIndex + frozenRowCount, { + width: newWidth + }); + } + + // 修改列序号Group x坐标 + this._frozenLeftColSeriesNumberGroup.setAttributes({ + x: newWidth + }); + // 修改列序号Group x坐标 + this._colSeriesNumberGroup.setAttributes({ + x: newWidth + this._frozenLeftColSeriesNumberGroup.getAttributes().width + }); + } + + getRowSeriesNumberCellGroup(index: number) { + const { frozenRowCount } = this.getAttributes() as TableSeriesNumberAttributes; + if (index >= 0 && index < frozenRowCount) { + return this._frozenTopRowSeriesNumberGroup.children[index]; + } + const rowSeriesNumberGroup = this._rowSeriesNumberGroup; + const rowSeriesNumberCell = rowSeriesNumberGroup.children[index - frozenRowCount - this._firstRowSeriesNumberIndex]; + return rowSeriesNumberCell; + } + getColSeriesNumberCellGroup(index: number) { + const { frozenColCount } = this.getAttributes() as TableSeriesNumberAttributes; + if (index >= 0 && index < frozenColCount) { + return this._frozenLeftColSeriesNumberGroup.children[index]; + } + const colSeriesNumberGroup = this._colSeriesNumberGroup; + const colSeriesNumberCell = colSeriesNumberGroup.children[index - frozenColCount - this._firstColSeriesNumberIndex]; + return colSeriesNumberCell; + } + getRowSeriesNumberCellAttributes(index: number) { + const { frozenRowCount } = this.getAttributes() as TableSeriesNumberAttributes; + if (index >= 0 && index < frozenRowCount) { + return this._frozenTopRowSeriesNumberGroup.children[index].attribute; + } + const rowSeriesNumberGroup = this._rowSeriesNumberGroup; + const rowSeriesNumberCell = rowSeriesNumberGroup.children[index - frozenRowCount - this._firstRowSeriesNumberIndex]; + return rowSeriesNumberCell.attribute; + } + getColSeriesNumberCellAttributes(index: number) { + const { frozenColCount } = this.getAttributes() as TableSeriesNumberAttributes; + if (index >= 0 && index < frozenColCount) { + return this._frozenLeftColSeriesNumberGroup.children[index].attribute; + } + const colSeriesNumberGroup = this._colSeriesNumberGroup; + const colSeriesNumberCell = colSeriesNumberGroup.children[index - frozenColCount - this._firstColSeriesNumberIndex]; + return colSeriesNumberCell.attribute; + } + + setRowSeriesNumberCellAttributes(index: number, attributes: TableSeriesNumberAttributes) { + //找到rowSeriesNumberGroup中对应的子元素,并设置其属性 + const { frozenRowCount } = this.getAttributes() as TableSeriesNumberAttributes; + let targetCellGroup: IGroup; + if (index >= 0 && index < frozenRowCount) { + const { height: oldHeight, width: oldWidth, y } = this._frozenTopRowSeriesNumberGroup.getAttributes(); + targetCellGroup = this._frozenTopRowSeriesNumberGroup.children[index]; + targetCellGroup.setAttributes(attributes); + if (attributes.height) { + this._frozenTopRowSeriesNumberGroup.setAttributes({ + height: this._frozenTopRowSeriesNumberGroup.getAttributes().height + (attributes.height - oldHeight) + }); + } + if (attributes.width) { + this._frozenTopRowSeriesNumberGroup.setAttributes({ + width: this._frozenTopRowSeriesNumberGroup.getAttributes().width + (attributes.width - oldWidth) + }); + } + if (attributes.height) { + this._rowSeriesNumberGroup.setAttributes({ + y: + this._frozenTopRowSeriesNumberGroup.getAttributes().height + + this._frozenTopRowSeriesNumberGroup.getAttributes().y + }); + } + } else { + const rowSeriesNumberGroup = this._rowSeriesNumberGroup; + targetCellGroup = rowSeriesNumberGroup.children[index - frozenRowCount - this._firstRowSeriesNumberIndex]; + targetCellGroup.setAttributes(attributes); + } + //#region 更新子元素Text的x坐标 + if (attributes.width) { + // debugger + let x; + const width = + attributes.width - this._parsedRowSeriesNumberCellPadding[3] - this._parsedRowSeriesNumberCellPadding[1]; + const textAlign = this.attribute.rowSeriesNumberCellStyle.text.textAlign; + const padding = this._parsedRowSeriesNumberCellPadding; + if (textAlign === 'center') { + x = padding[3] + +width / 2; + } else if (textAlign === 'right') { + x = padding[3] + width; + } else { + x = padding[3]; + } + // debugger + targetCellGroup.children[0].setAttributes({ + x + }); + } + //#endregion + + //#region 更新子元素Text的y坐标 + if (attributes.height) { + const height = + attributes.height - this._parsedRowSeriesNumberCellPadding[0] - this._parsedRowSeriesNumberCellPadding[2]; + const textBaseline = this.attribute.rowSeriesNumberCellStyle.text.textBaseline; + const padding = this._parsedRowSeriesNumberCellPadding; + let y; + if (textBaseline === 'middle') { + y = padding[0] + (height - this.attribute.rowSeriesNumberCellStyle.text.fontSize) / 2; + } else if (textBaseline === 'bottom') { + y = padding[0] + height - this.attribute.rowSeriesNumberCellStyle.text.fontSize; + } else { + y = padding[0]; + } + targetCellGroup.children[0].setAttributes({ + y + }); + } + //#endregion + } + setColSeriesNumberCellAttributes(index: number, attributes: TableSeriesNumberAttributes) { + //找到colSeriesNumberGroup中对应的子元素,并设置其属性 + const { frozenColCount: frozenColCount } = this.getAttributes() as TableSeriesNumberAttributes; + let targetCellGroup: IGroup; + if (index >= 0 && index < frozenColCount) { + targetCellGroup = this._frozenLeftColSeriesNumberGroup.children[index]; + const { height: oldHeight, width: oldWidth } = targetCellGroup.getAttributes(); + targetCellGroup.setAttributes(attributes); + + if (attributes.height) { + this._frozenLeftColSeriesNumberGroup.setAttributes({ + height: this._frozenLeftColSeriesNumberGroup.getAttributes().height + (attributes.height - oldHeight) + }); + } + if (attributes.width) { + this._frozenLeftColSeriesNumberGroup.setAttributes({ + width: this._frozenLeftColSeriesNumberGroup.getAttributes().width + (attributes.width - oldWidth) + }); + } + if (attributes.width) { + this._colSeriesNumberGroup.setAttributes({ + x: + this._frozenLeftColSeriesNumberGroup.getAttributes().width + + this._frozenLeftColSeriesNumberGroup.getAttributes().x + }); + } + } else { + const colSeriesNumberGroup = this._colSeriesNumberGroup; + targetCellGroup = colSeriesNumberGroup.children[index - frozenColCount - this._firstColSeriesNumberIndex]; + targetCellGroup.setAttributes(attributes); + } + //#region 更新子元素Text的x坐标 + if (attributes.width) { + let x; + const width = + attributes.width - this._parsedColSeriesNumberCellPadding[3] - this._parsedColSeriesNumberCellPadding[1]; + const textAlign = this.attribute.colSeriesNumberCellStyle.text.textAlign; + const padding = this._parsedColSeriesNumberCellPadding; + if (textAlign === 'center') { + x = padding[3] + +width / 2; + } else if (textAlign === 'right') { + x = padding[3] + width; + } else { + x = padding[3]; + } + targetCellGroup.children[0].setAttributes({ + x + }); + } + //#endregion + + //#region 更新子元素Text的y坐标 + if (attributes.height) { + const height = + attributes.height - this._parsedColSeriesNumberCellPadding[0] - this._parsedColSeriesNumberCellPadding[2]; + const textBaseline = this.attribute.colSeriesNumberCellStyle.text.textBaseline; + const padding = this._parsedColSeriesNumberCellPadding; + let y; + if (textBaseline === 'middle') { + y = padding[0] + (height - this.attribute.colSeriesNumberCellStyle.text.fontSize) / 2; + } else if (textBaseline === 'bottom') { + y = padding[0] + height - this.attribute.colSeriesNumberCellStyle.text.fontSize; + } else { + y = padding[0]; + } + targetCellGroup.children[0].setAttributes({ + y + }); + } + //#endregion + } + setRowSeriesNumberGroupAttributes(attributes: TableSeriesNumberAttributes) { + this._rowSeriesNumberGroup.setAttributes(attributes); + } + setColSeriesNumberGroupAttributes(attributes: TableSeriesNumberAttributes) { + this._colSeriesNumberGroup.setAttributes(attributes); + } + addSelectedIndex(isRow: boolean, index: number) { + let name: string; + if (isRow) { + name = `rowSeriesNumberCell-${index}`; + } else { + name = `colSeriesNumberCell-${index}`; + } + this.interactionState.selectIndexs.add(name); + } + addRowSelectedRanges(ranges: { startIndex: number; endIndex: number }[]) { + const t0 = performance.now(); + for (let i = 0; i < ranges.length; i++) { + const { startIndex, endIndex } = ranges[i]; + for (let j = startIndex; j <= endIndex; j++) { + const name = `rowSeriesNumberCell-${j}`; + this.interactionState.selectIndexs.add(name); + } + } + const t1 = performance.now(); + } + addColSelectedRanges(ranges: { startIndex: number; endIndex: number }[]) { + for (let i = 0; i < ranges.length; i++) { + const { startIndex, endIndex } = ranges[i]; + for (let j = startIndex; j <= endIndex; j++) { + const name = `colSeriesNumberCell-${j}`; + this.interactionState.selectIndexs.add(name); + } + } + } + addCornderSelected() { + this.interactionState.selectIndexs.add(this._cornerGroup.name); + } + resetAllSelectedIndexs({ rowIndexs, colIndexs }: { rowIndexs?: number[]; colIndexs?: number[] }) { + this.interactionState.selectIndexs = new Set(); + if (rowIndexs) { + for (let i = 0; i < rowIndexs.length; i++) { + const name = `rowSeriesNumberCell-${rowIndexs[i]}`; + this.interactionState.selectIndexs.add(name); + } + } + if (colIndexs) { + for (let i = 0; i < colIndexs.length; i++) { + const name = `colSeriesNumberCell-${colIndexs[i]}`; + this.interactionState.selectIndexs.add(name); + } + } + } + removeSelectedIndex(isRow: boolean, index: number) { + let name: string; + if (isRow) { + name = `rowSeriesNumberLeftCell-${index}`; + } else { + name = `colSeriesNumberCell-${index}`; + } + this.interactionState.selectIndexs.delete(name); + } + removeAllSelectedIndexs() { + for (const name of this.interactionState.selectIndexs) { + const isRow = name.startsWith('row'); + const isCol = name.startsWith('col'); + const index = Number(name.split('-')[1]); + if (isRow) { + this.getRowSeriesNumberCellGroup(index)?.removeState(SeriesNumberCellStateValue.select); + } else if (isCol) { + this.getColSeriesNumberCellGroup(index)?.removeState(SeriesNumberCellStateValue.select); + } else { + this._cornerGroup.removeState(SeriesNumberCellStateValue.select); + } + } + this.interactionState.selectIndexs.clear(); + } + removeOneGroupSelected(group: IGroup) { + this.interactionState.selectIndexs.delete(group.name); + group.removeState(SeriesNumberCellStateValue.select); + } + addOneGroupSelected(group: IGroup) { + this.interactionState.selectIndexs.add(group.name); + group.useStates([SeriesNumberCellStateValue.select]); + } + renderSelectedIndexsState() { + const { rowSeriesNumberCellStyle, colSeriesNumberCellStyle } = this.attribute as TableSeriesNumberAttributes; + for (const name of this.interactionState.selectIndexs) { + const isRow = name.startsWith('row'); + const isCol = name.startsWith('col'); + const index = Number(name.split('-')[1]); + if (isRow) { + this.getRowSeriesNumberCellGroup(index)?.useStates([SeriesNumberCellStateValue.select]); + } else if (isCol) { + this.getColSeriesNumberCellGroup(index)?.useStates([SeriesNumberCellStateValue.select]); + } else { + this._cornerGroup.useStates([SeriesNumberCellStateValue.select]); + } + } + this.stage.render(); + } +} diff --git a/packages/vrender-components/src/table-series-number/tools.ts b/packages/vrender-components/src/table-series-number/tools.ts new file mode 100644 index 000000000..6cffe5306 --- /dev/null +++ b/packages/vrender-components/src/table-series-number/tools.ts @@ -0,0 +1,22 @@ +/** + * 生成excel的列标题,规则和excel一致,如A~Z,AA~AZ,AB~AZ,AA~ZZ,AAA~ZZZ + * @param index 从0开始 + * @returns + */ +export function generateColField(index: number): string { + // 处理0-25的情况(A-Z) + if (index < 26) { + return String.fromCharCode(65 + index); + } + + const title = []; + index++; // 调整索引,使得第一个26变成AA + + while (index > 0) { + index--; // 每次循环前减1,以正确处理进位 + title.unshift(String.fromCharCode(65 + (index % 26))); + index = Math.floor(index / 26); + } + + return title.join(''); +} diff --git a/packages/vrender-components/src/table-series-number/type.ts b/packages/vrender-components/src/table-series-number/type.ts new file mode 100644 index 000000000..df7bb09d8 --- /dev/null +++ b/packages/vrender-components/src/table-series-number/type.ts @@ -0,0 +1,115 @@ +import type { + IColor, + IGroupGraphicAttribute, + IImageGraphicAttribute, + ILineGraphicAttribute, + ITextGraphicAttribute +} from '@visactor/vrender-core'; + +// export type EmptyTipIcon = IImageGraphicAttribute; +export enum SeriesNumberCellStateValue { + hover = 'hover', + select = 'select' +} +export enum SeriesNumberEvent { + seriesNumberCellHover = 'seriesNumberCellHover', + seriesNumberCellUnHover = 'seriesNumberCellUnHover', + seriesNumberCellClick = 'seriesNumberCellClick', + seriesNumberCellClickUp = 'seriesNumberCellClickUp', + seriesNumberCellCancelClick = 'seriesNumberCellCancelClick', + rowSeriesNumberWidthChange = 'rowSeriesNumberWidthChange', + + /** 调整行高开始 */ + resizeRowHeightStart = 'resizeRowHeightStart', + + /** 调整列宽开始 */ + resizeColWidthStart = 'resizeColWidthStart', + /** 右键事件 */ + seriesNumberCellRightClick = 'seriesNumberCellRightClick' +} +export type TableSeriesNumberAttributes = IGroupGraphicAttribute & { + frozenRowCount?: number; + frozenColCount?: number; + rightFrozenColCount?: number; + bottomFrozenRowCount?: number; + rowSeriesNumberGenerate?: (index: number) => string; + rowSeriesNumberWidth?: number | 'auto'; + rowHeight?: number | 'auto'; + rowCount?: number; + rowSeriesNumberCellStyle?: { + text?: ITextGraphicAttribute & { padding?: number | number[] }; + borderLine?: ILineGraphicAttribute; + bgColor?: IColor; + states?: { + hover: { + fill: IColor; + opacity: number; + }; + select?: { + fill: IColor; + opacity: number; + }; + }; + }; + colSeriesNumberGenerate?: (index: number) => string; + colSeriesNumberHeight?: number | 'auto'; + colWidth?: number | 'auto'; + colSeriesNumberCellStyle?: { + text?: ITextGraphicAttribute & { padding?: number | number[] }; + borderLine?: ILineGraphicAttribute; + bgColor?: IColor; + states?: { + hover: { + fill: IColor; + opacity: number; + }; + select?: { + fill: IColor; + opacity: number; + }; + }; + }; + colCount?: number; + cornerCellStyle?: { + borderLine?: ILineGraphicAttribute; + bgColor?: IColor; + states?: { + hover: { + fill: IColor; + opacity: number; + }; + select?: { + fill: IColor; + opacity: number; + }; + }; + }; + /** + * 是否开启选中交互 + */ + select?: boolean; + // | { + // /** + // * 触发选中交互的事件类型 + // * @since 0.20.13 + // **/ + // trigger?: GraphicEventType; + // }; + + /** + * 是否开启 hover 交互 + */ + hover?: boolean; + // | { + // /** + // * 触发hover交互的事件类型 + // * @since 0.20.13 + // **/ + // trigger?: GraphicEventType; + // /** + // * 触发取消hover交互的事件类型 + // * @since 0.20.13 + // **/ + // triggerOff?: GraphicEventType; + // }; +}; diff --git a/packages/vrender-core/CHANGELOG.json b/packages/vrender-core/CHANGELOG.json index b8b9e3e0a..7dcf1a575 100644 --- a/packages/vrender-core/CHANGELOG.json +++ b/packages/vrender-core/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@visactor/vrender-core", "entries": [ + { + "version": "1.0.14", + "tag": "@visactor/vrender-core_v1.0.14", + "date": "Fri, 29 Aug 2025 09:17:17 GMT", + "comments": { + "none": [ + { + "comment": "feat: support textMeasureId to select measure instance, closed #1897" + }, + { + "comment": "fix: fix issue with number text in cliped attr, closed #1834" + } + ] + } + }, { "version": "1.0.13", "tag": "@visactor/vrender-core_v1.0.13", diff --git a/packages/vrender-core/CHANGELOG.md b/packages/vrender-core/CHANGELOG.md index 952adf7a6..275ada5d1 100644 --- a/packages/vrender-core/CHANGELOG.md +++ b/packages/vrender-core/CHANGELOG.md @@ -1,6 +1,14 @@ # Change Log - @visactor/vrender-core -This log was last generated on Tue, 26 Aug 2025 11:35:34 GMT and should not be manually modified. +This log was last generated on Fri, 29 Aug 2025 09:17:17 GMT and should not be manually modified. + +## 1.0.14 +Fri, 29 Aug 2025 09:17:17 GMT + +### Updates + +- feat: support textMeasureId to select measure instance, closed #1897 +- fix: fix issue with number text in cliped attr, closed #1834 ## 1.0.13 Tue, 26 Aug 2025 11:35:34 GMT diff --git a/packages/vrender-core/package.json b/packages/vrender-core/package.json index 5b2194125..5007dfff3 100644 --- a/packages/vrender-core/package.json +++ b/packages/vrender-core/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender-core", - "version": "1.0.13", + "version": "1.0.14", "description": "", "sideEffects": [ "./src/modules.ts", diff --git a/packages/vrender-core/src/core/contributions/textMeasure/AtextMeasure.ts b/packages/vrender-core/src/core/contributions/textMeasure/AtextMeasure.ts index 132b35486..fc7025b2e 100644 --- a/packages/vrender-core/src/core/contributions/textMeasure/AtextMeasure.ts +++ b/packages/vrender-core/src/core/contributions/textMeasure/AtextMeasure.ts @@ -9,6 +9,7 @@ import { Logger } from '@visactor/vutils'; @injectable() export class ATextMeasure implements ITextMeasure { + id: string = 'ATextMeasure'; release: (...params: any) => void; protected canvas?: ICanvas; protected context?: IContext2d | null; diff --git a/packages/vrender-core/src/core/contributions/textMeasure/textMeasure-contribution.ts b/packages/vrender-core/src/core/contributions/textMeasure/textMeasure-contribution.ts index e1d3e2953..0638ec51b 100644 --- a/packages/vrender-core/src/core/contributions/textMeasure/textMeasure-contribution.ts +++ b/packages/vrender-core/src/core/contributions/textMeasure/textMeasure-contribution.ts @@ -4,4 +4,6 @@ import { ATextMeasure } from './AtextMeasure'; export const TextMeasureContribution = Symbol.for('TextMeasureContribution'); @injectable() -export class DefaultTextMeasureContribution extends ATextMeasure {} +export class DefaultTextMeasureContribution extends ATextMeasure { + id: string = 'DefaultTextMeasureContribution'; +} diff --git a/packages/vrender-core/src/core/graphic-utils.ts b/packages/vrender-core/src/core/graphic-utils.ts index a46b51b81..e13335abe 100644 --- a/packages/vrender-core/src/core/graphic-utils.ts +++ b/packages/vrender-core/src/core/graphic-utils.ts @@ -37,6 +37,7 @@ export class DefaultGraphicUtil implements IGraphicUtil { _canvas?: ICanvas; _context?: IContext2d | null; _textMeasure: ITextMeasure; + _textMeasureMap: Map; configured: boolean; global: IGlobal; @@ -47,6 +48,7 @@ export class DefaultGraphicUtil implements IGraphicUtil { ) { this.configured = false; this.global = application.global; + this._textMeasureMap = new Map(); this.global.hooks.onSetEnv.tap('graphic-util', (lastEnv, env, global) => { this.configured = false; this.configure(global, env); @@ -60,6 +62,14 @@ export class DefaultGraphicUtil implements IGraphicUtil { return this._textMeasure; } + getTextMeasureInstance(textMeasureId?: string): ITextMeasure { + if (!textMeasureId) { + return this.textMeasure; + } + const tm = this._textMeasureMap.get(textMeasureId); + return tm || this.textMeasure; + } + configure(global: IGlobal, env: EnvType) { if (this.configured) { return; @@ -79,7 +89,12 @@ export class DefaultGraphicUtil implements IGraphicUtil { } bindTextMeasure(tm: ITextMeasure) { - this._textMeasure = tm; + if (!this._textMeasure || tm.id === 'DefaultTextMeasureContribution') { + this._textMeasure = tm; + } + if (!this._textMeasureMap.has(tm.id)) { + this._textMeasureMap.set(tm.id, tm); + } } measureText( diff --git a/packages/vrender-core/src/graphic/graphic.ts b/packages/vrender-core/src/graphic/graphic.ts index 694da97a4..810d1b2d3 100644 --- a/packages/vrender-core/src/graphic/graphic.ts +++ b/packages/vrender-core/src/graphic/graphic.ts @@ -317,6 +317,9 @@ export abstract class Graphic = Partial; + // 外部设置,用于选择所使用的textMeasureId + declare textMeasureId?: string; + constructor(params: T = {} as T) { super(); this._AABBBounds = new AABBBounds(); diff --git a/packages/vrender-core/src/graphic/text.ts b/packages/vrender-core/src/graphic/text.ts index e39bf91ee..fc7afe336 100644 --- a/packages/vrender-core/src/graphic/text.ts +++ b/packages/vrender-core/src/graphic/text.ts @@ -97,7 +97,7 @@ export class Text extends Graphic implements IText { }); const originText = Array.isArray(text) ? text.join('') : text; - return originText !== mergedText; + return originText.toString() !== mergedText; } if (attribute.direction === 'vertical' && this.cache.verticalList && this.cache.verticalList[0]) { return this.cache.verticalList[0].map(item => item.text).join('') !== attribute.text.toString(); @@ -288,7 +288,7 @@ export class Text extends Graphic implements IText { } return this._AABBBounds; } - const textMeasure = application.graphicUtil.textMeasure; + const textMeasure = application.graphicUtil.getTextMeasureInstance(this.textMeasureId || this.stage?.textMeasureId); const layoutObj = new CanvasTextLayout(fontFamily, { fontSize, fontWeight, fontFamily, lineHeight }, textMeasure); const layoutData = layoutObj.GetLayoutByLines( text, @@ -356,7 +356,7 @@ export class Text extends Graphic implements IText { return this._AABBBounds; } - const textMeasure = application.graphicUtil.textMeasure; + const textMeasure = application.graphicUtil.getTextMeasureInstance(this.textMeasureId || this.stage?.textMeasureId); const textOptions = { fontSize, fontWeight, fontFamily, lineHeight }; const layoutObj = new CanvasTextLayout(fontFamily, textOptions, textMeasure as any); @@ -529,7 +529,7 @@ export class Text extends Graphic implements IText { */ updateVerticalMultilineAABBBounds(text: (number | string)[]): IAABBBounds { const textTheme = this.getGraphicTheme(); - const textMeasure = application.graphicUtil.textMeasure; + const textMeasure = application.graphicUtil.getTextMeasureInstance(this.textMeasureId || this.stage?.textMeasureId); let width: number; const attribute = this.attribute; const { diff --git a/packages/vrender-core/src/graphic/wrap-text.ts b/packages/vrender-core/src/graphic/wrap-text.ts index 1fce194ae..cb078f832 100644 --- a/packages/vrender-core/src/graphic/wrap-text.ts +++ b/packages/vrender-core/src/graphic/wrap-text.ts @@ -65,7 +65,7 @@ export class WrapText extends Text { return this._AABBBounds; } - const textMeasure = application.graphicUtil.textMeasure; + const textMeasure = application.graphicUtil.getTextMeasureInstance(this.textMeasureId || this.stage?.textMeasureId); const layoutObj = new CanvasTextLayout(fontFamily, { fontSize, fontWeight, fontFamily }, textMeasure as any) as any; // layoutObj内逻辑 diff --git a/packages/vrender-core/src/interface/core.ts b/packages/vrender-core/src/interface/core.ts index 71d6d03f5..3ba7937af 100644 --- a/packages/vrender-core/src/interface/core.ts +++ b/packages/vrender-core/src/interface/core.ts @@ -11,6 +11,7 @@ export interface IGraphicUtil { canvas?: ICanvas; context?: IContext2d | null; textMeasure: ITextMeasure; + getTextMeasureInstance: (textMeasureId?: string) => ITextMeasure; measureText: (text: string, tc: TextOptionsType) => { width: number; height: number }; bindTextMeasure: (tm: ITextMeasure) => void; createTextMeasureInstance: ( diff --git a/packages/vrender-core/src/interface/text.ts b/packages/vrender-core/src/interface/text.ts index c563aed87..ade87d51f 100644 --- a/packages/vrender-core/src/interface/text.ts +++ b/packages/vrender-core/src/interface/text.ts @@ -14,6 +14,7 @@ export interface TextOptionsType { } export interface ITextMeasure extends IContribution { + id: string; measureTextWidth: (text: string, options: TextOptionsType) => number; measureTextPixelHeight: (text: string, options: TextOptionsType) => number; measureTextBoundHieght: (text: string, options: TextOptionsType) => number; diff --git a/packages/vrender-kits/CHANGELOG.json b/packages/vrender-kits/CHANGELOG.json index 25eaa56d5..d9f91f0ec 100644 --- a/packages/vrender-kits/CHANGELOG.json +++ b/packages/vrender-kits/CHANGELOG.json @@ -1,6 +1,12 @@ { "name": "@visactor/vrender-kits", "entries": [ + { + "version": "1.0.14", + "tag": "@visactor/vrender-kits_v1.0.14", + "date": "Fri, 29 Aug 2025 09:17:17 GMT", + "comments": {} + }, { "version": "1.0.13", "tag": "@visactor/vrender-kits_v1.0.13", diff --git a/packages/vrender-kits/CHANGELOG.md b/packages/vrender-kits/CHANGELOG.md index 0dc20181e..abbe75cdb 100644 --- a/packages/vrender-kits/CHANGELOG.md +++ b/packages/vrender-kits/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log - @visactor/vrender-kits -This log was last generated on Tue, 26 Aug 2025 11:35:34 GMT and should not be manually modified. +This log was last generated on Fri, 29 Aug 2025 09:17:17 GMT and should not be manually modified. + +## 1.0.14 +Fri, 29 Aug 2025 09:17:17 GMT + +_Version update only_ ## 1.0.13 Tue, 26 Aug 2025 11:35:34 GMT diff --git a/packages/vrender-kits/package.json b/packages/vrender-kits/package.json index 3f20da9c1..5bce4d6bb 100644 --- a/packages/vrender-kits/package.json +++ b/packages/vrender-kits/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender-kits", - "version": "1.0.13", + "version": "1.0.14", "description": "", "sideEffects": false, "main": "cjs/index.js", @@ -21,7 +21,7 @@ }, "dependencies": { "@visactor/vutils": "1.0.6", - "@visactor/vrender-core": "workspace:1.0.13", + "@visactor/vrender-core": "workspace:1.0.14", "@resvg/resvg-js": "2.4.1", "roughjs": "4.5.2", "gifuct-js": "2.1.2", diff --git a/packages/vrender/CHANGELOG.json b/packages/vrender/CHANGELOG.json index 54cdc6e43..4455f95b3 100644 --- a/packages/vrender/CHANGELOG.json +++ b/packages/vrender/CHANGELOG.json @@ -1,6 +1,12 @@ { "name": "@visactor/vrender", "entries": [ + { + "version": "1.0.14", + "tag": "@visactor/vrender_v1.0.14", + "date": "Fri, 29 Aug 2025 09:17:17 GMT", + "comments": {} + }, { "version": "1.0.13", "tag": "@visactor/vrender_v1.0.13", diff --git a/packages/vrender/CHANGELOG.md b/packages/vrender/CHANGELOG.md index 407e9c915..30b0fa365 100644 --- a/packages/vrender/CHANGELOG.md +++ b/packages/vrender/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log - @visactor/vrender -This log was last generated on Tue, 26 Aug 2025 11:35:34 GMT and should not be manually modified. +This log was last generated on Fri, 29 Aug 2025 09:17:17 GMT and should not be manually modified. + +## 1.0.14 +Fri, 29 Aug 2025 09:17:17 GMT + +_Version update only_ ## 1.0.13 Tue, 26 Aug 2025 11:35:34 GMT diff --git a/packages/vrender/package.json b/packages/vrender/package.json index 9d61dc2c3..42aaef111 100644 --- a/packages/vrender/package.json +++ b/packages/vrender/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender", - "version": "1.0.13", + "version": "1.0.14", "description": "", "sideEffects": true, "main": "cjs/index.js", @@ -24,9 +24,9 @@ "test-watch": "cross-env DEBUG_MODE=1 jest --watch" }, "dependencies": { - "@visactor/vrender-core": "workspace:1.0.13", - "@visactor/vrender-kits": "workspace:1.0.13", - "@visactor/vrender-animate": "workspace:1.0.13" + "@visactor/vrender-core": "workspace:1.0.14", + "@visactor/vrender-kits": "workspace:1.0.14", + "@visactor/vrender-animate": "workspace:1.0.14" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/tools/bugserver-trigger/package.json b/tools/bugserver-trigger/package.json index c84bfa474..071e2eb3e 100644 --- a/tools/bugserver-trigger/package.json +++ b/tools/bugserver-trigger/package.json @@ -8,11 +8,11 @@ "ci": "ts-node --transpileOnly --skipProject ./scripts/trigger-test.ts" }, "dependencies": { - "@visactor/vrender": "workspace:1.0.13", - "@visactor/vrender-core": "workspace:1.0.13", - "@visactor/vrender-kits": "workspace:1.0.13", - "@visactor/vrender-components": "workspace:1.0.13", - "@visactor/vrender-animate": "workspace:1.0.13" + "@visactor/vrender": "workspace:1.0.14", + "@visactor/vrender-core": "workspace:1.0.14", + "@visactor/vrender-kits": "workspace:1.0.14", + "@visactor/vrender-components": "workspace:1.0.14", + "@visactor/vrender-animate": "workspace:1.0.14" }, "devDependencies": { "@rushstack/eslint-patch": "~1.1.4",