diff --git a/common/changes/@visactor/vtable/feat-custom-select_2024-11-19-09-29.json b/common/changes/@visactor/vtable/feat-custom-select_2024-11-19-09-29.json new file mode 100644 index 000000000..b92c25949 --- /dev/null +++ b/common/changes/@visactor/vtable/feat-custom-select_2024-11-19-09-29.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "feat: add setCustomSelectRanges in stateManager #2750 #2845", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file diff --git a/packages/vtable/examples/interactive/highlight-color.ts b/packages/vtable/examples/interactive/highlight-color.ts index 421cb1059..413107d71 100644 --- a/packages/vtable/examples/interactive/highlight-color.ts +++ b/packages/vtable/examples/interactive/highlight-color.ts @@ -77,6 +77,28 @@ export function createTable() { customGrapicKeys: ['col', 'row'] }); + tableInstance.stateManager.setCustomSelectRanges([ + { + range: { + start: { + col: 0, + row: 4 + }, + end: { + col: 5, + row: 4 + } + }, + style: { + cellBorderColor: 'blue', + cellBorderLineWidth: 2, + cellBorderLineDash: [5, 5] + } + } + ]); + const highlightPlugin = new VTable.HeaderHighlightPlugin(tableInstance); window.highlightPlugin = highlightPlugin; + + // tableInstance.scenegraph.temporarilyUpdateSelectRectStyle({stroke: false}) } diff --git a/packages/vtable/src/scenegraph/scenegraph.ts b/packages/vtable/src/scenegraph/scenegraph.ts index 31461988a..1f26edcf2 100644 --- a/packages/vtable/src/scenegraph/scenegraph.ts +++ b/packages/vtable/src/scenegraph/scenegraph.ts @@ -1,4 +1,4 @@ -import type { IStage, IRect, ITextCache, INode, Text, RichText, Stage } from '@src/vrender'; +import type { IStage, IRect, ITextCache, INode, Text, RichText, Stage, IRectGraphicAttribute } from '@src/vrender'; import { createStage, createRect, IContainPointMode, container, vglobal, registerForVrender } from '@src/vrender'; import type { CellRange, CellSubLocation } from '../ts-types'; import { @@ -76,6 +76,7 @@ import { dealWithAnimationAppear } from './animation/appear'; import { updateReactContainer } from './layout/frozen-react'; import * as registerIcons from '../icons'; +import { temporarilyUpdateSelectRectStyle } from './select/update-select-style'; // import { contextModule } from './context/module'; registerForVrender(); @@ -117,6 +118,7 @@ export class Scenegraph { selectedRangeComponents: Map; /** 当前正在选择区域对应的选框组件 为什么是map 以为可能一个选中区域会被拆分为多个rect组件 三块表头和body都分别对应不同组件*/ selectingRangeComponents: Map; + customSelectedRangeComponents: Map; lastSelectId: string; component: TableComponent; stage: IStage; @@ -359,6 +361,7 @@ export class Scenegraph { this.component.addToGroup(this.componentGroup); this.selectedRangeComponents = new Map(); this.selectingRangeComponents = new Map(); + this.customSelectedRangeComponents = new Map(); } updateComponent() { @@ -582,7 +585,10 @@ export class Scenegraph { this.stage.renderNextFrame(); } resetAllSelectComponent() { - if (this.table.stateManager.select?.ranges?.length > 0) { + if ( + this.table.stateManager.select?.ranges?.length > 0 || + this.table.stateManager.select?.customSelectRanges?.length > 0 + ) { updateAllSelectComponent(this); } } @@ -728,7 +734,7 @@ export class Scenegraph { removeFillHandleFromSelectComponents() { removeFillHandleFromSelectComponents(this); } - /** 根据select状态重新创建选中range节点 目前无调用者 */ + /** 根据select状态重新创建选中range节点 */ recreateAllSelectRangeComponents() { deleteAllSelectBorder(this); this.table.stateManager.select.ranges.forEach((cellRange: CellRange) => { @@ -2076,4 +2082,12 @@ export class Scenegraph { dealWithIcon(loadingIcon, iconGraphic, col, row); } } + + temporarilyUpdateSelectRectStyle(rectAttribute: IRectGraphicAttribute) { + temporarilyUpdateSelectRectStyle(rectAttribute, this); + } + + resetSelectRectStyle() { + this.recreateAllSelectRangeComponents(); + } } diff --git a/packages/vtable/src/scenegraph/select/update-select-border.ts b/packages/vtable/src/scenegraph/select/update-select-border.ts index 1385309f9..5fdd89cd6 100644 --- a/packages/vtable/src/scenegraph/select/update-select-border.ts +++ b/packages/vtable/src/scenegraph/select/update-select-border.ts @@ -1,9 +1,13 @@ -import type { IRect } from '@src/vrender'; +import { createRect, type IRect } from '@src/vrender'; import type { Scenegraph } from '../scenegraph'; import type { CellRange, CellSubLocation } from '../../ts-types'; import { getCellMergeInfo } from '../utils/get-cell-merge'; export function updateAllSelectComponent(scene: Scenegraph) { + scene.customSelectedRangeComponents.forEach((selectComp: { rect: IRect; role: CellSubLocation }, key: string) => { + updateComponent(selectComp, key, scene); + }); + scene.selectingRangeComponents.forEach( (selectComp: { rect: IRect; fillhandle?: IRect; role: CellSubLocation }, key: string) => { updateComponent(selectComp, key, scene); diff --git a/packages/vtable/src/scenegraph/select/update-select-style.ts b/packages/vtable/src/scenegraph/select/update-select-style.ts new file mode 100644 index 000000000..072562f45 --- /dev/null +++ b/packages/vtable/src/scenegraph/select/update-select-style.ts @@ -0,0 +1,11 @@ +import type { IRect, IRectGraphicAttribute } from '@src/vrender'; +import type { Scenegraph } from '../scenegraph'; + +// for fs big screen +export function temporarilyUpdateSelectRectStyle(rectAttribute: IRectGraphicAttribute, scene: Scenegraph) { + const { selectedRangeComponents } = scene; + selectedRangeComponents.forEach((selectComp: { rect: IRect }, key: string) => { + selectComp.rect.setAttributes(rectAttribute); + }); + scene.updateNextFrame(); +} diff --git a/packages/vtable/src/state/select/custom-select.ts b/packages/vtable/src/state/select/custom-select.ts new file mode 100644 index 000000000..e2dee272d --- /dev/null +++ b/packages/vtable/src/state/select/custom-select.ts @@ -0,0 +1,43 @@ +import type { CustomSelectionStyle, StateManager } from '../state'; +import type { CellRange } from '../../ts-types'; +import type { IRect, IRectGraphicAttribute } from '@visactor/vrender-core'; +import { createRect } from '@visactor/vrender-core'; +import { updateAllSelectComponent } from '../../scenegraph/select/update-select-border'; +import type { Scenegraph } from '../../scenegraph/scenegraph'; + +export function deletaCustomSelectRanges(state: StateManager) { + const { customSelectedRangeComponents } = state.table.scenegraph; + // delete graphic + customSelectedRangeComponents.forEach((selectComp: { rect: IRect }, key: string) => { + selectComp.rect.delete(); + }); + customSelectedRangeComponents.clear(); + state.select.customSelectRanges = []; +} + +export function addCustomSelectRanges( + customSelectRanges: { + range: CellRange; + style: CustomSelectionStyle; + }[], + state: StateManager +) { + const { customSelectedRangeComponents } = state.table.scenegraph; + customSelectRanges.forEach((customRange: { range: CellRange; style: CustomSelectionStyle }) => { + const { range, style } = customRange; + const rect = createRect({ + fill: style.cellBgColor ?? false, + stroke: style.cellBorderColor ?? false, + lineWidth: style.cellBorderLineWidth ?? 0, + lineDash: style.cellBorderLineDash ?? [], + pickable: false + }); + customSelectedRangeComponents.set(`${range.start.col}-${range.start.row}-${range.end.col}-${range.end.row}`, { + rect, + role: 'body' + }); + }); + state.select.customSelectRanges = customSelectRanges; + updateAllSelectComponent(state.table.scenegraph); + state.table.scenegraph.updateNextFrame(); +} diff --git a/packages/vtable/src/state/state.ts b/packages/vtable/src/state/state.ts index c7510e6dd..f95264f9a 100644 --- a/packages/vtable/src/state/state.ts +++ b/packages/vtable/src/state/state.ts @@ -30,7 +30,7 @@ import { Bounds, isObject, isString, isValid } from '@visactor/vutils'; import { updateDrill } from './drill'; import { clearChartHover, updateChartHover } from './spark-line'; import { endMoveCol, startMoveCol, updateMoveCol } from './cell-move'; -import type { FederatedWheelEvent } from '@src/vrender'; +import type { FederatedWheelEvent, IRectGraphicAttribute } from '@src/vrender'; import type { TooltipOptions } from '../ts-types/tooltip'; import { getIconAndPositionFromTarget } from '../scenegraph/utils/icon'; import type { BaseTableAPI, HeaderData } from '../ts-types/base-table'; @@ -51,6 +51,14 @@ import { deleteAllSelectingBorder } from '../scenegraph/select/delete-select-bor import type { PivotTable } from '../PivotTable'; import { traverseObject } from '../tools/util'; import type { ColumnData } from '../ts-types/list-table/layout-map/api'; +import { addCustomSelectRanges, deletaCustomSelectRanges } from './select/custom-select'; + +export type CustomSelectionStyle = { + cellBorderColor?: string; //边框颜色 + cellBorderLineWidth?: number; //边框线宽度 + cellBorderLineDash?: number[]; //边框线虚线 + cellBgColor?: string; //选择框背景颜色 +}; export class StateManager { table: BaseTableAPI; @@ -81,6 +89,10 @@ export class StateManager { headerSelectMode?: 'inline' | 'cell' | 'body'; highlightInRange?: boolean; selecting: boolean; + customSelectRanges?: { + range: CellRange; + style: CustomSelectionStyle; + }[]; }; fillHandle: { direction?: 'top' | 'bottom' | 'left' | 'right'; @@ -1571,4 +1583,14 @@ export class StateManager { changeRadioOrder(sourceIndex, targetIndex, this); } } + + setCustomSelectRanges( + customSelectRanges: { + range: CellRange; + style: CustomSelectionStyle; + }[] + ) { + deletaCustomSelectRanges(this); + addCustomSelectRanges(customSelectRanges, this); + } }