From 39eaa851d6a5415b9c7bba746d23ca173ccf675f Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 11 Mar 2025 11:55:46 +0800 Subject: [PATCH 01/51] refactor: modify file structor --- .../vtable-plugins/src/carousel-animation | 1 + packages/vtable-plugins/src/header-highlight | 1 + packages/vtable-plugins/src/index.ts | 1 + packages/vtable-plugins/src/invert-highlight | 1 + packages/vtable-plugins/src/plugins | 1 + packages/vtable-plugins/src/plus-row-column | 1 + .../vtable-plugins/src/plus-row-column.ts | 10 +++++++ packages/vtable/src/body-helper/style.ts | 2 +- packages/vtable/src/chartModule.ts | 4 +-- packages/vtable/src/components/axis/axis.ts | 2 +- packages/vtable/src/core/BaseTable.ts | 4 +-- packages/vtable/src/header-helper/style.ts | 2 +- packages/vtable/src/icons.ts | 4 +-- packages/vtable/src/plugins/chartModules.ts | 1 - packages/vtable/src/plugins/icons.ts | 30 ------------------- packages/vtable/src/register.ts | 6 ++-- packages/vtable/src/themes.ts | 4 +-- .../src/themes/{theme.ts => theme-define.ts} | 0 .../vtable/src/{plugins => themes}/themes.ts | 2 +- packages/vtable/src/ts-types/base-table.ts | 2 +- packages/vtable/src/ts-types/table-engine.ts | 2 +- 21 files changed, 32 insertions(+), 49 deletions(-) create mode 100644 packages/vtable-plugins/src/carousel-animation create mode 100644 packages/vtable-plugins/src/header-highlight create mode 100644 packages/vtable-plugins/src/invert-highlight create mode 100644 packages/vtable-plugins/src/plugins create mode 100644 packages/vtable-plugins/src/plus-row-column create mode 100644 packages/vtable-plugins/src/plus-row-column.ts delete mode 100644 packages/vtable/src/plugins/chartModules.ts delete mode 100644 packages/vtable/src/plugins/icons.ts rename packages/vtable/src/themes/{theme.ts => theme-define.ts} (100%) rename packages/vtable/src/{plugins => themes}/themes.ts (50%) diff --git a/packages/vtable-plugins/src/carousel-animation b/packages/vtable-plugins/src/carousel-animation new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/packages/vtable-plugins/src/carousel-animation @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/vtable-plugins/src/header-highlight b/packages/vtable-plugins/src/header-highlight new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/packages/vtable-plugins/src/header-highlight @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/vtable-plugins/src/index.ts b/packages/vtable-plugins/src/index.ts index dfb38a632a..eab9cc19e1 100644 --- a/packages/vtable-plugins/src/index.ts +++ b/packages/vtable-plugins/src/index.ts @@ -1,3 +1,4 @@ export * from './carousel-animation'; export * from './invert-highlight'; export * from './header-highlight'; +export * from './plus-row-column'; diff --git a/packages/vtable-plugins/src/invert-highlight b/packages/vtable-plugins/src/invert-highlight new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/packages/vtable-plugins/src/invert-highlight @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/vtable-plugins/src/plugins b/packages/vtable-plugins/src/plugins new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/packages/vtable-plugins/src/plugins @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/vtable-plugins/src/plus-row-column b/packages/vtable-plugins/src/plus-row-column new file mode 100644 index 0000000000..0519ecba6e --- /dev/null +++ b/packages/vtable-plugins/src/plus-row-column @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/vtable-plugins/src/plus-row-column.ts b/packages/vtable-plugins/src/plus-row-column.ts new file mode 100644 index 0000000000..abd7609889 --- /dev/null +++ b/packages/vtable-plugins/src/plus-row-column.ts @@ -0,0 +1,10 @@ +import type { BaseTableAPI } from '@visactor/vtable/src/ts-types/base-table'; + +export class PlusRowColumnPlugin { + constructor(private table: BaseTableAPI) { + this.table = table; + } + init() { + // + } +} diff --git a/packages/vtable/src/body-helper/style.ts b/packages/vtable/src/body-helper/style.ts index b82463ec65..e4011b331d 100644 --- a/packages/vtable/src/body-helper/style.ts +++ b/packages/vtable/src/body-helper/style.ts @@ -13,7 +13,7 @@ import { ImageStyle } from './style/ImageStyle'; import { TextStyle } from './style/MultilineTextStyle'; import { NumberStyle } from './style/NumberStyle'; import { Style } from './style/Style'; -import type { TableTheme } from '../themes/theme'; +import type { TableTheme } from '../themes/theme-define'; import { CheckboxStyle } from './style/CheckboxStyle'; import { RadioStyle } from './style/RadioStyle'; import { SwitchStyle } from './style/SwitchStyle'; diff --git a/packages/vtable/src/chartModule.ts b/packages/vtable/src/chartModule.ts index 06f9d4aee2..a44069e3a6 100644 --- a/packages/vtable/src/chartModule.ts +++ b/packages/vtable/src/chartModule.ts @@ -1,7 +1,7 @@ /* eslint-disable sort-imports */ import { extend } from './tools/helper'; -import { chartTypes as plugins } from './plugins/chartModules'; +export const chartTypes: { [key: string]: any } = {}; const builtin = {}; export function get(): { [key: string]: any } { - return extend(builtin, plugins); + return extend(builtin, chartTypes); } diff --git a/packages/vtable/src/components/axis/axis.ts b/packages/vtable/src/components/axis/axis.ts index 026a3862fa..2bd745a455 100644 --- a/packages/vtable/src/components/axis/axis.ts +++ b/packages/vtable/src/components/axis/axis.ts @@ -13,7 +13,7 @@ import type { IBaseScale } from '@visactor/vscale'; import { ticks } from '@src/vrender'; import { LinearAxisScale } from './linear-scale'; import { doOverlap } from './label-overlap'; -import type { TableTheme } from '../../themes/theme'; +import type { TableTheme } from '../../themes/theme-define'; const DEFAULT_BAND_INNER_PADDING = 0.1; const DEFAULT_BAND_OUTER_PADDING = 0.3; diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index 989ff2d10a..3bab62ec09 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -62,7 +62,7 @@ import { EventHandler } from '../event/EventHandler'; import { EventTarget } from '../event/EventTarget'; import { NumberMap } from '../tools/NumberMap'; import { Rect } from '../tools/Rect'; -import type { TableTheme } from '../themes/theme'; +import type { TableTheme } from '../themes/theme-define'; import { throttle2 } from '../tools/util'; import themes from '../themes'; import { Env } from '../tools/env'; @@ -96,7 +96,6 @@ import type { SeriesNumberColumnData } from '../ts-types/list-table/layout-map/api'; import type { TooltipOptions } from '../ts-types/tooltip'; -import { IconCache } from '../plugins/icons'; import { _applyColWidthLimits, _getScrollableVisibleRect, @@ -2256,7 +2255,6 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { } internalProps.tooltipHandler?.release?.(); internalProps.menuHandler?.release?.(); - IconCache.clearAll(); super.release?.(); internalProps.handler?.release?.(); diff --git a/packages/vtable/src/header-helper/style.ts b/packages/vtable/src/header-helper/style.ts index 89828219e2..53b791ea50 100644 --- a/packages/vtable/src/header-helper/style.ts +++ b/packages/vtable/src/header-helper/style.ts @@ -3,7 +3,7 @@ import type { FullExtendStyle, HeaderStyleOption, StylePropertyFunctionArg } fro import { TextHeaderStyle } from './style/MultilineTextHeaderStyle'; // import { SortHeaderStyle } from "./style/SortHeaderStyle"; import { Style } from './style/Style'; -import type { TableTheme } from '../themes/theme'; +import type { TableTheme } from '../themes/theme-define'; import { CheckboxStyle } from './style/CheckboxStyle'; export { Style, TextHeaderStyle }; diff --git a/packages/vtable/src/icons.ts b/packages/vtable/src/icons.ts index 0837289ee2..a022513c85 100644 --- a/packages/vtable/src/icons.ts +++ b/packages/vtable/src/icons.ts @@ -4,7 +4,7 @@ import type { ColumnIconOption, ImageIcon, ITableThemeDefine, SvgIcon } from './ts-types'; import { IconPosition, IconFuncTypeEnum } from './ts-types'; import { extend } from './tools/helper'; -import { icons as plugins } from './plugins/icons'; +import { icons as plugins } from './icons'; import { DrillDown, DrillUp } from './tools/global'; let sort_color: string; let sort_color_opacity: string; @@ -395,7 +395,7 @@ const builtins = { }; } }; - +export const icons: { [key: string]: ColumnIconOption } = {}; export function get(): { [key: string]: ColumnIconOption } { return extend(builtins, plugins); } diff --git a/packages/vtable/src/plugins/chartModules.ts b/packages/vtable/src/plugins/chartModules.ts deleted file mode 100644 index 9d89bf5763..0000000000 --- a/packages/vtable/src/plugins/chartModules.ts +++ /dev/null @@ -1 +0,0 @@ -export const chartTypes: { [key: string]: any } = {}; diff --git a/packages/vtable/src/plugins/icons.ts b/packages/vtable/src/plugins/icons.ts deleted file mode 100644 index c4c0391cac..0000000000 --- a/packages/vtable/src/plugins/icons.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { ColumnIconOption } from '../ts-types'; - -export const icons: { [key: string]: ColumnIconOption } = {}; - -export class IconCache { - private static cache: Map = new Map(); - - static setIcon(key: string, icon: ColumnIconOption) { - this.cache.set(key, icon); - } - - static getIcon(key: string): ColumnIconOption | null { - if (this.cache.has(key)) { - return this.cache.get(key) as ColumnIconOption; - } - return null; - } - - static hasIcon(key: string): boolean { - return this.cache.has(key); - } - - static clear(key: string): boolean { - return this.cache.delete(key); - } - - static clearAll() { - this.cache = new Map(); - } -} diff --git a/packages/vtable/src/register.ts b/packages/vtable/src/register.ts index 2fd8e14182..dcfe211036 100644 --- a/packages/vtable/src/register.ts +++ b/packages/vtable/src/register.ts @@ -1,6 +1,6 @@ -import { icons as iconPlugins } from './plugins/icons'; -import { themes as themePlugins } from './plugins/themes'; -import { chartTypes as chartTypePlugins } from './plugins/chartModules'; +import { icons as iconPlugins } from './icons'; +import { themes as themePlugins } from './themes/themes'; +import { chartTypes as chartTypePlugins } from './chartModule'; import type { ColumnIconOption, ITableThemeDefine } from './ts-types'; import type { IEditor } from '@visactor/vtable-editors'; import { editors } from './edit/editors'; diff --git a/packages/vtable/src/themes.ts b/packages/vtable/src/themes.ts index 0b71d9b9ce..b9dc51c180 100644 --- a/packages/vtable/src/themes.ts +++ b/packages/vtable/src/themes.ts @@ -5,8 +5,8 @@ import brightTheme from './themes/BRIGHT'; import arcoTheme from './themes/ARCO'; import defaultTheme from './themes/DEFAULT'; import materialDesignTheme from './themes/SIMPLIFY'; -import { themes as plugins } from './plugins/themes'; -import { TableTheme } from './themes/theme'; +import { themes as plugins } from './themes/themes'; +import { TableTheme } from './themes/theme-define'; import type { ITableThemeDefine } from './ts-types'; export const DARK = new TableTheme(darkTheme, darkTheme); export const BRIGHT = new TableTheme(brightTheme, brightTheme); diff --git a/packages/vtable/src/themes/theme.ts b/packages/vtable/src/themes/theme-define.ts similarity index 100% rename from packages/vtable/src/themes/theme.ts rename to packages/vtable/src/themes/theme-define.ts diff --git a/packages/vtable/src/plugins/themes.ts b/packages/vtable/src/themes/themes.ts similarity index 50% rename from packages/vtable/src/plugins/themes.ts rename to packages/vtable/src/themes/themes.ts index 5d0a211894..99c1f88a3f 100644 --- a/packages/vtable/src/plugins/themes.ts +++ b/packages/vtable/src/themes/themes.ts @@ -1,3 +1,3 @@ -import type { TableTheme } from '../themes/theme'; +import type { TableTheme } from '../themes/theme-define'; export const themes: { [key: string]: TableTheme } = {}; diff --git a/packages/vtable/src/ts-types/base-table.ts b/packages/vtable/src/ts-types/base-table.ts index 61ea79d176..31e2e3367b 100644 --- a/packages/vtable/src/ts-types/base-table.ts +++ b/packages/vtable/src/ts-types/base-table.ts @@ -27,7 +27,7 @@ import type { SeriesNumberColumnData } from './list-table/layout-map/api'; export type { HeaderData } from './list-table/layout-map/api'; -import type { TableTheme } from '../themes/theme'; +import type { TableTheme } from '../themes/theme-define'; import type { ICustomRender } from './customElement'; import type { LayoutObjectId } from './table-engine'; import type { Rect } from '../tools/Rect'; diff --git a/packages/vtable/src/ts-types/table-engine.ts b/packages/vtable/src/ts-types/table-engine.ts index 386a746940..fa020c9db4 100644 --- a/packages/vtable/src/ts-types/table-engine.ts +++ b/packages/vtable/src/ts-types/table-engine.ts @@ -33,7 +33,7 @@ import type { EditManager } from '../edit/edit-manager'; import type { ICustomRender } from './customElement'; import type { ICustomLayout } from './customLayout'; import type { ColorPropertyDefine, StylePropertyFunctionArg } from './style-define'; -import type { TableTheme } from '../themes/theme'; +import type { TableTheme } from '../themes/theme-define'; export interface CellAddress { col: number; From 3592409bb305d6f634e830948340524e3c99114c Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 13 Mar 2025 20:16:24 +0800 Subject: [PATCH 02/51] refactor: plugins manager --- .../demo/add-row-column/add-row-column.ts | 94 ++++ packages/vtable-plugins/demo/menu.ts | 9 + packages/vtable-plugins/src/add-row-column.ts | 420 ++++++++++++++++++ .../vtable-plugins/src/carousel-animation | 1 - .../vtable-plugins/src/case-before-init.ts | 23 + packages/vtable-plugins/src/header-highlight | 1 - packages/vtable-plugins/src/index.ts | 3 +- packages/vtable-plugins/src/invert-highlight | 1 - packages/vtable-plugins/src/plugins | 1 - packages/vtable-plugins/src/plus-row-column | 1 - .../vtable-plugins/src/plus-row-column.ts | 10 - packages/vtable/src/ListTable.ts | 12 +- packages/vtable/src/PivotChart.ts | 12 +- packages/vtable/src/PivotTable.ts | 12 +- packages/vtable/src/core/BaseTable.ts | 19 + packages/vtable/src/core/TABLE_EVENT_TYPE.ts | 6 + packages/vtable/src/index.ts | 7 +- packages/vtable/src/plugins/index.ts | 3 + packages/vtable/src/plugins/interface.ts | 25 ++ packages/vtable/src/plugins/plugin-manager.ts | 61 +++ packages/vtable/src/ts-types/base-table.ts | 3 + packages/vtable/src/ts-types/events.ts | 15 +- 22 files changed, 687 insertions(+), 52 deletions(-) create mode 100644 packages/vtable-plugins/demo/add-row-column/add-row-column.ts create mode 100644 packages/vtable-plugins/src/add-row-column.ts delete mode 100644 packages/vtable-plugins/src/carousel-animation create mode 100644 packages/vtable-plugins/src/case-before-init.ts delete mode 100644 packages/vtable-plugins/src/header-highlight delete mode 100644 packages/vtable-plugins/src/invert-highlight delete mode 100644 packages/vtable-plugins/src/plugins delete mode 100644 packages/vtable-plugins/src/plus-row-column delete mode 100644 packages/vtable-plugins/src/plus-row-column.ts create mode 100644 packages/vtable/src/plugins/index.ts create mode 100644 packages/vtable/src/plugins/interface.ts create mode 100644 packages/vtable/src/plugins/plugin-manager.ts diff --git a/packages/vtable-plugins/demo/add-row-column/add-row-column.ts b/packages/vtable-plugins/demo/add-row-column/add-row-column.ts new file mode 100644 index 0000000000..a8857fbd5e --- /dev/null +++ b/packages/vtable-plugins/demo/add-row-column/add-row-column.ts @@ -0,0 +1,94 @@ +import * as VTable from '@visactor/vtable'; +import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; +import { AddRowColumnPlugin } from '../../src'; +const CONTAINER_ID = 'vTable'; +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + +export function createTable() { + const records = generatePersons(20); + const columns: VTable.ColumnsDefine = [ + { + field: 'image', + title: '行号', + width: 80, + cellType: 'image', + keepAspectRatio: true + }, + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ]; + const addRowColumn = new AddRowColumnPlugin(); + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records, + columns, + padding: 30, + // theme: VTable.themes.DARK, + // heightMode: 'adaptive', + select: { + disableSelect: true + }, + plugins: [addRowColumn] + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + bindDebugTool(tableInstance.scenegraph.stage, { + customGrapicKeys: ['col', 'row'] + }); +} diff --git a/packages/vtable-plugins/demo/menu.ts b/packages/vtable-plugins/demo/menu.ts index 269806252f..8c3c265923 100644 --- a/packages/vtable-plugins/demo/menu.ts +++ b/packages/vtable-plugins/demo/menu.ts @@ -25,5 +25,14 @@ export const menus = [ name: 'invert-highlight' } ] + }, + { + menu: 'add-row-column', + children: [ + { + path: 'add-row-column', + name: 'add-row-column' + } + ] } ]; diff --git a/packages/vtable-plugins/src/add-row-column.ts b/packages/vtable-plugins/src/add-row-column.ts new file mode 100644 index 0000000000..f9bd25113d --- /dev/null +++ b/packages/vtable-plugins/src/add-row-column.ts @@ -0,0 +1,420 @@ +import * as VTable from '@visactor/vtable'; +export interface AddRowColumnOptions { + addColumnEnable?: boolean; + addRowEnable?: boolean; + addColumnCallback?: (col: number) => void; + addRowCallback?: (row: number) => void; +} + +export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { + id = 'add-row-column'; + name = 'Add-Row-Column'; + type: 'layout' = 'layout'; + runTime = [ + VTable.TABLE_EVENT_TYPE.MOUSEENTER_CELL, + VTable.TABLE_EVENT_TYPE.MOUSELEAVE_CELL, + VTable.TABLE_EVENT_TYPE.MOUSELEAVE_TABLE + ]; + pluginOptions: AddRowColumnOptions; + table: VTable.ListTable; + hoverCell: VTable.TYPES.CellAddressWithBound; + hideAllTimeoutId_addColumn: NodeJS.Timeout; + hideAllTimeoutId_addRow: NodeJS.Timeout; + leftDotForAddColumn: HTMLElement; + rightDotForAddColumn: HTMLElement; + addIconForAddColumn: HTMLElement; + addLineForAddColumn: HTMLElement; + topDotForAddRow: HTMLElement; + bottomDotForAddRow: HTMLElement; + addIconForAddRow: HTMLElement; + addLineForAddRow: HTMLElement; + + constructor( + pluginOptions: AddRowColumnOptions = { + addColumnEnable: true, + addRowEnable: true + } + ) { + this.pluginOptions = pluginOptions; + if (this.pluginOptions.addColumnEnable) { + this.initAddColumnDomElement(); + this.bindEventForAddColumn(); + } + if (this.pluginOptions.addRowEnable) { + this.initAddRowDomElement(); + this.bindEventForAddRow(); + } + } + run(...args: any[]) { + const eventArgs = args[0]; + const runTime = args[1]; + const table: VTable.BaseTableAPI = args[2]; + this.table = table as VTable.ListTable; + if (runTime === VTable.TABLE_EVENT_TYPE.MOUSEENTER_CELL) { + clearTimeout(this.hideAllTimeoutId_addColumn); + clearTimeout(this.hideAllTimeoutId_addRow); + console.log('mouseenter cell', args); + const canvasBounds = table.canvas.getBoundingClientRect(); + const cell = table.getCellAtRelativePosition( + eventArgs.event.clientX - canvasBounds.left, + eventArgs.event.clientY - canvasBounds.top + ); + this.hoverCell = cell; + const cellRect = table.getCellRelativeRect(cell.col, cell.row); + if (this.pluginOptions.addColumnEnable) { + this.showDotForAddColumn( + canvasBounds.top - 6, + cellRect.left + canvasBounds.left, + cellRect.right + canvasBounds.left + ); + } + if (this.pluginOptions.addRowEnable) { + this.showDotForAddRow( + cellRect.top + canvasBounds.top, + canvasBounds.left - 6, + cellRect.bottom + canvasBounds.top + ); + } + // console.log('cellRect', cellRect); + } else if (runTime === VTable.TABLE_EVENT_TYPE.MOUSELEAVE_CELL) { + console.log('mouseleave cell'); + } else if (runTime === VTable.TABLE_EVENT_TYPE.MOUSELEAVE_TABLE) { + if (this.pluginOptions.addColumnEnable) { + this.delayHideAllForAddColumn(); + } + if (this.pluginOptions.addRowEnable) { + this.delayHideAllForAddRow(); + } + } + } + // #region 添加列 + initAddColumnDomElement() { + //创建一个div 作为hoverCell的顶部左侧的圆点 + this.leftDotForAddColumn = document.createElement('div'); + this.leftDotForAddColumn.style.width = '6px'; + this.leftDotForAddColumn.style.height = '6px'; + this.leftDotForAddColumn.style.backgroundColor = '#4A90E2'; // 蓝色 + this.leftDotForAddColumn.style.position = 'absolute'; + this.leftDotForAddColumn.style.cursor = 'pointer'; + this.leftDotForAddColumn.style.zIndex = '1000'; + this.leftDotForAddColumn.style.borderRadius = '50%'; + this.leftDotForAddColumn.style.border = '1px solid white'; + this.leftDotForAddColumn.style.boxShadow = '0 1px 3px rgba(0,0,0,0.2)'; + document.body.appendChild(this.leftDotForAddColumn); + + //创建一个div 作为hoverCell的顶部右侧的圆点 + this.rightDotForAddColumn = document.createElement('div'); + this.rightDotForAddColumn.style.width = '6px'; + this.rightDotForAddColumn.style.height = '6px'; + this.rightDotForAddColumn.style.backgroundColor = '#4A90E2'; // 蓝色 + this.rightDotForAddColumn.style.position = 'absolute'; + this.rightDotForAddColumn.style.cursor = 'pointer'; + this.rightDotForAddColumn.style.zIndex = '1000'; + this.rightDotForAddColumn.style.borderRadius = '50%'; + this.rightDotForAddColumn.style.border = '1px solid white'; + this.rightDotForAddColumn.style.boxShadow = '0 1px 3px rgba(0,0,0,0.2)'; + document.body.appendChild(this.rightDotForAddColumn); + + //创建+加号 当鼠标hover到圆点上时,显示+加号 + this.addIconForAddColumn = document.createElement('div'); + this.addIconForAddColumn.style.width = '18px'; + this.addIconForAddColumn.style.height = '18px'; + this.addIconForAddColumn.style.backgroundColor = '#4A90E2'; // 蓝色 + this.addIconForAddColumn.style.position = 'absolute'; + this.addIconForAddColumn.style.zIndex = '1001'; + this.addIconForAddColumn.style.display = 'none'; + this.addIconForAddColumn.style.borderRadius = '50%'; + this.addIconForAddColumn.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)'; + this.addIconForAddColumn.style.display = 'flex'; + this.addIconForAddColumn.style.justifyContent = 'center'; + this.addIconForAddColumn.style.alignItems = 'center'; + this.addIconForAddColumn.style.border = '1px solid white'; + document.body.appendChild(this.addIconForAddColumn); + + //addIcon中添加一个+号 + const addIconText = document.createElement('div'); + addIconText.textContent = '+'; + addIconText.style.color = 'white'; + addIconText.style.fontSize = '18px'; + addIconText.style.fontWeight = 'bold'; + addIconText.style.lineHeight = '15px'; + addIconText.style.userSelect = 'none'; + addIconText.style.cursor = 'pointer'; + addIconText.style.verticalAlign = 'top'; + addIconText.style.textAlign = 'center'; + + this.addIconForAddColumn.appendChild(addIconText); + + // 创建加号下面列间隔线 + this.addLineForAddColumn = document.createElement('div'); + this.addLineForAddColumn.style.width = '2px'; + this.addLineForAddColumn.style.height = '10px'; + this.addLineForAddColumn.style.backgroundColor = '#4A90E2'; // 蓝色 + this.addLineForAddColumn.style.position = 'absolute'; + this.addLineForAddColumn.style.zIndex = '1001'; + this.addLineForAddColumn.style.display = 'none'; + document.body.appendChild(this.addLineForAddColumn); + } + bindEventForAddColumn() { + this.leftDotForAddColumn.addEventListener('mouseenter', () => { + clearTimeout(this.hideAllTimeoutId_addColumn); + this.addIconForAddColumn.style.display = 'block'; + const dotWidth = this.leftDotForAddColumn.offsetWidth; + const dotHeight = this.leftDotForAddColumn.offsetHeight; + this.showAddIconForAddColumn( + this.leftDotForAddColumn.offsetLeft + dotWidth / 2, + this.leftDotForAddColumn.offsetTop + dotHeight / 2, + true + ); + this.showSplitLineForAddColumn( + this.leftDotForAddColumn.offsetLeft + dotWidth / 2 - 1, + this.leftDotForAddColumn.offsetTop + dotHeight / 2 + 2, + this.table.getDrawRange().height + ); + }); + + this.rightDotForAddColumn.addEventListener('mouseenter', () => { + clearTimeout(this.hideAllTimeoutId_addColumn); + this.addIconForAddColumn.style.display = 'block'; + const dotWidth = this.rightDotForAddColumn.offsetWidth; + const dotHeight = this.rightDotForAddColumn.offsetHeight; + this.showAddIconForAddColumn( + this.rightDotForAddColumn.offsetLeft + dotWidth / 2, + this.rightDotForAddColumn.offsetTop + dotHeight / 2, + false + ); + this.showSplitLineForAddColumn( + this.rightDotForAddColumn.offsetLeft + dotWidth / 2 - 1, + this.rightDotForAddColumn.offsetTop + dotHeight / 2 + 2, + this.table.getDrawRange().height + ); + }); + + // this.addIconForAddColumn.addEventListener('mouseenter', () => { + // clearTimeout(this.hideAllTimeoutId_addColumn); + // }); + this.addIconForAddColumn.addEventListener('mouseleave', () => { + this.addIconForAddColumn.style.display = 'none'; + this.addLineForAddColumn.style.display = 'none'; + this.delayHideAllForAddColumn(); + }); + + this.addIconForAddColumn.addEventListener('click', (e: MouseEvent) => { + const isLeft = this.addIconForAddColumn.dataset.addIconType === 'left'; + const columns = this.table.options.columns; + const col = this.hoverCell.col; + const addColIndex = isLeft ? col : col + 1; + if (this.pluginOptions.addColumnCallback) { + this.pluginOptions.addColumnCallback(addColIndex); + } else { + columns.splice(addColIndex, 0, { + field: `new-column-${col}`, + title: `New Column ${col}`, + width: 100 + }); + this.table.updateColumns(columns); + } + this.delayHideAllForAddColumn(0); + }); + } + showDotForAddColumn(top: number, left: number, right: number) { + // 动态获取元素尺寸 + const dotWidth = this.leftDotForAddColumn.offsetWidth; + const dotHeight = this.leftDotForAddColumn.offsetHeight; + this.leftDotForAddColumn.style.left = `${left - dotWidth / 2}px`; + this.leftDotForAddColumn.style.top = `${top - dotHeight / 2}px`; + this.rightDotForAddColumn.style.left = `${right - dotWidth / 2}px`; + this.rightDotForAddColumn.style.top = `${top - dotHeight / 2}px`; + this.leftDotForAddColumn.style.display = 'block'; + this.rightDotForAddColumn.style.display = 'block'; + } + showAddIconForAddColumn(left: number, top: number, isLeft: boolean) { + // 动态获取元素尺寸 + const iconWidth = this.addIconForAddColumn.offsetWidth; + const iconHeight = this.addIconForAddColumn.offsetHeight; + const dotHeight = this.leftDotForAddColumn.offsetHeight; + this.addIconForAddColumn.style.left = `${left - iconWidth / 2}px`; + this.addIconForAddColumn.style.top = `${top - iconHeight / 2 - dotHeight / 2}px`; + if (isLeft) { + this.addIconForAddColumn.dataset.addIconType = 'left'; + } else { + this.addIconForAddColumn.dataset.addIconType = 'right'; + } + } + showSplitLineForAddColumn(left: number, top: number, height: number) { + this.addLineForAddColumn.style.left = `${left}px`; + this.addLineForAddColumn.style.top = `${top}px`; + this.addLineForAddColumn.style.height = `${height}px`; + this.addLineForAddColumn.style.display = 'block'; + } + delayHideAllForAddColumn(delay: number = 1000) { + this.hideAllTimeoutId_addColumn = setTimeout(() => { + this.addIconForAddColumn.style.display = 'none'; + this.addLineForAddColumn.style.display = 'none'; + this.leftDotForAddColumn.style.display = 'none'; + this.rightDotForAddColumn.style.display = 'none'; + }, delay); + } + // #endregion + + // #region 添加行 + initAddRowDomElement() { + //创建一个div 作为hoverCell的顶部左侧的圆点 + this.topDotForAddRow = document.createElement('div'); + this.topDotForAddRow.style.width = '6px'; + this.topDotForAddRow.style.height = '6px'; + this.topDotForAddRow.style.backgroundColor = '#4A90E2'; // 蓝色 + this.topDotForAddRow.style.position = 'absolute'; + this.topDotForAddRow.style.cursor = 'pointer'; + this.topDotForAddRow.style.zIndex = '1000'; + this.topDotForAddRow.style.borderRadius = '50%'; + this.topDotForAddRow.style.border = '1px solid white'; + this.topDotForAddRow.style.boxShadow = '0 1px 3px rgba(0,0,0,0.2)'; + document.body.appendChild(this.topDotForAddRow); + + //创建一个div 作为hoverCell的底部右侧的圆点 + this.bottomDotForAddRow = document.createElement('div'); + this.bottomDotForAddRow.style.width = '6px'; + this.bottomDotForAddRow.style.height = '6px'; + this.bottomDotForAddRow.style.backgroundColor = '#4A90E2'; // 蓝色 + this.bottomDotForAddRow.style.position = 'absolute'; + this.bottomDotForAddRow.style.cursor = 'pointer'; + this.bottomDotForAddRow.style.zIndex = '1000'; + this.bottomDotForAddRow.style.borderRadius = '50%'; + this.bottomDotForAddRow.style.border = '1px solid white'; + this.bottomDotForAddRow.style.boxShadow = '0 1px 3px rgba(0,0,0,0.2)'; + document.body.appendChild(this.bottomDotForAddRow); + + //创建+加号 当鼠标hover到圆点上时,显示+加号 + this.addIconForAddRow = document.createElement('div'); + this.addIconForAddRow.style.width = '18px'; + this.addIconForAddRow.style.height = '18px'; + this.addIconForAddRow.style.backgroundColor = '#4A90E2'; // 蓝色 + this.addIconForAddRow.style.position = 'absolute'; + this.addIconForAddRow.style.zIndex = '1001'; + this.addIconForAddRow.style.display = 'none'; + this.addIconForAddRow.style.borderRadius = '50%'; + this.addIconForAddRow.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)'; + this.addIconForAddRow.style.display = 'flex'; + this.addIconForAddRow.style.justifyContent = 'center'; + this.addIconForAddRow.style.alignItems = 'center'; + this.addIconForAddRow.style.border = '1px solid white'; + document.body.appendChild(this.addIconForAddRow); + + //addIcon中添加一个+号 + const addIconText = document.createElement('div'); + addIconText.textContent = '+'; + addIconText.style.color = 'white'; + addIconText.style.fontSize = '18px'; + addIconText.style.fontWeight = 'bold'; + addIconText.style.lineHeight = '15px'; + addIconText.style.userSelect = 'none'; + addIconText.style.cursor = 'pointer'; + addIconText.style.verticalAlign = 'top'; + addIconText.style.textAlign = 'center'; + + this.addIconForAddRow.appendChild(addIconText); + + // 创建加号下面行间隔线 + this.addLineForAddRow = document.createElement('div'); + this.addLineForAddRow.style.width = '10px'; + this.addLineForAddRow.style.height = '2px'; + this.addLineForAddRow.style.backgroundColor = '#4A90E2'; // 蓝色 + this.addLineForAddRow.style.position = 'absolute'; + this.addLineForAddRow.style.zIndex = '1001'; + this.addLineForAddRow.style.display = 'none'; + document.body.appendChild(this.addLineForAddRow); + } + bindEventForAddRow() { + this.topDotForAddRow.addEventListener('mouseenter', () => { + clearTimeout(this.hideAllTimeoutId_addRow); + this.addIconForAddRow.style.display = 'block'; + const dotWidth = this.topDotForAddRow.offsetWidth; + const dotHeight = this.topDotForAddRow.offsetHeight; + this.showAddIconForAddRow( + this.topDotForAddRow.offsetLeft + dotWidth / 2, + this.topDotForAddRow.offsetTop + dotHeight / 2, + true + ); + this.showSplitLineForAddRow( + this.topDotForAddRow.offsetLeft + dotWidth + 2, + this.topDotForAddRow.offsetTop + dotHeight / 2 - 1, + this.table.getDrawRange().width + ); + }); + + this.bottomDotForAddRow.addEventListener('mouseenter', () => { + clearTimeout(this.hideAllTimeoutId_addRow); + this.addIconForAddRow.style.display = 'block'; + const dotWidth = this.bottomDotForAddRow.offsetWidth; + const dotHeight = this.bottomDotForAddRow.offsetHeight; + this.showAddIconForAddRow( + this.bottomDotForAddRow.offsetLeft + dotWidth / 2, + this.bottomDotForAddRow.offsetTop + dotHeight / 2, + false + ); + this.showSplitLineForAddRow( + this.bottomDotForAddRow.offsetLeft + dotWidth + 2, + this.bottomDotForAddRow.offsetTop + dotHeight / 2 - 1, + this.table.getDrawRange().height + ); + }); + + this.addIconForAddRow.addEventListener('mouseleave', () => { + this.addIconForAddRow.style.display = 'none'; + this.addLineForAddRow.style.display = 'none'; + this.delayHideAllForAddRow(); + }); + + this.addIconForAddRow.addEventListener('click', (e: MouseEvent) => { + const isTop = this.addIconForAddRow.dataset.addIconType === 'top'; + const row = this.hoverCell.row; + const addRowIndex = isTop ? row : row + 1; + if (this.pluginOptions.addRowCallback) { + this.pluginOptions.addRowCallback(addRowIndex); + } else { + //debugger; + } + this.delayHideAllForAddRow(0); + }); + } + showDotForAddRow(top: number, left: number, bottom: number) { + // 动态获取元素尺寸 + const dotWidth = this.topDotForAddRow.offsetWidth; + const dotHeight = this.topDotForAddRow.offsetHeight; + this.topDotForAddRow.style.left = `${left - dotWidth / 2}px`; + this.topDotForAddRow.style.top = `${top - dotHeight / 2}px`; + this.bottomDotForAddRow.style.left = `${left - dotWidth / 2}px`; + this.bottomDotForAddRow.style.top = `${bottom - dotHeight / 2}px`; + this.topDotForAddRow.style.display = 'block'; + this.bottomDotForAddRow.style.display = 'block'; + } + showAddIconForAddRow(left: number, top: number, isTop: boolean) { + // 动态获取元素尺寸 + const iconWidth = this.addIconForAddRow.offsetWidth; + const iconHeight = this.addIconForAddRow.offsetHeight; + const dotWidth = this.topDotForAddRow.offsetWidth; + this.addIconForAddRow.style.left = `${left - iconWidth / 2 - dotWidth / 2}px`; + this.addIconForAddRow.style.top = `${top - iconHeight / 2}px`; + if (isTop) { + this.addIconForAddRow.dataset.addIconType = 'top'; + } else { + this.addIconForAddRow.dataset.addIconType = 'bottom'; + } + } + showSplitLineForAddRow(left: number, top: number, width: number) { + this.addLineForAddRow.style.left = `${left}px`; + this.addLineForAddRow.style.top = `${top}px`; + this.addLineForAddRow.style.width = `${width}px`; + this.addLineForAddRow.style.display = 'block'; + } + delayHideAllForAddRow(delay: number = 1000) { + this.hideAllTimeoutId_addRow = setTimeout(() => { + this.addIconForAddRow.style.display = 'none'; + this.addLineForAddRow.style.display = 'none'; + this.topDotForAddRow.style.display = 'none'; + this.bottomDotForAddRow.style.display = 'none'; + }, delay); + } + // #endregion +} diff --git a/packages/vtable-plugins/src/carousel-animation b/packages/vtable-plugins/src/carousel-animation deleted file mode 100644 index 0519ecba6e..0000000000 --- a/packages/vtable-plugins/src/carousel-animation +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/vtable-plugins/src/case-before-init.ts b/packages/vtable-plugins/src/case-before-init.ts new file mode 100644 index 0000000000..50f0c3366c --- /dev/null +++ b/packages/vtable-plugins/src/case-before-init.ts @@ -0,0 +1,23 @@ +import * as VTable from '@visactor/vtable'; +export interface SomeOptions { + propone: string; +} + +export class BeforeInitPlugin implements VTable.plugins.IVTablePlugin { + id = '....'; + name = '...'; + type: 'layout' = 'layout'; + runTime = VTable.TABLE_EVENT_TYPE.BEFORE_INIT; + options: SomeOptions; + table: any; + constructor(options: SomeOptions) { + this.options = options; + } + run(...args: any[]) { + console.log('Table BEFORE_INIT'); + // const table = args[0]; + // const eventArgs = args[1]; + // const options = eventArgs.options; + // const container = eventArgs.container; + } +} diff --git a/packages/vtable-plugins/src/header-highlight b/packages/vtable-plugins/src/header-highlight deleted file mode 100644 index 0519ecba6e..0000000000 --- a/packages/vtable-plugins/src/header-highlight +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/vtable-plugins/src/index.ts b/packages/vtable-plugins/src/index.ts index eab9cc19e1..17f01fcf87 100644 --- a/packages/vtable-plugins/src/index.ts +++ b/packages/vtable-plugins/src/index.ts @@ -1,4 +1,5 @@ export * from './carousel-animation'; export * from './invert-highlight'; export * from './header-highlight'; -export * from './plus-row-column'; +export * from './case-before-init'; +export * from './add-row-column'; diff --git a/packages/vtable-plugins/src/invert-highlight b/packages/vtable-plugins/src/invert-highlight deleted file mode 100644 index 0519ecba6e..0000000000 --- a/packages/vtable-plugins/src/invert-highlight +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/vtable-plugins/src/plugins b/packages/vtable-plugins/src/plugins deleted file mode 100644 index 0519ecba6e..0000000000 --- a/packages/vtable-plugins/src/plugins +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/vtable-plugins/src/plus-row-column b/packages/vtable-plugins/src/plus-row-column deleted file mode 100644 index 0519ecba6e..0000000000 --- a/packages/vtable-plugins/src/plus-row-column +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/vtable-plugins/src/plus-row-column.ts b/packages/vtable-plugins/src/plus-row-column.ts deleted file mode 100644 index abd7609889..0000000000 --- a/packages/vtable-plugins/src/plus-row-column.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { BaseTableAPI } from '@visactor/vtable/src/ts-types/base-table'; - -export class PlusRowColumnPlugin { - constructor(private table: BaseTableAPI) { - this.table = table; - } - init() { - // - } -} diff --git a/packages/vtable/src/ListTable.ts b/packages/vtable/src/ListTable.ts index ac44e2ae41..cda2f64b15 100644 --- a/packages/vtable/src/ListTable.ts +++ b/packages/vtable/src/ListTable.ts @@ -103,18 +103,8 @@ export class ListTable extends BaseTable implements ListTableAPI { constructor(options: ListTableConstructorOptions); constructor(container: HTMLElement, options: ListTableConstructorOptions); constructor(container?: HTMLElement | ListTableConstructorOptions, options?: ListTableConstructorOptions) { - if (Env.mode === 'node') { - options = container as ListTableConstructorOptions; - container = null; - } else if (!(container instanceof HTMLElement)) { - options = container as ListTableConstructorOptions; - if ((container as ListTableConstructorOptions).container) { - container = (container as ListTableConstructorOptions).container; - } else { - container = null; - } - } super(container as HTMLElement, options); + options = this.options; const internalProps = this.internalProps; internalProps.frozenColDragHeaderMode = options.dragOrder?.frozenColDragHeaderMode ?? options.frozenColDragHeaderMode; diff --git a/packages/vtable/src/PivotChart.ts b/packages/vtable/src/PivotChart.ts index 8f06adfca3..5043d3acbd 100644 --- a/packages/vtable/src/PivotChart.ts +++ b/packages/vtable/src/PivotChart.ts @@ -107,18 +107,8 @@ export class PivotChart extends BaseTable implements PivotChartAPI { constructor(options: PivotChartConstructorOptions); constructor(container: HTMLElement, options: PivotChartConstructorOptions); constructor(container?: HTMLElement | PivotChartConstructorOptions, options?: PivotChartConstructorOptions) { - if (Env.mode === 'node') { - options = container as PivotChartConstructorOptions; - container = null; - } else if (!(container instanceof HTMLElement)) { - options = container as PivotChartConstructorOptions; - if ((container as PivotChartConstructorOptions).container) { - container = (container as PivotChartConstructorOptions).container; - } else { - container = null; - } - } super(container as HTMLElement, options); + options = this.options; if ((options as any).layout) { //TODO hack处理之前的demo都是定义到layout上的 所以这里直接并到options中 Object.assign(options, (options as any).layout); diff --git a/packages/vtable/src/PivotTable.ts b/packages/vtable/src/PivotTable.ts index 5fdfbc58d3..464831f3a2 100644 --- a/packages/vtable/src/PivotTable.ts +++ b/packages/vtable/src/PivotTable.ts @@ -68,18 +68,8 @@ export class PivotTable extends BaseTable implements PivotTableAPI { constructor(options: PivotTableConstructorOptions); constructor(container: HTMLElement, options: PivotTableConstructorOptions); constructor(container?: HTMLElement | PivotTableConstructorOptions, options?: PivotTableConstructorOptions) { - if (Env.mode === 'node') { - options = container as PivotTableConstructorOptions; - container = null; - } else if (!(container instanceof HTMLElement)) { - options = container as PivotTableConstructorOptions; - if ((container as PivotTableConstructorOptions).container) { - container = (container as PivotTableConstructorOptions).container; - } else { - container = null; - } - } super(container as HTMLElement, options); + options = this.options; if (options) { if (!options.rowHierarchyType) { options.rowHierarchyType = 'grid'; diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index 3bab62ec09..a682c5f62a 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -153,6 +153,8 @@ import type { CustomCellStylePlugin, ICustomCellStylePlugin } from '../plugins/c import { isCellDisableSelect } from '../state/select/is-cell-select-highlight'; import { getCustomMergeCellFunc } from './utils/get-custom-merge-cell-func'; import { vglobal } from '@src/vrender'; +import { PluginManager } from '../plugins/plugin-manager'; +import type { IVTablePlugin } from '../plugins/interface'; const { toBoxArray } = utilStyle; const { isTouchEvent } = event; @@ -228,12 +230,28 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { reactCustomLayout?: ReactCustomLayout; _hasAutoImageColumn?: boolean; + pluginManager: PluginManager; constructor(container: HTMLElement, options: BaseTableConstructorOptions = {}) { super(); + + if (Env.mode === 'node') { + options = container as BaseTableConstructorOptions; + container = null; + } else if (!(container instanceof HTMLElement)) { + options = container as BaseTableConstructorOptions; + if ((container as BaseTableConstructorOptions).container) { + container = (container as BaseTableConstructorOptions).container; + } else { + container = null; + } + } if (!container && options.mode !== 'node' && !options.canvas) { throw new Error("vtable's container is undefined"); } + this.pluginManager = new PluginManager(this, options); + this.fireListeners(TABLE_EVENT_TYPE.BEFORE_INIT, { options, container }); + container = options.container; // for image anonymous if (options.customConfig?.imageAnonymous === false) { vglobal.isImageAnonymous = false; @@ -2288,6 +2306,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { this.internalProps = null; this.reactCustomLayout?.clearCache(); + this.plugins.release(); } fireListeners( diff --git a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts index d56917da1c..ed46acef5f 100644 --- a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts +++ b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts @@ -157,6 +157,10 @@ export interface TableEvents { RADIO_STATE_CHANGE: 'radio_state_change'; SWITCH_STATE_CHANGE: 'switch_state_change'; //#region lifecircle + /** 表格实例初始化前触发 */ + BEFORE_INIT: 'before_init'; + /** 设置表格大小前触发 */ + BEFORE_SET_SIZE: 'before_set_size'; /** 每次渲染完成触发 */ AFTER_RENDER: 'after_render'; /** 表格实例初始化完成 */ @@ -253,6 +257,8 @@ export const TABLE_EVENT_TYPE: TableEvents = { CHECKBOX_STATE_CHANGE: 'checkbox_state_change', RADIO_STATE_CHANGE: 'radio_state_change', SWITCH_STATE_CHANGE: 'switch_state_change', + BEFORE_SET_SIZE: 'before_set_size', + BEFORE_INIT: 'before_init', AFTER_RENDER: 'after_render', INITIALIZED: 'initialized', CHANGE_CELL_VALUE: 'change_cell_value', diff --git a/packages/vtable/src/index.ts b/packages/vtable/src/index.ts index 9fc8b7745c..0ecd316bcc 100644 --- a/packages/vtable/src/index.ts +++ b/packages/vtable/src/index.ts @@ -9,6 +9,7 @@ import * as icons from './icons'; import * as register from './register'; import * as themes from './themes'; import * as DataStatistics from './dataset/DataStatistics'; +import * as plugins from './plugins'; import type { ColumnDefine, ColumnsDefine, @@ -42,6 +43,7 @@ import * as CustomLayout from './render/layout'; import { updateCell } from './scenegraph/group-creater/cell-helper'; import { renderChart } from './scenegraph/graphic/contributions/chart-render-helper'; import { restoreMeasureText, setCustomAlphabetCharSet } from './scenegraph/utils/text-measure'; +import type { BaseTableAPI } from './ts-types/base-table'; // import { container, loadCanvasPicker } from '@src/vrender'; // loadCanvasPicker(container); @@ -68,6 +70,7 @@ export { core, ListTable, ListTableSimple, + BaseTableAPI, ListTableConstructorOptions, PivotTable, PivotTableSimple, @@ -106,8 +109,8 @@ export { renderChart, graphicUtil, setCustomAlphabetCharSet, - restoreMeasureText - + restoreMeasureText, + plugins // VRender // should use import {xxx} from '@visactor/vtable/es/vrender' }; diff --git a/packages/vtable/src/plugins/index.ts b/packages/vtable/src/plugins/index.ts new file mode 100644 index 0000000000..dc5c41f6f0 --- /dev/null +++ b/packages/vtable/src/plugins/index.ts @@ -0,0 +1,3 @@ +export type { IVTablePlugin } from './interface'; +export { PluginManager } from './plugin-manager'; +export { CustomCellStylePlugin } from './custom-cell-style'; diff --git a/packages/vtable/src/plugins/interface.ts b/packages/vtable/src/plugins/interface.ts new file mode 100644 index 0000000000..3b6969dd4c --- /dev/null +++ b/packages/vtable/src/plugins/interface.ts @@ -0,0 +1,25 @@ +import type { TableEvents } from '../core/TABLE_EVENT_TYPE'; +import type { BaseTableAPI } from '../ts-types/base-table'; + +// 插件生命周期接口 +export interface IVTablePlugin { + // 插件唯一标识 + id: string; + // 插件名称 + name: string; + // 插件优先级,数字越小优先级越高 + priority?: number; + + // 插件类型,用于区分不同功能的插件 + type: 'layout' | 'interaction' | 'style' | 'animation'; + // 插件运行时机 + runTime: TableEvents[keyof TableEvents] | TableEvents[keyof TableEvents][]; + // 插件依赖 + dependencies?: string[]; + // 初始化方法,在VTable实例创建后、首次渲染前调用 + run: (...args: any[]) => void; + // 更新方法,当表格数据或配置更新时调用 + // update?: (table: VTable, options?: any) => void; + // // 销毁方法,在VTable实例销毁前调用 + // release?: (table: VTable) => void; +} diff --git a/packages/vtable/src/plugins/plugin-manager.ts b/packages/vtable/src/plugins/plugin-manager.ts new file mode 100644 index 0000000000..c3d6773927 --- /dev/null +++ b/packages/vtable/src/plugins/plugin-manager.ts @@ -0,0 +1,61 @@ +import type { TableEvents } from '../core/TABLE_EVENT_TYPE'; +import type { BaseTableAPI, BaseTableConstructorOptions } from '../ts-types/base-table'; +import type { IVTablePlugin } from './interface'; + +export class PluginManager { + private plugins: Map = new Map(); + private table: BaseTableAPI; + + constructor(table: BaseTableAPI, options: BaseTableConstructorOptions) { + this.table = table; + options.plugins?.map(plugin => { + this.register(plugin); + }); + this.initPlugins(table); + } + + // 注册插件 + register(plugin: IVTablePlugin): void { + this.plugins.set(plugin.id, plugin); + } + + // 注册多个插件 + registerAll(plugins: IVTablePlugin[]): void { + plugins.forEach(plugin => this.register(plugin)); + } + + // 获取插件 + getPlugin(id: string): IVTablePlugin | undefined { + return this.plugins.get(id); + } + + initPlugins(table: BaseTableAPI) { + this.plugins.forEach(plugin => { + if (Array.isArray(plugin.runTime)) { + plugin.runTime.forEach(runTime => { + table.on(runTime, (...args) => { + plugin.run?.(...args, runTime, table); + }); + }); + } else { + table.on(plugin.runTime, (...args) => { + plugin.run?.(table, ...args, plugin.runTime as TableEvents[keyof TableEvents]); + }); + } + }); + } + + // 更新所有插件 + updatePlugins(): void { + this.plugins.forEach(plugin => { + if (plugin.update) { + plugin.update(this.table); + } + }); + } + release() { + this.plugins.forEach(plugin => { + plugin.release?.(this.table); + }); + } +} diff --git a/packages/vtable/src/ts-types/base-table.ts b/packages/vtable/src/ts-types/base-table.ts index 31e2e3367b..13025fe35b 100644 --- a/packages/vtable/src/ts-types/base-table.ts +++ b/packages/vtable/src/ts-types/base-table.ts @@ -104,6 +104,7 @@ import type { EmptyTip } from '../components/empty-tip/empty-tip'; import type { EditManager } from '../edit/edit-manager'; import type { TableAnimationManager } from '../core/animation'; import type { CustomCellStylePlugin } from '../plugins/custom-cell-style'; +import type { IVTablePlugin } from '../plugins/interface'; export interface IBaseTableProtected { element: HTMLElement; @@ -586,6 +587,8 @@ export interface BaseTableConstructorOptions { /** 拖拽移动位置结束时进行验证 */ validateDragOrderOnEnd?: (source: CellAddress, target: CellAddress) => boolean; }; + /** 插件配置 */ + plugins?: IVTablePlugin[]; } export interface BaseTableAPI { id: string; diff --git a/packages/vtable/src/ts-types/events.ts b/packages/vtable/src/ts-types/events.ts index dfbe0f4f9a..3d092c4270 100644 --- a/packages/vtable/src/ts-types/events.ts +++ b/packages/vtable/src/ts-types/events.ts @@ -1,10 +1,19 @@ -import type { CellAddress, CellRange, CellLocation, FieldDef, CellAddressWithBound } from './table-engine'; +import type { + CellAddress, + CellRange, + CellLocation, + FieldDef, + CellAddressWithBound, + ListTableConstructorOptions, + PivotTableConstructorOptions +} from './table-engine'; import type { DropDownMenuEventArgs, MenuListItem, PivotInfo } from './menu'; import type { IDimensionInfo, MergeCellInfo, RectProps, SortOrder } from './common'; import type { IconFuncTypeEnum, CellInfo, HierarchyState } from '.'; import type { Icon } from '../scenegraph/graphic/icon'; import type { FederatedPointerEvent, IEventTarget } from '@src/vrender'; +import type { BaseTableConstructorOptions } from './base-table'; export type KeyboardEventListener = (e: KeyboardEvent) => void; export type TableEventListener = ( @@ -209,6 +218,8 @@ export interface TableEventHandlersEventArgumentMap { checkbox_state_change: MousePointerCellEvent & { checked: boolean }; radio_state_change: MousePointerCellEvent & { radioIndexInCell: number | undefined }; switch_state_change: MousePointerCellEvent & { checked: boolean }; + before_init: { options: BaseTableConstructorOptions; container: HTMLElement | null }; + before_set_size: { width: number; height: number }; after_render: null; initialized: null; @@ -307,6 +318,8 @@ export interface TableEventHandlersReturnMap { checkbox_state_change: void; radio_state_change: void; switch_state_change: void; + before_init: void; + before_set_size: void; after_render: void; initialized: void; From d1dfb4df61f8d8b38f717c9b81b8a3e508d87de2 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 13 Mar 2025 20:17:57 +0800 Subject: [PATCH 03/51] refactor: plugins manager --- packages/vtable/src/core/BaseTable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index a682c5f62a..d4c2a8fb0a 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -2306,7 +2306,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { this.internalProps = null; this.reactCustomLayout?.clearCache(); - this.plugins.release(); + this.pluginManager.release(); } fireListeners( From 9498c2a9ec5535521b54edf578515ad55da72d52 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Fri, 14 Mar 2025 14:26:54 +0800 Subject: [PATCH 04/51] refactor: plugins progress --- packages/vtable/src/core/BaseTable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index d4c2a8fb0a..9bc87c6c3f 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -251,7 +251,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { this.pluginManager = new PluginManager(this, options); this.fireListeners(TABLE_EVENT_TYPE.BEFORE_INIT, { options, container }); - container = options.container; + container = options.container || container; // for image anonymous if (options.customConfig?.imageAnonymous === false) { vglobal.isImageAnonymous = false; From 003eb24a173753d1e4a930910a57ea8c5e22563e Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Fri, 14 Mar 2025 14:58:57 +0800 Subject: [PATCH 05/51] refactor: plugins progress --- packages/vtable-plugins/src/add-row-column.ts | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/packages/vtable-plugins/src/add-row-column.ts b/packages/vtable-plugins/src/add-row-column.ts index f9bd25113d..e0065a3cb7 100644 --- a/packages/vtable-plugins/src/add-row-column.ts +++ b/packages/vtable-plugins/src/add-row-column.ts @@ -1,11 +1,31 @@ import * as VTable from '@visactor/vtable'; +/** + * 添加行和列的插件的配置选项 + */ export interface AddRowColumnOptions { + /** + * 是否启用添加列 + */ addColumnEnable?: boolean; + /** + * 是否启用添加行 + */ addRowEnable?: boolean; + /** + * 添加列的回调函数 + */ addColumnCallback?: (col: number) => void; + /** + * 添加行的回调函数 + */ addRowCallback?: (row: number) => void; } - +/** + * 添加行和列的插件 + * 该插件监听了table的MOUSEENTER_CELL,MOUSELEAVE_CELL,MOUSELEAVE_TABLE事件 + * 当鼠标hover到table的cell时,会显示添加行和列的dot和加号 + * 当鼠标离开table的cell时,会隐藏添加行和列的dot和加号 + */ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { id = 'add-row-column'; name = 'Add-Row-Column'; @@ -53,7 +73,6 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { if (runTime === VTable.TABLE_EVENT_TYPE.MOUSEENTER_CELL) { clearTimeout(this.hideAllTimeoutId_addColumn); clearTimeout(this.hideAllTimeoutId_addRow); - console.log('mouseenter cell', args); const canvasBounds = table.canvas.getBoundingClientRect(); const cell = table.getCellAtRelativePosition( eventArgs.event.clientX - canvasBounds.left, @@ -62,22 +81,25 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { this.hoverCell = cell; const cellRect = table.getCellRelativeRect(cell.col, cell.row); if (this.pluginOptions.addColumnEnable) { + const isRowSerierNumberCol = table.isSeriesNumber(cell.col); this.showDotForAddColumn( canvasBounds.top - 6, cellRect.left + canvasBounds.left, - cellRect.right + canvasBounds.left + cellRect.right + canvasBounds.left, + !isRowSerierNumberCol ); } if (this.pluginOptions.addRowEnable) { + const isHeader = table.isHeader(cell.col, cell.row); this.showDotForAddRow( cellRect.top + canvasBounds.top, canvasBounds.left - 6, - cellRect.bottom + canvasBounds.top + cellRect.bottom + canvasBounds.top, + !isHeader, + !isHeader ); } - // console.log('cellRect', cellRect); } else if (runTime === VTable.TABLE_EVENT_TYPE.MOUSELEAVE_CELL) { - console.log('mouseleave cell'); } else if (runTime === VTable.TABLE_EVENT_TYPE.MOUSELEAVE_TABLE) { if (this.pluginOptions.addColumnEnable) { this.delayHideAllForAddColumn(); @@ -217,7 +239,13 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { this.delayHideAllForAddColumn(0); }); } - showDotForAddColumn(top: number, left: number, right: number) { + showDotForAddColumn( + top: number, + left: number, + right: number, + isShowLeft: boolean = true, + isShowRight: boolean = true + ) { // 动态获取元素尺寸 const dotWidth = this.leftDotForAddColumn.offsetWidth; const dotHeight = this.leftDotForAddColumn.offsetHeight; @@ -225,8 +253,8 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { this.leftDotForAddColumn.style.top = `${top - dotHeight / 2}px`; this.rightDotForAddColumn.style.left = `${right - dotWidth / 2}px`; this.rightDotForAddColumn.style.top = `${top - dotHeight / 2}px`; - this.leftDotForAddColumn.style.display = 'block'; - this.rightDotForAddColumn.style.display = 'block'; + this.leftDotForAddColumn.style.display = isShowLeft ? 'block' : 'none'; + this.rightDotForAddColumn.style.display = isShowRight ? 'block' : 'none'; } showAddIconForAddColumn(left: number, top: number, isLeft: boolean) { // 动态获取元素尺寸 @@ -373,12 +401,13 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { if (this.pluginOptions.addRowCallback) { this.pluginOptions.addRowCallback(addRowIndex); } else { - //debugger; + const recordIndex = this.table.getRecordIndexByCell(0, addRowIndex); + this.table.addRecord({}, recordIndex); } this.delayHideAllForAddRow(0); }); } - showDotForAddRow(top: number, left: number, bottom: number) { + showDotForAddRow(top: number, left: number, bottom: number, isShowTop: boolean = true, isShowBottom: boolean = true) { // 动态获取元素尺寸 const dotWidth = this.topDotForAddRow.offsetWidth; const dotHeight = this.topDotForAddRow.offsetHeight; @@ -386,8 +415,8 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { this.topDotForAddRow.style.top = `${top - dotHeight / 2}px`; this.bottomDotForAddRow.style.left = `${left - dotWidth / 2}px`; this.bottomDotForAddRow.style.top = `${bottom - dotHeight / 2}px`; - this.topDotForAddRow.style.display = 'block'; - this.bottomDotForAddRow.style.display = 'block'; + this.topDotForAddRow.style.display = isShowTop ? 'block' : 'none'; + this.bottomDotForAddRow.style.display = isShowBottom ? 'block' : 'none'; } showAddIconForAddRow(left: number, top: number, isTop: boolean) { // 动态获取元素尺寸 From b35ee3fa425c02c22cba99a2bdb2f1ff5f41204b Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Fri, 14 Mar 2025 19:40:38 +0800 Subject: [PATCH 06/51] feat: add column series plugins --- packages/vtable-editors/src/input-editor.ts | 13 ++++ .../demo/add-row-column/add-row-column.ts | 5 -- .../demo/column-series/column-series.ts | 41 ++++++++++ .../demo/combine-plugins/combine-plugins.ts | 40 ++++++++++ packages/vtable-plugins/demo/menu.ts | 44 ++++------- packages/vtable-plugins/src/add-row-column.ts | 12 +++ .../vtable-plugins/src/case-before-init.ts | 1 + packages/vtable-plugins/src/column-series.ts | 76 +++++++++++++++++++ packages/vtable-plugins/src/index.ts | 2 + packages/vtable-plugins/src/row-series.ts | 40 ++++++++++ packages/vtable/src/core/BaseTable.ts | 2 +- packages/vtable/src/edit/edit-manager.ts | 4 + 12 files changed, 246 insertions(+), 34 deletions(-) create mode 100644 packages/vtable-plugins/demo/column-series/column-series.ts create mode 100644 packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts create mode 100644 packages/vtable-plugins/src/column-series.ts create mode 100644 packages/vtable-plugins/src/row-series.ts diff --git a/packages/vtable-editors/src/input-editor.ts b/packages/vtable-editors/src/input-editor.ts index 0cd54890ac..eeafd3de57 100644 --- a/packages/vtable-editors/src/input-editor.ts +++ b/packages/vtable-editors/src/input-editor.ts @@ -29,6 +29,19 @@ export class InputEditor implements IEditor { input.style.width = '100%'; input.style.boxSizing = 'border-box'; input.style.backgroundColor = '#FFFFFF'; + input.style.borderRadius = '0px'; + input.style.border = '2px solid #d9d9d9'; + // #region 为了保证input在focus时,没有圆角 + input.addEventListener('focus', () => { + input.style.borderColor = '#4A90E2'; + input.style.outline = 'none'; + }); + + input.addEventListener('blur', () => { + input.style.borderColor = '#d9d9d9'; + // input.style.boxShadow = 'none'; + }); + // #endregion this.element = input; this.container.appendChild(input); diff --git a/packages/vtable-plugins/demo/add-row-column/add-row-column.ts b/packages/vtable-plugins/demo/add-row-column/add-row-column.ts index a8857fbd5e..f63e3a869e 100644 --- a/packages/vtable-plugins/demo/add-row-column/add-row-column.ts +++ b/packages/vtable-plugins/demo/add-row-column/add-row-column.ts @@ -78,11 +78,6 @@ export function createTable() { records, columns, padding: 30, - // theme: VTable.themes.DARK, - // heightMode: 'adaptive', - select: { - disableSelect: true - }, plugins: [addRowColumn] }; const tableInstance = new VTable.ListTable(option); diff --git a/packages/vtable-plugins/demo/column-series/column-series.ts b/packages/vtable-plugins/demo/column-series/column-series.ts new file mode 100644 index 0000000000..17f070116a --- /dev/null +++ b/packages/vtable-plugins/demo/column-series/column-series.ts @@ -0,0 +1,41 @@ +import * as VTable from '@visactor/vtable'; +import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; +import { ColumnSeriesPlugin, RowSeriesPlugin } from '../../src'; +const CONTAINER_ID = 'vTable'; +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + +export function createTable() { + const records = generatePersons(20); + + const columnSeries = new ColumnSeriesPlugin({ + columnCount: 100 + }); + const rowSeries = new RowSeriesPlugin({ + rowCount: 100 + }); + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records, + plugins: [columnSeries, rowSeries] + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + bindDebugTool(tableInstance.scenegraph.stage, { + customGrapicKeys: ['col', 'row'] + }); +} diff --git a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts new file mode 100644 index 0000000000..18c62592c7 --- /dev/null +++ b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts @@ -0,0 +1,40 @@ +import * as VTable from '@visactor/vtable'; +import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; +import { AddRowColumnPlugin, ColumnSeriesPlugin, RowSeriesPlugin } from '../../src'; +import { InputEditor } from '@visactor/vtable-editors'; +const CONTAINER_ID = 'vTable'; +const input_editor = new InputEditor({}); +VTable.register.editor('input', input_editor); + +export function createTable() { + const addRowColumn = new AddRowColumnPlugin({ + addColumnCallback: col => { + columnSeries.resetColumnCount(columnSeries.pluginOptions.columnCount + 1); + } + }); + + const columnSeries = new ColumnSeriesPlugin({ + columnCount: 100 + }); + const rowSeries = new RowSeriesPlugin({ + rowCount: 100 + }); + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records: [], + columns: [], + padding: 30, + editor: 'input', + editCellTrigger: 'click', + select: { + disableSelect: true + }, + plugins: [addRowColumn, columnSeries, rowSeries] + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + bindDebugTool(tableInstance.scenegraph.stage, { + customGrapicKeys: ['col', 'row'] + }); +} diff --git a/packages/vtable-plugins/demo/menu.ts b/packages/vtable-plugins/demo/menu.ts index 8c3c265923..dffa87b84c 100644 --- a/packages/vtable-plugins/demo/menu.ts +++ b/packages/vtable-plugins/demo/menu.ts @@ -1,38 +1,26 @@ export const menus = [ { - menu: 'carousel-animation', - children: [ - { - path: 'carousel-animation', - name: 'carousel-animation' - } - ] + path: 'carousel-animation', + name: 'carousel-animation' }, { - menu: 'header-highlight', - children: [ - { - path: 'header-highlight', - name: 'header-highlight' - } - ] + path: 'header-highlight', + name: 'header-highlight' }, { - menu: 'invert-highlight', - children: [ - { - path: 'invert-highlight', - name: 'invert-highlight' - } - ] + path: 'invert-highlight', + name: 'invert-highlight' }, { - menu: 'add-row-column', - children: [ - { - path: 'add-row-column', - name: 'add-row-column' - } - ] + path: 'add-row-column', + name: 'add-row-column' + }, + { + path: 'column-series', + name: 'column-series' + }, + { + path: 'combine-plugins', + name: 'combine-plugins' } ]; diff --git a/packages/vtable-plugins/src/add-row-column.ts b/packages/vtable-plugins/src/add-row-column.ts index e0065a3cb7..ce2b2a4dab 100644 --- a/packages/vtable-plugins/src/add-row-column.ts +++ b/packages/vtable-plugins/src/add-row-column.ts @@ -56,6 +56,8 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { } ) { this.pluginOptions = pluginOptions; + this.pluginOptions.addColumnEnable = this.pluginOptions.addColumnEnable ?? true; + this.pluginOptions.addRowEnable = this.pluginOptions.addRowEnable ?? true; if (this.pluginOptions.addColumnEnable) { this.initAddColumnDomElement(); this.bindEventForAddColumn(); @@ -446,4 +448,14 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { }, delay); } // #endregion + release() { + this.leftDotForAddColumn.remove(); + this.rightDotForAddColumn.remove(); + this.addIconForAddColumn.remove(); + this.addLineForAddColumn.remove(); + this.topDotForAddRow.remove(); + this.bottomDotForAddRow.remove(); + this.addIconForAddRow.remove(); + this.addLineForAddRow.remove(); + } } diff --git a/packages/vtable-plugins/src/case-before-init.ts b/packages/vtable-plugins/src/case-before-init.ts index 50f0c3366c..4ac5ea5e89 100644 --- a/packages/vtable-plugins/src/case-before-init.ts +++ b/packages/vtable-plugins/src/case-before-init.ts @@ -19,5 +19,6 @@ export class BeforeInitPlugin implements VTable.plugins.IVTablePlugin { // const eventArgs = args[1]; // const options = eventArgs.options; // const container = eventArgs.container; + // 可以通过options.container重置替换容器 } } diff --git a/packages/vtable-plugins/src/column-series.ts b/packages/vtable-plugins/src/column-series.ts new file mode 100644 index 0000000000..386d0ee01c --- /dev/null +++ b/packages/vtable-plugins/src/column-series.ts @@ -0,0 +1,76 @@ +import * as VTable from '@visactor/vtable'; +/** + * 添加行和列的插件的配置选项 + */ +export interface ColumnSeriesOptions { + columnCount: number; + generateColumnTitle?: (index: number) => string; + generateColumnField?: (index: number) => string; +} +/** + * 生成列序号标题的插件 + */ +export class ColumnSeriesPlugin implements VTable.plugins.IVTablePlugin { + id = 'column-series'; + name = 'Column-Series'; + type: 'layout' = 'layout'; + runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT]; + pluginOptions: ColumnSeriesOptions; + table: VTable.ListTable; + columns: { field: string; title: string }[] = []; + constructor(pluginOptions: ColumnSeriesOptions = { columnCount: 100 }) { + this.pluginOptions = pluginOptions; + } + run(...args: any[]) { + const eventArgs = args[0]; + const table: VTable.BaseTableAPI = args[2]; + this.table = table as VTable.ListTable; + const options = eventArgs.options; + //根据pluginOptions的columnCount组织columns,column的title生成规则和excel一致,如A~Z,AA~AZ,AB~AZ,AA~ZZ,AAA~ZZZ + this.columns = this.generateColumnFields(this.pluginOptions.columnCount); + options.columns = this.columns; + } + generateColumnFields(columnCount: number): { field: string; title: string }[] { + const columnFields = []; + for (let i = 0; i < columnCount; i++) { + const column = { + field: this.pluginOptions.generateColumnField + ? this.pluginOptions.generateColumnField(i) + : this.generateColumnField(i), + title: this.pluginOptions.generateColumnTitle + ? this.pluginOptions.generateColumnTitle(i) + : this.generateColumnField(i) + }; + columnFields.push(column); + } + return columnFields; + } + /** + * 生成excel的列标题,规则和excel一致,如A~Z,AA~AZ,AB~AZ,AA~ZZ,AAA~ZZZ + * @param index 从0开始 + * @returns + */ + generateColumnField(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(''); + } + + resetColumnCount(columnCount: number) { + this.pluginOptions.columnCount = columnCount; + this.columns = this.generateColumnFields(columnCount); + this.table.updateColumns(this.columns); + } +} diff --git a/packages/vtable-plugins/src/index.ts b/packages/vtable-plugins/src/index.ts index 17f01fcf87..e0a63beda4 100644 --- a/packages/vtable-plugins/src/index.ts +++ b/packages/vtable-plugins/src/index.ts @@ -3,3 +3,5 @@ export * from './invert-highlight'; export * from './header-highlight'; export * from './case-before-init'; export * from './add-row-column'; +export * from './column-series'; +export * from './row-series'; diff --git a/packages/vtable-plugins/src/row-series.ts b/packages/vtable-plugins/src/row-series.ts new file mode 100644 index 0000000000..7e668c22a5 --- /dev/null +++ b/packages/vtable-plugins/src/row-series.ts @@ -0,0 +1,40 @@ +import * as VTable from '@visactor/vtable'; +/** + * 添加行和列的插件的配置选项 + */ +export interface RowSeriesOptions { + rowCount: number; + generateRowTitle?: (index: number) => string; +} +/** + * 生成行序号标题的插件 + */ +export class RowSeriesPlugin implements VTable.plugins.IVTablePlugin { + id = 'row-series'; + name = 'Row-Series'; + type: 'layout' = 'layout'; + runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT]; + pluginOptions: RowSeriesOptions; + table: VTable.ListTable; + + constructor(pluginOptions: RowSeriesOptions = { rowCount: 100 }) { + this.pluginOptions = pluginOptions; + } + run(...args: any[]) { + const eventArgs = args[0]; + const table: VTable.BaseTableAPI = args[2]; + this.table = table as VTable.ListTable; + const options: VTable.ListTableConstructorOptions = eventArgs.options; + const records = options.records ?? []; + //用空数据将records填充到pluginOptions.rowCount + for (let i = records.length; i < this.pluginOptions.rowCount; i++) { + records.push({}); + } + options.records = records; + if (!options.rowSeriesNumber) { + options.rowSeriesNumber = { + width: 'auto' + }; + } + } +} diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index 9bc87c6c3f..a2eef25c5a 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -251,7 +251,7 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { this.pluginManager = new PluginManager(this, options); this.fireListeners(TABLE_EVENT_TYPE.BEFORE_INIT, { options, container }); - container = options.container || container; + container = options.container && options.container instanceof HTMLElement ? options.container : container; // for image anonymous if (options.customConfig?.imageAnonymous === false) { vglobal.isImageAnonymous = false; diff --git a/packages/vtable/src/edit/edit-manager.ts b/packages/vtable/src/edit/edit-manager.ts index 04ac48e225..a9e20bc398 100644 --- a/packages/vtable/src/edit/edit-manager.ts +++ b/packages/vtable/src/edit/edit-manager.ts @@ -103,9 +103,13 @@ export class EditManager { // adjust last col&row, same as packages/vtable/src/scenegraph/graphic/contributions/group-contribution-render.ts getCellSizeForDraw if (col === this.table.colCount - 1) { referencePosition.rect.width = rect.width - 1; + } else { + referencePosition.rect.width = rect.width + 1; // 这里的1应该根据单元格的borderWidth来定; } if (row === this.table.rowCount - 1) { referencePosition.rect.height = rect.height - 1; + } else { + referencePosition.rect.height = rect.height + 1; // 这里的1应该根据单元格的borderWidth来定; } editor.beginEditing && console.warn('VTable Warn: `beginEditing` is deprecated, please use `onStart` instead.'); From 2ccc0102e9c9dbc074d2d956970e1a7718431350 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Mon, 17 Mar 2025 19:55:04 +0800 Subject: [PATCH 07/51] feat: add column series plugin --- packages/vtable-editors/src/input-editor.ts | 15 +++++-- .../demo/column-series/column-series.ts | 7 +++- .../demo/combine-plugins/combine-plugins.ts | 41 ++++++++++++++++--- packages/vtable-plugins/src/add-row-column.ts | 4 +- packages/vtable-plugins/src/column-series.ts | 14 +++++-- packages/vtable-plugins/src/row-series.ts | 4 +- packages/vtable/src/data/DataSource.ts | 9 ++++ 7 files changed, 76 insertions(+), 18 deletions(-) diff --git a/packages/vtable-editors/src/input-editor.ts b/packages/vtable-editors/src/input-editor.ts index eeafd3de57..22ee60e469 100644 --- a/packages/vtable-editors/src/input-editor.ts +++ b/packages/vtable-editors/src/input-editor.ts @@ -85,10 +85,17 @@ export class InputEditor implements IEditor { } adjustPosition(rect: RectProps) { - this.element.style.top = rect.top + 'px'; - this.element.style.left = rect.left + 'px'; - this.element.style.width = rect.width + 'px'; - this.element.style.height = rect.height + 'px'; + //使border均分input位置rect的上下左右 + const borderWidth = 2; + const top = rect.top - borderWidth / 2; + const left = rect.left - borderWidth / 2; + const width = rect.width + borderWidth; + const height = rect.height + borderWidth; + + this.element.style.top = top + 'px'; + this.element.style.left = left + 'px'; + this.element.style.width = width + 'px'; + this.element.style.height = height + 'px'; } endEditing() { diff --git a/packages/vtable-plugins/demo/column-series/column-series.ts b/packages/vtable-plugins/demo/column-series/column-series.ts index 17f070116a..895c4a418b 100644 --- a/packages/vtable-plugins/demo/column-series/column-series.ts +++ b/packages/vtable-plugins/demo/column-series/column-series.ts @@ -30,7 +30,12 @@ export function createTable() { const option: VTable.ListTableConstructorOptions = { container: document.getElementById(CONTAINER_ID), records, - plugins: [columnSeries, rowSeries] + plugins: [columnSeries, rowSeries], + theme: { + selectionStyle: { + cellBorderLineWidth: 4 + } + } }; const tableInstance = new VTable.ListTable(option); window.tableInstance = tableInstance; diff --git a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts index 18c62592c7..528efeca25 100644 --- a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts +++ b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts @@ -2,6 +2,7 @@ import * as VTable from '@visactor/vtable'; import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; import { AddRowColumnPlugin, ColumnSeriesPlugin, RowSeriesPlugin } from '../../src'; import { InputEditor } from '@visactor/vtable-editors'; +import { table } from 'console'; const CONTAINER_ID = 'vTable'; const input_editor = new InputEditor({}); VTable.register.editor('input', input_editor); @@ -10,25 +11,55 @@ export function createTable() { const addRowColumn = new AddRowColumnPlugin({ addColumnCallback: col => { columnSeries.resetColumnCount(columnSeries.pluginOptions.columnCount + 1); + const newRecords = tableInstance.records.map(record => { + if (Array.isArray(record)) { + record.splice(col - 1, 0, ''); + } + return record; + }); + tableInstance.setRecords(newRecords); + }, + addRowCallback: row => { + tableInstance.addRecord([], row - tableInstance.columnHeaderLevelCount); } }); const columnSeries = new ColumnSeriesPlugin({ - columnCount: 100 + columnCount: 26 }); const rowSeries = new RowSeriesPlugin({ - rowCount: 100 + rowCount: 100, + fillRowRecord: (index: number) => { + return []; + } }); const option: VTable.ListTableConstructorOptions = { container: document.getElementById(CONTAINER_ID), - records: [], - columns: [], + records: [ + ['姓名', '年龄', '地址'], + ['张三', 18, '北京'], + ['李四', 20, '上海'], + ['王五', 22, '广州'], + ['赵六', 24, '深圳'], + ['孙七', 26, '成都'] + ], + padding: 30, editor: 'input', editCellTrigger: 'click', select: { - disableSelect: true + // disableSelect: true }, + theme: VTable.themes.DEFAULT.extends({ + defaultStyle: { + textAlign: 'left', + padding: [2, 6, 2, 6] + }, + headerStyle: { + textAlign: 'center' + } + }), + defaultRowHeight: 30, plugins: [addRowColumn, columnSeries, rowSeries] }; const tableInstance = new VTable.ListTable(option); diff --git a/packages/vtable-plugins/src/add-row-column.ts b/packages/vtable-plugins/src/add-row-column.ts index ce2b2a4dab..06128035fa 100644 --- a/packages/vtable-plugins/src/add-row-column.ts +++ b/packages/vtable-plugins/src/add-row-column.ts @@ -83,7 +83,7 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { this.hoverCell = cell; const cellRect = table.getCellRelativeRect(cell.col, cell.row); if (this.pluginOptions.addColumnEnable) { - const isRowSerierNumberCol = table.isSeriesNumber(cell.col); + const isRowSerierNumberCol = table.isSeriesNumber(cell.col, 0); this.showDotForAddColumn( canvasBounds.top - 6, cellRect.left + canvasBounds.left, @@ -232,7 +232,7 @@ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { this.pluginOptions.addColumnCallback(addColIndex); } else { columns.splice(addColIndex, 0, { - field: `new-column-${col}`, + field: ``, title: `New Column ${col}`, width: 100 }); diff --git a/packages/vtable-plugins/src/column-series.ts b/packages/vtable-plugins/src/column-series.ts index 386d0ee01c..0b36fdf326 100644 --- a/packages/vtable-plugins/src/column-series.ts +++ b/packages/vtable-plugins/src/column-series.ts @@ -30,13 +30,19 @@ export class ColumnSeriesPlugin implements VTable.plugins.IVTablePlugin { this.columns = this.generateColumnFields(this.pluginOptions.columnCount); options.columns = this.columns; } - generateColumnFields(columnCount: number): { field: string; title: string }[] { + /** + * 生成列字段和标题 + * 规则和excel一致,如A~Z,AA~AZ,AB~AZ,AA~ZZ,AAA~ZZZ + * @param columnCount 列数 + * @returns 列字段和标题的数组 + */ + generateColumnFields(columnCount: number): { field?: string; title: string }[] { const columnFields = []; for (let i = 0; i < columnCount; i++) { const column = { - field: this.pluginOptions.generateColumnField - ? this.pluginOptions.generateColumnField(i) - : this.generateColumnField(i), + // field: this.pluginOptions.generateColumnField + // ? this.pluginOptions.generateColumnField(i) + // : this.generateColumnField(i), title: this.pluginOptions.generateColumnTitle ? this.pluginOptions.generateColumnTitle(i) : this.generateColumnField(i) diff --git a/packages/vtable-plugins/src/row-series.ts b/packages/vtable-plugins/src/row-series.ts index 7e668c22a5..671755d183 100644 --- a/packages/vtable-plugins/src/row-series.ts +++ b/packages/vtable-plugins/src/row-series.ts @@ -4,7 +4,7 @@ import * as VTable from '@visactor/vtable'; */ export interface RowSeriesOptions { rowCount: number; - generateRowTitle?: (index: number) => string; + fillRowRecord?: (index: number) => any; } /** * 生成行序号标题的插件 @@ -28,7 +28,7 @@ export class RowSeriesPlugin implements VTable.plugins.IVTablePlugin { const records = options.records ?? []; //用空数据将records填充到pluginOptions.rowCount for (let i = records.length; i < this.pluginOptions.rowCount; i++) { - records.push({}); + records.push(this.pluginOptions.fillRowRecord ? this.pluginOptions.fillRowRecord(i) : {}); } options.records = records; if (!options.rowSeriesNumber) { diff --git a/packages/vtable/src/data/DataSource.ts b/packages/vtable/src/data/DataSource.ts index c181c763fe..a59994e0c6 100644 --- a/packages/vtable/src/data/DataSource.ts +++ b/packages/vtable/src/data/DataSource.ts @@ -95,6 +95,11 @@ export function getField( return record.then((r: any) => getField(r, field, col, row, table, promiseCallBack)); } const fieldGet: any = isFieldAssessor(field) ? field.get : field; + // 如果fieldGet为undefined或'' 并且record是数组 则取值逻辑按照colIndex取数组值 返回record[col - table.leftRowSeriesNumberCount] + if ((fieldGet === undefined || fieldGet === '') && Array.isArray(record)) { + const colIndex = col - table.leftRowSeriesNumberCount; + return record[colIndex]; + } if (isObject(record) && fieldGet in (record as any)) { const fieldResult = (record as any)[fieldGet]; @@ -757,6 +762,10 @@ export class DataSource extends EventTarget implements DataSourceAPI { const dataIndex = this.getIndexKey(index); this.cacheBeforeChangedRecord(dataIndex, table); + // 如果field为undefined或'' 按照colIndex取数组值 + if (field === undefined || field === '') { + field = col - table.leftRowSeriesNumberCount; + } if (typeof field === 'string' || typeof field === 'number') { const beforeChangedValue = this.beforeChangedRecordsMap.get(dataIndex.toString())?.[field as any]; // this.getOriginalField(index, field, col, row, table); const record = this.getOriginalRecord(dataIndex); From e7bfa5356db0e489a72a1a11ad5afd0260af1f4d Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Mon, 17 Mar 2025 19:59:23 +0800 Subject: [PATCH 08/51] feat: add column series plugin --- packages/vtable/src/data/DataSource.ts | 2 +- packages/vtable/src/plugins/interface.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vtable/src/data/DataSource.ts b/packages/vtable/src/data/DataSource.ts index a59994e0c6..9c6e8dbc60 100644 --- a/packages/vtable/src/data/DataSource.ts +++ b/packages/vtable/src/data/DataSource.ts @@ -776,7 +776,7 @@ export class DataSource extends EventTarget implements DataSourceAPI { if (isPromise(record)) { record .then(record => { - record[field] = formatValue; + record[field as string | number] = formatValue; }) .catch((err: Error) => { console.error('VTable Error:', err); diff --git a/packages/vtable/src/plugins/interface.ts b/packages/vtable/src/plugins/interface.ts index 3b6969dd4c..66734c52fd 100644 --- a/packages/vtable/src/plugins/interface.ts +++ b/packages/vtable/src/plugins/interface.ts @@ -19,7 +19,7 @@ export interface IVTablePlugin { // 初始化方法,在VTable实例创建后、首次渲染前调用 run: (...args: any[]) => void; // 更新方法,当表格数据或配置更新时调用 - // update?: (table: VTable, options?: any) => void; - // // 销毁方法,在VTable实例销毁前调用 - // release?: (table: VTable) => void; + update?: (table: BaseTableAPI, options?: any) => void; + // 销毁方法,在VTable实例销毁前调用 + release?: (table: BaseTableAPI) => void; } From 0f65af1402dd9e10f8c8de7b74ab2f3d55ffcf2b Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Fri, 21 Mar 2025 18:14:57 +0800 Subject: [PATCH 09/51] feat: add excel keyboard plugin --- .../demo/combine-plugins/combine-plugins.ts | 19 +- .../demo/highlight-header/highlight-header.ts | 89 +++++++++ packages/vtable-plugins/demo/menu.ts | 4 + packages/vtable-plugins/src/column-series.ts | 2 +- .../src/excel-edit-cell-keyboard.ts | 105 ++++++++++ .../vtable-plugins/src/highlight-header.ts | 186 ++++++++++++++++++ packages/vtable-plugins/src/index.ts | 3 + packages/vtable-plugins/src/types.ts | 4 + packages/vtable/src/core/TABLE_EVENT_TYPE.ts | 9 +- packages/vtable/src/edit/edit-manager.ts | 5 +- .../src/event/listener/container-dom.ts | 10 + packages/vtable/src/ts-types/events.ts | 2 + 12 files changed, 432 insertions(+), 6 deletions(-) create mode 100644 packages/vtable-plugins/demo/highlight-header/highlight-header.ts create mode 100644 packages/vtable-plugins/src/excel-edit-cell-keyboard.ts create mode 100644 packages/vtable-plugins/src/highlight-header.ts create mode 100644 packages/vtable-plugins/src/types.ts diff --git a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts index 528efeca25..35105b9e0f 100644 --- a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts +++ b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts @@ -1,6 +1,12 @@ import * as VTable from '@visactor/vtable'; import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; -import { AddRowColumnPlugin, ColumnSeriesPlugin, RowSeriesPlugin } from '../../src'; +import { + AddRowColumnPlugin, + ColumnSeriesPlugin, + ExcelEditCellKeyboardPlugin, + HighlightHeaderPlugin, + RowSeriesPlugin +} from '../../src'; import { InputEditor } from '@visactor/vtable-editors'; import { table } from 'console'; const CONTAINER_ID = 'vTable'; @@ -33,6 +39,13 @@ export function createTable() { return []; } }); + const highlightPlugin = new HighlightHeaderPlugin({ + colHighlight: true, + rowHighlight: true + }); + const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin({ + replaceMode: true + }); const option: VTable.ListTableConstructorOptions = { container: document.getElementById(CONTAINER_ID), records: [ @@ -46,7 +59,7 @@ export function createTable() { padding: 30, editor: 'input', - editCellTrigger: 'click', + editCellTrigger: ['api', 'keydown', 'doubleclick'], select: { // disableSelect: true }, @@ -60,7 +73,7 @@ export function createTable() { } }), defaultRowHeight: 30, - plugins: [addRowColumn, columnSeries, rowSeries] + plugins: [addRowColumn, columnSeries, rowSeries, highlightPlugin, excelEditCellKeyboardPlugin] }; const tableInstance = new VTable.ListTable(option); window.tableInstance = tableInstance; diff --git a/packages/vtable-plugins/demo/highlight-header/highlight-header.ts b/packages/vtable-plugins/demo/highlight-header/highlight-header.ts new file mode 100644 index 0000000000..0f0fd5c37e --- /dev/null +++ b/packages/vtable-plugins/demo/highlight-header/highlight-header.ts @@ -0,0 +1,89 @@ +import * as VTable from '@visactor/vtable'; +import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; +import * as VTable_editors from '@visactor/vtable-editors'; + +import { HighlightHeaderPlugin } from '../../src'; +const CONTAINER_ID = 'vTable'; +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + +export function createTable() { + const input_editor = new VTable_editors.InputEditor(); + VTable.register.editor('input-editor', input_editor); + + const records = generatePersons(20); + const columns: VTable.ColumnsDefine = [ + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true, + headerEditor: 'input-editor', + editor: 'input-editor' + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ]; + + const highlightPlugin = new HighlightHeaderPlugin({ + colHighlight: true, + rowHighlight: true + }); + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records, + columns, + rowSeriesNumber: {}, + select: { + outsideClickDeselect: true, + headerSelectMode: 'body' + }, + autoWrapText: true, + editor: 'input-editor', + menu: { + contextMenuItems: ['copy', 'paste', 'delete', '...'] + }, + plugins: [highlightPlugin] + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + bindDebugTool(tableInstance.scenegraph.stage, { + customGrapicKeys: ['col', 'row'] + }); + + // tableInstance.scenegraph.temporarilyUpdateSelectRectStyle({stroke: false}) +} diff --git a/packages/vtable-plugins/demo/menu.ts b/packages/vtable-plugins/demo/menu.ts index dffa87b84c..1ebe6f4bfc 100644 --- a/packages/vtable-plugins/demo/menu.ts +++ b/packages/vtable-plugins/demo/menu.ts @@ -22,5 +22,9 @@ export const menus = [ { path: 'combine-plugins', name: 'combine-plugins' + }, + { + path: 'highlight-header', + name: 'highlight-header' } ]; diff --git a/packages/vtable-plugins/src/column-series.ts b/packages/vtable-plugins/src/column-series.ts index 0b36fdf326..4722f0d38a 100644 --- a/packages/vtable-plugins/src/column-series.ts +++ b/packages/vtable-plugins/src/column-series.ts @@ -17,7 +17,7 @@ export class ColumnSeriesPlugin implements VTable.plugins.IVTablePlugin { runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT]; pluginOptions: ColumnSeriesOptions; table: VTable.ListTable; - columns: { field: string; title: string }[] = []; + columns: { field?: string; title: string }[] = []; constructor(pluginOptions: ColumnSeriesOptions = { columnCount: 100 }) { this.pluginOptions = pluginOptions; } diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts new file mode 100644 index 0000000000..2fb05ca2da --- /dev/null +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -0,0 +1,105 @@ +import type { CellRange } from '@visactor/vtable/es/ts-types'; +import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; +import * as VTable from '@visactor/vtable'; +import type { TableEvents } from '@visactor/vtable/src/core/TABLE_EVENT_TYPE'; +import type { EventArg } from './types'; + +interface IExcelEditCellKeyboardPluginOptions { + replaceMode?: boolean; +} + +export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin { + id = 'excel-edit-cell-keyboard'; + name = 'Excel Edit Cell Keyboard'; + type: 'layout' = 'layout'; + runTime = [VTable.TABLE_EVENT_TYPE.INITIALIZED, VTable.TABLE_EVENT_TYPE.KEYDOWN]; + table: VTable.ListTable; + pluginOptions: IExcelEditCellKeyboardPluginOptions; + constructor(pluginOptions: IExcelEditCellKeyboardPluginOptions) { + this.pluginOptions = pluginOptions; + + this.bindEvent(); + } + run(...args: [EventArg, TableEvents[keyof TableEvents] | TableEvents[keyof TableEvents][], VTable.BaseTableAPI]) { + const eventArgs = args[0]; + const runTime = args[1]; + const table: VTable.BaseTableAPI = args[2]; + this.table = table as VTable.ListTable; + if (runTime === VTable.TABLE_EVENT_TYPE.KEYDOWN) { + this.handleWithKeyDown(eventArgs); + } else if (runTime === VTable.TABLE_EVENT_TYPE.INITIALIZED) { + // + } + } + + handleWithKeyDown(eventArgs: EventArg) { + const select = this.table.stateManager.select; + const cellPos = select.cellPos; + const event = eventArgs.event as KeyboardEvent; + //判断event的keycode如果不是excel的快捷键,如left enter tab 而是数字字母符号等 则调用table的startEditCell方法 进入编辑 且替换单元格已有内容 + if (!this.isExcelShortcutKey(event)) { + // this.table.startEditCell(cellPos.col, cellPos.row, ''); + } else if (event.key === 'Enter') { + this.table.startEditCell(cellPos.col, cellPos.row, ''); + } + } + // 判断event的keyCode是否是excel的快捷键 + isExcelShortcutKey(event: KeyboardEvent) { + return ( + event.key === 'Enter' || + event.key === 'Tab' || + event.key === 'ArrowLeft' || + event.key === 'ArrowRight' || + event.key === 'ArrowDown' || + event.key === 'ArrowUp' + ); + } + bindEvent() { + //监听document全局的keydown事件 捕获阶段 + document.addEventListener( + 'keydown', + event => { + if (this.table.editorManager.beginTriggerEditCellMode === 'keydown') { + if (this.table.editorManager.editingEditor && this.isExcelShortcutKey(event)) { + const { col, row } = this.table.editorManager.editCell; + this.table.editorManager.completeEdit(); + if (event.key === 'Enter') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'Tab') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowLeft') { + this.table.selectCell(col - 1, row); + } else if (event.key === 'ArrowRight') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowDown') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'ArrowUp') { + this.table.selectCell(col, row - 1); + } + // 阻止事件传播和默认行为 + event.stopPropagation(); + event.preventDefault(); + } + } + }, + true + ); + // this.table.on('selected_cell', () => { + // this.updateHighlight(); + // }); + + // this.table.on('selected_clear', () => { + // this.clearHighlight(); + // }); + + // this.table.on('mousemove_table', () => { + // if (this.table.stateManager.select.selecting) { + // this.updateHighlight(); + // } + // }); + } + + release() { + // + } +} diff --git a/packages/vtable-plugins/src/highlight-header.ts b/packages/vtable-plugins/src/highlight-header.ts new file mode 100644 index 0000000000..4c2d5dd2a3 --- /dev/null +++ b/packages/vtable-plugins/src/highlight-header.ts @@ -0,0 +1,186 @@ +import type { CellRange } from '@visactor/vtable/es/ts-types'; +import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; +import * as VTable from '@visactor/vtable'; +interface IHeaderHighlightPluginOptions { + rowHighlight?: boolean; + colHighlight?: boolean; + colHighlightBGColor?: string; + colHighlightColor?: string; + rowHighlightBGColor?: string; + rowHighlightColor?: string; +} + +export class HighlightHeaderPlugin implements VTable.plugins.IVTablePlugin { + id = 'highlight-header'; + name = 'Highlight Header'; + type: 'layout' = 'layout'; + runTime = [ + VTable.TABLE_EVENT_TYPE.INITIALIZED, + VTable.TABLE_EVENT_TYPE.SELECTED_CLEAR, + VTable.TABLE_EVENT_TYPE.SELECTED_CELL, + VTable.TABLE_EVENT_TYPE.MOUSEMOVE_TABLE + ]; + table: VTable.ListTable; + pluginOptions: IHeaderHighlightPluginOptions; + colHeaderRanges: CellRange[] = []; + rowHeaderRanges: CellRange[] = []; + constructor(pluginOptions: IHeaderHighlightPluginOptions) { + this.pluginOptions = pluginOptions; + } + run(...args: any[]) { + const eventArgs = args[0]; + const runTime = args[1]; + const table: VTable.BaseTableAPI = args[2]; + this.table = table as VTable.ListTable; + if (runTime === VTable.TABLE_EVENT_TYPE.SELECTED_CLEAR) { + this.clearHighlight(); + } else if (runTime === VTable.TABLE_EVENT_TYPE.SELECTED_CELL) { + this.updateHighlight(); + } else if (runTime === VTable.TABLE_EVENT_TYPE.MOUSEMOVE_TABLE) { + this.updateHighlight(); + } else if (runTime === VTable.TABLE_EVENT_TYPE.INITIALIZED) { + this.registerStyle(); + } + } + + registerStyle() { + this.table.registerCustomCellStyle('col-highlight', { + bgColor: this.pluginOptions?.colHighlightBGColor ?? '#82b2f5', + color: this.pluginOptions?.colHighlightColor ?? '#FFF' + }); + + this.table.registerCustomCellStyle('row-highlight', { + bgColor: this.pluginOptions?.rowHighlightBGColor ?? '#82b2f5', + color: this.pluginOptions?.rowHighlightColor ?? 'yellow' + }); + } + + clearHighlight() { + if (this.colHeaderRanges) { + this.colHeaderRanges.forEach(range => { + this.table.arrangeCustomCellStyle({ range }, undefined, true); + }); + } + if (this.rowHeaderRanges) { + this.rowHeaderRanges.forEach(range => { + this.table.arrangeCustomCellStyle({ range }, undefined, true); + }); + } + // clear range + this.colHeaderRanges = []; + this.rowHeaderRanges = []; + } + + updateHighlight() { + if (this.pluginOptions?.colHighlight === false && this.pluginOptions?.rowHighlight === false) { + return; + } + const selectRanges = this.table.getSelectedCellRanges(); + if (selectRanges.length < 2) { + this.clearHighlight(); + // return; + } + for (let i = 0; i < selectRanges.length; i++) { + const selectRange = selectRanges[i]; + const rowSelectRange = [selectRange.start.row, selectRange.end.row]; + rowSelectRange.sort((a, b) => a - b); // sort + const colSelectRange = [selectRange.start.col, selectRange.end.col]; + colSelectRange.sort((a, b) => a - b); // sort + + let colHeaderRange: CellRange; + let rowHeaderRange: CellRange; + if (this.table.isPivotTable()) { + colHeaderRange = { + start: { + col: colSelectRange[0], + row: 0 + }, + end: { + col: colSelectRange[1], + row: this.table.columnHeaderLevelCount - 1 + } + }; + rowHeaderRange = { + start: { + col: 0, + row: rowSelectRange[0] + }, + end: { + col: this.table.rowHeaderLevelCount - 1, + row: rowSelectRange[1] + } + }; + } else if (this.table.internalProps.transpose) { + rowHeaderRange = { + start: { + col: 0, + row: rowSelectRange[0] + }, + end: { + col: this.table.rowHeaderLevelCount - 1, + row: rowSelectRange[1] + } + }; + } else { + colHeaderRange = { + start: { + col: colSelectRange[0], + row: 0 + }, + end: { + col: colSelectRange[1], + row: this.table.columnHeaderLevelCount - 1 + } + }; + if (this.table.internalProps.rowSeriesNumber) { + rowHeaderRange = { + start: { + col: 0, + row: rowSelectRange[0] + }, + end: { + col: 0, + row: rowSelectRange[1] + } + }; + } + } + + if ( + this.pluginOptions?.colHighlight !== false && + !this.colHeaderRanges.find(range => isSameRange(range, colHeaderRange)) + ) { + // this.colHeaderRanges && this.table.arrangeCustomCellStyle({ range: this.colHeaderRanges }, undefined); + colHeaderRange && this.table.arrangeCustomCellStyle({ range: colHeaderRange }, 'col-highlight'); + this.colHeaderRanges.push(colHeaderRange); + } + + if ( + this.pluginOptions?.rowHighlight !== false && + !this.rowHeaderRanges.find(range => isSameRange(range, rowHeaderRange)) + ) { + // this.rowHeaderRanges && this.table.arrangeCustomCellStyle({ range: this.rowHeaderRanges }, undefined); + rowHeaderRange && this.table.arrangeCustomCellStyle({ range: rowHeaderRange }, 'row-highlight'); + this.rowHeaderRanges.push(rowHeaderRange); + } + } + } + release() { + this.rowHeaderRanges = []; + this.colHeaderRanges = []; + } +} + +function isSameRange(a: CellRange | undefined, b: CellRange | undefined) { + if (a === undefined && b === undefined) { + return true; + } + + if (a === undefined || b === undefined) { + return false; + } + + return ( + a.start.col === b.start.col && a.start.row === b.start.row && a.end.col === b.end.col && a.end.row === b.end.row + ); +} diff --git a/packages/vtable-plugins/src/index.ts b/packages/vtable-plugins/src/index.ts index e0a63beda4..8b01deec3d 100644 --- a/packages/vtable-plugins/src/index.ts +++ b/packages/vtable-plugins/src/index.ts @@ -5,3 +5,6 @@ export * from './case-before-init'; export * from './add-row-column'; export * from './column-series'; export * from './row-series'; +export * from './highlight-header'; +export * from './excel-edit-cell-keyboard'; +export * from './types'; diff --git a/packages/vtable-plugins/src/types.ts b/packages/vtable-plugins/src/types.ts new file mode 100644 index 0000000000..3aaa64e1d8 --- /dev/null +++ b/packages/vtable-plugins/src/types.ts @@ -0,0 +1,4 @@ +// 定义一个接口,要求必须包含 event 属性 +export type EventArg = { + event: MouseEvent | KeyboardEvent; +}; diff --git a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts index ed46acef5f..8b9c0960f5 100644 --- a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts +++ b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts @@ -25,8 +25,11 @@ export interface TableEvents { * 单元格选中状态改变事件 */ SELECTED_CLEAR: 'selected_clear'; + + /** 键盘按下事件 内部逻辑处理前 */ + BEFORE_KEYDOWN: 'before_keydown'; /** - * 键盘按下事件 + * 键盘按下事件 触发时机是在内部处理keydown逻辑之后 */ KEYDOWN: 'keydown'; /** @@ -167,6 +170,9 @@ export interface TableEvents { INITIALIZED: 'initialized'; //#endregion + /** 开始编辑单元格 */ + BEFORE_EDIT_CELL: 'before_edit_cell'; + /** 编辑单元格 */ CHANGE_CELL_VALUE: 'change_cell_value'; /** @@ -206,6 +212,7 @@ export const TABLE_EVENT_TYPE: TableEvents = { MOUSEUP_CELL: 'mouseup_cell', SELECTED_CELL: 'selected_cell', SELECTED_CLEAR: 'selected_clear', + BEFORE_KEYDOWN: 'before_keydown', KEYDOWN: 'keydown', MOUSEENTER_TABLE: 'mouseenter_table', MOUSELEAVE_TABLE: 'mouseleave_table', diff --git a/packages/vtable/src/edit/edit-manager.ts b/packages/vtable/src/edit/edit-manager.ts index a9e20bc398..6a8695894d 100644 --- a/packages/vtable/src/edit/edit-manager.ts +++ b/packages/vtable/src/edit/edit-manager.ts @@ -13,7 +13,7 @@ export class EditManager { isValidatingValue: boolean = false; editCell: { col: number; row: number }; listenersId: number[] = []; - + beginTriggerEditCellMode: 'doubleclick' | 'click' | 'keydown'; constructor(table: BaseTableAPI) { this.table = table; this.bindEvent(); @@ -43,12 +43,14 @@ export class EditManager { // 如果是双击自动列宽 则编辑不开启 return; } + this.beginTriggerEditCellMode = 'doubleclick'; this.startEditCell(col, row); }); const clickEventId = table.on(TABLE_EVENT_TYPE.CLICK_CELL, e => { const { editCellTrigger = 'doubleclick' } = table.options; if (editCellTrigger === 'click' || (Array.isArray(editCellTrigger) && editCellTrigger.includes('click'))) { + this.beginTriggerEditCellMode = 'click'; const { col, row } = e; this.startEditCell(col, row); } @@ -213,6 +215,7 @@ export class EditManager { this.editingEditor.onEnd?.(); this.editingEditor = null; this.isValidatingValue = false; + this.beginTriggerEditCellMode = null; } cancelEdit() { diff --git a/packages/vtable/src/event/listener/container-dom.ts b/packages/vtable/src/event/listener/container-dom.ts index 6085ec2406..789c3c7796 100644 --- a/packages/vtable/src/event/listener/container-dom.ts +++ b/packages/vtable/src/event/listener/container-dom.ts @@ -28,6 +28,15 @@ export function bindContainerDomListener(eventManager: EventManager) { // 监听键盘事件 handler.on(table.getElement(), 'keydown', (e: KeyboardEvent) => { + console.log('keydown', e.key); + // 键盘按下事件 内部逻辑处理前 + const beforeKeydownEvent: KeydownEvent = { + keyCode: e.keyCode ?? e.which, + code: e.code, + event: e + }; + table.fireListeners(TABLE_EVENT_TYPE.BEFORE_KEYDOWN, beforeKeydownEvent); + // 键盘按下事件 内部逻辑处理 if (e.key === 'a' && (e.ctrlKey || e.metaKey)) { if (table.keyboardOptions?.selectAllOnCtrlA) { // 处理全选 @@ -212,6 +221,7 @@ export function bindContainerDomListener(eventManager: EventManager) { ) { const allowedKeys = /^[a-zA-Z0-9+\-*\/%=.,\s]$/; // 允许的键值正则表达式 if (e.key.match(allowedKeys)) { + table.editorManager.beginTriggerEditCellMode = 'keydown'; table.editorManager.startEditCell(stateManager.select.cellPos.col, stateManager.select.cellPos.row, ''); } } diff --git a/packages/vtable/src/ts-types/events.ts b/packages/vtable/src/ts-types/events.ts index 3d092c4270..4d6432d9e5 100644 --- a/packages/vtable/src/ts-types/events.ts +++ b/packages/vtable/src/ts-types/events.ts @@ -83,6 +83,7 @@ export interface TableEventHandlersEventArgumentMap { mousedown_cell: MousePointerCellEvent; mouseup_cell: MousePointerCellEvent; contextmenu_cell: MousePointerMultiCellEvent; + before_keydown: KeydownEvent; keydown: KeydownEvent; scroll: { event: WheelEvent; @@ -270,6 +271,7 @@ export interface TableEventHandlersReturnMap { mousedown_cell: boolean; mouseup_cell: void; contextmenu_cell: void; + before_keydown: void; keydown: void; scroll: void; focus_table: void; From f7402c42219a8a2dca94b902cd9570af87b19065 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 25 Mar 2025 19:48:45 +0800 Subject: [PATCH 10/51] refactor: invert-highlight change to focus highlight --- .../demo/focus-highlight/focus-highlight.ts | 116 ++++++++++++++++ packages/vtable-plugins/demo/menu.ts | 4 + .../vtable-plugins/src/focus-highlight.ts | 124 ++++++++++++++++++ .../vtable-plugins/src/header-highlight.ts | 3 + .../vtable-plugins/src/highlight-header.ts | 34 ++--- packages/vtable-plugins/src/index.ts | 1 + .../vtable-plugins/src/invert-highlight.ts | 3 + packages/vtable/src/ts-types/index.ts | 1 + 8 files changed, 269 insertions(+), 17 deletions(-) create mode 100644 packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts create mode 100644 packages/vtable-plugins/src/focus-highlight.ts diff --git a/packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts b/packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts new file mode 100644 index 0000000000..2efc8ff474 --- /dev/null +++ b/packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts @@ -0,0 +1,116 @@ +import * as VTable from '@visactor/vtable'; +import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; +import { FocusHighlightPlugin } from '../../src'; +const CONTAINER_ID = 'vTable'; +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + +export function createTable() { + const highlightPlugin = new FocusHighlightPlugin(); + const records = generatePersons(20); + const columns: VTable.ColumnsDefine = [ + { + field: 'image', + title: '行号', + width: 80, + cellType: 'image', + keepAspectRatio: true + }, + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ]; + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records, + columns, + theme: VTable.themes.DARK, + // heightMode: 'adaptive', + // select: { + // disableSelect: true + // }, + plugins: [highlightPlugin] + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + bindDebugTool(tableInstance.scenegraph.stage, { + customGrapicKeys: ['col', 'row'] + }); + + // highlightPlugin.setInvertHighlightRange({ + // start: { + // col: 0, + // row: 6 + // }, + // end: { + // col: 6, + // row: 6 + // } + // }); + + // const ca = new CarouselAnimationPlugin(tableInstance, { + // rowCount: 2, + // replaceScrollAction: true + // }); + + // ca.play(); + + // setInterval(() => { + // row += 2; + // tableInstance.scrollToRow(row, { duration: 500 }); + // }, 2000); +} diff --git a/packages/vtable-plugins/demo/menu.ts b/packages/vtable-plugins/demo/menu.ts index 1ebe6f4bfc..b3b6da4e5c 100644 --- a/packages/vtable-plugins/demo/menu.ts +++ b/packages/vtable-plugins/demo/menu.ts @@ -23,6 +23,10 @@ export const menus = [ path: 'combine-plugins', name: 'combine-plugins' }, + { + path: 'focus-highlight', + name: 'focus-highlight' + }, { path: 'highlight-header', name: 'highlight-header' diff --git a/packages/vtable-plugins/src/focus-highlight.ts b/packages/vtable-plugins/src/focus-highlight.ts new file mode 100644 index 0000000000..baecf44f5e --- /dev/null +++ b/packages/vtable-plugins/src/focus-highlight.ts @@ -0,0 +1,124 @@ +import type { INode } from '@visactor/vtable/es/vrender'; +import { createRect } from '@visactor/vtable/es/vrender'; +import type { Group } from '@visactor/vtable/es/scenegraph/graphic/group'; +import { isSameRange } from '@visactor/vtable/es/tools/cell-range'; +import type { CellRange } from '@visactor/vtable/es/ts-types'; +import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; +import { cellInRange } from '@visactor/vtable/es/tools/helper'; +import { TABLE_EVENT_TYPE } from '@visactor/vtable'; +export interface FocusHighlightPluginOptions { + fill?: string; + opacity?: number; +} + +export class FocusHighlightPlugin { + id = 'focus-highlight'; + name = 'Focus Highlight'; + type: 'layout' = 'layout'; + runTime = [TABLE_EVENT_TYPE.CLICK_CELL]; + table: BaseTableAPI; + range?: CellRange; + pluginOptions: FocusHighlightPluginOptions; + + constructor( + options: FocusHighlightPluginOptions = { + fill: '#000', + opacity: 0.5 + } + ) { + this.pluginOptions = options; + } + run(...args: any[]) { + if (!this.table) { + this.table = args[2] as BaseTableAPI; + } + const { col, row } = args[0]; + if (this.table.isHeader(col, row)) { + this.setFocusHighlightRange(undefined); + } else { + this.setFocusHighlightRange({ + start: { + col: 0, + row + }, + end: { + col: this.table.colCount - 1, + row + } + }); + } + } + + setFocusHighlightRange(range?: CellRange) { + if (isSameRange(this.range, range)) { + return; + } + + this.range = range; + if (!range) { + // reset highlight + this.deleteAllCellGroupShadow(); + } else { + // update highlight + this.updateCellGroupShadow(); + } + + this.table.scenegraph.updateNextFrame(); + } + + deleteAllCellGroupShadow() { + if (!this.table.isPivotTable()) { + this.updateCellGroupShadowInContainer(this.table.scenegraph.rowHeaderGroup); + this.updateCellGroupShadowInContainer(this.table.scenegraph.leftBottomCornerGroup); + } + this.updateCellGroupShadowInContainer(this.table.scenegraph.bodyGroup); + this.updateCellGroupShadowInContainer(this.table.scenegraph.rightFrozenGroup); + this.updateCellGroupShadowInContainer(this.table.scenegraph.bottomFrozenGroup); + this.updateCellGroupShadowInContainer(this.table.scenegraph.rightBottomCornerGroup); + } + + updateCellGroupShadow() { + if (!this.table.isPivotTable()) { + this.updateCellGroupShadowInContainer(this.table.scenegraph.rowHeaderGroup, this.range); + this.updateCellGroupShadowInContainer(this.table.scenegraph.leftBottomCornerGroup, this.range); + } + this.updateCellGroupShadowInContainer(this.table.scenegraph.bodyGroup, this.range); + this.updateCellGroupShadowInContainer(this.table.scenegraph.rightFrozenGroup, this.range); + this.updateCellGroupShadowInContainer(this.table.scenegraph.bottomFrozenGroup), this.range; + this.updateCellGroupShadowInContainer(this.table.scenegraph.rightBottomCornerGroup, this.range); + } + updateCellGroupShadowInContainer(container: Group, range?: CellRange) { + container.forEachChildrenSkipChild((item: INode) => { + const column = item as unknown as Group; + if (column.role === 'column') { + column.forEachChildrenSkipChild((item: INode) => { + const cell = item as unknown as Group; + if (cell.role !== 'cell') { + return; + } + cell.attachShadow(cell.shadowRoot); + const shadowGroup = cell.shadowRoot; + if (!range) { + // no highlight + shadowGroup.removeAllChild(); + } else if (cellInRange(range, cell.col, cell.row)) { + // inside highlight + shadowGroup.removeAllChild(); + } else if (!shadowGroup.firstChild) { + // outside highlight + const shadowRect = createRect({ + x: 0, + y: 0, + width: cell.attribute.width, + height: cell.attribute.height, + fill: this.pluginOptions.fill, + opacity: this.pluginOptions.opacity + }); + shadowRect.name = 'shadow-rect'; + shadowGroup.appendChild(shadowRect); + } + }); + } + }); + } +} diff --git a/packages/vtable-plugins/src/header-highlight.ts b/packages/vtable-plugins/src/header-highlight.ts index 3d2c4fec9a..6b83c67778 100644 --- a/packages/vtable-plugins/src/header-highlight.ts +++ b/packages/vtable-plugins/src/header-highlight.ts @@ -10,6 +10,9 @@ export interface IHeaderHighlightPluginOptions { rowHighlightColor?: string; } +/** + * @deprecated 请使用 HighlightHeaderPlugin 插件 + */ export class HeaderHighlightPlugin { table: BaseTableAPI; options: IHeaderHighlightPluginOptions; diff --git a/packages/vtable-plugins/src/highlight-header.ts b/packages/vtable-plugins/src/highlight-header.ts index 4c2d5dd2a3..3ec03c8629 100644 --- a/packages/vtable-plugins/src/highlight-header.ts +++ b/packages/vtable-plugins/src/highlight-header.ts @@ -1,6 +1,6 @@ import type { CellRange } from '@visactor/vtable/es/ts-types'; -import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; -import * as VTable from '@visactor/vtable'; +import { TABLE_EVENT_TYPE } from '@visactor/vtable'; +import type { BaseTableAPI, plugins } from '@visactor/vtable'; interface IHeaderHighlightPluginOptions { rowHighlight?: boolean; colHighlight?: boolean; @@ -10,17 +10,17 @@ interface IHeaderHighlightPluginOptions { rowHighlightColor?: string; } -export class HighlightHeaderPlugin implements VTable.plugins.IVTablePlugin { +export class HighlightHeaderPlugin implements plugins.IVTablePlugin { id = 'highlight-header'; name = 'Highlight Header'; type: 'layout' = 'layout'; runTime = [ - VTable.TABLE_EVENT_TYPE.INITIALIZED, - VTable.TABLE_EVENT_TYPE.SELECTED_CLEAR, - VTable.TABLE_EVENT_TYPE.SELECTED_CELL, - VTable.TABLE_EVENT_TYPE.MOUSEMOVE_TABLE + TABLE_EVENT_TYPE.INITIALIZED, + TABLE_EVENT_TYPE.SELECTED_CLEAR, + TABLE_EVENT_TYPE.SELECTED_CELL, + TABLE_EVENT_TYPE.MOUSEMOVE_TABLE ]; - table: VTable.ListTable; + table: BaseTableAPI; pluginOptions: IHeaderHighlightPluginOptions; colHeaderRanges: CellRange[] = []; rowHeaderRanges: CellRange[] = []; @@ -28,17 +28,17 @@ export class HighlightHeaderPlugin implements VTable.plugins.IVTablePlugin { this.pluginOptions = pluginOptions; } run(...args: any[]) { - const eventArgs = args[0]; + // const eventArgs = args[0]; const runTime = args[1]; - const table: VTable.BaseTableAPI = args[2]; - this.table = table as VTable.ListTable; - if (runTime === VTable.TABLE_EVENT_TYPE.SELECTED_CLEAR) { + const table: BaseTableAPI = args[2]; + this.table = table; + if (runTime === TABLE_EVENT_TYPE.SELECTED_CLEAR) { this.clearHighlight(); - } else if (runTime === VTable.TABLE_EVENT_TYPE.SELECTED_CELL) { + } else if (runTime === TABLE_EVENT_TYPE.SELECTED_CELL) { this.updateHighlight(); - } else if (runTime === VTable.TABLE_EVENT_TYPE.MOUSEMOVE_TABLE) { + } else if (runTime === TABLE_EVENT_TYPE.MOUSEMOVE_TABLE) { this.updateHighlight(); - } else if (runTime === VTable.TABLE_EVENT_TYPE.INITIALIZED) { + } else if (runTime === TABLE_EVENT_TYPE.INITIALIZED) { this.registerStyle(); } } @@ -58,12 +58,12 @@ export class HighlightHeaderPlugin implements VTable.plugins.IVTablePlugin { clearHighlight() { if (this.colHeaderRanges) { this.colHeaderRanges.forEach(range => { - this.table.arrangeCustomCellStyle({ range }, undefined, true); + this.table.arrangeCustomCellStyle({ range }, undefined); }); } if (this.rowHeaderRanges) { this.rowHeaderRanges.forEach(range => { - this.table.arrangeCustomCellStyle({ range }, undefined, true); + this.table.arrangeCustomCellStyle({ range }, undefined); }); } // clear range diff --git a/packages/vtable-plugins/src/index.ts b/packages/vtable-plugins/src/index.ts index 8b01deec3d..20dcdec22b 100644 --- a/packages/vtable-plugins/src/index.ts +++ b/packages/vtable-plugins/src/index.ts @@ -8,3 +8,4 @@ export * from './row-series'; export * from './highlight-header'; export * from './excel-edit-cell-keyboard'; export * from './types'; +export * from './focus-highlight'; diff --git a/packages/vtable-plugins/src/invert-highlight.ts b/packages/vtable-plugins/src/invert-highlight.ts index c5f5fd13b5..6047c7e0a3 100644 --- a/packages/vtable-plugins/src/invert-highlight.ts +++ b/packages/vtable-plugins/src/invert-highlight.ts @@ -11,6 +11,9 @@ export interface InvertHighlightPluginOptions { opacity?: number; } +/** + * @deprecated 请使用 FocusHighlightPlugin 插件 + */ export class InvertHighlightPlugin { table: BaseTableAPI; range?: CellRange; diff --git a/packages/vtable/src/ts-types/index.ts b/packages/vtable/src/ts-types/index.ts index a9d2de4f59..633f6f0d5e 100644 --- a/packages/vtable/src/ts-types/index.ts +++ b/packages/vtable/src/ts-types/index.ts @@ -15,3 +15,4 @@ export * from './pivot-table'; export * from './component'; export * from './animation'; export * from './dataset'; +export * from './base-table'; From d1ae0e718a0e3ba9f55e7853f7f6722cadf171a7 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 25 Mar 2025 20:16:12 +0800 Subject: [PATCH 11/51] refactor: carouselAnimationPlugin change --- ...n.ts => (deprecated)carousel-animation.ts} | 0 ...ght.ts => (deprecated)header-highlight.ts} | 0 ...ght.ts => (deprecated)invert-highlight.ts} | 0 packages/vtable-plugins/demo/menu.ts | 26 ++- .../table-carousel-animation.ts | 99 +++++++++ packages/vtable-plugins/src/index.ts | 1 + .../src/table-carousel-animation.ts | 193 ++++++++++++++++++ 7 files changed, 308 insertions(+), 11 deletions(-) rename packages/vtable-plugins/demo/carousel-animation/{carousel-animation.ts => (deprecated)carousel-animation.ts} (100%) rename packages/vtable-plugins/demo/header-highlight/{header-highlight.ts => (deprecated)header-highlight.ts} (100%) rename packages/vtable-plugins/demo/invert-highlight/{invert-highlight.ts => (deprecated)invert-highlight.ts} (100%) create mode 100644 packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts create mode 100644 packages/vtable-plugins/src/table-carousel-animation.ts diff --git a/packages/vtable-plugins/demo/carousel-animation/carousel-animation.ts b/packages/vtable-plugins/demo/carousel-animation/(deprecated)carousel-animation.ts similarity index 100% rename from packages/vtable-plugins/demo/carousel-animation/carousel-animation.ts rename to packages/vtable-plugins/demo/carousel-animation/(deprecated)carousel-animation.ts diff --git a/packages/vtable-plugins/demo/header-highlight/header-highlight.ts b/packages/vtable-plugins/demo/header-highlight/(deprecated)header-highlight.ts similarity index 100% rename from packages/vtable-plugins/demo/header-highlight/header-highlight.ts rename to packages/vtable-plugins/demo/header-highlight/(deprecated)header-highlight.ts diff --git a/packages/vtable-plugins/demo/invert-highlight/invert-highlight.ts b/packages/vtable-plugins/demo/invert-highlight/(deprecated)invert-highlight.ts similarity index 100% rename from packages/vtable-plugins/demo/invert-highlight/invert-highlight.ts rename to packages/vtable-plugins/demo/invert-highlight/(deprecated)invert-highlight.ts diff --git a/packages/vtable-plugins/demo/menu.ts b/packages/vtable-plugins/demo/menu.ts index b3b6da4e5c..3716d4bf86 100644 --- a/packages/vtable-plugins/demo/menu.ts +++ b/packages/vtable-plugins/demo/menu.ts @@ -1,15 +1,27 @@ export const menus = [ { path: 'carousel-animation', - name: 'carousel-animation' + name: '(deprecated)carousel-animation' }, { path: 'header-highlight', - name: 'header-highlight' + name: '(deprecated)header-highlight' }, { path: 'invert-highlight', - name: 'invert-highlight' + name: '(deprecated)invert-highlight' + }, + { + path: 'focus-highlight', + name: 'focus-highlight' + }, + { + path: 'highlight-header', + name: 'highlight-header' + }, + { + path: 'table-carousel-animation', + name: 'table-carousel-animation' }, { path: 'add-row-column', @@ -22,13 +34,5 @@ export const menus = [ { path: 'combine-plugins', name: 'combine-plugins' - }, - { - path: 'focus-highlight', - name: 'focus-highlight' - }, - { - path: 'highlight-header', - name: 'highlight-header' } ]; diff --git a/packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts b/packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts new file mode 100644 index 0000000000..0ca247ae63 --- /dev/null +++ b/packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts @@ -0,0 +1,99 @@ +import * as VTable from '@visactor/vtable'; +import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; +import { InvertHighlightPlugin, TableCarouselAnimationPlugin } from '../../src'; +const CONTAINER_ID = 'vTable'; +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + +export function createTable() { + const records = generatePersons(20); + const columns: VTable.ColumnsDefine = [ + { + field: 'image', + title: '行号', + width: 80, + cellType: 'image', + keepAspectRatio: true + }, + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ]; + const tca = new TableCarouselAnimationPlugin({ + rowCount: 2, + // colCount: 2, + replaceScrollAction: true, + autoPlay: true, + autoPlayDelay: 1000 + }); + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records, + columns, + theme: VTable.themes.DARK, + // heightMode: 'adaptive', + select: { + disableSelect: true + }, + plugins: [tca] + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + bindDebugTool(tableInstance.scenegraph.stage, { + customGrapicKeys: ['col', 'row'] + }); +} diff --git a/packages/vtable-plugins/src/index.ts b/packages/vtable-plugins/src/index.ts index 20dcdec22b..6de0e85227 100644 --- a/packages/vtable-plugins/src/index.ts +++ b/packages/vtable-plugins/src/index.ts @@ -9,3 +9,4 @@ export * from './highlight-header'; export * from './excel-edit-cell-keyboard'; export * from './types'; export * from './focus-highlight'; +export * from './table-carousel-animation'; diff --git a/packages/vtable-plugins/src/table-carousel-animation.ts b/packages/vtable-plugins/src/table-carousel-animation.ts new file mode 100644 index 0000000000..ee4d5caa96 --- /dev/null +++ b/packages/vtable-plugins/src/table-carousel-animation.ts @@ -0,0 +1,193 @@ +import type { EasingType } from '@visactor/vtable/es/vrender'; +import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; +import { TABLE_EVENT_TYPE } from '@visactor/vtable'; + +function isInteger(value: number) { + return Math.floor(value) === value; +} + +export interface ITableCarouselAnimationPluginOptions { + rowCount?: number; + colCount?: number; + animationDuration?: number; + animationDelay?: number; + animationEasing?: EasingType; + replaceScrollAction?: boolean; + autoPlay?: boolean; + autoPlayDelay?: number; + + customDistRowFunction?: (row: number, table: BaseTableAPI) => { distRow: number; animation?: boolean } | undefined; + customDistColFunction?: (col: number, table: BaseTableAPI) => { distCol: number; animation?: boolean } | undefined; +} + +export class TableCarouselAnimationPlugin { + id = 'table-carousel-animation'; + name = 'Table Carousel Animation'; + type: 'layout' = 'layout'; + runTime = [TABLE_EVENT_TYPE.INITIALIZED]; + table: BaseTableAPI; + + rowCount: number; + colCount: number; + animationDuration: number; + animationDelay: number; + animationEasing: EasingType; + replaceScrollAction: boolean; + + playing: boolean; + row: number; + col: number; + willUpdateRow: boolean = false; + willUpdateCol: boolean = false; + autoPlay: boolean; + autoPlayDelay: number; + + customDistRowFunction?: (row: number, table: BaseTableAPI) => { distRow: number; animation?: boolean } | undefined; + customDistColFunction?: (col: number, table: BaseTableAPI) => { distCol: number; animation?: boolean } | undefined; + constructor(options: ITableCarouselAnimationPluginOptions = {}) { + this.rowCount = options?.rowCount ?? undefined; + this.colCount = options?.colCount ?? undefined; + this.animationDuration = options?.animationDuration ?? 500; + this.animationDelay = options?.animationDelay ?? 1000; + this.animationEasing = options?.animationEasing ?? 'linear'; + this.replaceScrollAction = options?.replaceScrollAction ?? false; + this.autoPlay = options?.autoPlay ?? false; + this.autoPlayDelay = options?.autoPlayDelay ?? 0; + this.customDistColFunction = options.customDistColFunction; + this.customDistRowFunction = options.customDistRowFunction; + } + run(...args: any[]) { + if (!this.table) { + this.table = args[2] as BaseTableAPI; + } + this.reset(); + this.init(); + if (this.autoPlay) { + setTimeout(() => { + this.play(); + }, this.autoPlayDelay); + } + } + init() { + if (this.replaceScrollAction) { + this.table.disableScroll(); + + this.table.scenegraph.stage.addEventListener('wheel', this.onScrollEnd.bind(this)); + } + } + + reset() { + this.playing = false; + this.row = this.table.frozenRowCount; + this.col = this.table.frozenColCount; + } + + onScrollEnd(e: Event) { + if (this.rowCount) { + if ((e as any).deltaY > 0) { + this.row += this.rowCount; + this.row = Math.min(this.row, this.table.rowCount - this.table.frozenRowCount); + } else if ((e as any).deltaY < 0) { + this.row -= this.rowCount; + this.row = Math.max(this.row, this.table.frozenRowCount); + } + this.table.scrollToRow(this.row, { duration: this.animationDuration, easing: this.animationEasing }); + } else if (this.colCount) { + if ((e as any).deltaX > 0) { + this.col += this.colCount; + this.col = Math.min(this.col, this.table.colCount - this.table.frozenColCount); + } else if ((e as any).deltaX < 0) { + this.col -= this.colCount; + this.col = Math.max(this.col, this.table.frozenColCount); + } + this.table.scrollToCol(this.col, { duration: this.animationDuration, easing: this.animationEasing }); + } + } + + play() { + if (!this.table) { + throw new Error('table is not initialized'); + } + this.playing = true; + + if (this.rowCount && !this.willUpdateRow) { + this.updateRow(); + } else if (this.colCount && !this.willUpdateCol) { + this.updateCol(); + } + } + + pause() { + this.playing = false; + } + + updateRow() { + if (!this.playing || this.table.isReleased) { + return; + } + + let animation = true; + const customRow = this.customDistRowFunction && this.customDistRowFunction(this.row, this.table); + if (customRow) { + this.row = customRow.distRow; + animation = customRow.animation ?? true; + } else if (isInteger(this.row) && this.table.scenegraph.proxy.screenTopRow !== this.row) { + this.row = this.table.frozenRowCount; + animation = false; + } else if (!isInteger(this.row) && this.table.scenegraph.proxy.screenTopRow !== Math.floor(this.row)) { + this.row = this.table.frozenRowCount; + animation = false; + } else { + this.row += this.rowCount; + } + this.table.scrollToRow( + this.row, + animation ? { duration: this.animationDuration, easing: this.animationEasing } : undefined + ); + this.willUpdateRow = true; + setTimeout( + () => { + this.willUpdateRow = false; + this.updateRow(); + }, + // animation ? this.animationDuration + this.animationDelay : 0 + this.animationDuration + this.animationDelay + ); + } + + updateCol() { + if (!this.playing || this.table.isReleased) { + return; + } + + let animation = true; + const customCol = this.customDistColFunction && this.customDistColFunction(this.col, this.table); + if (customCol) { + this.col = customCol.distCol; + animation = customCol.animation ?? true; + } else if (isInteger(this.col) && this.table.scenegraph.proxy.screenLeftCol !== this.col) { + this.col = this.table.frozenColCount; + animation = false; + } else if (!isInteger(this.col) && this.table.scenegraph.proxy.screenLeftCol !== Math.floor(this.col)) { + this.col = this.table.frozenColCount; + animation = false; + } else { + this.col += this.colCount; + } + + this.table.scrollToCol( + this.col, + animation ? { duration: this.animationDuration, easing: this.animationEasing } : undefined + ); + + this.willUpdateCol = true; + setTimeout( + () => { + this.willUpdateCol = false; + this.updateCol(); + }, + // animation ? this.animationDuration + this.animationDelay : 0 + this.animationDuration + this.animationDelay + ); + } +} From bd4ebdbdfd47661e7abb28eebf8781053fa27b87 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 27 Mar 2025 15:45:13 +0800 Subject: [PATCH 12/51] refactor: excel keyboard plugin --- .../src/excel-edit-cell-keyboard.ts | 69 +++++++++---------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts index 2fb05ca2da..f5e39680ed 100644 --- a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -12,7 +12,7 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin id = 'excel-edit-cell-keyboard'; name = 'Excel Edit Cell Keyboard'; type: 'layout' = 'layout'; - runTime = [VTable.TABLE_EVENT_TYPE.INITIALIZED, VTable.TABLE_EVENT_TYPE.KEYDOWN]; + runTime = [VTable.TABLE_EVENT_TYPE.INITIALIZED]; table: VTable.ListTable; pluginOptions: IExcelEditCellKeyboardPluginOptions; constructor(pluginOptions: IExcelEditCellKeyboardPluginOptions) { @@ -21,28 +21,10 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin this.bindEvent(); } run(...args: [EventArg, TableEvents[keyof TableEvents] | TableEvents[keyof TableEvents][], VTable.BaseTableAPI]) { - const eventArgs = args[0]; - const runTime = args[1]; const table: VTable.BaseTableAPI = args[2]; this.table = table as VTable.ListTable; - if (runTime === VTable.TABLE_EVENT_TYPE.KEYDOWN) { - this.handleWithKeyDown(eventArgs); - } else if (runTime === VTable.TABLE_EVENT_TYPE.INITIALIZED) { - // - } } - handleWithKeyDown(eventArgs: EventArg) { - const select = this.table.stateManager.select; - const cellPos = select.cellPos; - const event = eventArgs.event as KeyboardEvent; - //判断event的keycode如果不是excel的快捷键,如left enter tab 而是数字字母符号等 则调用table的startEditCell方法 进入编辑 且替换单元格已有内容 - if (!this.isExcelShortcutKey(event)) { - // this.table.startEditCell(cellPos.col, cellPos.row, ''); - } else if (event.key === 'Enter') { - this.table.startEditCell(cellPos.col, cellPos.row, ''); - } - } // 判断event的keyCode是否是excel的快捷键 isExcelShortcutKey(event: KeyboardEvent) { return ( @@ -59,26 +41,39 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin document.addEventListener( 'keydown', event => { - if (this.table.editorManager.beginTriggerEditCellMode === 'keydown') { - if (this.table.editorManager.editingEditor && this.isExcelShortcutKey(event)) { - const { col, row } = this.table.editorManager.editCell; - this.table.editorManager.completeEdit(); - if (event.key === 'Enter') { - this.table.selectCell(col, row + 1); - } else if (event.key === 'Tab') { - this.table.selectCell(col + 1, row); - } else if (event.key === 'ArrowLeft') { - this.table.selectCell(col - 1, row); - } else if (event.key === 'ArrowRight') { - this.table.selectCell(col + 1, row); - } else if (event.key === 'ArrowDown') { + if (this.table.editorManager) { + if (this.table.editorManager.beginTriggerEditCellMode === 'keydown') { + if (this.table.editorManager.editingEditor && this.isExcelShortcutKey(event)) { + const { col, row } = this.table.editorManager.editCell; + this.table.editorManager.completeEdit(); + if (event.key === 'Enter') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'Tab') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowLeft') { + this.table.selectCell(col - 1, row); + } else if (event.key === 'ArrowRight') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowDown') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'ArrowUp') { + this.table.selectCell(col, row - 1); + } + this.table.getElement().focus(); + // 阻止事件传播和默认行为 + event.stopPropagation(); + event.preventDefault(); + } + } else { + const { col, row } = this.table.stateManager.select.cellPos; + if (this.table.editorManager.editingEditor && event.key === 'Enter') { + this.table.editorManager.completeEdit(); + this.table.getElement().focus(); this.table.selectCell(col, row + 1); - } else if (event.key === 'ArrowUp') { - this.table.selectCell(col, row - 1); + // 阻止事件传播和默认行为 + event.stopPropagation(); + event.preventDefault(); } - // 阻止事件传播和默认行为 - event.stopPropagation(); - event.preventDefault(); } } }, From 6f779212db4082802f477f0a581ceac7c6a4e5bd Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 1 Apr 2025 17:26:13 +0800 Subject: [PATCH 13/51] feat: refactor carousel animation --- .../(deprecated)carousel-animation.ts | 16 +-- .../table-carousel-animation.ts | 3 +- .../src/excel-edit-cell-keyboard.ts | 104 +++++++++--------- .../src/table-carousel-animation.ts | 36 +----- 4 files changed, 63 insertions(+), 96 deletions(-) diff --git a/packages/vtable-plugins/demo/carousel-animation/(deprecated)carousel-animation.ts b/packages/vtable-plugins/demo/carousel-animation/(deprecated)carousel-animation.ts index c9108ce291..3a01bd3fd0 100644 --- a/packages/vtable-plugins/demo/carousel-animation/(deprecated)carousel-animation.ts +++ b/packages/vtable-plugins/demo/carousel-animation/(deprecated)carousel-animation.ts @@ -19,7 +19,7 @@ const generatePersons = count => { }; export function createTable() { - const records = generatePersons(20); + const records = generatePersons(30); const columns: VTable.ColumnsDefine = [ { field: 'image', @@ -76,7 +76,11 @@ export function createTable() { container: document.getElementById(CONTAINER_ID), records, columns, - theme: VTable.themes.DARK, + theme: VTable.themes.DARK.extends({ + scrollStyle: { + visible: 'none' + } + }), // heightMode: 'adaptive', select: { disableSelect: true @@ -84,14 +88,10 @@ export function createTable() { }; const tableInstance = new VTable.ListTable(option); window.tableInstance = tableInstance; - - bindDebugTool(tableInstance.scenegraph.stage, { - customGrapicKeys: ['col', 'row'] - }); - + tableInstance.disableScroll(); const ca = new CarouselAnimationPlugin(tableInstance, { rowCount: 2, - replaceScrollAction: true + replaceScrollAction: false }); ca.play(); diff --git a/packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts b/packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts index 0ca247ae63..e5c78fcae1 100644 --- a/packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts +++ b/packages/vtable-plugins/demo/table-carousel-animation/table-carousel-animation.ts @@ -19,7 +19,7 @@ const generatePersons = count => { }; export function createTable() { - const records = generatePersons(20); + const records = generatePersons(30); const columns: VTable.ColumnsDefine = [ { field: 'image', @@ -75,7 +75,6 @@ export function createTable() { const tca = new TableCarouselAnimationPlugin({ rowCount: 2, // colCount: 2, - replaceScrollAction: true, autoPlay: true, autoPlayDelay: 1000 }); diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts index f5e39680ed..e5edfb2b7b 100644 --- a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -25,60 +25,9 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin this.table = table as VTable.ListTable; } - // 判断event的keyCode是否是excel的快捷键 - isExcelShortcutKey(event: KeyboardEvent) { - return ( - event.key === 'Enter' || - event.key === 'Tab' || - event.key === 'ArrowLeft' || - event.key === 'ArrowRight' || - event.key === 'ArrowDown' || - event.key === 'ArrowUp' - ); - } bindEvent() { //监听document全局的keydown事件 捕获阶段 - document.addEventListener( - 'keydown', - event => { - if (this.table.editorManager) { - if (this.table.editorManager.beginTriggerEditCellMode === 'keydown') { - if (this.table.editorManager.editingEditor && this.isExcelShortcutKey(event)) { - const { col, row } = this.table.editorManager.editCell; - this.table.editorManager.completeEdit(); - if (event.key === 'Enter') { - this.table.selectCell(col, row + 1); - } else if (event.key === 'Tab') { - this.table.selectCell(col + 1, row); - } else if (event.key === 'ArrowLeft') { - this.table.selectCell(col - 1, row); - } else if (event.key === 'ArrowRight') { - this.table.selectCell(col + 1, row); - } else if (event.key === 'ArrowDown') { - this.table.selectCell(col, row + 1); - } else if (event.key === 'ArrowUp') { - this.table.selectCell(col, row - 1); - } - this.table.getElement().focus(); - // 阻止事件传播和默认行为 - event.stopPropagation(); - event.preventDefault(); - } - } else { - const { col, row } = this.table.stateManager.select.cellPos; - if (this.table.editorManager.editingEditor && event.key === 'Enter') { - this.table.editorManager.completeEdit(); - this.table.getElement().focus(); - this.table.selectCell(col, row + 1); - // 阻止事件传播和默认行为 - event.stopPropagation(); - event.preventDefault(); - } - } - } - }, - true - ); + document.addEventListener('keydown', this.handleKeyDown.bind(this), true); // this.table.on('selected_cell', () => { // this.updateHighlight(); // }); @@ -93,8 +42,55 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin // } // }); } - + handleKeyDown(event: KeyboardEvent) { + if (this.table.editorManager) { + if (this.table.editorManager.beginTriggerEditCellMode === 'keydown') { + if (this.table.editorManager.editingEditor && this.isExcelShortcutKey(event)) { + const { col, row } = this.table.editorManager.editCell; + this.table.editorManager.completeEdit(); + if (event.key === 'Enter') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'Tab') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowLeft') { + this.table.selectCell(col - 1, row); + } else if (event.key === 'ArrowRight') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowDown') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'ArrowUp') { + this.table.selectCell(col, row - 1); + } + this.table.getElement().focus(); + // 阻止事件传播和默认行为 + event.stopPropagation(); + event.preventDefault(); + } + } else { + const { col, row } = this.table.stateManager.select.cellPos; + if (this.table.editorManager.editingEditor && event.key === 'Enter') { + this.table.editorManager.completeEdit(); + this.table.getElement().focus(); + this.table.selectCell(col, row + 1); + // 阻止事件传播和默认行为 + event.stopPropagation(); + event.preventDefault(); + } + } + } + } + // 判断event的keyCode是否是excel的快捷键 + isExcelShortcutKey(event: KeyboardEvent) { + return ( + event.key === 'Enter' || + event.key === 'Tab' || + event.key === 'ArrowLeft' || + event.key === 'ArrowRight' || + event.key === 'ArrowDown' || + event.key === 'ArrowUp' + ); + } release() { - // + document.removeEventListener('keydown', this.handleKeyDown, true); } } diff --git a/packages/vtable-plugins/src/table-carousel-animation.ts b/packages/vtable-plugins/src/table-carousel-animation.ts index ee4d5caa96..19e795ace5 100644 --- a/packages/vtable-plugins/src/table-carousel-animation.ts +++ b/packages/vtable-plugins/src/table-carousel-animation.ts @@ -32,7 +32,6 @@ export class TableCarouselAnimationPlugin { animationDuration: number; animationDelay: number; animationEasing: EasingType; - replaceScrollAction: boolean; playing: boolean; row: number; @@ -50,7 +49,6 @@ export class TableCarouselAnimationPlugin { this.animationDuration = options?.animationDuration ?? 500; this.animationDelay = options?.animationDelay ?? 1000; this.animationEasing = options?.animationEasing ?? 'linear'; - this.replaceScrollAction = options?.replaceScrollAction ?? false; this.autoPlay = options?.autoPlay ?? false; this.autoPlayDelay = options?.autoPlayDelay ?? 0; this.customDistColFunction = options.customDistColFunction; @@ -61,20 +59,13 @@ export class TableCarouselAnimationPlugin { this.table = args[2] as BaseTableAPI; } this.reset(); - this.init(); + if (this.autoPlay) { setTimeout(() => { this.play(); }, this.autoPlayDelay); } } - init() { - if (this.replaceScrollAction) { - this.table.disableScroll(); - - this.table.scenegraph.stage.addEventListener('wheel', this.onScrollEnd.bind(this)); - } - } reset() { this.playing = false; @@ -82,28 +73,6 @@ export class TableCarouselAnimationPlugin { this.col = this.table.frozenColCount; } - onScrollEnd(e: Event) { - if (this.rowCount) { - if ((e as any).deltaY > 0) { - this.row += this.rowCount; - this.row = Math.min(this.row, this.table.rowCount - this.table.frozenRowCount); - } else if ((e as any).deltaY < 0) { - this.row -= this.rowCount; - this.row = Math.max(this.row, this.table.frozenRowCount); - } - this.table.scrollToRow(this.row, { duration: this.animationDuration, easing: this.animationEasing }); - } else if (this.colCount) { - if ((e as any).deltaX > 0) { - this.col += this.colCount; - this.col = Math.min(this.col, this.table.colCount - this.table.frozenColCount); - } else if ((e as any).deltaX < 0) { - this.col -= this.colCount; - this.col = Math.max(this.col, this.table.frozenColCount); - } - this.table.scrollToCol(this.col, { duration: this.animationDuration, easing: this.animationEasing }); - } - } - play() { if (!this.table) { throw new Error('table is not initialized'); @@ -190,4 +159,7 @@ export class TableCarouselAnimationPlugin { this.animationDuration + this.animationDelay ); } + release() { + // do nothing + } } From 03b9f7980053e0c9afdc6a2590b5404561cb019c Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 3 Apr 2025 11:08:45 +0800 Subject: [PATCH 14/51] fix: excel keyboard action --- .../src/excel-edit-cell-keyboard.ts | 36 ++++++++++--------- .../src/event/listener/container-dom.ts | 2 +- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts index e5edfb2b7b..601450c2cd 100644 --- a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -44,27 +44,31 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin } handleKeyDown(event: KeyboardEvent) { if (this.table.editorManager) { + //判断是键盘触发开始编辑的情况,那么在编辑状态中切换方向需要选中下一个继续编辑 if (this.table.editorManager.beginTriggerEditCellMode === 'keydown') { if (this.table.editorManager.editingEditor && this.isExcelShortcutKey(event)) { const { col, row } = this.table.editorManager.editCell; this.table.editorManager.completeEdit(); - if (event.key === 'Enter') { - this.table.selectCell(col, row + 1); - } else if (event.key === 'Tab') { - this.table.selectCell(col + 1, row); - } else if (event.key === 'ArrowLeft') { - this.table.selectCell(col - 1, row); - } else if (event.key === 'ArrowRight') { - this.table.selectCell(col + 1, row); - } else if (event.key === 'ArrowDown') { - this.table.selectCell(col, row + 1); - } else if (event.key === 'ArrowUp') { - this.table.selectCell(col, row - 1); - } this.table.getElement().focus(); - // 阻止事件传播和默认行为 - event.stopPropagation(); - event.preventDefault(); + if (!event.shiftKey && !event.ctrlKey && !event.metaKey) { + //有这些配合键,则不进行选中下一个单元格的行为 执行vtable内部逻辑 + if (event.key === 'Enter') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'Tab') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowLeft') { + this.table.selectCell(col - 1, row); + } else if (event.key === 'ArrowRight') { + this.table.selectCell(col + 1, row); + } else if (event.key === 'ArrowDown') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'ArrowUp') { + this.table.selectCell(col, row - 1); + } + // 阻止事件传播和默认行为 + event.stopPropagation(); + event.preventDefault(); + } } } else { const { col, row } = this.table.stateManager.select.cellPos; diff --git a/packages/vtable/src/event/listener/container-dom.ts b/packages/vtable/src/event/listener/container-dom.ts index 789c3c7796..cee0f23906 100644 --- a/packages/vtable/src/event/listener/container-dom.ts +++ b/packages/vtable/src/event/listener/container-dom.ts @@ -213,7 +213,7 @@ export function bindContainerDomListener(eventManager: EventManager) { } } } - } else if (!(e.ctrlKey || e.metaKey || e.shiftKey)) { + } else if (!(e.ctrlKey || e.metaKey)) { const editCellTrigger = (table.options as ListTableConstructorOptions).editCellTrigger; if ( (editCellTrigger === 'keydown' || (Array.isArray(editCellTrigger) && editCellTrigger.includes('keydown'))) && From 11392ba4052d80dd5f0bd7998248452a4034dd4e Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 3 Apr 2025 11:10:19 +0800 Subject: [PATCH 15/51] chore: update start server command --- packages/vtable-plugins/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vtable-plugins/package.json b/packages/vtable-plugins/package.json index 6a3cb1d4a9..c0a3b2e4cd 100644 --- a/packages/vtable-plugins/package.json +++ b/packages/vtable-plugins/package.json @@ -23,7 +23,7 @@ } }, "scripts": { - "start": "vite ./demo", + "demo": "vite ./demo", "build": "bundle --clean" }, "unpkg": "latest", @@ -87,4 +87,4 @@ "@types/react-is": "^17.0.3", "rollup-plugin-node-resolve": "5.2.0" } -} +} \ No newline at end of file From 3eb0d5bf5cb053e6266769f8feeeecb5c5ef40de Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 9 Apr 2025 19:52:05 +0800 Subject: [PATCH 16/51] docs: add plugins usage --- docs/assets/guide/menu.json | 13 ++- docs/assets/guide/zh/plugin/contribute.md | 0 .../assets/guide/zh/plugin/focus-highlight.md | 57 +++++++++++++ .../guide/zh/plugin/header-highlight.md | 27 +++++- .../guide/zh/plugin/invert-highlight.md | 49 ----------- .../guide/zh/plugin/row-column-series.md | 83 +++++++++++++++++++ docs/assets/guide/zh/plugin/usage.md | 0 .../demo/column-series/column-series.ts | 5 ++ .../demo/highlight-header/highlight-header.ts | 3 +- .../src/excel-edit-cell-keyboard.ts | 18 ++++ 10 files changed, 200 insertions(+), 55 deletions(-) create mode 100644 docs/assets/guide/zh/plugin/contribute.md create mode 100644 docs/assets/guide/zh/plugin/focus-highlight.md delete mode 100644 docs/assets/guide/zh/plugin/invert-highlight.md create mode 100644 docs/assets/guide/zh/plugin/row-column-series.md create mode 100644 docs/assets/guide/zh/plugin/usage.md diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 388fd59d60..21b099e2bc 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -726,10 +726,17 @@ }, "children": [ { - "path": "invert-highlight", + "path": "row-column-series", "title": { - "zh": "反选高亮", - "en": "Invert Highlight" + "zh": "行列序号", + "en": "Row Column Series" + } + }, + { + "path": "focus-highlight", + "title": { + "zh": "聚焦高亮", + "en": "Focus Highlight" } }, { diff --git a/docs/assets/guide/zh/plugin/contribute.md b/docs/assets/guide/zh/plugin/contribute.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/assets/guide/zh/plugin/focus-highlight.md b/docs/assets/guide/zh/plugin/focus-highlight.md new file mode 100644 index 0000000000..05f9d2e194 --- /dev/null +++ b/docs/assets/guide/zh/plugin/focus-highlight.md @@ -0,0 +1,57 @@ +# 聚焦高亮插件 + +VTable 提供聚焦高亮插件,支持聚焦高亮指定区域。 + +
+ +
+ +## 聚焦高亮插件配置项 + +- `FocusHighlightPlugin` 聚焦高亮插件,可以配置以下参数: + - `fill` 聚焦高亮背景色 + - `opacity` 反选高亮透明度 + +``` +export interface FocusHighlightPluginOptions { + fill?: string; + opacity?: number; +} +``` + +## 使用示例: +```js + + const highlightPlugin = new FocusHighlightPlugin({ + fill: '#000', + opacity: 0.5 + }); + + const option: VTable.ListTableConstructorOptions = { + records, + columns, + theme: VTable.themes.DARK, + plugins: [highlightPlugin] + }; +``` + +具体使用参考[demo](../../demo/interaction/head-highlight) + +## 反选高亮插件 API + +### setInvertHighlightRange + +设置反选高亮范围。 + +```ts +setInvertHighlightRange(range: { + start: { + col: number; + row: number; + }; + end: { + col: number; + row: number; + }; +}): void; +``` \ No newline at end of file diff --git a/docs/assets/guide/zh/plugin/header-highlight.md b/docs/assets/guide/zh/plugin/header-highlight.md index a017810452..2f64b86b38 100644 --- a/docs/assets/guide/zh/plugin/header-highlight.md +++ b/docs/assets/guide/zh/plugin/header-highlight.md @@ -15,9 +15,34 @@ VTable 提供表头高亮插件,支持选中单元格后,高亮对应的表 - `rowHighlightBGColor` 行头高亮背景色 - `colHighlightColor` 列头高亮字体色 - `rowHighlightColor` 行头高亮字体色 + +插件参数类型: +``` +interface IHeaderHighlightPluginOptions { + rowHighlight?: boolean; + colHighlight?: boolean; + colHighlightBGColor?: string; + colHighlightColor?: string; + rowHighlightBGColor?: string; + rowHighlightColor?: string; +} +``` +## 使用示例: ```js -const highlightPlugin = new HeaderHighlightPlugin(tableInstance, {}); + const highlightPlugin = new HighlightHeaderPlugin({ + colHighlight: true, + rowHighlight: true + }); + const option: VTable.ListTableConstructorOptions = { + records, + columns, + select: { + outsideClickDeselect: true, + headerSelectMode: 'body' + }, + plugins: [highlightPlugin] + }; ``` 具体使用参考[demo](../../demo/interaction/head-highlight) diff --git a/docs/assets/guide/zh/plugin/invert-highlight.md b/docs/assets/guide/zh/plugin/invert-highlight.md deleted file mode 100644 index 1be1fee5b7..0000000000 --- a/docs/assets/guide/zh/plugin/invert-highlight.md +++ /dev/null @@ -1,49 +0,0 @@ -# 反选高亮插件 - -VTable 提供反选高亮插件,支持反选高亮指定区域。 - -
- -
- -## 反选高亮插件配置项 - -- `InvertHighlightPlugin` 反选高亮插件,可以配置以下参数: - - `fill` 反选高亮背景色 - - `opacity` 反选高亮透明度 - -```js -const highlightPlugin = new InvertHighlightPlugin(tableInstance, {}); - -highlightPlugin.setInvertHighlightRange({ - start: { - col: 0, - row: 6 - }, - end: { - col: 5, - row: 6 - } -}); -``` - -具体使用参考[demo](../../demo/interaction/head-highlight) - -## 反选高亮插件 API - -### setInvertHighlightRange - -设置反选高亮范围。 - -```ts -setInvertHighlightRange(range: { - start: { - col: number; - row: number; - }; - end: { - col: number; - row: number; - }; -}): void; -``` \ No newline at end of file diff --git a/docs/assets/guide/zh/plugin/row-column-series.md b/docs/assets/guide/zh/plugin/row-column-series.md new file mode 100644 index 0000000000..1ae6c09699 --- /dev/null +++ b/docs/assets/guide/zh/plugin/row-column-series.md @@ -0,0 +1,83 @@ +# 行列序号插件 + +## 功能介绍 + +ColumnSeriesPlugin 和 RowSeriesPlugin 这两个插件 是 VTable 的扩展组件,能够自动生成行列序号。 + +
+ +
+ +## 插件参数 + +```typescript +export interface ColumnSeriesOptions { + columnCount: number; + generateColumnTitle?: (index: number) => string; // 自定义列标题生成函数 + generateColumnField?: (index: number) => string;// 自定义列字段名生成函数 +} + +export interface RowSeriesOptions { + rowCount: number; + fillRowRecord?: (index: number) => any; // 填充空行的 自定义生成数据函数 +} +``` + +## 基本用法 + +```typescript +import * as VTable from '@visactor/vtable'; +import { ColumnSeriesPlugin } from '@visactor/vtable-plugins'; + +// 创建 ColumnSeries 插件实例 +const columnSeries = new ColumnSeriesPlugin({ + columnCount: 100 // 设置列数量 +}); + +// 创建 RowSeries 插件实例 +const rowSeries = new RowSeriesPlugin({ + rowCount: 100 // 设置行数量 +}); + +// 在 VTable 选项中使用插件 +const option: VTable.ListTableConstructorOptions = { + container: document.getElementById('container'), + records: data, + plugins: [columnSeries, rowSeries], + // 其他 VTable 配置... +}; + +// 创建表格实例 +const tableInstance = new VTable.ListTable(option); +``` + +## 高级用法 + +### 自定义列标题和字段名 + +```typescript +const columnSeries = new ColumnSeriesPlugin({ + columnCount: 100, + // 自定义列标题生成 + columnTitleGenerator: (index) => `自定义标题 ${index}`, + // 自定义字段名生成 + columnFieldGenerator: (index) => `field_${index}` +}); +``` + +### 自定义行数据 + +```typescript +const rowSeries = new RowSeriesPlugin({ + rowCount: 100, + // 自定义行数据生成 + fillRowRecord: (index) => ([]) +}); + +// or +const rowSeries = new RowSeriesPlugin({ + rowCount: 100, + // 自定义行数据生成 + fillRowRecord: (index) => (['姓名', '年龄', '地址']) +}); +``` diff --git a/docs/assets/guide/zh/plugin/usage.md b/docs/assets/guide/zh/plugin/usage.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/vtable-plugins/demo/column-series/column-series.ts b/packages/vtable-plugins/demo/column-series/column-series.ts index 895c4a418b..07a796bbac 100644 --- a/packages/vtable-plugins/demo/column-series/column-series.ts +++ b/packages/vtable-plugins/demo/column-series/column-series.ts @@ -26,6 +26,11 @@ export function createTable() { }); const rowSeries = new RowSeriesPlugin({ rowCount: 100 + // fillRowRecord: index => { + // const record = generatePersons(1)[0]; + // record.id = index; + // return record; + // } }); const option: VTable.ListTableConstructorOptions = { container: document.getElementById(CONTAINER_ID), diff --git a/packages/vtable-plugins/demo/highlight-header/highlight-header.ts b/packages/vtable-plugins/demo/highlight-header/highlight-header.ts index 0f0fd5c37e..75a1f62415 100644 --- a/packages/vtable-plugins/demo/highlight-header/highlight-header.ts +++ b/packages/vtable-plugins/demo/highlight-header/highlight-header.ts @@ -63,7 +63,6 @@ export function createTable() { rowHighlight: true }); const option: VTable.ListTableConstructorOptions = { - container: document.getElementById(CONTAINER_ID), records, columns, rowSeriesNumber: {}, @@ -78,7 +77,7 @@ export function createTable() { }, plugins: [highlightPlugin] }; - const tableInstance = new VTable.ListTable(option); + const tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID)!, option); window.tableInstance = tableInstance; bindDebugTool(tableInstance.scenegraph.stage, { diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts index 601450c2cd..2e75de04a0 100644 --- a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -79,6 +79,16 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin // 阻止事件传播和默认行为 event.stopPropagation(); event.preventDefault(); + } else if (event.key === 'Delete') { + //响应删除键,删除 + const selectCells = this.table.getSelectedCellInfos(); + if (selectCells?.length > 0) { + // 如果选中的是范围,则删除范围内的所有单元格 + deleteSelectRange(selectCells, this.table); + } + // 阻止事件传播和默认行为 + event.stopPropagation(); + event.preventDefault(); } } } @@ -98,3 +108,11 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin document.removeEventListener('keydown', this.handleKeyDown, true); } } +//将选中单元格的值设置为空 +function deleteSelectRange(selectCells: VTable.TYPES.CellInfo[][], tableInstance: VTable.ListTable) { + for (let i = 0; i < selectCells.length; i++) { + for (let j = 0; j < selectCells[i].length; j++) { + tableInstance.changeCellValue(selectCells[i][j].col, selectCells[i][j].row, ''); + } + } +} From 23245fde4430659ca8ffd5e1e7d26d02d1463586 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Fri, 11 Apr 2025 16:08:14 +0800 Subject: [PATCH 17/51] docs: add plugins tutorial --- docs/assets/guide/menu.json | 7 ++ .../zh/plugin/excel-keyboard-alignment.md | 66 +++++++++++++++++++ .../guide/zh/plugin/header-highlight.md | 10 +-- .../guide/zh/plugin/row-column-series.md | 7 +- .../demo/combine-plugins/combine-plugins.ts | 6 +- .../vtable-plugins/src/case-before-init.ts | 24 ------- .../src/excel-edit-cell-keyboard.ts | 21 +++--- ...s => highlight-header-when-select-cell.ts} | 12 ++-- packages/vtable-plugins/src/index.ts | 3 +- packages/vtable-plugins/src/row-series.ts | 8 ++- 10 files changed, 116 insertions(+), 48 deletions(-) create mode 100644 docs/assets/guide/zh/plugin/excel-keyboard-alignment.md delete mode 100644 packages/vtable-plugins/src/case-before-init.ts rename packages/vtable-plugins/src/{highlight-header.ts => highlight-header-when-select-cell.ts} (93%) diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 2b05fbd6c1..0eef3d9208 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -759,6 +759,13 @@ "zh": "表头高亮", "en": "Header Highlight" } + }, + { + "path": "excel-keyboard-alignment", + "title": { + "zh": "excel键盘交互对齐", + "en": "excel keyboard interaction alignment" + } } ] }, diff --git a/docs/assets/guide/zh/plugin/excel-keyboard-alignment.md b/docs/assets/guide/zh/plugin/excel-keyboard-alignment.md new file mode 100644 index 0000000000..35565655fd --- /dev/null +++ b/docs/assets/guide/zh/plugin/excel-keyboard-alignment.md @@ -0,0 +1,66 @@ +# 编辑单元格键盘行为对齐Excel插件使用说明 + +`ExcelEditCellKeyboardPlugin`是 VTable 的扩展组件,能够实现编辑单元格键盘行为对齐Excel的功能。 + +## 插件实现能力说明 +关于键盘响应方便VTable原有的能力有以下两个配置入口, + +| keyboard | 响应 | +| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| enter | 如果在编辑状态,则确认编辑完成;
如果 keyboardOptions.moveFocusCellOnEnter 为 true 时,按下 enter 会切换选中单元格到下面的单元格。
如果 keyboardOptions.editCellOnEnter 为 true 时,如果当前选中了某个可编辑的单元格,按 enter 进入编辑状态。 | +| tab | 需开启 keyboardOptions.moveFocusCellOnTab。
按 tab 切换选中单元格,如果当前是在编辑单元格 则移动到下一个单元格也是编辑状态。 | +| left | 方向键,切换选中单元格。
如果开启 keyboardOptions.moveEditCellOnArrowKeys,那么在编辑状态中也可以切换编辑单元格 | +| right | 同上 | +| top | 同上 | +| bottom | 同上 | +| ctrl+c | 键位不准,这个 copy 是和浏览器的快捷键一致的。
复制选中单元格内容,需要开启 keyboardOptions.copySelected | +| ctrl+v | 键位不准,粘贴快捷键和浏览器的快捷键一致的。
粘贴内容到单元格,需要开启 keyboardOptions.pasteValueToCell,粘贴生效仅针对配置了编辑 editor 的单元格 | +| ctrl+a | 全选,需要开启 keyboardOptions.selectAllOnCtrlA | +| shift | 按住 shift 和鼠标左键,连续区域选中单元格 | +| ctrl | 按住 ctrl 和鼠标左键,选中多个区域 | +| 任何一个键 | 可以监听 tableInstance.on('keydown',(args)=>{ }) | + +能满足大部分的编辑表格的键盘响应要求,但相比Excel来说,VTable的键盘行为还是有一些差异的,比如: + +- 在VTable中,编辑单元格时,按下方向键不会切换到下一个单元格,而是会切换到编辑单元格的光标。 +- 在VTable中,编辑单元格时,按下 enter 不会确认编辑完成,而是会切换到下一个单元格。 +- 在VTable中,编辑单元格时,按下 tab 不会切换到下一个单元格,而是会切换到编辑单元格的光标。 +- 在VTable中,编辑单元格时,按下 shift 和鼠标左键,不会连续区域选中单元格。 +- 在VTable中,编辑单元格时,按住 ctrl 和鼠标左键,不会选中多个区域。 + + +结合VTable已有的部分符合需求的能力,我们开发了`ExcelEditCellKeyboardPlugin`插件,能够实现编辑单元格键盘行为对齐Excel的功能。 + +## 插件使用说明 + +```ts + + const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin(); + + const option: VTable.ListTableConstructorOptions = { + records, + columns, + theme: VTable.themes.DARK, + plugins: [excelEditCellKeyboardPlugin] + }; +``` + +## 插件后续完善 + +其他和Excel不一致的键盘行为,如: + +- 支持配置项,是否响应删除键 +- 支持配置项,是否响应 ctrl+c 和 ctrl+v +- 支持配置项,是否响应 shift 和鼠标左键 +- 支持配置项,是否响应 ctrl 和鼠标左键 + +各个响应的行为是否需要使用者明确进行配置,如提供配置项: +```ts +const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin({ + enableDeleteKey: false +}); +const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin(excelEditCellKeyboardPlugin); + +``` + +欢迎大家贡献自己的力量,一起来写更多插件!一起建设VTable的生态! \ No newline at end of file diff --git a/docs/assets/guide/zh/plugin/header-highlight.md b/docs/assets/guide/zh/plugin/header-highlight.md index 2f64b86b38..d980018260 100644 --- a/docs/assets/guide/zh/plugin/header-highlight.md +++ b/docs/assets/guide/zh/plugin/header-highlight.md @@ -1,6 +1,6 @@ -# 表头高亮插件 +# 选中单元格对应表头高亮插件 -VTable 提供表头高亮插件,支持选中单元格后,高亮对应的表头(行头和列头)。 +VTable 提供选中单元格对应表头高亮插件,支持选中单元格后,高亮对应的表头(行头和列头)。
@@ -8,7 +8,7 @@ VTable 提供表头高亮插件,支持选中单元格后,高亮对应的表 ## 表头高亮插件配置项 -- `HeaderHighlightPlugin` 表头高亮插件,可以配置以下参数: +- `HighlightHeaderWhenSelectCellPlugin` 选中单元格对应表头高亮插件,可以配置以下参数: - `columnHighlight` 是否高亮列头 - `rowHighlight` 是否高亮行头 - `colHighlightBGColor` 列头高亮背景色 @@ -18,7 +18,7 @@ VTable 提供表头高亮插件,支持选中单元格后,高亮对应的表 插件参数类型: ``` -interface IHeaderHighlightPluginOptions { +interface IHighlightHeaderWhenSelectCellPluginOptions { rowHighlight?: boolean; colHighlight?: boolean; colHighlightBGColor?: string; @@ -30,7 +30,7 @@ interface IHeaderHighlightPluginOptions { ## 使用示例: ```js - const highlightPlugin = new HighlightHeaderPlugin({ + const highlightPlugin = new HighlightHeaderWhenSelectCellPlugin({ colHighlight: true, rowHighlight: true }); diff --git a/docs/assets/guide/zh/plugin/row-column-series.md b/docs/assets/guide/zh/plugin/row-column-series.md index 1ae6c09699..c8e031d35a 100644 --- a/docs/assets/guide/zh/plugin/row-column-series.md +++ b/docs/assets/guide/zh/plugin/row-column-series.md @@ -20,9 +20,14 @@ export interface ColumnSeriesOptions { export interface RowSeriesOptions { rowCount: number; fillRowRecord?: (index: number) => any; // 填充空行的 自定义生成数据函数 + rowSeriesNumber?: VTable.TYPES.IRowSeriesNumber; } ``` +列序号插件的配置中除了可以配置生成列的数量,以及对应到VTable中columns的配置所需要的字段名field和标题title。 + +行序号插件的配置中`rowCount`可以配置生成行的数量,`rowSeriesNumber`可以配置行序号的配置,这里配置后比new VTable实例中options.rowSeriesNumber优先级更高。`fillRowRecord`可以配置生成行的数据,如果不配置的话 默认是返回个空对象`{}`。 + ## 基本用法 ```typescript @@ -70,7 +75,7 @@ const columnSeries = new ColumnSeriesPlugin({ ```typescript const rowSeries = new RowSeriesPlugin({ rowCount: 100, - // 自定义行数据生成 + // 自定义行数据生成 返回一个空数组 fillRowRecord: (index) => ([]) }); diff --git a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts index 35105b9e0f..99755f0cc9 100644 --- a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts +++ b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts @@ -37,6 +37,9 @@ export function createTable() { rowCount: 100, fillRowRecord: (index: number) => { return []; + }, + rowSeriesNumber: { + width: 'auto' } }); const highlightPlugin = new HighlightHeaderPlugin({ @@ -61,7 +64,8 @@ export function createTable() { editor: 'input', editCellTrigger: ['api', 'keydown', 'doubleclick'], select: { - // disableSelect: true + cornerHeaderSelectMode: 'body', + headerSelectMode: 'body' }, theme: VTable.themes.DEFAULT.extends({ defaultStyle: { diff --git a/packages/vtable-plugins/src/case-before-init.ts b/packages/vtable-plugins/src/case-before-init.ts deleted file mode 100644 index 4ac5ea5e89..0000000000 --- a/packages/vtable-plugins/src/case-before-init.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as VTable from '@visactor/vtable'; -export interface SomeOptions { - propone: string; -} - -export class BeforeInitPlugin implements VTable.plugins.IVTablePlugin { - id = '....'; - name = '...'; - type: 'layout' = 'layout'; - runTime = VTable.TABLE_EVENT_TYPE.BEFORE_INIT; - options: SomeOptions; - table: any; - constructor(options: SomeOptions) { - this.options = options; - } - run(...args: any[]) { - console.log('Table BEFORE_INIT'); - // const table = args[0]; - // const eventArgs = args[1]; - // const options = eventArgs.options; - // const container = eventArgs.container; - // 可以通过options.container重置替换容器 - } -} diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts index 2e75de04a0..3f30714836 100644 --- a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -3,10 +3,11 @@ import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; import * as VTable from '@visactor/vtable'; import type { TableEvents } from '@visactor/vtable/src/core/TABLE_EVENT_TYPE'; import type { EventArg } from './types'; - -interface IExcelEditCellKeyboardPluginOptions { - replaceMode?: boolean; -} +//备用 插件配置项 目前感觉都走默认逻辑就行 +export type IExcelEditCellKeyboardPluginOptions = { + // 是否响应删除 + // enableDeleteKey?: boolean; +}; export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin { id = 'excel-edit-cell-keyboard'; @@ -26,7 +27,7 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin } bindEvent() { - //监听document全局的keydown事件 捕获阶段 + //监听document全局的keydown事件 捕获阶段监听 可以及时阻止事件传播和默认行为 document.addEventListener('keydown', this.handleKeyDown.bind(this), true); // this.table.on('selected_cell', () => { // this.updateHighlight(); @@ -44,7 +45,7 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin } handleKeyDown(event: KeyboardEvent) { if (this.table.editorManager) { - //判断是键盘触发开始编辑的情况,那么在编辑状态中切换方向需要选中下一个继续编辑 + //判断是键盘触发编辑单元格的情况下,那么在编辑状态中切换方向需要选中下一个继续编辑 if (this.table.editorManager.beginTriggerEditCellMode === 'keydown') { if (this.table.editorManager.editingEditor && this.isExcelShortcutKey(event)) { const { col, row } = this.table.editorManager.editCell; @@ -72,10 +73,14 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin } } else { const { col, row } = this.table.stateManager.select.cellPos; - if (this.table.editorManager.editingEditor && event.key === 'Enter') { + if (this.table.editorManager.editingEditor && (event.key === 'Enter' || event.key === 'Tab')) { this.table.editorManager.completeEdit(); this.table.getElement().focus(); - this.table.selectCell(col, row + 1); + if (event.key === 'Enter') { + this.table.selectCell(col, row + 1); + } else if (event.key === 'Tab') { + this.table.selectCell(col + 1, row); + } // 阻止事件传播和默认行为 event.stopPropagation(); event.preventDefault(); diff --git a/packages/vtable-plugins/src/highlight-header.ts b/packages/vtable-plugins/src/highlight-header-when-select-cell.ts similarity index 93% rename from packages/vtable-plugins/src/highlight-header.ts rename to packages/vtable-plugins/src/highlight-header-when-select-cell.ts index 3ec03c8629..25c8d09fbc 100644 --- a/packages/vtable-plugins/src/highlight-header.ts +++ b/packages/vtable-plugins/src/highlight-header-when-select-cell.ts @@ -1,7 +1,7 @@ import type { CellRange } from '@visactor/vtable/es/ts-types'; import { TABLE_EVENT_TYPE } from '@visactor/vtable'; import type { BaseTableAPI, plugins } from '@visactor/vtable'; -interface IHeaderHighlightPluginOptions { +interface IHighlightHeaderWhenSelectCellPluginOptions { rowHighlight?: boolean; colHighlight?: boolean; colHighlightBGColor?: string; @@ -10,9 +10,9 @@ interface IHeaderHighlightPluginOptions { rowHighlightColor?: string; } -export class HighlightHeaderPlugin implements plugins.IVTablePlugin { - id = 'highlight-header'; - name = 'Highlight Header'; +export class HighlightHeaderWhenSelectCellPlugin implements plugins.IVTablePlugin { + id = 'highlight-header-when-select-cell'; + name = 'Highlight Header When Select Cell'; type: 'layout' = 'layout'; runTime = [ TABLE_EVENT_TYPE.INITIALIZED, @@ -21,10 +21,10 @@ export class HighlightHeaderPlugin implements plugins.IVTablePlugin { TABLE_EVENT_TYPE.MOUSEMOVE_TABLE ]; table: BaseTableAPI; - pluginOptions: IHeaderHighlightPluginOptions; + pluginOptions: IHighlightHeaderWhenSelectCellPluginOptions; colHeaderRanges: CellRange[] = []; rowHeaderRanges: CellRange[] = []; - constructor(pluginOptions: IHeaderHighlightPluginOptions) { + constructor(pluginOptions: IHighlightHeaderWhenSelectCellPluginOptions) { this.pluginOptions = pluginOptions; } run(...args: any[]) { diff --git a/packages/vtable-plugins/src/index.ts b/packages/vtable-plugins/src/index.ts index 6de0e85227..90b20be375 100644 --- a/packages/vtable-plugins/src/index.ts +++ b/packages/vtable-plugins/src/index.ts @@ -1,11 +1,10 @@ export * from './carousel-animation'; export * from './invert-highlight'; export * from './header-highlight'; -export * from './case-before-init'; export * from './add-row-column'; export * from './column-series'; export * from './row-series'; -export * from './highlight-header'; +export * from './highlight-header-when-select-cell'; export * from './excel-edit-cell-keyboard'; export * from './types'; export * from './focus-highlight'; diff --git a/packages/vtable-plugins/src/row-series.ts b/packages/vtable-plugins/src/row-series.ts index 671755d183..e868004f74 100644 --- a/packages/vtable-plugins/src/row-series.ts +++ b/packages/vtable-plugins/src/row-series.ts @@ -5,6 +5,7 @@ import * as VTable from '@visactor/vtable'; export interface RowSeriesOptions { rowCount: number; fillRowRecord?: (index: number) => any; + rowSeriesNumber?: VTable.TYPES.IRowSeriesNumber; } /** * 生成行序号标题的插件 @@ -31,7 +32,12 @@ export class RowSeriesPlugin implements VTable.plugins.IVTablePlugin { records.push(this.pluginOptions.fillRowRecord ? this.pluginOptions.fillRowRecord(i) : {}); } options.records = records; - if (!options.rowSeriesNumber) { + if (this.pluginOptions.rowSeriesNumber) { + options.rowSeriesNumber = this.pluginOptions.rowSeriesNumber; + if (!this.pluginOptions.rowSeriesNumber.width) { + options.rowSeriesNumber.width = 'auto'; + } + } else if (!options.rowSeriesNumber) { options.rowSeriesNumber = { width: 'auto' }; From 8183fd063bea5760703b2168792afbcf0e60f57c Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Fri, 11 Apr 2025 21:13:53 +0800 Subject: [PATCH 18/51] docs: add row column plus plugin --- docs/assets/guide/menu.json | 7 ++ docs/assets/guide/zh/plugin/row-column-add.md | 69 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 docs/assets/guide/zh/plugin/row-column-add.md diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 0eef3d9208..5792b9f885 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -766,6 +766,13 @@ "zh": "excel键盘交互对齐", "en": "excel keyboard interaction alignment" } + }, + { + "path": "row-column-add", + "title": { + "zh": "行列新增插件", + "en": "add row column plugin" + } } ] }, diff --git a/docs/assets/guide/zh/plugin/row-column-add.md b/docs/assets/guide/zh/plugin/row-column-add.md new file mode 100644 index 0000000000..4c074afefa --- /dev/null +++ b/docs/assets/guide/zh/plugin/row-column-add.md @@ -0,0 +1,69 @@ +# 行列新增插件 + +## 功能介绍 + +AddRowColumnPlugin 是为了扩展VTable支持动态新增行列而写的插件。 + +该插件监听了`vTable`实例的 `MOUSEENTER_CELL`, `MOUSELEAVE_CELL`, `MOUSELEAVE_TABLE`事件! + +当鼠标hover到table的cell时,会显示添加行和列的dot和加号;当鼠标离开table的cell时,会隐藏添加行和列的dot和加号。 + +## 插件配置 + +添加行和列的插件的配置选项: + +```ts +export interface AddRowColumnOptions { + /** + * 是否启用添加列 + */ + addColumnEnable?: boolean; + /** + * 是否启用添加行 + */ + addRowEnable?: boolean; + /** + * 添加列的回调函数 + */ + addColumnCallback?: (col: number) => void; + /** + * 添加行的回调函数 + */ + addRowCallback?: (row: number) => void; +} +``` + +## 插件示例 +初始化插件对象,添加到vTable配置的plugins中。 +``` +const addRowColumn = new AddRowColumnPlugin(); +const option = { + records, + columns, + padding: 30, + plugins: [addRowColumn] +}; +``` +为了能控制新增行数据的内容,以及控制新增列后数据的更新以及columns的信息,可以使用插件提供的配置项来优化使用,在初始化插件对象时提供新增行列的勾子函数,在函数中赋值新增的行数据或者列信息。 +```ts + const addRowColumn = new AddRowColumnPlugin({ + addColumnCallback: col => { + columns.splice(addColIndex, 0, { + field: ``, + title: `New Column ${col}`, + width: 100 + }); + this.table.updateColumns(columns); + const newRecords = tableInstance.records.map(record => { + if (Array.isArray(record)) { + record.splice(col - 1, 0, ''); + } + return record; + }); + tableInstance.setRecords(newRecords); + }, + addRowCallback: row => { + tableInstance.addRecord([], row - tableInstance.columnHeaderLevelCount); + } + }); +``` \ No newline at end of file From ff4f9599c5ebbb8492643b2996cb126ef3b98374 Mon Sep 17 00:00:00 2001 From: along Date: Mon, 14 Apr 2025 10:14:30 +0800 Subject: [PATCH 19/51] feat: add menu/disabled config --- packages/vtable/src/ts-types/menu.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vtable/src/ts-types/menu.ts b/packages/vtable/src/ts-types/menu.ts index d5b8b84aea..a19dcfc0ac 100644 --- a/packages/vtable/src/ts-types/menu.ts +++ b/packages/vtable/src/ts-types/menu.ts @@ -30,6 +30,7 @@ export type MenuListItem = selectedIcon?: Icon; stateIcon?: Icon; children?: MenuListItem[]; + disabled?: boolean; // 禁用菜单项 }; export type PivotInfo = { From 7d0c5b7fe05545d6e7266f857d55cd740602679d Mon Sep 17 00:00:00 2001 From: along Date: Mon, 14 Apr 2025 10:26:21 +0800 Subject: [PATCH 20/51] feat: add menu/disabled config --- .../components/menu/dom/logic/MenuElement.ts | 23 ++++++++++++++++++- .../menu/dom/logic/MenuElementStyle.ts | 11 ++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/vtable/src/components/menu/dom/logic/MenuElement.ts b/packages/vtable/src/components/menu/dom/logic/MenuElement.ts index 511c5605ce..c3a7618898 100644 --- a/packages/vtable/src/components/menu/dom/logic/MenuElement.ts +++ b/packages/vtable/src/components/menu/dom/logic/MenuElement.ts @@ -30,6 +30,7 @@ const TITLE_CLASSNAME = `${CLASSNAME}__title`; const ARROW_CLASSNAME = `${CLASSNAME}__arrow`; const NOEVENT_CLASSNAME = `${CLASSNAME}__no-event`; const ITEMTEXT_CLASSNAME = `${CLASSNAME}__item-text`; +const ITEM_DISABLED_CLASSNAME = `${CLASSNAME}__item-disabled`; function createMenuDomElement(): HTMLElement { const rootElement = createElement('div', [CLASSNAME, HIDDEN_CLASSNAME]); @@ -118,6 +119,11 @@ export class MenuElement { this._rootElement?.addEventListener('touchend', e => { e.stopPropagation(); e.preventDefault(); + + // disabled菜单项,禁用菜单点击 + if ((e.target as HTMLElement).classList.contains(ITEM_DISABLED_CLASSNAME)) { + return; + } if (this._rootElement.classList.contains(HIDDEN_CLASSNAME)) { return; } @@ -155,6 +161,11 @@ export class MenuElement { this._rootElement?.addEventListener('click', e => { e.stopPropagation(); e.preventDefault(); + + // disabled菜单项,禁用菜单点击 + if ((e.target as HTMLElement).classList.contains(ITEM_DISABLED_CLASSNAME)) { + return; + } if (this._rootElement.classList.contains(HIDDEN_CLASSNAME)) { return; } @@ -283,6 +294,11 @@ export class MenuElement { this._secondElement?.addEventListener('click', e => { e.stopPropagation(); e.preventDefault(); + + // disabled菜单项,禁用菜单点击 + if ((e.target as HTMLElement).classList.contains(ITEM_DISABLED_CLASSNAME)) { + return; + } if (this._secondElement.classList.contains(HIDDEN_CLASSNAME)) { return; } @@ -608,7 +624,7 @@ export class MenuElement { y: secondTop, width: secondWidth, height: secondHeight - } = rootElement.getBoundingClientRect(); + } = secondElement.getBoundingClientRect(); if ( x > secondLeft - 5 && x < secondLeft + secondWidth + 5 && @@ -628,6 +644,11 @@ function createItem(info: MenuListItem, isHighlight: boolean): HTMLDivElement { isHighlight ? SELECT_CLASSNAME : NORAML_CLASSNAME ]) as HTMLDivElement; + // 添加disabled样式 + if (typeof info === 'object' && info.disabled) { + itemContainer.classList.add(ITEM_DISABLED_CLASSNAME); + } + if (typeof info === 'string') { const item = createElement('span', [CONTENT_CLASSNAME, NOEVENT_CLASSNAME, ITEMTEXT_CLASSNAME]); item.innerHTML = info; diff --git a/packages/vtable/src/components/menu/dom/logic/MenuElementStyle.ts b/packages/vtable/src/components/menu/dom/logic/MenuElementStyle.ts index dfecb6fa1a..bd86ec0031 100644 --- a/packages/vtable/src/components/menu/dom/logic/MenuElementStyle.ts +++ b/packages/vtable/src/components/menu/dom/logic/MenuElementStyle.ts @@ -75,9 +75,18 @@ export function importStyle() { } .vtable__menu-element--select { color: #2E68CF; -}.vtable__menu-element--normal { +} +.vtable__menu-element--normal { color: rgba(20, 20, 20, 0.9);; } +.vtable__menu-element__item-disabled { + color: rgba(0, 0, 0, 0.25); + cursor: not-allowed; + background-color: #fff; +} +.vtable__menu-element__item-disabled:hover { + background-color: #fff; +} .vtable__menu-element__split { height: 0px; border: 1px solid rgb(209, 213, 218); From 07490d81d5275a5cf69867b458718361490308f4 Mon Sep 17 00:00:00 2001 From: along Date: Mon, 14 Apr 2025 11:07:08 +0800 Subject: [PATCH 21/51] feat: add list-contextMenu-disabledMenu demo --- .../list/list-contextMenu-disabledMenu.ts | 191 ++++++++++++++++++ packages/vtable/examples/menu.ts | 5 + .../vtable/examples/pivot/pivot-grid-tree.ts | 19 +- 3 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 packages/vtable/examples/list/list-contextMenu-disabledMenu.ts diff --git a/packages/vtable/examples/list/list-contextMenu-disabledMenu.ts b/packages/vtable/examples/list/list-contextMenu-disabledMenu.ts new file mode 100644 index 0000000000..c1c12a964c --- /dev/null +++ b/packages/vtable/examples/list/list-contextMenu-disabledMenu.ts @@ -0,0 +1,191 @@ +import * as VTable from '../../src'; +import { bindDebugTool } from '../../src/scenegraph/debug-tool'; +const CONTAINER_ID = 'vTable'; +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' : 'front-end engineer', + city: 'beijing' + })); +}; + +export function createTable() { + const records = generatePersons(20); + const columns: VTable.ColumnsDefine = [ + { + field: 'id', + title: 'ID', + width: '1%', + minWidth: 200, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + + { + field: 'tel', + title: 'telephone', + width: 150 + }, + { + field: 'work', + title: 'job', + width: 200 + }, + { + field: 'city', + title: 'city', + width: 150 + } + ]; + const option: VTable.ListTableConstructorOptions = { + container: document.getElementById(CONTAINER_ID), + records, + columns, + tooltip: { + isShowOverflowTextTooltip: true + }, + pagination: { + perPageCount: 10, + currentPage: 0 + }, + + rowSeriesNumber: { + title: '行号', + dragOrder: true, + headerStyle: { + bgColor: '#EEF1F5', + borderColor: '#e1e4e8' + }, + style: { + borderColor: '#e1e4e8' + } + }, + menu: { + // contextMenuItems: ['向下插入数据', '向下插入空行', '修改掉整行值', '修改值', '删除该行'], + contextMenuItems: [ + { + text: '向下插入数据', + menuKey: 'insertData' + }, + { + text: '向下插入空行', + menuKey: 'insertRow' + }, + { + text: '修改掉整行值', + menuKey: 'modifyRow', + disabled: true + }, + { + text: '修改值', + menuKey: 'modifyCell' + }, + { + text: '删除该行', + menuKey: 'deleteRow', + children: [ + { + text: '删除1行', + menuKey: 'deleteRow1' + }, + { + text: '删除2行', + menuKey: 'deleteRow2', + disabled: true + } + ] + } + ], + dropDownMenuHighlight: [ + { + menuKey: 'se3' + } + ], + defaultHeaderMenuItems: [ + { + text: '刷新', + menuKey: 'refresh' + }, + { + text: '关闭', + menuKey: 'close', + disabled: true, + children: [ + { + text: '二级菜单1', + menuKey: 'se1', + disabled: true, + children: [ + { + text: '三级菜单1', + menuKey: 'se1-1' + }, + { + text: '三级菜单2', + menuKey: 'se1-2' + } + ] + }, + { + text: '二级菜单2', + menuKey: 'se2' + }, + { + text: '二级菜单3', + menuKey: 'se3' + } + ] + }, + { + text: '删除', + menuKey: 'delete' + } + ] + } + + // bottomFrozenRowCount: 1 + // autoWrapText: true, + // heightMode: 'autoHeight', + // widthMode: 'adaptive' + }; + const tableInstance = new VTable.ListTable(option); + window.tableInstance = tableInstance; + + // bindDebugTool(tableInstance.scenegraph.stage, { customGrapicKeys: ['col', 'row'] }); + // tableInstance.on('sort_click', args => { + // tableInstance.updateSortState( + // { + // field: args.field, + // order: Date.now() % 3 === 0 ? 'desc' : Date.now() % 3 === 1 ? 'asc' : 'normal' + // }, + // false + // ); + // return false; //return false代表不执行内部排序逻辑 + // }); +} diff --git a/packages/vtable/examples/menu.ts b/packages/vtable/examples/menu.ts index 88c4060648..43acadaad6 100644 --- a/packages/vtable/examples/menu.ts +++ b/packages/vtable/examples/menu.ts @@ -107,6 +107,11 @@ export const menus = [ path: 'list', name: 'list-100w' }, + { + path: 'list', + name: 'list-contextMenu-disabledMenu' + }, + { path: 'list', name: 'list-rowSeriesNumber' diff --git a/packages/vtable/examples/pivot/pivot-grid-tree.ts b/packages/vtable/examples/pivot/pivot-grid-tree.ts index 673a2899d3..1eb179cdfa 100644 --- a/packages/vtable/examples/pivot/pivot-grid-tree.ts +++ b/packages/vtable/examples/pivot/pivot-grid-tree.ts @@ -260,7 +260,24 @@ export function createTable() { title: '类别', headerFormat(value) { return `${value}`; - } + }, + + // corner菜单 + cornerDropDownMenu: [ + { + menuKey: '升序排序C', + text: '升序排序C', + disabled: true + }, + { + menuKey: '降序排序I', + text: '降序排序I' + }, + { + menuKey: '冻结列I', + text: '冻结列I' + } + ] // width: 200 } // { From 06bc107c5465d04e320d2ede6dcb130897b815b4 Mon Sep 17 00:00:00 2001 From: along Date: Mon, 14 Apr 2025 11:26:53 +0800 Subject: [PATCH 22/51] docs: add MenuListItem/disabled config and update menu-list-item.md related docs --- docs/assets/option/en/common/menu-list-item.md | 3 ++- docs/assets/option/zh/common/menu-list-item.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/assets/option/en/common/menu-list-item.md b/docs/assets/option/en/common/menu-list-item.md index 658be74fdb..b2f71027f5 100644 --- a/docs/assets/option/en/common/menu-list-item.md +++ b/docs/assets/option/en/common/menu-list-item.md @@ -13,5 +13,6 @@ type MenuListItem = selectedIcon?: Icon; stateIcon?: Icon; children?: MenuListItem[]; + disabled?: boolean; }; -``` \ No newline at end of file +``` diff --git a/docs/assets/option/zh/common/menu-list-item.md b/docs/assets/option/zh/common/menu-list-item.md index b90a421215..9d5066ce9e 100644 --- a/docs/assets/option/zh/common/menu-list-item.md +++ b/docs/assets/option/zh/common/menu-list-item.md @@ -1,6 +1,6 @@ {{ target: common-menu-list-item }} -MenuListItem定义如下: +MenuListItem 定义如下: ``` type MenuListItem = @@ -13,5 +13,6 @@ type MenuListItem = selectedIcon?: Icon; stateIcon?: Icon; children?: MenuListItem[]; + disabled?: boolean; }; ``` From 92863199d37b9c2ff0f9cda82c6a611eecb27212 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Mon, 14 Apr 2025 17:57:05 +0800 Subject: [PATCH 23/51] feat: add onBeforeCacheChartImage event --- packages/react-vtable/src/eventsUtils.ts | 4 +++- packages/vtable/examples/pivot-chart/pivotChart.ts | 3 +++ packages/vtable/src/core/TABLE_EVENT_TYPE.ts | 7 ++++++- .../graphic/contributions/chart-render-helper.ts | 1 + packages/vtable/src/ts-types/events.ts | 2 ++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/react-vtable/src/eventsUtils.ts b/packages/react-vtable/src/eventsUtils.ts index 6d49a1424c..75e3c5a58d 100644 --- a/packages/react-vtable/src/eventsUtils.ts +++ b/packages/react-vtable/src/eventsUtils.ts @@ -86,6 +86,7 @@ export interface EventsProps { onEmptyTipClick?: EventCallback; onEmptyTipDblClick?: EventCallback; onButtonClick?: EventCallback; + onBeforeCacheChartImage?: EventCallback; } export const TABLE_EVENTS = { @@ -160,7 +161,8 @@ export const TABLE_EVENTS = { onChangCellValue: EVENT_TYPE.CHANGE_CELL_VALUE, onEmptyTipClick: EVENT_TYPE.EMPTY_TIP_CLICK, onEmptyTipDblClick: EVENT_TYPE.EMPTY_TIP_DBLCLICK, - onButtonClick: EVENT_TYPE.BUTTON_CLICK + onButtonClick: EVENT_TYPE.BUTTON_CLICK, + onBeforeCacheChartImage: EVENT_TYPE.BEFORE_CACHE_CHART_IMAGE }; export const TABLE_EVENTS_KEYS = Object.keys(TABLE_EVENTS); diff --git a/packages/vtable/examples/pivot-chart/pivotChart.ts b/packages/vtable/examples/pivot-chart/pivotChart.ts index f3090bf0c3..1d1d37a040 100644 --- a/packages/vtable/examples/pivot-chart/pivotChart.ts +++ b/packages/vtable/examples/pivot-chart/pivotChart.ts @@ -9477,6 +9477,9 @@ export function createTable() { }; const tableInstance = new VTable.PivotChart(option); + tableInstance.on('before_cache_chart_image', args => { + console.log('before_cache_chart_image', args); + }); tableInstance.onVChartEvent('click', args => { console.log('onVChartEvent click', args); }); diff --git a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts index 66a2929d1d..4edad1c160 100644 --- a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts +++ b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts @@ -192,6 +192,10 @@ export interface TableEvents { * 按钮点击事件 */ BUTTON_CLICK: 'button_click'; + /** + * 缓存图表事件 + */ + BEFORE_CACHE_CHART_IMAGE: 'before_cache_chart_image'; } /** * Table event types @@ -265,5 +269,6 @@ export const TABLE_EVENT_TYPE: TableEvents = { EMPTY_TIP_CLICK: 'empty_tip_click', EMPTY_TIP_DBLCLICK: 'empty_tip_dblclick', - BUTTON_CLICK: 'button_click' + BUTTON_CLICK: 'button_click', + BEFORE_CACHE_CHART_IMAGE: 'before_cache_chart_image' } as TableEvents; diff --git a/packages/vtable/src/scenegraph/graphic/contributions/chart-render-helper.ts b/packages/vtable/src/scenegraph/graphic/contributions/chart-render-helper.ts index 44fae47464..4831633f7b 100644 --- a/packages/vtable/src/scenegraph/graphic/contributions/chart-render-helper.ts +++ b/packages/vtable/src/scenegraph/graphic/contributions/chart-render-helper.ts @@ -158,6 +158,7 @@ export function renderChart(chart: Chart) { } } + table.fireListeners('before_cache_chart_image', { chartInstance }); const sg = chartInstance.getStage(); cacheStageCanvas(sg, chart); // chart.cacheCanvas = sg.toCanvas(); diff --git a/packages/vtable/src/ts-types/events.ts b/packages/vtable/src/ts-types/events.ts index acab71eb7f..3155873717 100644 --- a/packages/vtable/src/ts-types/events.ts +++ b/packages/vtable/src/ts-types/events.ts @@ -249,6 +249,7 @@ export interface TableEventHandlersEventArgumentMap { row: number; event: Event; }; + before_cache_chart_image: { chartInstance: any }; } export interface DrillMenuEventInfo { dimensionKey: string | number; @@ -341,4 +342,5 @@ export interface TableEventHandlersReturnMap { empty_tip_dblclick: void; button_click: void; + before_cache_chart_image: void; } From 1b626321ab4abb3bc19152cc6b7f288718a67e80 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Mon, 14 Apr 2025 17:57:25 +0800 Subject: [PATCH 24/51] docs: update changlog of rush --- ...feat-onBeforeCacheChartImage_2025-04-14-09-57.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json diff --git a/common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json b/common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json new file mode 100644 index 0000000000..8dfb67199d --- /dev/null +++ b/common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "feat: add onBeforeCacheChartImage event\n\n", + "type": "none", + "packageName": "@visactor/vtable" + } + ], + "packageName": "@visactor/vtable", + "email": "892739385@qq.com" +} \ No newline at end of file From e30b002572210e0864bcd41d9fbc93434e69fb5b Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Mon, 14 Apr 2025 20:08:20 +0800 Subject: [PATCH 25/51] docs: add plugin usage and contribute guide --- docs/assets/guide/menu.json | 21 ++++ docs/assets/guide/zh/plugin/contribute.md | 96 +++++++++++++++ .../zh/plugin/excel-keyboard-alignment.md | 89 ++++++++++++-- .../assets/guide/zh/plugin/focus-highlight.md | 115 ++++++++++++++---- .../guide/zh/plugin/row-column-series.md | 42 +++++++ .../zh/plugin/table-carousel-animation.md | 52 ++++++++ docs/assets/guide/zh/plugin/usage.md | 42 +++++++ .../demo/column-series/column-series.ts | 12 +- .../demo/focus-highlight/focus-highlight.ts | 39 +++--- packages/vtable-plugins/src/add-row-column.ts | 2 - packages/vtable-plugins/src/column-series.ts | 2 - .../src/excel-edit-cell-keyboard.ts | 2 - .../vtable-plugins/src/focus-highlight.ts | 88 ++++++++++---- .../src/highlight-header-when-select-cell.ts | 2 - packages/vtable-plugins/src/row-series.ts | 2 - .../src/table-carousel-animation.ts | 7 +- packages/vtable/src/plugins/interface.ts | 14 +-- packages/vtable/src/tools/cell-range.ts | 8 +- 18 files changed, 518 insertions(+), 117 deletions(-) create mode 100644 docs/assets/guide/zh/plugin/table-carousel-animation.md diff --git a/docs/assets/guide/menu.json b/docs/assets/guide/menu.json index 5792b9f885..9d69adf87c 100644 --- a/docs/assets/guide/menu.json +++ b/docs/assets/guide/menu.json @@ -739,6 +739,20 @@ "en": "plugin" }, "children": [ + { + "path": "usage", + "title": { + "zh": "插件使用", + "en": "plugin usage" + } + }, + { + "path": "contribute", + "title": { + "zh": "插件贡献", + "en": "plugin contribute" + } + }, { "path": "row-column-series", "title": { @@ -773,6 +787,13 @@ "zh": "行列新增插件", "en": "add row column plugin" } + }, + { + "path": "table-carousel-animation", + "title": { + "zh": "表格轮播动画", + "en": "table carousel animation" + } } ] }, diff --git a/docs/assets/guide/zh/plugin/contribute.md b/docs/assets/guide/zh/plugin/contribute.md index e69de29bb2..8ff72ff740 100644 --- a/docs/assets/guide/zh/plugin/contribute.md +++ b/docs/assets/guide/zh/plugin/contribute.md @@ -0,0 +1,96 @@ +# 贡献插件 + +每个业务使用 VTable 时,可能需要一些定制化的功能,此时可以通过插件来实现。把通用功能抽离成插件,可以避免重复造轮子,同时也可以方便其他业务使用。 + +共享插件,可以提高开发效率,减少维护成本!期望大家积极贡献插件,共同完善 VTable 生态! + +## 贡献插件注意事项 + +1. 插件需要遵循 VTable 的插件规范。 +2. 插件需要有详细的文档说明,包括插件的参数说明、使用示例等。 + +### 插件规范 +#### 接口规范 + +插件需要实现 `VTable.plugins.IVTablePlugin` 接口。 + +```ts +// 插件统一接口 +export interface IVTablePlugin { + // 插件唯一标识 + id: string; + // 插件运行时机 + runTime: TableEvents[keyof TableEvents] | TableEvents[keyof TableEvents][]; + // 初始化方法,在VTable实例创建后、首次渲染前调用 + run: (...args: any[]) => void; + // 更新方法,当表格数据或配置更新时调用 + update?: (table: BaseTableAPI, options?: any) => void; + // 销毁方法,在VTable实例销毁前调用 + release?: (table: BaseTableAPI) => void; +} +``` + +其中`runTime`指定了插件的运行时机,配置是`TableEvents`中的事件类型。 + +#### 组件的生命周期过程: + +
+ +
+ +附Mermaid 序列图代码(后续如果有变动可以根据如下代码做调整更新,并更新上面的图片): +```mermaid +sequenceDiagram + participant User + participant DOM + participant ListTable + participant EventManager + participant PluginManager + participant Plugin as IVTablePlugin + participant RenderManager + + %% Initialization + ListTable->>PluginManager: register plugins + PluginManager->>Plugin: store plugin instances + + %% User interaction flow + User->>DOM: interact (click, scroll, etc.) + DOM->>EventManager: dispatch browser event + EventManager->>PluginManager: notify(eventType, args) + PluginManager->>PluginManager: filter plugins by runTime + + loop For each matching plugin + PluginManager->>Plugin: run(eventArgs, runTime, tableAPI) + Plugin->>ListTable: read/modify table state + Plugin->>Plugin: process event logic + end + + Plugin->>RenderManager: requestRender() + RenderManager->>ListTable: render updates + ListTable->>DOM: update display + + %% Release + ListTable->>PluginManager: release + PluginManager->>Plugin: release() +``` + +通过上图可以了解到插件的运行时机: +- `runTime`在插件中的关键作用是指定了依赖VTable的哪些事件。 +- 在插件的`run`方法中,可以获取到表格的实例,以及表格的配置和数据;同时需要在`run`方法中,处理插件具体的业务逻辑。 +- 请记得在插件的`release`方法中,释放插件占用的资源,避免内存泄漏。 + +### 插件文档说明 + +插件需要提供详细的文档说明,包括插件的参数说明、使用示例等。 + +文档一般需要包含以下内容: +- 插件的名称 +- 插件的描述 +- 插件的参数说明 +- 插件的使用示例 +- 插件的注意事项 +- 插件的源码地址 + +文档需要放在 `docs/assets/plugins` 目录下,文件名称为 `plugin-name.md`。 + + diff --git a/docs/assets/guide/zh/plugin/excel-keyboard-alignment.md b/docs/assets/guide/zh/plugin/excel-keyboard-alignment.md index 35565655fd..352f7677aa 100644 --- a/docs/assets/guide/zh/plugin/excel-keyboard-alignment.md +++ b/docs/assets/guide/zh/plugin/excel-keyboard-alignment.md @@ -31,18 +31,87 @@ 结合VTable已有的部分符合需求的能力,我们开发了`ExcelEditCellKeyboardPlugin`插件,能够实现编辑单元格键盘行为对齐Excel的功能。 -## 插件使用说明 - -```ts - - const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin(); - - const option: VTable.ListTableConstructorOptions = { - records, - columns, - theme: VTable.themes.DARK, +## 插件使用示例 + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + const excelEditCellKeyboardPlugin = new VTablePlugins.ExcelEditCellKeyboardPlugin(); + + const option = { + records: generatePersons(20), + columns:[ + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + editor: new VTable_editors.InputEditor(), + editCellTrigger: ['keydown'], plugins: [excelEditCellKeyboardPlugin] }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; + + ``` ## 插件后续完善 diff --git a/docs/assets/guide/zh/plugin/focus-highlight.md b/docs/assets/guide/zh/plugin/focus-highlight.md index 05f9d2e194..8bcf498907 100644 --- a/docs/assets/guide/zh/plugin/focus-highlight.md +++ b/docs/assets/guide/zh/plugin/focus-highlight.md @@ -11,47 +11,110 @@ VTable 提供聚焦高亮插件,支持聚焦高亮指定区域。 - `FocusHighlightPlugin` 聚焦高亮插件,可以配置以下参数: - `fill` 聚焦高亮背景色 - `opacity` 反选高亮透明度 + - `highlightRange` 初始化聚焦高亮范围 ``` export interface FocusHighlightPluginOptions { fill?: string; opacity?: number; + highlightRange?: CellRange; } ``` ## 使用示例: -```js - const highlightPlugin = new FocusHighlightPlugin({ + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const highlightPlugin = new VTablePlugins.FocusHighlightPlugin({ fill: '#000', - opacity: 0.5 + opacity: 0.5, + highlightRange: { + start: { + col: 4, + row: 4 + }, + end: { + col: 4, + row: 4 + } + } }); - - const option: VTable.ListTableConstructorOptions = { - records, - columns, + const option = { + records: generatePersons(20), + columns:[ + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], theme: VTable.themes.DARK, plugins: [highlightPlugin] }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; + + ``` 具体使用参考[demo](../../demo/interaction/head-highlight) - -## 反选高亮插件 API - -### setInvertHighlightRange - -设置反选高亮范围。 - -```ts -setInvertHighlightRange(range: { - start: { - col: number; - row: number; - }; - end: { - col: number; - row: number; - }; -}): void; -``` \ No newline at end of file diff --git a/docs/assets/guide/zh/plugin/row-column-series.md b/docs/assets/guide/zh/plugin/row-column-series.md index c8e031d35a..054e3da1af 100644 --- a/docs/assets/guide/zh/plugin/row-column-series.md +++ b/docs/assets/guide/zh/plugin/row-column-series.md @@ -86,3 +86,45 @@ const rowSeries = new RowSeriesPlugin({ fillRowRecord: (index) => (['姓名', '年龄', '地址']) }); ``` + +## 具体示例 + +```javascript livedemo template=vtable + +let tableInstance; +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +// 创建 ColumnSeries 插件实例 +const columnSeries = new VTablePlugins.ColumnSeriesPlugin({ + columnCount: 100, + // 自定义列标题生成 + // generateColumnTitle(index) + // { + // return `自定义标题 ${index}` + // }, + // 自定义字段名生成 + generateColumnField: (index) => `field_${index}` +}); + +// 创建 RowSeries 插件实例 +const rowSeries = new VTablePlugins.RowSeriesPlugin({ + rowCount: 100, + // 自定义行数据生成 + fillRowRecord: (index) => ([]) +}); + +// 在 VTable 选项中使用插件 +const option = { + records: [], + plugins: [columnSeries, rowSeries], + // 其他 VTable 配置... +}; + +// 创建表格实例 +tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); +window.tableInstance = tableInstance; +``` diff --git a/docs/assets/guide/zh/plugin/table-carousel-animation.md b/docs/assets/guide/zh/plugin/table-carousel-animation.md new file mode 100644 index 0000000000..f2f28a58b9 --- /dev/null +++ b/docs/assets/guide/zh/plugin/table-carousel-animation.md @@ -0,0 +1,52 @@ +# 表格轮播动画插件 + +VTable 提供表格轮播动画插件,支持表格的行或列的轮播动画。 + +效果如下: +
+ +
+ +## 使用示例 + +```ts +const tableCarouselAnimationPlugin = new TableCarouselAnimationPlugin({ + rowCount: 10, + colCount: 10, + animationDuration: 1000, + animationDelay: 0, + animationEasing: 'linear', + autoPlay: true, + autoPlayDelay: 1000, +}); + +const option: VTable.ListTableConstructorOptions = { + records, + columns, + plugins: [tableCarouselAnimationPlugin], +}; + +``` +如果并不期望表格初始化后马上进行播放的话,可以配置`autoPlay`为`false`,然后手动调用`play`方法进行播放。 + +```ts +tableCarouselAnimationPlugin.play(); +``` + + + +## 参数说明 + +插件提供个性化配置,可以配置以下参数: + +| 参数 | 类型 | 说明 | +| --- | --- | --- | +| rowCount | number | 每次动画滚动行数 | +| colCount | number | 每次动画滚动列数 | +| animationDuration | number | 动画时长 | +| animationDelay | number | 动画延迟 | +| animationEasing | string | 动画缓动函数 | +| autoPlay | boolean | 是否自动播放 | +| autoPlayDelay | number | 自动播放延迟 | +| customDistRowFunction | (row: number, table: BaseTableAPI) => { distRow: number; animation?: boolean } | 自定义动画距离 | +| customDistColFunction | (col: number, table: BaseTableAPI) => { distCol: number; animation?: boolean } | 自定义动画距离 | diff --git a/docs/assets/guide/zh/plugin/usage.md b/docs/assets/guide/zh/plugin/usage.md index e69de29bb2..494a15edee 100644 --- a/docs/assets/guide/zh/plugin/usage.md +++ b/docs/assets/guide/zh/plugin/usage.md @@ -0,0 +1,42 @@ +# 插件使用 + +获取插件包 + +```bash +npm install @visactor/vtable-plugins +``` +引入插件 + +```ts +import { TableCarouselAnimationPlugin } from '@visactor/vtable-plugins'; +``` + +使用插件 + +```ts +const tableCarouselAnimationPlugin = new TableCarouselAnimationPlugin({ + ... +}); +``` + +在插件列表中添加插件 + +```ts +const option: VTable.ListTableConstructorOptions = { + ... + plugins: [tableCarouselAnimationPlugin] +}; +``` + +插件组合使用 + +```ts +const option: VTable.ListTableConstructorOptions = { + ... + plugins: [tableCarouselAnimationPlugin, ...] +}; +``` + +插件使用顺序一般情况没有特殊要求,请详细阅读每个插件的文档,了解插件的执行时机,如果必要可阅读插件的源码。 + +如果你发现使用插件上存在问题,请及时反馈。 \ No newline at end of file diff --git a/packages/vtable-plugins/demo/column-series/column-series.ts b/packages/vtable-plugins/demo/column-series/column-series.ts index 07a796bbac..df518c6ec3 100644 --- a/packages/vtable-plugins/demo/column-series/column-series.ts +++ b/packages/vtable-plugins/demo/column-series/column-series.ts @@ -35,12 +35,12 @@ export function createTable() { const option: VTable.ListTableConstructorOptions = { container: document.getElementById(CONTAINER_ID), records, - plugins: [columnSeries, rowSeries], - theme: { - selectionStyle: { - cellBorderLineWidth: 4 - } - } + plugins: [columnSeries, rowSeries] + // theme: { + // selectionStyle: { + // cellBorderLineWidth: 4 + // } + // } }; const tableInstance = new VTable.ListTable(option); window.tableInstance = tableInstance; diff --git a/packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts b/packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts index 2efc8ff474..9188f66c0d 100644 --- a/packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts +++ b/packages/vtable-plugins/demo/focus-highlight/focus-highlight.ts @@ -19,7 +19,18 @@ const generatePersons = count => { }; export function createTable() { - const highlightPlugin = new FocusHighlightPlugin(); + const highlightPlugin = new FocusHighlightPlugin({ + highlightRange: { + start: { + col: 0, + row: 5 + }, + end: { + col: 6, + row: 6 + } + } + }); const records = generatePersons(20); const columns: VTable.ColumnsDefine = [ { @@ -78,6 +89,9 @@ export function createTable() { records, columns, theme: VTable.themes.DARK, + select: { + headerSelectMode: 'cell' + }, // heightMode: 'adaptive', // select: { // disableSelect: true @@ -90,27 +104,4 @@ export function createTable() { bindDebugTool(tableInstance.scenegraph.stage, { customGrapicKeys: ['col', 'row'] }); - - // highlightPlugin.setInvertHighlightRange({ - // start: { - // col: 0, - // row: 6 - // }, - // end: { - // col: 6, - // row: 6 - // } - // }); - - // const ca = new CarouselAnimationPlugin(tableInstance, { - // rowCount: 2, - // replaceScrollAction: true - // }); - - // ca.play(); - - // setInterval(() => { - // row += 2; - // tableInstance.scrollToRow(row, { duration: 500 }); - // }, 2000); } diff --git a/packages/vtable-plugins/src/add-row-column.ts b/packages/vtable-plugins/src/add-row-column.ts index 06128035fa..5fc230e59b 100644 --- a/packages/vtable-plugins/src/add-row-column.ts +++ b/packages/vtable-plugins/src/add-row-column.ts @@ -28,8 +28,6 @@ export interface AddRowColumnOptions { */ export class AddRowColumnPlugin implements VTable.plugins.IVTablePlugin { id = 'add-row-column'; - name = 'Add-Row-Column'; - type: 'layout' = 'layout'; runTime = [ VTable.TABLE_EVENT_TYPE.MOUSEENTER_CELL, VTable.TABLE_EVENT_TYPE.MOUSELEAVE_CELL, diff --git a/packages/vtable-plugins/src/column-series.ts b/packages/vtable-plugins/src/column-series.ts index 4722f0d38a..08686f6f08 100644 --- a/packages/vtable-plugins/src/column-series.ts +++ b/packages/vtable-plugins/src/column-series.ts @@ -12,8 +12,6 @@ export interface ColumnSeriesOptions { */ export class ColumnSeriesPlugin implements VTable.plugins.IVTablePlugin { id = 'column-series'; - name = 'Column-Series'; - type: 'layout' = 'layout'; runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT]; pluginOptions: ColumnSeriesOptions; table: VTable.ListTable; diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts index 3f30714836..122ec1eba3 100644 --- a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -11,8 +11,6 @@ export type IExcelEditCellKeyboardPluginOptions = { export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin { id = 'excel-edit-cell-keyboard'; - name = 'Excel Edit Cell Keyboard'; - type: 'layout' = 'layout'; runTime = [VTable.TABLE_EVENT_TYPE.INITIALIZED]; table: VTable.ListTable; pluginOptions: IExcelEditCellKeyboardPluginOptions; diff --git a/packages/vtable-plugins/src/focus-highlight.ts b/packages/vtable-plugins/src/focus-highlight.ts index baecf44f5e..126384354b 100644 --- a/packages/vtable-plugins/src/focus-highlight.ts +++ b/packages/vtable-plugins/src/focus-highlight.ts @@ -2,20 +2,21 @@ import type { INode } from '@visactor/vtable/es/vrender'; import { createRect } from '@visactor/vtable/es/vrender'; import type { Group } from '@visactor/vtable/es/scenegraph/graphic/group'; import { isSameRange } from '@visactor/vtable/es/tools/cell-range'; -import type { CellRange } from '@visactor/vtable/es/ts-types'; +import type { CellAddress, CellRange } from '@visactor/vtable/es/ts-types'; import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; import { cellInRange } from '@visactor/vtable/es/tools/helper'; import { TABLE_EVENT_TYPE } from '@visactor/vtable'; +import type * as VTable from '@visactor/vtable'; export interface FocusHighlightPluginOptions { fill?: string; opacity?: number; + highlightRange?: CellAddress | CellRange; //初始化聚焦高亮范围 } -export class FocusHighlightPlugin { +export class FocusHighlightPlugin implements VTable.plugins.IVTablePlugin { id = 'focus-highlight'; name = 'Focus Highlight'; - type: 'layout' = 'layout'; - runTime = [TABLE_EVENT_TYPE.CLICK_CELL]; + runTime = [TABLE_EVENT_TYPE.INITIALIZED, TABLE_EVENT_TYPE.SELECTED_CELL]; table: BaseTableAPI; range?: CellRange; pluginOptions: FocusHighlightPluginOptions; @@ -23,38 +24,68 @@ export class FocusHighlightPlugin { constructor( options: FocusHighlightPluginOptions = { fill: '#000', - opacity: 0.5 + opacity: 0.5, + highlightRange: undefined } ) { - this.pluginOptions = options; + this.pluginOptions = Object.assign( + { + fill: '#000', + opacity: 0.5 + }, + options + ); } run(...args: any[]) { if (!this.table) { this.table = args[2] as BaseTableAPI; } - const { col, row } = args[0]; - if (this.table.isHeader(col, row)) { - this.setFocusHighlightRange(undefined); - } else { + if (args[1] === TABLE_EVENT_TYPE.INITIALIZED) { + this.pluginOptions.highlightRange && this.setFocusHighlightRange(this.pluginOptions.highlightRange); + } else if (args[1] === TABLE_EVENT_TYPE.CLICK_CELL) { + const { col, row } = args[0]; + if (this.table.isHeader(col, row)) { + this.setFocusHighlightRange(undefined); + } else { + this.setFocusHighlightRange({ + start: { + col: 0, + row + }, + end: { + col: this.table.colCount - 1, + row + } + }); + } + } else if (args[1] === TABLE_EVENT_TYPE.SELECTED_CELL) { + const ranges = this.table.stateManager.select.ranges; + const min_col = 0; + const max_col = this.table.colCount - 1; + const min_row = Math.min(ranges[0].start.row, ranges[0].end.row); + const max_row = Math.max(ranges[0].start.row, ranges[0].end.row); this.setFocusHighlightRange({ - start: { - col: 0, - row - }, - end: { - col: this.table.colCount - 1, - row - } + start: { col: min_col, row: min_row }, + end: { col: max_col, row: max_row } }); } } - setFocusHighlightRange(range?: CellRange) { - if (isSameRange(this.range, range)) { + setFocusHighlightRange(range?: CellAddress | CellRange) { + let cellRange: CellRange; + if (range && 'start' in range && 'end' in range) { + cellRange = range as CellRange; + } else { + cellRange = { + start: range as CellAddress, + end: range as CellAddress + }; + } + if (isSameRange(this.range, cellRange)) { return; } - this.range = range; + this.range = cellRange; if (!range) { // reset highlight this.deleteAllCellGroupShadow(); @@ -87,7 +118,16 @@ export class FocusHighlightPlugin { this.updateCellGroupShadowInContainer(this.table.scenegraph.bottomFrozenGroup), this.range; this.updateCellGroupShadowInContainer(this.table.scenegraph.rightBottomCornerGroup, this.range); } - updateCellGroupShadowInContainer(container: Group, range?: CellRange) { + updateCellGroupShadowInContainer(container: Group, range?: CellAddress | CellRange) { + let cellRange: CellRange; + if (range && 'start' in range && 'end' in range) { + cellRange = range; + } else { + cellRange = { + start: range as CellAddress, + end: range as CellAddress + }; + } container.forEachChildrenSkipChild((item: INode) => { const column = item as unknown as Group; if (column.role === 'column') { @@ -98,10 +138,10 @@ export class FocusHighlightPlugin { } cell.attachShadow(cell.shadowRoot); const shadowGroup = cell.shadowRoot; - if (!range) { + if (!cellRange) { // no highlight shadowGroup.removeAllChild(); - } else if (cellInRange(range, cell.col, cell.row)) { + } else if (cellInRange(cellRange, cell.col, cell.row)) { // inside highlight shadowGroup.removeAllChild(); } else if (!shadowGroup.firstChild) { diff --git a/packages/vtable-plugins/src/highlight-header-when-select-cell.ts b/packages/vtable-plugins/src/highlight-header-when-select-cell.ts index 25c8d09fbc..992c2171e5 100644 --- a/packages/vtable-plugins/src/highlight-header-when-select-cell.ts +++ b/packages/vtable-plugins/src/highlight-header-when-select-cell.ts @@ -12,8 +12,6 @@ interface IHighlightHeaderWhenSelectCellPluginOptions { export class HighlightHeaderWhenSelectCellPlugin implements plugins.IVTablePlugin { id = 'highlight-header-when-select-cell'; - name = 'Highlight Header When Select Cell'; - type: 'layout' = 'layout'; runTime = [ TABLE_EVENT_TYPE.INITIALIZED, TABLE_EVENT_TYPE.SELECTED_CLEAR, diff --git a/packages/vtable-plugins/src/row-series.ts b/packages/vtable-plugins/src/row-series.ts index e868004f74..ec1cc18eef 100644 --- a/packages/vtable-plugins/src/row-series.ts +++ b/packages/vtable-plugins/src/row-series.ts @@ -12,8 +12,6 @@ export interface RowSeriesOptions { */ export class RowSeriesPlugin implements VTable.plugins.IVTablePlugin { id = 'row-series'; - name = 'Row-Series'; - type: 'layout' = 'layout'; runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT]; pluginOptions: RowSeriesOptions; table: VTable.ListTable; diff --git a/packages/vtable-plugins/src/table-carousel-animation.ts b/packages/vtable-plugins/src/table-carousel-animation.ts index 19e795ace5..8777b5c73c 100644 --- a/packages/vtable-plugins/src/table-carousel-animation.ts +++ b/packages/vtable-plugins/src/table-carousel-animation.ts @@ -1,7 +1,7 @@ import type { EasingType } from '@visactor/vtable/es/vrender'; import type { BaseTableAPI } from '@visactor/vtable/es/ts-types/base-table'; import { TABLE_EVENT_TYPE } from '@visactor/vtable'; - +import type * as VTable from '@visactor/vtable'; function isInteger(value: number) { return Math.floor(value) === value; } @@ -12,7 +12,6 @@ export interface ITableCarouselAnimationPluginOptions { animationDuration?: number; animationDelay?: number; animationEasing?: EasingType; - replaceScrollAction?: boolean; autoPlay?: boolean; autoPlayDelay?: number; @@ -20,10 +19,8 @@ export interface ITableCarouselAnimationPluginOptions { customDistColFunction?: (col: number, table: BaseTableAPI) => { distCol: number; animation?: boolean } | undefined; } -export class TableCarouselAnimationPlugin { +export class TableCarouselAnimationPlugin implements VTable.plugins.IVTablePlugin { id = 'table-carousel-animation'; - name = 'Table Carousel Animation'; - type: 'layout' = 'layout'; runTime = [TABLE_EVENT_TYPE.INITIALIZED]; table: BaseTableAPI; diff --git a/packages/vtable/src/plugins/interface.ts b/packages/vtable/src/plugins/interface.ts index 66734c52fd..5792b723be 100644 --- a/packages/vtable/src/plugins/interface.ts +++ b/packages/vtable/src/plugins/interface.ts @@ -5,17 +5,15 @@ import type { BaseTableAPI } from '../ts-types/base-table'; export interface IVTablePlugin { // 插件唯一标识 id: string; - // 插件名称 - name: string; - // 插件优先级,数字越小优先级越高 - priority?: number; + // // 插件优先级,数字越小优先级越高 TODO:目前还没起作用,后续是否有安排插件优先级的需求 + // priority?: number; - // 插件类型,用于区分不同功能的插件 - type: 'layout' | 'interaction' | 'style' | 'animation'; + // // 插件类型,用于区分不同功能的插件 + // type: 'layout' | 'interaction' | 'style' | 'animation'; // 插件运行时机 runTime: TableEvents[keyof TableEvents] | TableEvents[keyof TableEvents][]; - // 插件依赖 - dependencies?: string[]; + // // 插件依赖 + // dependencies?: string[]; // 初始化方法,在VTable实例创建后、首次渲染前调用 run: (...args: any[]) => void; // 更新方法,当表格数据或配置更新时调用 diff --git a/packages/vtable/src/tools/cell-range.ts b/packages/vtable/src/tools/cell-range.ts index 87e137b898..010b32b351 100644 --- a/packages/vtable/src/tools/cell-range.ts +++ b/packages/vtable/src/tools/cell-range.ts @@ -10,9 +10,9 @@ export function isSameRange(range1: CellRange | undefined | null, range2: CellRa } return ( - range1.start.col === range2.start.col && - range1.start.row === range2.start.row && - range1.end.col === range2.end.col && - range1.end.row === range2.end.row + range1.start?.col === range2.start?.col && + range1.start?.row === range2.start?.row && + range1.end?.col === range2.end?.col && + range1.end?.row === range2.end?.row ); } From 49976e15696e6e113e133fdc1d52ae6ed823d963 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 15 Apr 2025 12:14:42 +0800 Subject: [PATCH 26/51] docs: add plugin demos --- .../assets/guide/zh/plugin/focus-highlight.md | 2 - .../guide/zh/plugin/header-highlight.md | 74 +++++++++++++++-- docs/assets/guide/zh/plugin/row-column-add.md | 72 +++++++++++++++- .../zh/plugin/table-carousel-animation.md | 82 ++++++++++++++++++- .../demo/combine-plugins/combine-plugins.ts | 4 +- .../demo/highlight-header/highlight-header.ts | 4 +- .../vtable-plugins/src/focus-highlight.ts | 39 ++++----- 7 files changed, 237 insertions(+), 40 deletions(-) diff --git a/docs/assets/guide/zh/plugin/focus-highlight.md b/docs/assets/guide/zh/plugin/focus-highlight.md index 8bcf498907..f67a743076 100644 --- a/docs/assets/guide/zh/plugin/focus-highlight.md +++ b/docs/assets/guide/zh/plugin/focus-highlight.md @@ -113,8 +113,6 @@ const generatePersons = count => { }; const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); window.tableInstance = tableInstance; - - ``` 具体使用参考[demo](../../demo/interaction/head-highlight) diff --git a/docs/assets/guide/zh/plugin/header-highlight.md b/docs/assets/guide/zh/plugin/header-highlight.md index d980018260..113dafff89 100644 --- a/docs/assets/guide/zh/plugin/header-highlight.md +++ b/docs/assets/guide/zh/plugin/header-highlight.md @@ -29,20 +29,78 @@ interface IHighlightHeaderWhenSelectCellPluginOptions { ``` ## 使用示例: -```js - const highlightPlugin = new HighlightHeaderWhenSelectCellPlugin({ + + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const highlightPlugin = new VTablePlugins.HighlightHeaderWhenSelectCellPlugin({ colHighlight: true, rowHighlight: true }); - const option: VTable.ListTableConstructorOptions = { - records, - columns, - select: { - outsideClickDeselect: true, - headerSelectMode: 'body' + const option = { + records: generatePersons(20), + rowSeriesNumber: {}, + columns:[ + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } }, + + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + }, + + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + plugins: [highlightPlugin] }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; ``` 具体使用参考[demo](../../demo/interaction/head-highlight) diff --git a/docs/assets/guide/zh/plugin/row-column-add.md b/docs/assets/guide/zh/plugin/row-column-add.md index 4c074afefa..a14b333c0e 100644 --- a/docs/assets/guide/zh/plugin/row-column-add.md +++ b/docs/assets/guide/zh/plugin/row-column-add.md @@ -66,4 +66,74 @@ const option = { tableInstance.addRecord([], row - tableInstance.columnHeaderLevelCount); } }); -``` \ No newline at end of file +``` + +可运行示例: + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + const addRowColumn = new VTablePlugins.AddRowColumnPlugin(); +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const option = { + records: generatePersons(20), + rowSeriesNumber: {}, + columns:[ + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + }, + + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + + plugins: [addRowColumn] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; +``` diff --git a/docs/assets/guide/zh/plugin/table-carousel-animation.md b/docs/assets/guide/zh/plugin/table-carousel-animation.md index f2f28a58b9..a2aacb6b25 100644 --- a/docs/assets/guide/zh/plugin/table-carousel-animation.md +++ b/docs/assets/guide/zh/plugin/table-carousel-animation.md @@ -35,7 +35,7 @@ tableCarouselAnimationPlugin.play(); -## 参数说明 +## 插件参数说明 插件提供个性化配置,可以配置以下参数: @@ -50,3 +50,83 @@ tableCarouselAnimationPlugin.play(); | autoPlayDelay | number | 自动播放延迟 | | customDistRowFunction | (row: number, table: BaseTableAPI) => { distRow: number; animation?: boolean } | 自定义动画距离 | | customDistColFunction | (col: number, table: BaseTableAPI) => { distCol: number; animation?: boolean } | 自定义动画距离 | + +## 运行示例 + + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const animationPlugin = new VTablePlugins.TableCarouselAnimationPlugin({ + rowCount: 2, + // colCount: 2, + autoPlay: true, + autoPlayDelay: 1000 + }); + const option = { + records: generatePersons(30), + rowSeriesNumber: { + title: 'No.' + }, + columns:[ + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + }, + + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + + plugins: [animationPlugin] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; +``` + diff --git a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts index 99755f0cc9..00a0ef4e94 100644 --- a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts +++ b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts @@ -4,7 +4,7 @@ import { AddRowColumnPlugin, ColumnSeriesPlugin, ExcelEditCellKeyboardPlugin, - HighlightHeaderPlugin, + HighlightHeaderWhenSelectCellPlugin, RowSeriesPlugin } from '../../src'; import { InputEditor } from '@visactor/vtable-editors'; @@ -42,7 +42,7 @@ export function createTable() { width: 'auto' } }); - const highlightPlugin = new HighlightHeaderPlugin({ + const highlightPlugin = new HighlightHeaderWhenSelectCellPlugin({ colHighlight: true, rowHighlight: true }); diff --git a/packages/vtable-plugins/demo/highlight-header/highlight-header.ts b/packages/vtable-plugins/demo/highlight-header/highlight-header.ts index 75a1f62415..50a3fb5f71 100644 --- a/packages/vtable-plugins/demo/highlight-header/highlight-header.ts +++ b/packages/vtable-plugins/demo/highlight-header/highlight-header.ts @@ -2,7 +2,7 @@ import * as VTable from '@visactor/vtable'; import { bindDebugTool } from '@visactor/vtable/es/scenegraph/debug-tool'; import * as VTable_editors from '@visactor/vtable-editors'; -import { HighlightHeaderPlugin } from '../../src'; +import { HighlightHeaderWhenSelectCellPlugin } from '../../src'; const CONTAINER_ID = 'vTable'; const generatePersons = count => { return Array.from(new Array(count)).map((_, i) => ({ @@ -58,7 +58,7 @@ export function createTable() { } ]; - const highlightPlugin = new HighlightHeaderPlugin({ + const highlightPlugin = new HighlightHeaderWhenSelectCellPlugin({ colHighlight: true, rowHighlight: true }); diff --git a/packages/vtable-plugins/src/focus-highlight.ts b/packages/vtable-plugins/src/focus-highlight.ts index 126384354b..98e3b956a3 100644 --- a/packages/vtable-plugins/src/focus-highlight.ts +++ b/packages/vtable-plugins/src/focus-highlight.ts @@ -16,7 +16,7 @@ export interface FocusHighlightPluginOptions { export class FocusHighlightPlugin implements VTable.plugins.IVTablePlugin { id = 'focus-highlight'; name = 'Focus Highlight'; - runTime = [TABLE_EVENT_TYPE.INITIALIZED, TABLE_EVENT_TYPE.SELECTED_CELL]; + runTime = [TABLE_EVENT_TYPE.INITIALIZED, TABLE_EVENT_TYPE.SELECTED_CELL, TABLE_EVENT_TYPE.SELECTED_CLEAR]; table: BaseTableAPI; range?: CellRange; pluginOptions: FocusHighlightPluginOptions; @@ -42,32 +42,23 @@ export class FocusHighlightPlugin implements VTable.plugins.IVTablePlugin { } if (args[1] === TABLE_EVENT_TYPE.INITIALIZED) { this.pluginOptions.highlightRange && this.setFocusHighlightRange(this.pluginOptions.highlightRange); - } else if (args[1] === TABLE_EVENT_TYPE.CLICK_CELL) { - const { col, row } = args[0]; - if (this.table.isHeader(col, row)) { + } else if (args[1] === TABLE_EVENT_TYPE.SELECTED_CELL) { + const posCell = this.table.stateManager.select.cellPos; + if (this.table.isHeader(posCell.col, posCell.row)) { this.setFocusHighlightRange(undefined); } else { + const ranges = this.table.stateManager.select.ranges; + const min_col = 0; + const max_col = this.table.colCount - 1; + const min_row = Math.min(ranges[0].start.row, ranges[0].end.row); + const max_row = Math.max(ranges[0].start.row, ranges[0].end.row); this.setFocusHighlightRange({ - start: { - col: 0, - row - }, - end: { - col: this.table.colCount - 1, - row - } + start: { col: min_col, row: min_row }, + end: { col: max_col, row: max_row } }); } - } else if (args[1] === TABLE_EVENT_TYPE.SELECTED_CELL) { - const ranges = this.table.stateManager.select.ranges; - const min_col = 0; - const max_col = this.table.colCount - 1; - const min_row = Math.min(ranges[0].start.row, ranges[0].end.row); - const max_row = Math.max(ranges[0].start.row, ranges[0].end.row); - this.setFocusHighlightRange({ - start: { col: min_col, row: min_row }, - end: { col: max_col, row: max_row } - }); + } else if (args[1] === TABLE_EVENT_TYPE.SELECTED_CLEAR) { + this.setFocusHighlightRange(undefined); } } @@ -75,7 +66,7 @@ export class FocusHighlightPlugin implements VTable.plugins.IVTablePlugin { let cellRange: CellRange; if (range && 'start' in range && 'end' in range) { cellRange = range as CellRange; - } else { + } else if (range) { cellRange = { start: range as CellAddress, end: range as CellAddress @@ -122,7 +113,7 @@ export class FocusHighlightPlugin implements VTable.plugins.IVTablePlugin { let cellRange: CellRange; if (range && 'start' in range && 'end' in range) { cellRange = range; - } else { + } else if (range) { cellRange = { start: range as CellAddress, end: range as CellAddress From 6ea5f55ca76d0339ff23160b31ea688958c291bb Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 15 Apr 2025 14:35:01 +0800 Subject: [PATCH 27/51] docs: add plugin tutorial english --- .../demo/en/animation/carousel-animation.md | 35 +++-- .../demo/en/interaction/head-highlight.md | 9 +- .../demo/en/interaction/invert-highlight.md | 19 +-- .../demo/zh/animation/carousel-animation.md | 17 +-- .../demo/zh/interaction/head-highlight.md | 9 +- .../demo/zh/interaction/invert-highlight.md | 19 +-- .../guide/en/animation/carousel_animation.md | 51 +------ docs/assets/guide/en/plugin/contribute.md | 96 ++++++++++++ .../en/plugin/excel-keyboard-alignment.md | 135 +++++++++++++++++ .../assets/guide/en/plugin/focus-highlight.md | 118 +++++++++++++++ .../guide/en/plugin/header-highlight.md | 109 ++++++++++++-- .../guide/en/plugin/invert-highlight.md | 50 ------- docs/assets/guide/en/plugin/row-column-add.md | 139 ++++++++++++++++++ .../guide/en/plugin/row-column-series.md | 130 ++++++++++++++++ .../en/plugin/table-carousel-animation.md | 132 +++++++++++++++++ docs/assets/guide/en/plugin/usage.md | 42 ++++++ .../guide/zh/animation/carousel_animation.md | 51 +------ packages/vtable/src/core/TABLE_EVENT_TYPE.ts | 2 - packages/vtable/src/plugins/interface.ts | 2 +- packages/vtable/src/plugins/plugin-manager.ts | 14 +- 20 files changed, 939 insertions(+), 240 deletions(-) create mode 100644 docs/assets/guide/en/plugin/contribute.md create mode 100644 docs/assets/guide/en/plugin/excel-keyboard-alignment.md create mode 100644 docs/assets/guide/en/plugin/focus-highlight.md delete mode 100644 docs/assets/guide/en/plugin/invert-highlight.md create mode 100644 docs/assets/guide/en/plugin/row-column-add.md create mode 100644 docs/assets/guide/en/plugin/row-column-series.md create mode 100644 docs/assets/guide/en/plugin/table-carousel-animation.md create mode 100644 docs/assets/guide/en/plugin/usage.md diff --git a/docs/assets/demo/en/animation/carousel-animation.md b/docs/assets/demo/en/animation/carousel-animation.md index 97cf86297b..06c9bbecb6 100644 --- a/docs/assets/demo/en/animation/carousel-animation.md +++ b/docs/assets/demo/en/animation/carousel-animation.md @@ -1,26 +1,25 @@ --- category: examples group: Animation -title: carousel animation +title: Carousel Animation cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/carousel-animation.gif link: animation/carousel_animation --- # Carousel Animation -Carousel animation in VTable +Table carousel animation display -## Key configuration +## Key Configuration -- `CarouselAnimationPlugin` carousel animation plugin - - `rowCount` scroll row count in a carousel animation - - `colCount` scroll column count in a carousel animation - - `animationDuration` The duration of a single carousel animation, in milliseconds - - `animationDelay` The delay of a single carousel animation, in milliseconds - - `animationEasing` The easing function of a single carousel animation - - `replaceScrollAction` Whether to replace the scroll action, if true, the scroll action will be replaced by the carousel animation +- `TableCarouselAnimationPlugin` Carousel animation plugin + - `rowCount` Number of rows scrolled in one animation + - `colCount` Number of columns scrolled in one animation + - `animationDuration` Duration of a single scroll animation + - `animationDelay` Time interval between animations + - `animationEasing` Animation easing function -## Code demonstration +## Code demo ```javascript livedemo template=vtable // use this for project @@ -31,6 +30,10 @@ let tableInstance; fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/North_American_Superstore_data100.json') .then(res => res.json()) .then(data => { + + const animationPlugin = new VTablePlugins.TableCarouselAnimationPlugin( { + rowCount: 2, + }); const columns = [ { field: 'Category', @@ -92,16 +95,12 @@ fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/North_American const option = { records: data.slice(0, 20), columns, - widthMode: 'standard' + widthMode: 'standard', + plugins: [animationPlugin] }; tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID), option); window['tableInstance'] = tableInstance; - const ca = new VTablePlugins.CarouselAnimationPlugin(tableInstance, { - rowCount: 2, - replaceScrollAction: true - }); - - ca.play(); + }); ``` diff --git a/docs/assets/demo/en/interaction/head-highlight.md b/docs/assets/demo/en/interaction/head-highlight.md index 627d2a8328..22a5a3bbee 100644 --- a/docs/assets/demo/en/interaction/head-highlight.md +++ b/docs/assets/demo/en/interaction/head-highlight.md @@ -12,7 +12,7 @@ Highlight the header when selecting the cell. ## Key Configurations -- `HeaderHighlightPlugin` highlight plugin +- `HighlightHeaderWhenSelectCellPlugin` highlight plugin - `columnHighlight` whether highlight the column - `rowHighlight` whether highlight the row - `colHighlightBGColor` the background color of the column highlight @@ -90,14 +90,15 @@ const columns = [ width: 100 } ]; - +const highlightPlugin = new VTablePlugins.HighlightHeaderWhenSelectCellPlugin(); const option = { records, columns, - rowSeriesNumber: {} + rowSeriesNumber: {}, + plugins: [highlightPlugin] }; const tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID), option); window['tableInstance'] = tableInstance; -const highlightPlugin = new VTablePlugins.HeaderHighlightPlugin(tableInstance, {}); + ``` diff --git a/docs/assets/demo/en/interaction/invert-highlight.md b/docs/assets/demo/en/interaction/invert-highlight.md index b1c1d10ea5..f7ab935d30 100644 --- a/docs/assets/demo/en/interaction/invert-highlight.md +++ b/docs/assets/demo/en/interaction/invert-highlight.md @@ -12,7 +12,7 @@ Show the highlight effect when set highlight range. ## Key Configurations -- `InvertHighlightPlugin` invert highlight plugin +- `FocusHighlightPlugin` invert highlight plugin - `fill` invert highlight background color - `opacity` invert highlight opacity - `setInvertHighlightRange` set highlight range @@ -87,25 +87,16 @@ const columns = [ width: 100 } ]; - +const highlightPlugin = new VTablePlugins.FocusHighlightPlugin(); const option = { records, columns, - theme: VTable.themes.DARK + theme: VTable.themes.DARK, + plugins: [highlightPlugin] }; const tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID), option); window['tableInstance'] = tableInstance; -const highlightPlugin = new VTablePlugins.InvertHighlightPlugin(tableInstance, {}); -highlightPlugin.setInvertHighlightRange({ - start: { - col: 0, - row: 6 - }, - end: { - col: 5, - row: 6 - } -}); + ``` diff --git a/docs/assets/demo/zh/animation/carousel-animation.md b/docs/assets/demo/zh/animation/carousel-animation.md index 5df873ba27..5d10703650 100644 --- a/docs/assets/demo/zh/animation/carousel-animation.md +++ b/docs/assets/demo/zh/animation/carousel-animation.md @@ -12,13 +12,12 @@ link: animation/carousel_animation ## 关键配置 -- `CarouselAnimationPlugin` 轮播动画插件 +- `TableCarouselAnimationPlugin` 轮播动画插件 - `rowCount` 一次动画滚动的行数 - `colCount` 一次动画滚动的列数 - `animationDuration` 一次滚动动画的时间 - `animationDelay` 动画间隔时间 - `animationEasing` 动画缓动函数 - - `replaceScrollAction` 是否替换滚动行为,如果为 true ,每次滚动操作会移动对于的行数/列数 ## 代码演示 @@ -31,6 +30,10 @@ let tableInstance; fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/North_American_Superstore_data100.json') .then(res => res.json()) .then(data => { + + const animationPlugin = new VTablePlugins.TableCarouselAnimationPlugin( { + rowCount: 2, + }); const columns = [ { field: 'Category', @@ -92,16 +95,12 @@ fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/North_American const option = { records: data.slice(0, 20), columns, - widthMode: 'standard' + widthMode: 'standard', + plugins: [animationPlugin] }; tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID), option); window['tableInstance'] = tableInstance; - const ca = new VTablePlugins.CarouselAnimationPlugin(tableInstance, { - rowCount: 2, - replaceScrollAction: true - }); - - ca.play(); + }); ``` diff --git a/docs/assets/demo/zh/interaction/head-highlight.md b/docs/assets/demo/zh/interaction/head-highlight.md index 347b00b9e7..58afa26726 100644 --- a/docs/assets/demo/zh/interaction/head-highlight.md +++ b/docs/assets/demo/zh/interaction/head-highlight.md @@ -12,7 +12,7 @@ link: plugin/header-highlight ## 关键配置 -- `HeaderHighlightPlugin` 高亮表头插件 +- `HighlightHeaderWhenSelectCellPlugin` 高亮表头插件 - `columnHighlight` 是否高亮列头 - `rowHighlight` 是否高亮行头 - `colHighlightBGColor` 列头高亮背景色 @@ -90,14 +90,13 @@ const columns = [ width: 100 } ]; - +const highlightPlugin = new VTablePlugins.HighlightHeaderWhenSelectCellPlugin(); const option = { records, columns, - rowSeriesNumber: {} + rowSeriesNumber: {}, + plugins: [highlightPlugin] }; const tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID), option); window['tableInstance'] = tableInstance; - -const highlightPlugin = new VTablePlugins.HeaderHighlightPlugin(tableInstance, {}); ``` diff --git a/docs/assets/demo/zh/interaction/invert-highlight.md b/docs/assets/demo/zh/interaction/invert-highlight.md index 3b1dae99a7..1720566ed8 100644 --- a/docs/assets/demo/zh/interaction/invert-highlight.md +++ b/docs/assets/demo/zh/interaction/invert-highlight.md @@ -12,7 +12,7 @@ link: plugin/invert-highlight ## 关键配置 -- `InvertHighlightPlugin` 反选高亮插件 +- `FocusHighlightPlugin` 反选高亮插件 - `fill` 反选高亮背景色 - `opacity` 反选高亮透明度 - `setInvertHighlightRange` 设置反选高亮范围 @@ -87,25 +87,16 @@ const columns = [ width: 100 } ]; - +const highlightPlugin = new VTablePlugins.FocusHighlightPlugin(); const option = { records, columns, - theme: VTable.themes.DARK + theme: VTable.themes.DARK, + plugins: [highlightPlugin] }; const tableInstance = new VTable.ListTable(document.getElementById(CONTAINER_ID), option); window['tableInstance'] = tableInstance; -const highlightPlugin = new VTablePlugins.InvertHighlightPlugin(tableInstance, {}); -highlightPlugin.setInvertHighlightRange({ - start: { - col: 0, - row: 6 - }, - end: { - col: 5, - row: 6 - } -}); + ``` diff --git a/docs/assets/guide/en/animation/carousel_animation.md b/docs/assets/guide/en/animation/carousel_animation.md index 796799d660..be3a225d3b 100644 --- a/docs/assets/guide/en/animation/carousel_animation.md +++ b/docs/assets/guide/en/animation/carousel_animation.md @@ -1,51 +1,2 @@ # Carousel Animation - -VTable provides carousel animation plugin, which can implement the carousel scrolling animation effect of the table. - -
- -
- -## Carousel Animation Configuration - -- `CarouselAnimationPlugin` carousel animation plugin, can configure the following parameters: - - `rowCount` scroll row count in a carousel animation - - `colCount` scroll column count in a carousel animation - - `animationDuration` The duration of a single carousel animation, in milliseconds - - `animationDelay` The delay of a single carousel animation, in milliseconds - - `animationEasing` The easing function of a single carousel animation - - `replaceScrollAction` Whether to replace the scroll action, if true, the scroll action will be replaced by the carousel animation - -```js -const carouselAnimationPlugin = new CarouselAnimationPlugin(tableInstance, { - rowCount: 2, - replaceScrollAction: true -}); - -carouselAnimationPlugin.play(); -``` - -For specific usage, please refer to [demo](../../demo/animation/carousel-animation) - -## Carousel Animation API - -### play - -Start carousel animation. -``` -carouselAnimationPlugin.play() -``` - -### pause - -Pause carousel animation. -``` -carouselAnimationPlugin.pause() -``` - -### reset - -Reset carousel animation. -``` -carouselAnimationPlugin.reset() -``` +Please jump to the link: [Table Carousel Animation](../plugin/table-carousel-animation) \ No newline at end of file diff --git a/docs/assets/guide/en/plugin/contribute.md b/docs/assets/guide/en/plugin/contribute.md new file mode 100644 index 0000000000..6b8ee79ab5 --- /dev/null +++ b/docs/assets/guide/en/plugin/contribute.md @@ -0,0 +1,96 @@ +# Contributing Plugins + +When businesses use VTable, they may need customized functionality, which can be implemented through plugins. Extracting common functionality into plugins avoids reinventing the wheel and makes it easier for other businesses to use these features. + +Sharing plugins can improve development efficiency and reduce maintenance costs! We encourage everyone to actively contribute plugins and help improve the VTable ecosystem! + +## Guidelines for Contributing Plugins + +1. Plugins must follow VTable's plugin specifications. +2. Plugins must include detailed documentation, including parameter descriptions, usage examples, etc. + +### Plugin Specifications +#### Interface Specifications + +Plugins need to implement the `VTable.plugins.IVTablePlugin` interface. + +```ts +// Plugin unified interface +export interface IVTablePlugin { + // Plugin unique identifier + id: string; + // Plugin runtime trigger + runTime: TableEvents[keyof TableEvents] | TableEvents[keyof TableEvents][]; + // Initialization method, called after VTable instance creation and before first render + run: (...args: any[]) => void; + // Update method, called when table data or configuration updates + update?: (table: BaseTableAPI, options?: any) => void; + // Destruction method, called before VTable instance is destroyed + release?: (table: BaseTableAPI) => void; +} +``` + +The `runTime` parameter specifies when the plugin will run, configuring it with event types from `TableEvents`. + +#### Component Lifecycle Process: + +
+ +
+ +Attached Mermaid sequence diagram code (for future updates, you can modify this code and update the image above): +```mermaid +sequenceDiagram + participant User + participant DOM + participant ListTable + participant EventManager + participant PluginManager + participant Plugin as IVTablePlugin + participant RenderManager + + %% Initialization + ListTable->>PluginManager: register plugins + PluginManager->>Plugin: store plugin instances + + %% User interaction flow + User->>DOM: interact (click, scroll, etc.) + DOM->>EventManager: dispatch browser event + EventManager->>PluginManager: notify(eventType, args) + PluginManager->>PluginManager: filter plugins by runTime + + loop For each matching plugin + PluginManager->>Plugin: run(eventArgs, runTime, tableAPI) + Plugin->>ListTable: read/modify table state + Plugin->>Plugin: process event logic + end + + Plugin->>RenderManager: requestRender() + RenderManager->>ListTable: render updates + ListTable->>DOM: update display + + %% Release + ListTable->>PluginManager: release + PluginManager->>Plugin: release() +``` + +From the above diagram, you can understand the runtime timing of plugins: +- The key role of `runTime` in plugins is to specify which VTable events they depend on. +- In the plugin's `run` method, you can access the table instance, configuration, and data; you should also handle the plugin's specific business logic in the `run` method. +- Remember to release resources in the plugin's `release` method to avoid memory leaks. + +### Plugin Documentation + +Plugins need to provide detailed documentation, including parameter descriptions, usage examples, etc. + +Documentation generally should include the following: +- Plugin name +- Plugin description +- Plugin parameter descriptions +- Plugin usage examples +- Plugin notes and considerations +- Plugin source code link + +Documentation should be placed in the `docs/assets/plugins` directory, with the filename `plugin-name.md`. + + diff --git a/docs/assets/guide/en/plugin/excel-keyboard-alignment.md b/docs/assets/guide/en/plugin/excel-keyboard-alignment.md new file mode 100644 index 0000000000..c69608537f --- /dev/null +++ b/docs/assets/guide/en/plugin/excel-keyboard-alignment.md @@ -0,0 +1,135 @@ +# Excel Edit Cell Keyboard Behavior Alignment Plugin + +`ExcelEditCellKeyboardPlugin` is a VTable extension component that aligns keyboard behavior in cell editing with Excel functionality. + +## Plugin Capabilities +Regarding keyboard response settings, VTable has the following two configuration entry points: + +| keyboard | Response | +| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| enter | If in edit state, confirms editing completion;
If keyboardOptions.moveFocusCellOnEnter is true, pressing enter switches the selected cell to the cell below.
If keyboardOptions.editCellOnEnter is true, pressing enter will enter edit mode when a cell is selected. | +| tab | Requires keyboardOptions.moveFocusCellOnTab to be enabled.
Pressing tab switches the selected cell, if currently editing a cell, the next cell will also be in edit mode. | +| left | Direction key, switches the selected cell.
If keyboardOptions.moveEditCellOnArrowKeys is enabled, you can also switch the editing cell in edit mode | +| right | Same as above | +| top | Same as above | +| bottom | Same as above | +| ctrl+c | The keybinding is not exact, this copy matches the browser's shortcut.
Copies selected cell content, requires keyboardOptions.copySelected to be enabled | +| ctrl+v | The keybinding is not exact, paste shortcut matches the browser's shortcut.
Pastes content to cells, requires keyboardOptions.pasteValueToCell to be enabled, paste only works on cells configured with editor | +| ctrl+a | Select all, requires keyboardOptions.selectAllOnCtrlA to be enabled | +| shift | Hold shift and left mouse button to select cells in a continuous area | +| ctrl | Hold ctrl and left mouse button to select multiple areas | +| any key | Can listen to tableInstance.on('keydown',(args)=>{ }) | + +These settings can satisfy most editing table keyboard response requirements, but compared to Excel, VTable's keyboard behavior still has some differences, such as: + +- In VTable, when editing a cell, pressing arrow keys doesn't switch to the next cell, but moves the cursor within the editing cell. +- In VTable, when editing a cell, pressing enter doesn't confirm editing completion, but switches to the next cell. +- In VTable, when editing a cell, pressing tab doesn't switch to the next cell, but moves the cursor within the editing cell. +- In VTable, when editing a cell, pressing shift and left mouse button doesn't select cells in a continuous area. +- In VTable, when editing a cell, holding ctrl and left mouse button doesn't select multiple areas. + + +Combined with VTable's existing capabilities that partially meet the requirements, we developed the `ExcelEditCellKeyboardPlugin` plugin to align cell editing keyboard behavior with Excel functionality. + +## Plugin Usage Example + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + const excelEditCellKeyboardPlugin = new VTablePlugins.ExcelEditCellKeyboardPlugin(); + + const option = { + records: generatePersons(20), + columns:[ + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + editor: new VTable_editors.InputEditor(), + editCellTrigger: ['keydown'], + plugins: [excelEditCellKeyboardPlugin] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; + + +``` + +## Future Plugin Improvements + +Other keyboard behaviors that differ from Excel, such as: + +- Support for configuration option to respond to the delete key +- Support for configuration option to respond to ctrl+c and ctrl+v +- Support for configuration option to respond to shift and left mouse button +- Support for configuration option to respond to ctrl and left mouse button + +Whether each response behavior needs to be explicitly configured by users, such as providing configuration options: +```ts +const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin({ + enableDeleteKey: false +}); +const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin(excelEditCellKeyboardPlugin); + +``` + +We welcome your contributions to write more plugins! Let's build the VTable ecosystem together! \ No newline at end of file diff --git a/docs/assets/guide/en/plugin/focus-highlight.md b/docs/assets/guide/en/plugin/focus-highlight.md new file mode 100644 index 0000000000..d97780014a --- /dev/null +++ b/docs/assets/guide/en/plugin/focus-highlight.md @@ -0,0 +1,118 @@ +# Focus Highlight Plugin + +VTable provides a focus highlight plugin that supports highlighting specified areas. + +
+ +
+ +## Focus Highlight Plugin Configuration Options + +- `FocusHighlightPlugin` Focus Highlight Plugin, can be configured with the following parameters: + - `fill` Focus highlight background color + - `opacity` Focus highlight opacity + - `highlightRange` Initial focus highlight range + +``` +export interface FocusHighlightPluginOptions { + fill?: string; + opacity?: number; + highlightRange?: CellRange; +} +``` + +## Usage Example: + + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const highlightPlugin = new VTablePlugins.FocusHighlightPlugin({ + fill: '#000', + opacity: 0.5, + highlightRange: { + start: { + col: 4, + row: 4 + }, + end: { + col: 4, + row: 4 + } + } + }); + const option = { + records: generatePersons(20), + columns:[ + { + field: 'id', + title: 'ID', + width: 'auto', + minWidth: 50, + sort: true + }, + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + { + title: 'full name', + columns: [ + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + } + ] + }, + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + theme: VTable.themes.DARK, + plugins: [highlightPlugin] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; +``` + +For specific usage, refer to the [demo](../../demo/interaction/head-highlight) diff --git a/docs/assets/guide/en/plugin/header-highlight.md b/docs/assets/guide/en/plugin/header-highlight.md index 4e73715f38..0b3b1e4863 100644 --- a/docs/assets/guide/en/plugin/header-highlight.md +++ b/docs/assets/guide/en/plugin/header-highlight.md @@ -1,23 +1,106 @@ -# Header Highlight Plugin +# Highlight Header When Cell Selected Plugin -VTable provides Header Highlight plugin, which can highlight the corresponding header (row header and column header) after selecting a cell. +VTable provides a plugin to highlight the corresponding headers when a cell is selected, supporting highlighting of row and column headers.
-## Header Highlight Plugin Configuration +## Header Highlight Plugin Configuration Options -- `HeaderHighlightPlugin` Header Highlight, can configure the following parameters: - - `columnHighlight` whether highlight the column - - `rowHighlight` whether highlight the row - - `colHighlightBGColor` the background color of the column highlight - - `rowHighlightBGColor` the background color of the row highlight - - `colHighlightColor` the color of the column highlight - - `rowHighlightColor` the color of the row highlight +- `HighlightHeaderWhenSelectCellPlugin` Header highlight when cell selected plugin, can be configured with the following parameters: + - `columnHighlight` Whether to highlight column headers + - `rowHighlight` Whether to highlight row headers + - `colHighlightBGColor` Column header highlight background color + - `rowHighlightBGColor` Row header highlight background color + - `colHighlightColor` Column header highlight font color + - `rowHighlightColor` Row header highlight font color + +Plugin parameter types: +``` +interface IHighlightHeaderWhenSelectCellPluginOptions { + rowHighlight?: boolean; + colHighlight?: boolean; + colHighlightBGColor?: string; + colHighlightColor?: string; + rowHighlightBGColor?: string; + rowHighlightColor?: string; +} +``` + +## Usage Example: + + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const highlightPlugin = new VTablePlugins.HighlightHeaderWhenSelectCellPlugin({ + colHighlight: true, + rowHighlight: true + }); + const option = { + records: generatePersons(20), + rowSeriesNumber: {}, + columns:[ + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + }, + + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], -```js -const highlightPlugin = new HeaderHighlightPlugin(tableInstance, {}); + plugins: [highlightPlugin] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; ``` -For specific usage, please refer to [demo](../../demo/interaction/head-highlight) +For specific usage, refer to the [demo](../../demo/interaction/head-highlight) diff --git a/docs/assets/guide/en/plugin/invert-highlight.md b/docs/assets/guide/en/plugin/invert-highlight.md deleted file mode 100644 index 6b26c31a06..0000000000 --- a/docs/assets/guide/en/plugin/invert-highlight.md +++ /dev/null @@ -1,50 +0,0 @@ -# Invert Highlight Plugin - -VTable provides Invert Highlight plugin, which can highlight the specified area after deselection. - -
- -
- -## Invert Highlight Plugin Configuration - -- `InvertHighlightPlugin` Invert Highlight Plugin, can configure the following parameters: - - `fill` invert highlight background color - - `opacity` invert highlight opacity -- `setInvertHighlightRange` set highlight range - -```js -const highlightPlugin = new InvertHighlightPlugin(tableInstance, {}); - -highlightPlugin.setInvertHighlightRange({ - start: { - col: 0, - row: 6 - }, - end: { - col: 5, - row: 6 - } -}); -``` - -For specific usage, please refer to [demo](../../demo/interaction/head-highlight) - -## Invert Highlight Plugin API - -### setInvertHighlightRange - -Set highlight range. - -```ts -setInvertHighlightRange(range: { - start: { - col: number; - row: number; - }; - end: { - col: number; - row: number; - }; -}): void; -``` \ No newline at end of file diff --git a/docs/assets/guide/en/plugin/row-column-add.md b/docs/assets/guide/en/plugin/row-column-add.md new file mode 100644 index 0000000000..e61aac7129 --- /dev/null +++ b/docs/assets/guide/en/plugin/row-column-add.md @@ -0,0 +1,139 @@ +# Row and Column Addition Plugin + +## Introduction + +AddRowColumnPlugin is a plugin designed to extend VTable with dynamic row and column addition capabilities. + +This plugin monitors the `vTable` instance's `MOUSEENTER_CELL`, `MOUSELEAVE_CELL`, and `MOUSELEAVE_TABLE` events! + +When the mouse hovers over a table cell, dots and plus signs for adding rows and columns will be displayed; when the mouse leaves the table cell, these indicators will be hidden. + +## Plugin Configuration + +Configuration options for the row and column addition plugin: + +```ts +export interface AddRowColumnOptions { + /** + * Whether to enable column addition + */ + addColumnEnable?: boolean; + /** + * Whether to enable row addition + */ + addRowEnable?: boolean; + /** + * Callback function for adding a column + */ + addColumnCallback?: (col: number) => void; + /** + * Callback function for adding a row + */ + addRowCallback?: (row: number) => void; +} +``` + +## Plugin Example +Initialize the plugin object and add it to the vTable configuration's plugins. +``` +const addRowColumn = new AddRowColumnPlugin(); +const option = { + records, + columns, + padding: 30, + plugins: [addRowColumn] +}; +``` +To control the content of newly added row data and update data and column information after adding columns, you can use the configuration options provided by the plugin. When initializing the plugin object, provide hook functions for adding rows and columns, and set the values for new rows or column information in these functions. +```ts + const addRowColumn = new AddRowColumnPlugin({ + addColumnCallback: col => { + columns.splice(addColIndex, 0, { + field: ``, + title: `New Column ${col}`, + width: 100 + }); + this.table.updateColumns(columns); + const newRecords = tableInstance.records.map(record => { + if (Array.isArray(record)) { + record.splice(col - 1, 0, ''); + } + return record; + }); + tableInstance.setRecords(newRecords); + }, + addRowCallback: row => { + tableInstance.addRecord([], row - tableInstance.columnHeaderLevelCount); + } + }); +``` + +Runnable example: + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + const addRowColumn = new VTablePlugins.AddRowColumnPlugin(); +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const option = { + records: generatePersons(20), + rowSeriesNumber: {}, + columns:[ + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + }, + + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + + plugins: [addRowColumn] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; +``` diff --git a/docs/assets/guide/en/plugin/row-column-series.md b/docs/assets/guide/en/plugin/row-column-series.md new file mode 100644 index 0000000000..6b9068afab --- /dev/null +++ b/docs/assets/guide/en/plugin/row-column-series.md @@ -0,0 +1,130 @@ +# Row and Column Series Plugins + +## Introduction + +ColumnSeriesPlugin and RowSeriesPlugin are VTable extension components that automatically generate row and column numbers. + +
+ +
+ +## Plugin Parameters + +```typescript +export interface ColumnSeriesOptions { + columnCount: number; + generateColumnTitle?: (index: number) => string; // Custom column title generation function + generateColumnField?: (index: number) => string;// Custom column field name generation function +} + +export interface RowSeriesOptions { + rowCount: number; + fillRowRecord?: (index: number) => any; // Custom data generation function for filling empty rows + rowSeriesNumber?: VTable.TYPES.IRowSeriesNumber; +} +``` + +In the column series plugin configuration, in addition to setting the number of columns to generate, you can also configure the field names and titles needed for VTable column configuration. + +In the row series plugin configuration, `rowCount` can be set to configure the number of rows to generate, `rowSeriesNumber` can be used to configure row numbering, which takes precedence over the options.rowSeriesNumber in the VTable instance initialization. `fillRowRecord` can be configured to generate row data; if not configured, it defaults to returning an empty object `{}`. + +## Basic Usage + +```typescript +import * as VTable from '@visactor/vtable'; +import { ColumnSeriesPlugin } from '@visactor/vtable-plugins'; + +// Create a ColumnSeries plugin instance +const columnSeries = new ColumnSeriesPlugin({ + columnCount: 100 // Set the number of columns +}); + +// Create a RowSeries plugin instance +const rowSeries = new RowSeriesPlugin({ + rowCount: 100 // Set the number of rows +}); + +// Use the plugins in VTable options +const option: VTable.ListTableConstructorOptions = { + container: document.getElementById('container'), + records: data, + plugins: [columnSeries, rowSeries], + // Other VTable configurations... +}; + +// Create the table instance +const tableInstance = new VTable.ListTable(option); +``` + +## Advanced Usage + +### Custom Column Titles and Field Names + +```typescript +const columnSeries = new ColumnSeriesPlugin({ + columnCount: 100, + // Custom column title generation + columnTitleGenerator: (index) => `Custom Title ${index}`, + // Custom field name generation + columnFieldGenerator: (index) => `field_${index}` +}); +``` + +### Custom Row Data + +```typescript +const rowSeries = new RowSeriesPlugin({ + rowCount: 100, + // Custom row data generation returning an empty array + fillRowRecord: (index) => ([]) +}); + +// or +const rowSeries = new RowSeriesPlugin({ + rowCount: 100, + // Custom row data generation + fillRowRecord: (index) => (['Name', 'Age', 'Address']) +}); +``` + +## Specific Example + +```javascript livedemo template=vtable + +let tableInstance; +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +// 创建 ColumnSeries 插件实例 +const columnSeries = new VTablePlugins.ColumnSeriesPlugin({ + columnCount: 100, + // 自定义列标题生成 + // generateColumnTitle(index) + // { + // return `自定义标题 ${index}` + // }, + // 自定义字段名生成 + generateColumnField: (index) => `field_${index}` +}); + +// 创建 RowSeries 插件实例 +const rowSeries = new VTablePlugins.RowSeriesPlugin({ + rowCount: 100, + // 自定义行数据生成 + fillRowRecord: (index) => ([]) +}); + +// 在 VTable 选项中使用插件 +const option = { + records: [], + plugins: [columnSeries, rowSeries], + // 其他 VTable 配置... +}; + +// 创建表格实例 +tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); +window.tableInstance = tableInstance; +``` diff --git a/docs/assets/guide/en/plugin/table-carousel-animation.md b/docs/assets/guide/en/plugin/table-carousel-animation.md new file mode 100644 index 0000000000..692a09ff65 --- /dev/null +++ b/docs/assets/guide/en/plugin/table-carousel-animation.md @@ -0,0 +1,132 @@ +# Table Carousel Animation Plugin + +VTable provides a table carousel animation plugin that supports row or column carousel animations for tables. + +Effect shown below: +
+ +
+ +## Usage Example + +```ts +const tableCarouselAnimationPlugin = new TableCarouselAnimationPlugin({ + rowCount: 10, + colCount: 10, + animationDuration: 1000, + animationDelay: 0, + animationEasing: 'linear', + autoPlay: true, + autoPlayDelay: 1000, +}); + +const option: VTable.ListTableConstructorOptions = { + records, + columns, + plugins: [tableCarouselAnimationPlugin], +}; + +``` +If you don't want the table to start playing immediately after initialization, you can set `autoPlay` to `false` and then call the `play` method manually to start playing. + +```ts +tableCarouselAnimationPlugin.play(); +``` + + + +## Plugin Parameter Description + +The plugin provides customization options, with the following parameters: + +| Parameter | Type | Description | +| --- | --- | --- | +| rowCount | number | Number of rows to scroll per animation | +| colCount | number | Number of columns to scroll per animation | +| animationDuration | number | Animation duration | +| animationDelay | number | Animation delay | +| animationEasing | string | Animation easing function | +| autoPlay | boolean | Whether to auto-play | +| autoPlayDelay | number | Auto-play delay | +| customDistRowFunction | (row: number, table: BaseTableAPI) => { distRow: number; animation?: boolean } | Custom animation distance function for rows | +| customDistColFunction | (col: number, table: BaseTableAPI) => { distCol: number; animation?: boolean } | Custom animation distance function for columns | + +## Running Example + + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +const generatePersons = count => { + return Array.from(new Array(count)).map((_, i) => ({ + id: i + 1, + email1: `${i + 1}@xxx.com`, + name: `小明${i + 1}`, + lastName: '王', + date1: '2022年9月1日', + tel: '000-0000-0000', + sex: i % 2 === 0 ? 'boy' : 'girl', + work: i % 2 === 0 ? 'back-end engineer' + (i + 1) : 'front-end engineer' + (i + 1), + city: 'beijing', + image: + '' + })); +}; + + const animationPlugin = new VTablePlugins.TableCarouselAnimationPlugin({ + rowCount: 2, + // colCount: 2, + autoPlay: true, + autoPlayDelay: 1000 + }); + const option = { + records: generatePersons(30), + rowSeriesNumber: { + title: 'No.' + }, + columns:[ + { + field: 'email1', + title: 'email', + width: 200, + sort: true, + style: { + underline: true, + underlineDash: [2, 0], + underlineOffset: 3 + } + }, + + { + field: 'name', + title: 'First Name', + width: 200 + }, + { + field: 'name', + title: 'Last Name', + width: 200 + }, + + { + field: 'date1', + title: 'birthday', + width: 200 + }, + { + field: 'sex', + title: 'sex', + width: 100 + } + ], + + plugins: [animationPlugin] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; +``` + diff --git a/docs/assets/guide/en/plugin/usage.md b/docs/assets/guide/en/plugin/usage.md new file mode 100644 index 0000000000..1d7a4f6040 --- /dev/null +++ b/docs/assets/guide/en/plugin/usage.md @@ -0,0 +1,42 @@ +# Plugin Usage + +Get the plugin package + +```bash +npm install @visactor/vtable-plugins +``` +Import plugins + +```ts +import { TableCarouselAnimationPlugin } from '@visactor/vtable-plugins'; +``` + +Use the plugin + +```ts +const tableCarouselAnimationPlugin = new TableCarouselAnimationPlugin({ + ... +}); +``` + +Add the plugin to the plugin list + +```ts +const option: VTable.ListTableConstructorOptions = { + ... + plugins: [tableCarouselAnimationPlugin] +}; +``` + +Combining multiple plugins + +```ts +const option: VTable.ListTableConstructorOptions = { + ... + plugins: [tableCarouselAnimationPlugin, ...] +}; +``` + +The order of plugin usage generally has no special requirements. Please carefully read the documentation for each plugin to understand its execution timing, and if necessary, refer to the plugin's source code. + +If you encounter issues with plugin usage, please provide feedback promptly. \ No newline at end of file diff --git a/docs/assets/guide/zh/animation/carousel_animation.md b/docs/assets/guide/zh/animation/carousel_animation.md index 4d3aa22fbf..3a9b2db7d6 100644 --- a/docs/assets/guide/zh/animation/carousel_animation.md +++ b/docs/assets/guide/zh/animation/carousel_animation.md @@ -1,51 +1,2 @@ # 表格轮播动画 - -VTable 提供轮播动画插件,可以实现表格的轮播滚动动画效果。 - -
- -
- -## 轮播动画配置项 - -- `CarouselAnimationPlugin` 轮播动画插件,可以配置以下参数: - - `rowCount` 一次动画滚动的行数 - - `colCount` 一次动画滚动的列数 - - `animationDuration` 一次滚动动画的时间 - - `animationDelay` 动画间隔时间 - - `animationEasing` 动画缓动函数 - - `replaceScrollAction` 是否替换滚动行为,如果为 true ,每次滚动操作会移动对于的行数/列数 - -```js -const carouselAnimationPlugin = new CarouselAnimationPlugin(tableInstance, { - rowCount: 2, - replaceScrollAction: true -}); - -carouselAnimationPlugin.play(); -``` - -具体使用参考[demo](../../demo/animation/carousel-animation) - -## 轮播动画API - -### play - -开始轮播动画。 -``` -carouselAnimationPlugin.play() -``` - -### pause - -暂停轮播动画。 -``` -carouselAnimationPlugin.pause() -``` - -### reset - -重置轮播动画。 -``` -carouselAnimationPlugin.reset() -``` +请跳转到链接:[表格轮播动画](../plugin/table-carousel-animation) \ No newline at end of file diff --git a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts index 42e7062cb0..11d8b3b1a3 100644 --- a/packages/vtable/src/core/TABLE_EVENT_TYPE.ts +++ b/packages/vtable/src/core/TABLE_EVENT_TYPE.ts @@ -171,8 +171,6 @@ export interface TableEvents { INITIALIZED: 'initialized'; //#endregion - /** 开始编辑单元格 */ - BEFORE_EDIT_CELL: 'before_edit_cell'; /** 编辑单元格 */ CHANGE_CELL_VALUE: 'change_cell_value'; diff --git a/packages/vtable/src/plugins/interface.ts b/packages/vtable/src/plugins/interface.ts index 5792b723be..094baf2760 100644 --- a/packages/vtable/src/plugins/interface.ts +++ b/packages/vtable/src/plugins/interface.ts @@ -11,7 +11,7 @@ export interface IVTablePlugin { // // 插件类型,用于区分不同功能的插件 // type: 'layout' | 'interaction' | 'style' | 'animation'; // 插件运行时机 - runTime: TableEvents[keyof TableEvents] | TableEvents[keyof TableEvents][]; + runTime: TableEvents[keyof TableEvents][]; // // 插件依赖 // dependencies?: string[]; // 初始化方法,在VTable实例创建后、首次渲染前调用 diff --git a/packages/vtable/src/plugins/plugin-manager.ts b/packages/vtable/src/plugins/plugin-manager.ts index c3d6773927..074075d696 100644 --- a/packages/vtable/src/plugins/plugin-manager.ts +++ b/packages/vtable/src/plugins/plugin-manager.ts @@ -31,17 +31,11 @@ export class PluginManager { initPlugins(table: BaseTableAPI) { this.plugins.forEach(plugin => { - if (Array.isArray(plugin.runTime)) { - plugin.runTime.forEach(runTime => { - table.on(runTime, (...args) => { - plugin.run?.(...args, runTime, table); - }); + plugin.runTime?.forEach(runTime => { + table.on(runTime, (...args) => { + plugin.run?.(...args, runTime, table); }); - } else { - table.on(plugin.runTime, (...args) => { - plugin.run?.(table, ...args, plugin.runTime as TableEvents[keyof TableEvents]); - }); - } + }); }); } From 8a0f3692725a640aa937549b6cc8ca7b0faa81eb Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 15 Apr 2025 19:14:44 +0800 Subject: [PATCH 28/51] docs: add plugins tutorial --- .../demo/en/plugin/excel-online-editing.md | 114 +++++++ docs/assets/demo/menu.json | 16 + .../demo/zh/plugin/excel-online-editing.md | 114 +++++++ docs/assets/guide/en/plugin/usage.md | 12 +- docs/assets/guide/zh/plugin/usage.md | 13 +- .../option/en/common/option-secondary.md | 20 +- .../option/zh/common/option-secondary.md | 8 + .../demo/combine-plugins/combine-plugins.ts | 4 +- packages/vtable-plugins/demo/menu.ts | 9 + .../vtable-plugins/demo/pivot/pivot-plugin.ts | 319 ++++++++++++++++++ .../src/excel-edit-cell-keyboard.ts | 2 +- .../src/event/listener/container-dom.ts | 1 - 12 files changed, 620 insertions(+), 12 deletions(-) create mode 100644 docs/assets/demo/en/plugin/excel-online-editing.md create mode 100644 docs/assets/demo/zh/plugin/excel-online-editing.md create mode 100644 packages/vtable-plugins/demo/pivot/pivot-plugin.ts diff --git a/docs/assets/demo/en/plugin/excel-online-editing.md b/docs/assets/demo/en/plugin/excel-online-editing.md new file mode 100644 index 0000000000..7ea44127c7 --- /dev/null +++ b/docs/assets/demo/en/plugin/excel-online-editing.md @@ -0,0 +1,114 @@ +--- +category: examples +group: plugin +title: Excel-like Online Editing +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/excel-online-editing.gif +link: plugin/usage +option: plugins +--- + +# Excel-like Online Editing + +Based on VTable's plugin mechanism, this example implements Excel-like online editing functionality. + +In this example, we use the following plugins in combination: +- `AddRowColumnPlugin`: Add rows and columns +- `ColumnSeriesPlugin`: Column series plugin +- `RowSeriesPlugin`: Row series plugin +- `HighlightHeaderWhenSelectCellPlugin`: Highlight selected cells +- `ExcelEditCellKeyboardPlugin`: Excel-style cell editing keyboard plugin + +It's important to note that there are dependencies between plugins. For example, in the `AddRowColumnPlugin`, we call the `columnSeries.resetColumnCount` method to reset the column count, ensuring that after adding columns, the count remains consistent with the column count in the `ColumnSeriesPlugin`. + +## Key Configuration + +- `editCellTrigger`: Cell editing trigger method +- `editor`: Editor type +- `plugins`: Plugin list + + +## Code Demo + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +// 注册编辑器 +const input_editor = new VTable_editors.InputEditor(); +VTable.register.editor('input', input_editor); + +// 注册插件 + const addRowColumn = new VTablePlugins.AddRowColumnPlugin({ + addColumnCallback: col => { + // 新增列时,重置列数 + columnSeries.resetColumnCount(columnSeries.pluginOptions.columnCount + 1); + // 将table实例中的数据源records每一个数组中新增一个空字符串,对应新增的列 + const newRecords = tableInstance.records.map(record => { + if (Array.isArray(record)) { + record.splice(col - 1, 0, ''); + } + return record; + }); + tableInstance.setRecords(newRecords); + }, + addRowCallback: row => { + // 新增行时,填充空行数据 + tableInstance.addRecord([], row - tableInstance.columnHeaderLevelCount); + } + }); + + const columnSeries = new VTablePlugins.ColumnSeriesPlugin({ + columnCount: 26 + }); + const rowSeries = new VTablePlugins.RowSeriesPlugin({ + rowCount: 100, + //records数据以外 填充空行数据 + fillRowRecord: (index) => { + return []; + }, + rowSeriesNumber: { + width: 'auto' + } + }); + const highlightPlugin = new VTablePlugins.HighlightHeaderWhenSelectCellPlugin({ + colHighlight: true, + rowHighlight: true + }); + const excelEditCellKeyboardPlugin = new VTablePlugins.ExcelEditCellKeyboardPlugin(); + const option = { + // 二维数组的数据 和excel的行列一致 + records: [ + ['姓名', '年龄', '地址'], + ['张三', 18, '北京'], + ['李四', 20, '上海'], + ['王五', 22, '广州'], + ['赵六', 24, '深圳'], + ['孙七', 26, '成都'] + ], + + padding: 30, + editor: 'input', + editCellTrigger: ['api', 'keydown', 'doubleclick'],// 编辑单元格触发方式 + select: { + cornerHeaderSelectMode: 'body', + headerSelectMode: 'body' + }, + theme: VTable.themes.DEFAULT.extends({ + defaultStyle: { + textAlign: 'left', + padding: [2, 6, 2, 6] + }, + headerStyle: { + textAlign: 'center' + } + }), + defaultRowHeight: 30, + plugins: [addRowColumn, columnSeries, rowSeries, highlightPlugin, excelEditCellKeyboardPlugin] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; + +``` \ No newline at end of file diff --git a/docs/assets/demo/menu.json b/docs/assets/demo/menu.json index 465824021a..f1944b1de4 100644 --- a/docs/assets/demo/menu.json +++ b/docs/assets/demo/menu.json @@ -1482,6 +1482,22 @@ } ] }, + { + "path": "plugin", + "title": { + "zh": "插件库", + "en": "plugin library" + }, + "children": [ + { + "path": "excel-online-editing", + "title": { + "zh": "类Excel在线编辑", + "en": "Excel online editing" + } + } + ] + }, { "path": "export", "title": { diff --git a/docs/assets/demo/zh/plugin/excel-online-editing.md b/docs/assets/demo/zh/plugin/excel-online-editing.md new file mode 100644 index 0000000000..38e6a27c97 --- /dev/null +++ b/docs/assets/demo/zh/plugin/excel-online-editing.md @@ -0,0 +1,114 @@ +--- +category: examples +group: plugin +title: 类Excel在线编辑 +cover: https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/VTable/preview/excel-online-editing.gif +link: plugin/usage +option: plugins +--- + +# 类Excel在线编辑 + +基于VTable的插件机制,实现类Excel在线编辑功能。 + +在本示例中我们组合运用了以下插件: +- `AddRowColumnPlugin`:添加行和列; +- `ColumnSeriesPlugin`:列系列插件; +- `RowSeriesPlugin`:行系列插件; +- `HighlightHeaderWhenSelectCellPlugin`:高亮选中单元格; +- `ExcelEditCellKeyboardPlugin`:Excel编辑单元格键盘插件; + +需要注意的是插件之间存在一定的依赖关系,如在新增行列插件`AddRowColumnPlugin`中,我们调用了`columnSeries.resetColumnCount`方法,重置列数,以确保新增列后,列数与列系列插件`ColumnSeriesPlugin`中的列数一致。 + +## 关键配置 + +- `editCellTrigger`: 编辑单元格触发方式 +- `editor`: 编辑器类型 +- `plugins`: 插件列表 + + +## 代码演示 + +```javascript livedemo template=vtable +// import * as VTable from '@visactor/vtable'; +// 使用时需要引入插件包@visactor/vtable-plugins +// import * as VTablePlugins from '@visactor/vtable-plugins'; +// 正常使用方式 const columnSeries = new VTable.plugins.ColumnSeriesPlugin({}); +// 官网编辑器中将 VTable.plugins重命名成了VTablePlugins + +// 注册编辑器 +const input_editor = new VTable_editors.InputEditor(); +VTable.register.editor('input', input_editor); + +// 注册插件 + const addRowColumn = new VTablePlugins.AddRowColumnPlugin({ + addColumnCallback: col => { + // 新增列时,重置列数 + columnSeries.resetColumnCount(columnSeries.pluginOptions.columnCount + 1); + // 将table实例中的数据源records每一个数组中新增一个空字符串,对应新增的列 + const newRecords = tableInstance.records.map(record => { + if (Array.isArray(record)) { + record.splice(col - 1, 0, ''); + } + return record; + }); + tableInstance.setRecords(newRecords); + }, + addRowCallback: row => { + // 新增行时,填充空行数据 + tableInstance.addRecord([], row - tableInstance.columnHeaderLevelCount); + } + }); + + const columnSeries = new VTablePlugins.ColumnSeriesPlugin({ + columnCount: 26 + }); + const rowSeries = new VTablePlugins.RowSeriesPlugin({ + rowCount: 100, + //records数据以外 填充空行数据 + fillRowRecord: (index) => { + return []; + }, + rowSeriesNumber: { + width: 'auto' + } + }); + const highlightPlugin = new VTablePlugins.HighlightHeaderWhenSelectCellPlugin({ + colHighlight: true, + rowHighlight: true + }); + const excelEditCellKeyboardPlugin = new VTablePlugins.ExcelEditCellKeyboardPlugin(); + const option = { + // 二维数组的数据 和excel的行列一致 + records: [ + ['姓名', '年龄', '地址'], + ['张三', 18, '北京'], + ['李四', 20, '上海'], + ['王五', 22, '广州'], + ['赵六', 24, '深圳'], + ['孙七', 26, '成都'] + ], + + padding: 30, + editor: 'input', + editCellTrigger: ['api', 'keydown', 'doubleclick'],// 编辑单元格触发方式 + select: { + cornerHeaderSelectMode: 'body', + headerSelectMode: 'body' + }, + theme: VTable.themes.DEFAULT.extends({ + defaultStyle: { + textAlign: 'left', + padding: [2, 6, 2, 6] + }, + headerStyle: { + textAlign: 'center' + } + }), + defaultRowHeight: 30, + plugins: [addRowColumn, columnSeries, rowSeries, highlightPlugin, excelEditCellKeyboardPlugin] + }; + const tableInstance = new VTable.ListTable( document.getElementById(CONTAINER_ID),option); + window.tableInstance = tableInstance; + +``` \ No newline at end of file diff --git a/docs/assets/guide/en/plugin/usage.md b/docs/assets/guide/en/plugin/usage.md index 1d7a4f6040..178583d244 100644 --- a/docs/assets/guide/en/plugin/usage.md +++ b/docs/assets/guide/en/plugin/usage.md @@ -39,4 +39,14 @@ const option: VTable.ListTableConstructorOptions = { The order of plugin usage generally has no special requirements. Please carefully read the documentation for each plugin to understand its execution timing, and if necessary, refer to the plugin's source code. -If you encounter issues with plugin usage, please provide feedback promptly. \ No newline at end of file +If you encounter issues with plugin usage, please provide feedback promptly. + +## Plugin List +| Plugin Name | Plugin Description | Applicable Object | +| --- | --- | --- | +| `AddRowColumnPlugin` | Add rows and columns | `ListTable` | +| `ColumnSeriesPlugin` | Column series plugin, can specify the number of columns in the table and define the function to generate the column serial number | `ListTable` | +| `RowSeriesPlugin` | Row series plugin, can specify the number of rows in the table and define the function to generate the data corresponding to the empty number | `ListTable` | +| `HighlightHeaderWhenSelectCellPlugin` | Highlight the selected cell | `ListTable`,`PivotTable` | +| `ExcelEditCellKeyboardPlugin` | Excel edit cell keyboard plugin | `ListTable`,`PivotTable` | +| `TableCarouselAnimationPlugin` | Table carousel animation plugin | `ListTable`,`PivotTable` | \ No newline at end of file diff --git a/docs/assets/guide/zh/plugin/usage.md b/docs/assets/guide/zh/plugin/usage.md index 494a15edee..43234c0e78 100644 --- a/docs/assets/guide/zh/plugin/usage.md +++ b/docs/assets/guide/zh/plugin/usage.md @@ -39,4 +39,15 @@ const option: VTable.ListTableConstructorOptions = { 插件使用顺序一般情况没有特殊要求,请详细阅读每个插件的文档,了解插件的执行时机,如果必要可阅读插件的源码。 -如果你发现使用插件上存在问题,请及时反馈。 \ No newline at end of file +如果你发现使用插件上存在问题,请及时反馈。 + + +## 插件列表 +| 插件名称 | 插件描述 |适用对象| +| --- | --- | --- | +| `AddRowColumnPlugin` | 添加行和列 | `ListTable` | +| `ColumnSeriesPlugin` | 列序号插件,可以指定表格列数,并定义生成列序号的函数 | `ListTable` | +| `RowSeriesPlugin` | 行序号插件,可以指定表格行数,并定义生成空号对应数据的函数 | `ListTable` | +| `HighlightHeaderWhenSelectCellPlugin` | 高亮选中单元格 | `ListTable`,`PivotTable` | +| `ExcelEditCellKeyboardPlugin` | Excel编辑单元格键盘插件 | `ListTable`,`PivotTable` | +| `TableCarouselAnimationPlugin` | 表格轮播动画插件 | `ListTable`,`PivotTable` | \ No newline at end of file diff --git a/docs/assets/option/en/common/option-secondary.md b/docs/assets/option/en/common/option-secondary.md index 0b91964b75..a507b7aa96 100644 --- a/docs/assets/option/en/common/option-secondary.md +++ b/docs/assets/option/en/common/option-secondary.md @@ -505,6 +505,15 @@ Custom cell style assignment - Cell range: `{ range: { start: { row: number, column: number }, end: { row: number, column: number} } }` - customStyleId: Custom style id, the same as the id defined when registering the custom style + +#${prefix} rowSeriesNumber(IRowSeriesNumber) + +set row serial number. +{{ use: row-series-number( + prefix = '###', +) }} + + #${prefix} editor (string|Object|Function) Global configuration cell editor @@ -534,12 +543,13 @@ The trigger timing for entering the editing state. editCellTrigger?:'doubleclick' | 'click' | 'api' | 'keydown' | ('doubleclick' | 'click' | 'api' | 'keydown')[]; ``` -#${prefix} rowSeriesNumber(IRowSeriesNumber) +#${prefix} plugins(IVTablePlugin[]) -set row serial number. -{{ use: row-series-number( - prefix = '###', -) }} +Configure plugins. For details, please refer to the tutorial [click here](../guide/plugin/usage) + +``` +plugins?: IVTablePlugin[]; +``` #${prefix} enableLineBreak(boolean) = false diff --git a/docs/assets/option/zh/common/option-secondary.md b/docs/assets/option/zh/common/option-secondary.md index 9290e53fb5..4d027d2697 100644 --- a/docs/assets/option/zh/common/option-secondary.md +++ b/docs/assets/option/zh/common/option-secondary.md @@ -539,6 +539,14 @@ editCellTrigger?: 'doubleclick' | 'click' | 'api' | 'keydown' | ('doubleclick' | ``` +#${prefix} plugins(IVTablePlugin[]) + +配置插件。具体教程[点击这里](../guide/plugin/usage) + +``` +plugins?: IVTablePlugin[]; +``` + #${prefix} enableLineBreak(boolean) = false 是否开启换行符解析,开启后,单元格内容中包含换行符时,会自动解析换行。 diff --git a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts index 00a0ef4e94..49aa0d4542 100644 --- a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts +++ b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts @@ -46,9 +46,7 @@ export function createTable() { colHighlight: true, rowHighlight: true }); - const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin({ - replaceMode: true - }); + const excelEditCellKeyboardPlugin = new ExcelEditCellKeyboardPlugin(); const option: VTable.ListTableConstructorOptions = { container: document.getElementById(CONTAINER_ID), records: [ diff --git a/packages/vtable-plugins/demo/menu.ts b/packages/vtable-plugins/demo/menu.ts index 3716d4bf86..d6b5778cf2 100644 --- a/packages/vtable-plugins/demo/menu.ts +++ b/packages/vtable-plugins/demo/menu.ts @@ -34,5 +34,14 @@ export const menus = [ { path: 'combine-plugins', name: 'combine-plugins' + }, + { + menu: 'pivot-plugin', + children: [ + { + path: 'pivot', + name: 'pivot-plugin' + } + ] } ]; diff --git a/packages/vtable-plugins/demo/pivot/pivot-plugin.ts b/packages/vtable-plugins/demo/pivot/pivot-plugin.ts new file mode 100644 index 0000000000..5d78acba80 --- /dev/null +++ b/packages/vtable-plugins/demo/pivot/pivot-plugin.ts @@ -0,0 +1,319 @@ +import * as VTable from '@visactor/vtable'; +import { + ExcelEditCellKeyboardPlugin, + HighlightHeaderWhenSelectCellPlugin, + TableCarouselAnimationPlugin +} from '../../src'; +import { InputEditor } from '@visactor/vtable-editors'; +const PivotTable = VTable.PivotTable; +const CONTAINER_ID = 'vTable'; +const input_editor = new InputEditor({}); +VTable.register.editor('input', input_editor); +export function createTable() { + const tableCarouselAnimationPlugin = new TableCarouselAnimationPlugin({ + rowCount: 2, + // colCount: 2, + autoPlay: true, + autoPlayDelay: 1000 + }); + const option: VTable.PivotTableConstructorOptions = { + rows: ['province', 'city'], + columns: ['category', 'sub_category'], + indicators: ['sales', 'number'], + plugins: [tableCarouselAnimationPlugin], + editor: 'input', + editCellTrigger: ['api', 'keydown', 'doubleclick'], + indicatorTitle: '指标名称', + indicatorsAsCol: false, + dataConfig: { + totals: { + row: { + showGrandTotals: true, + showSubTotals: true, + subTotalsDimensions: ['province'], + grandTotalLabel: '行总计', + subTotalLabel: '小计' + }, + column: { + showGrandTotals: true, + showSubTotals: true, + subTotalsDimensions: ['category'], + grandTotalLabel: '列总计', + subTotalLabel: '小计' + } + } + }, + columnResizeMode: 'header', + corner: { titleOnDimension: 'row' }, + theme: VTable.themes.DEFAULT.extends({ + columnResize: { + visibleOnHover: true + } + }), + records: [ + { + sales: 891, + number: 7789, + province: '浙江省', + city: '杭州市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 792, + number: 2367, + province: '浙江省', + city: '绍兴市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 893, + number: 3877, + province: '浙江省', + city: '宁波市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 1094, + number: 4342, + province: '浙江省', + city: '舟山市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 1295, + number: 5343, + province: '浙江省', + city: '杭州市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 496, + number: 632, + province: '浙江省', + city: '绍兴市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 1097, + number: 7234, + province: '浙江省', + city: '宁波市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 998, + number: 834, + province: '浙江省', + city: '舟山市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 766, + number: 945, + province: '浙江省', + city: '杭州市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 990, + number: 1304, + province: '浙江省', + city: '绍兴市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 891, + number: 1145, + province: '浙江省', + city: '宁波市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 792, + number: 1432, + province: '浙江省', + city: '舟山市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 745, + number: 1343, + province: '浙江省', + city: '杭州市', + category: '办公用品', + sub_category: '纸张' + }, + { + sales: 843, + number: 1354, + province: '浙江省', + city: '绍兴市', + category: '办公用品', + sub_category: '纸张' + }, + { + sales: 895, + number: 1523, + province: '浙江省', + city: '宁波市', + category: '办公用品', + sub_category: '纸张' + }, + { + sales: 965, + number: 1634, + province: '浙江省', + city: '舟山市', + category: '办公用品', + sub_category: '纸张' + }, + { + sales: 776, + number: 1723, + province: '四川省', + city: '成都市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 634, + number: 1822, + province: '四川省', + city: '绵阳市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 909, + number: 1943, + province: '四川省', + city: '南充市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 399, + number: 2330, + province: '四川省', + city: '乐山市', + category: '家具', + sub_category: '桌子' + }, + { + sales: 700, + number: 2451, + province: '四川省', + city: '成都市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 689, + number: 2244, + province: '四川省', + city: '绵阳市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 500, + number: 2333, + province: '四川省', + city: '南充市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 800, + number: 2445, + province: '四川省', + city: '乐山市', + category: '家具', + sub_category: '沙发' + }, + { + sales: 1044, + number: 2335, + province: '四川省', + city: '成都市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 689, + number: 245, + province: '四川省', + city: '绵阳市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 794, + number: 2457, + province: '四川省', + city: '南充市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 566, + number: 2458, + province: '四川省', + city: '乐山市', + category: '办公用品', + sub_category: '笔' + }, + { + sales: 865, + number: 4004, + province: '四川省', + city: '成都市', + category: '办公用品', + sub_category: '纸张' + }, + { + sales: 999, + number: 3077, + province: '四川省', + city: '绵阳市', + category: '办公用品', + sub_category: '纸张' + }, + { + sales: 999, + number: 3551, + province: '四川省', + city: '南充市', + category: '办公用品', + sub_category: '纸张' + }, + { + sales: 999, + number: 352, + province: '四川省', + city: '乐山市', + category: '办公用品', + sub_category: '纸张' + } + ], + widthMode: 'autoWidth' // 宽度模式:standard 标准模式; adaptive 自动填满容器 + }; + + const instance = new PivotTable(document.getElementById(CONTAINER_ID)!, option); + window.tableInstance = instance; + + // 只为了方便控制太调试用,不要拷贝 + window.tableInstance = instance; +} diff --git a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts index 122ec1eba3..c835ce9c77 100644 --- a/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts +++ b/packages/vtable-plugins/src/excel-edit-cell-keyboard.ts @@ -14,7 +14,7 @@ export class ExcelEditCellKeyboardPlugin implements VTable.plugins.IVTablePlugin runTime = [VTable.TABLE_EVENT_TYPE.INITIALIZED]; table: VTable.ListTable; pluginOptions: IExcelEditCellKeyboardPluginOptions; - constructor(pluginOptions: IExcelEditCellKeyboardPluginOptions) { + constructor(pluginOptions?: IExcelEditCellKeyboardPluginOptions) { this.pluginOptions = pluginOptions; this.bindEvent(); diff --git a/packages/vtable/src/event/listener/container-dom.ts b/packages/vtable/src/event/listener/container-dom.ts index ab8975c6e5..4a5fbe571b 100644 --- a/packages/vtable/src/event/listener/container-dom.ts +++ b/packages/vtable/src/event/listener/container-dom.ts @@ -28,7 +28,6 @@ export function bindContainerDomListener(eventManager: EventManager) { // 监听键盘事件 handler.on(table.getElement(), 'keydown', (e: KeyboardEvent) => { - console.log('keydown', e.key); // 键盘按下事件 内部逻辑处理前 const beforeKeydownEvent: KeydownEvent = { keyCode: e.keyCode ?? e.which, From 672d28a51727cbc54899002b782d9d9d0af347c2 Mon Sep 17 00:00:00 2001 From: zzzhrookie Date: Wed, 16 Apr 2025 10:37:02 +0800 Subject: [PATCH 29/51] fix: correct column index calculation when rowSeriesNumber is configured --- packages/vtable/src/layout/simple-header-layout.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vtable/src/layout/simple-header-layout.ts b/packages/vtable/src/layout/simple-header-layout.ts index 40c529e298..753fee65f2 100644 --- a/packages/vtable/src/layout/simple-header-layout.ts +++ b/packages/vtable/src/layout/simple-header-layout.ts @@ -1462,7 +1462,7 @@ export class SimpleHeaderLayoutMap implements LayoutMapAPI { let col; const result = this.columnObjects?.find((columnData: ColumnData, index) => { if (columnData.define?.key === key) { - col = index; + col = index + this.leftRowSeriesNumberColumnCount; return true; } return false; From b7e6410e4e2c48f6c33faa23b5305333e26ac128 Mon Sep 17 00:00:00 2001 From: zzzhrookie Date: Wed, 16 Apr 2025 13:30:15 +0800 Subject: [PATCH 30/51] docs: update changlog of rush --- ...lculation-with-series-number_2025-04-16-05-30.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json diff --git a/common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json b/common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json new file mode 100644 index 0000000000..b6efc9d319 --- /dev/null +++ b/common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "fix: correct column index calculation when rowSeriesNumber is configured\n\n", + "type": "none", + "packageName": "@visactor/vtable" + } + ], + "packageName": "@visactor/vtable", + "email": "zzh7498624@163.com" +} \ No newline at end of file From 3c3063015d7190dc983be5e583ad62a61409cdbb Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 16 Apr 2025 15:57:16 +0800 Subject: [PATCH 31/51] feat: add autoExtendColumn for plugin --- .../guide/en/plugin/row-column-series.md | 10 +++ .../guide/zh/plugin/row-column-series.md | 10 +++ .../demo/combine-plugins/combine-plugins.ts | 8 +- packages/vtable-plugins/src/column-series.ts | 65 ++++++++++------ packages/vtable-plugins/src/row-series.ts | 74 ++++++++++++------- packages/vtable/src/ListTable.ts | 9 +++ 6 files changed, 127 insertions(+), 49 deletions(-) diff --git a/docs/assets/guide/en/plugin/row-column-series.md b/docs/assets/guide/en/plugin/row-column-series.md index 6b9068afab..e9aec194c2 100644 --- a/docs/assets/guide/en/plugin/row-column-series.md +++ b/docs/assets/guide/en/plugin/row-column-series.md @@ -15,12 +15,22 @@ export interface ColumnSeriesOptions { columnCount: number; generateColumnTitle?: (index: number) => string; // Custom column title generation function generateColumnField?: (index: number) => string;// Custom column field name generation function + /** + * Whether to automatically extend columns + * @default true + */ + autoExtendColumn?: boolean; } export interface RowSeriesOptions { rowCount: number; fillRowRecord?: (index: number) => any; // Custom data generation function for filling empty rows rowSeriesNumber?: VTable.TYPES.IRowSeriesNumber; + /** + * Whether to automatically extend rows + * @default true + */ + autoExtendRow?: boolean; } ``` diff --git a/docs/assets/guide/zh/plugin/row-column-series.md b/docs/assets/guide/zh/plugin/row-column-series.md index 054e3da1af..3b3bb9e42e 100644 --- a/docs/assets/guide/zh/plugin/row-column-series.md +++ b/docs/assets/guide/zh/plugin/row-column-series.md @@ -15,12 +15,22 @@ export interface ColumnSeriesOptions { columnCount: number; generateColumnTitle?: (index: number) => string; // 自定义列标题生成函数 generateColumnField?: (index: number) => string;// 自定义列字段名生成函数 + /** + * 是否自动扩展列 + * @default true + */ + autoExtendColumn?: boolean; } export interface RowSeriesOptions { rowCount: number; fillRowRecord?: (index: number) => any; // 填充空行的 自定义生成数据函数 rowSeriesNumber?: VTable.TYPES.IRowSeriesNumber; + /** + * 是否自动扩展行 + * @default true + */ + autoExtendRow?: boolean; } ``` diff --git a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts index 49aa0d4542..e04b475bda 100644 --- a/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts +++ b/packages/vtable-plugins/demo/combine-plugins/combine-plugins.ts @@ -31,10 +31,10 @@ export function createTable() { }); const columnSeries = new ColumnSeriesPlugin({ - columnCount: 26 + columnCount: 3 }); const rowSeries = new RowSeriesPlugin({ - rowCount: 100, + rowCount: 6, fillRowRecord: (index: number) => { return []; }, @@ -74,6 +74,10 @@ export function createTable() { textAlign: 'center' } }), + keyboardOptions: { + moveFocusCellOnEnter: true + // editCellOnEnter: false + }, defaultRowHeight: 30, plugins: [addRowColumn, columnSeries, rowSeries, highlightPlugin, excelEditCellKeyboardPlugin] }; diff --git a/packages/vtable-plugins/src/column-series.ts b/packages/vtable-plugins/src/column-series.ts index 08686f6f08..5e30bf65b4 100644 --- a/packages/vtable-plugins/src/column-series.ts +++ b/packages/vtable-plugins/src/column-series.ts @@ -6,27 +6,45 @@ export interface ColumnSeriesOptions { columnCount: number; generateColumnTitle?: (index: number) => string; generateColumnField?: (index: number) => string; + /** + * 是否自动扩展列 + * @default true + */ + autoExtendColumn?: boolean; } /** * 生成列序号标题的插件 */ export class ColumnSeriesPlugin implements VTable.plugins.IVTablePlugin { id = 'column-series'; - runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT]; + runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT, VTable.TABLE_EVENT_TYPE.BEFORE_KEYDOWN]; pluginOptions: ColumnSeriesOptions; table: VTable.ListTable; columns: { field?: string; title: string }[] = []; - constructor(pluginOptions: ColumnSeriesOptions = { columnCount: 100 }) { - this.pluginOptions = pluginOptions; + constructor(pluginOptions: ColumnSeriesOptions) { + this.pluginOptions = Object.assign({ columnCount: 100, autoExtendColumn: true }, pluginOptions); } run(...args: any[]) { - const eventArgs = args[0]; - const table: VTable.BaseTableAPI = args[2]; - this.table = table as VTable.ListTable; - const options = eventArgs.options; - //根据pluginOptions的columnCount组织columns,column的title生成规则和excel一致,如A~Z,AA~AZ,AB~AZ,AA~ZZ,AAA~ZZZ - this.columns = this.generateColumnFields(this.pluginOptions.columnCount); - options.columns = this.columns; + if (args[1] === VTable.TABLE_EVENT_TYPE.BEFORE_INIT) { + const eventArgs = args[0]; + const table: VTable.BaseTableAPI = args[2]; + this.table = table as VTable.ListTable; + const options = eventArgs.options; + //根据pluginOptions的columnCount组织columns,column的title生成规则和excel一致,如A~Z,AA~AZ,AB~AZ,AA~ZZ,AAA~ZZZ + this.columns = this.generateColumns(this.pluginOptions.columnCount); + options.columns = this.columns; + } else if (args[1] === VTable.TABLE_EVENT_TYPE.BEFORE_KEYDOWN) { + const eventArgs = args[0]; + const e = eventArgs.event; + if (e.key === 'ArrowRight') { + if ( + this.pluginOptions.autoExtendColumn && + this.table.stateManager.select.cellPos.col === this.table.colCount - 1 + ) { + this.table.addColumn(this.generateColumn(this.table.colCount - 1) as VTable.ColumnDefine); + } + } + } } /** * 生成列字段和标题 @@ -34,21 +52,24 @@ export class ColumnSeriesPlugin implements VTable.plugins.IVTablePlugin { * @param columnCount 列数 * @returns 列字段和标题的数组 */ - generateColumnFields(columnCount: number): { field?: string; title: string }[] { + generateColumns(columnCount: number): { field?: string; title: string }[] { const columnFields = []; for (let i = 0; i < columnCount; i++) { - const column = { - // field: this.pluginOptions.generateColumnField - // ? this.pluginOptions.generateColumnField(i) - // : this.generateColumnField(i), - title: this.pluginOptions.generateColumnTitle - ? this.pluginOptions.generateColumnTitle(i) - : this.generateColumnField(i) - }; - columnFields.push(column); + columnFields.push(this.generateColumn(i)); } return columnFields; } + generateColumn(index: number): { field?: string; title: string } { + const column = { + // field: this.pluginOptions.generateColumnField + // ? this.pluginOptions.generateColumnField(i) + // : this.generateColumnField(i), + title: this.pluginOptions.generateColumnTitle + ? this.pluginOptions.generateColumnTitle(index) + : this.generateColumnField(index) + }; + return column; + } /** * 生成excel的列标题,规则和excel一致,如A~Z,AA~AZ,AB~AZ,AA~ZZ,AAA~ZZZ * @param index 从0开始 @@ -74,7 +95,7 @@ export class ColumnSeriesPlugin implements VTable.plugins.IVTablePlugin { resetColumnCount(columnCount: number) { this.pluginOptions.columnCount = columnCount; - this.columns = this.generateColumnFields(columnCount); - this.table.updateColumns(this.columns); + this.columns = this.generateColumns(columnCount); + this.table.updateColumns(this.columns as VTable.ColumnsDefine); } } diff --git a/packages/vtable-plugins/src/row-series.ts b/packages/vtable-plugins/src/row-series.ts index ec1cc18eef..6e730577aa 100644 --- a/packages/vtable-plugins/src/row-series.ts +++ b/packages/vtable-plugins/src/row-series.ts @@ -1,44 +1,68 @@ -import * as VTable from '@visactor/vtable'; +import { TABLE_EVENT_TYPE } from '@visactor/vtable'; +import type { TYPES, BaseTableAPI, ListTable, ListTableConstructorOptions, plugins } from '@visactor/vtable'; /** * 添加行和列的插件的配置选项 */ export interface RowSeriesOptions { rowCount: number; fillRowRecord?: (index: number) => any; - rowSeriesNumber?: VTable.TYPES.IRowSeriesNumber; + rowSeriesNumber?: TYPES.IRowSeriesNumber; + /** + * 是否自动扩展行 + * @default true + */ + autoExtendRow?: boolean; } /** * 生成行序号标题的插件 */ -export class RowSeriesPlugin implements VTable.plugins.IVTablePlugin { +export class RowSeriesPlugin implements plugins.IVTablePlugin { id = 'row-series'; - runTime = [VTable.TABLE_EVENT_TYPE.BEFORE_INIT]; + runTime = [TABLE_EVENT_TYPE.BEFORE_INIT, TABLE_EVENT_TYPE.BEFORE_KEYDOWN]; pluginOptions: RowSeriesOptions; - table: VTable.ListTable; + table: ListTable; - constructor(pluginOptions: RowSeriesOptions = { rowCount: 100 }) { - this.pluginOptions = pluginOptions; + constructor(pluginOptions: RowSeriesOptions) { + this.pluginOptions = Object.assign({ rowCount: 100, autoExtendRow: true }, pluginOptions); } run(...args: any[]) { - const eventArgs = args[0]; - const table: VTable.BaseTableAPI = args[2]; - this.table = table as VTable.ListTable; - const options: VTable.ListTableConstructorOptions = eventArgs.options; - const records = options.records ?? []; - //用空数据将records填充到pluginOptions.rowCount - for (let i = records.length; i < this.pluginOptions.rowCount; i++) { - records.push(this.pluginOptions.fillRowRecord ? this.pluginOptions.fillRowRecord(i) : {}); - } - options.records = records; - if (this.pluginOptions.rowSeriesNumber) { - options.rowSeriesNumber = this.pluginOptions.rowSeriesNumber; - if (!this.pluginOptions.rowSeriesNumber.width) { - options.rowSeriesNumber.width = 'auto'; + if (args[1] === TABLE_EVENT_TYPE.BEFORE_INIT) { + const eventArgs = args[0]; + const table: BaseTableAPI = args[2]; + this.table = table as ListTable; + const options: ListTableConstructorOptions = eventArgs.options; + const records = options.records ?? []; + //用空数据将records填充到pluginOptions.rowCount + for (let i = records.length; i < this.pluginOptions.rowCount; i++) { + records.push(this.pluginOptions.fillRowRecord ? this.pluginOptions.fillRowRecord(i) : {}); + } + options.records = records; + if (this.pluginOptions.rowSeriesNumber) { + options.rowSeriesNumber = this.pluginOptions.rowSeriesNumber; + if (!this.pluginOptions.rowSeriesNumber.width) { + options.rowSeriesNumber.width = 'auto'; + } + } else if (!options.rowSeriesNumber) { + options.rowSeriesNumber = { + width: 'auto' + }; + } + } else if (args[1] === TABLE_EVENT_TYPE.BEFORE_KEYDOWN) { + const eventArgs = args[0]; + + const e = eventArgs.event; + if (e.key === 'ArrowDown') { + if ( + this.pluginOptions.autoExtendRow && + this.table.stateManager.select.cellPos.row === this.table.rowCount - 1 + ) { + (this.table as ListTable).addRecord( + this.pluginOptions.fillRowRecord + ? this.pluginOptions.fillRowRecord(this.table.rowCount - this.table.columnHeaderLevelCount) + : {} + ); + } } - } else if (!options.rowSeriesNumber) { - options.rowSeriesNumber = { - width: 'auto' - }; } } } diff --git a/packages/vtable/src/ListTable.ts b/packages/vtable/src/ListTable.ts index 7c76807bad..10535e0417 100644 --- a/packages/vtable/src/ListTable.ts +++ b/packages/vtable/src/ListTable.ts @@ -239,6 +239,15 @@ export class ListTable extends BaseTable implements ListTableAPI { this.renderAsync(); this.eventManager.updateEventBinder(); } + /** + * 添加列 TODO: 需要优化 这个方法目前直接调用了updateColumns 可以避免调用 做优化性能 + * @param column + */ + addColumn(column: ColumnDefine) { + const columns = this.options.columns; + columns.push(column); + this.updateColumns(columns); + } get columns(): ColumnsDefine { // return this.internalProps.columns; return this.internalProps.layoutMap.columnTree.getCopiedTree(); //调整顺序后的columns From e4604a31d4cd2a83deff3c1afe9bea95c90a1ae8 Mon Sep 17 00:00:00 2001 From: "lixuefei.1313" Date: Mon, 24 Mar 2025 19:02:10 +0800 Subject: [PATCH 32/51] feat: add chart picker --- .../vtable/src/scenegraph/graphic/chart.ts | 6 +-- .../scenegraph/graphic/contributions/index.ts | 10 +++- .../contributions/picker-interceptor.ts | 52 +++++++++++++++++++ .../contributions/vchart-graphic-picker.ts | 33 ++++++++++++ 4 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 packages/vtable/src/scenegraph/graphic/contributions/picker-interceptor.ts create mode 100644 packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts diff --git a/packages/vtable/src/scenegraph/graphic/chart.ts b/packages/vtable/src/scenegraph/graphic/chart.ts index 499b595305..57f80f653d 100644 --- a/packages/vtable/src/scenegraph/graphic/chart.ts +++ b/packages/vtable/src/scenegraph/graphic/chart.ts @@ -1,5 +1,5 @@ -import type { GraphicType, IGroupGraphicAttribute, Stage } from '@src/vrender'; -import { genNumberType, Group } from '@src/vrender'; +import type { GraphicType, IGroupGraphicAttribute, Stage, Group } from '@src/vrender'; +import { genNumberType, Rect } from '@src/vrender'; import { Bounds, merge } from '@visactor/vutils'; import type { BaseTableAPI } from '../../ts-types/base-table'; import type { PivotChart } from '../../PivotChart'; @@ -29,7 +29,7 @@ interface IChartGraphicAttribute extends IGroupGraphicAttribute { export const CHART_NUMBER_TYPE = genNumberType(); -export class Chart extends Group { +export class Chart extends Rect { type: GraphicType = 'chart' as any; declare attribute: IChartGraphicAttribute; chartInstance: any; diff --git a/packages/vtable/src/scenegraph/graphic/contributions/index.ts b/packages/vtable/src/scenegraph/graphic/contributions/index.ts index ea284520e4..19926b756a 100644 --- a/packages/vtable/src/scenegraph/graphic/contributions/index.ts +++ b/packages/vtable/src/scenegraph/graphic/contributions/index.ts @@ -7,7 +7,8 @@ import { SplitRectAfterRenderContribution, ContainerModule, DrawItemInterceptor, - TextRenderContribution + TextRenderContribution, + CanvasPickerContribution } from '@src/vrender'; import { ChartRender, DefaultCanvasChartRender } from './chart-render'; import { @@ -34,6 +35,8 @@ import { } from './group-contribution-render'; import { VTableDrawItemInterceptorContribution } from './draw-interceptor'; import { SuffixTextBeforeRenderContribution } from './text-contribution-render'; +import { VChartPicker } from './vchart-graphic-picker'; +// import { VChartPickServiceInterceptorContribution } from './picker-interceptor'; export default new ContainerModule((bind, unbind, isBound, rebind) => { // rect 渲染器注入contributions @@ -54,6 +57,11 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(DefaultCanvasChartRender).toSelf().inSingletonScope(); bind(ChartRender).to(DefaultCanvasChartRender); bind(GraphicRender).to(DefaultCanvasChartRender); + // chart picker 注入 + bind(VChartPicker).toSelf().inSingletonScope(); + bind(CanvasPickerContribution).toService(VChartPicker); + // bind(VChartPickServiceInterceptorContribution).toSelf().inSingletonScope(); + // bind(PickServiceInterceptor).toService(VChartPickServiceInterceptorContribution); // image 渲染器注入contributions bind(BeforeImageRenderContribution).toSelf().inSingletonScope(); diff --git a/packages/vtable/src/scenegraph/graphic/contributions/picker-interceptor.ts b/packages/vtable/src/scenegraph/graphic/contributions/picker-interceptor.ts new file mode 100644 index 0000000000..81ed9c4d25 --- /dev/null +++ b/packages/vtable/src/scenegraph/graphic/contributions/picker-interceptor.ts @@ -0,0 +1,52 @@ +import type { IPickerService, IPickParams, PickResult } from '@src/vrender'; +import { injectable } from '@src/vrender'; +import type { IMatrix, IPointLike } from '@visactor/vutils'; + +@injectable() +export class VChartPickServiceInterceptorContribution { + order: number = 1; + afterPickItem( + result: PickResult, + pickerService: IPickerService, + point: IPointLike, + pickParams: IPickParams, + params?: { + parentMatrix: IMatrix; + } + ): null | PickResult { + // 点击到图表的空白区域了,那么就判断该位置是否有其他图元,如果有,那就返回false,否则还是认为选中了图表 + if ( + result.graphic === null && + result.group && + (result.group as any).stage && + (result.group as any).stage.id === 'vstory' + ) { + // console.log('aaaa', result); + const stage = (result.group as any).stage; + const charts = stage.getElementsByType('chart'); + const nextPoint = { x: point.x, y: point.y }; + if (params && params.parentMatrix) { + params.parentMatrix.transformPoint(point, nextPoint); + } + + for (let i = charts.length - 1; i >= 0; i--) { + const chart = charts[i]; + const pointInChart = { x: nextPoint.x, y: nextPoint.y }; + chart.globalTransMatrix.transformPoint(pointInChart, pointInChart); + if (!chart.activeChartInstance) { + continue; + } + const viewBox = chart.activeChartInstance.getStage().viewBox; + // console.log(chart); + if (viewBox.contains(pointInChart.x, pointInChart.y)) { + result.graphic = chart; + result.group = null; + // result.group = + return result; + } + } + } + + return result; + } +} diff --git a/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts new file mode 100644 index 0000000000..b376a7cc0e --- /dev/null +++ b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts @@ -0,0 +1,33 @@ +import { injectable } from '@src/vrender'; +import type { IGraphicPicker, IPickParams } from '@src/vrender'; +import type { Chart as VChartGraphic } from '../chart'; +import { CHART_NUMBER_TYPE } from '../chart'; + +@injectable() +export class VChartPicker implements IGraphicPicker { + type = 'chart'; + numberType: number = CHART_NUMBER_TYPE; + + contains(chart: any, point: any, params?: IPickParams): boolean | any { + // 将当前的point转化到global + const matrix = chart.parent.globalTransMatrix.clone(); + const stageMatrix = chart.stage.window.getViewBoxTransform(); + matrix.multiply(stageMatrix.a, stageMatrix.b, stageMatrix.c, stageMatrix.d, stageMatrix.e, stageMatrix.f); + const toGlobalMatrix = matrix.getInverse(); + const nextP = { x: 0, y: 0 }; + toGlobalMatrix.transformPoint(point, nextP); + + // 得到 vchart stage + const vChart = (chart as VChartGraphic).activeChartInstance; + const vchartStage = vChart.getStage(); + vchartStage.dirtyBounds?.clear(); + const toChartMatrix = vchartStage.window.getViewBoxTransform(); + toChartMatrix.transformPoint(nextP, nextP); + const pick = vchartStage.pick(nextP.x, nextP.y); + // @ts-ignore + if (pick.graphic === null && pick.group.name === 'root') { + return false; + } + return pick; + } +} From d8011dddf5d522fc1867b12d3f03c0a1b0f70811 Mon Sep 17 00:00:00 2001 From: "lixuefei.1313" Date: Mon, 24 Mar 2025 19:14:26 +0800 Subject: [PATCH 33/51] feat: add chart picker --- .../graphic/contributions/vchart-graphic-picker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts index b376a7cc0e..019b0e7e3f 100644 --- a/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts +++ b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts @@ -9,6 +9,10 @@ export class VChartPicker implements IGraphicPicker { numberType: number = CHART_NUMBER_TYPE; contains(chart: any, point: any, params?: IPickParams): boolean | any { + const vChart = (chart as VChartGraphic).activeChartInstance; + if (!vChart) { + return false; + } // 将当前的point转化到global const matrix = chart.parent.globalTransMatrix.clone(); const stageMatrix = chart.stage.window.getViewBoxTransform(); @@ -18,7 +22,6 @@ export class VChartPicker implements IGraphicPicker { toGlobalMatrix.transformPoint(point, nextP); // 得到 vchart stage - const vChart = (chart as VChartGraphic).activeChartInstance; const vchartStage = vChart.getStage(); vchartStage.dirtyBounds?.clear(); const toChartMatrix = vchartStage.window.getViewBoxTransform(); From e41c9afde518047142dcb9ca7fa1fdfb28ed28fa Mon Sep 17 00:00:00 2001 From: "lixuefei.1313" Date: Tue, 25 Mar 2025 16:27:12 +0800 Subject: [PATCH 34/51] feat: use group point to pick --- .../graphic/contributions/vchart-graphic-picker.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts index 019b0e7e3f..b4b345a336 100644 --- a/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts +++ b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts @@ -13,20 +13,11 @@ export class VChartPicker implements IGraphicPicker { if (!vChart) { return false; } - // 将当前的point转化到global - const matrix = chart.parent.globalTransMatrix.clone(); - const stageMatrix = chart.stage.window.getViewBoxTransform(); - matrix.multiply(stageMatrix.a, stageMatrix.b, stageMatrix.c, stageMatrix.d, stageMatrix.e, stageMatrix.f); - const toGlobalMatrix = matrix.getInverse(); - const nextP = { x: 0, y: 0 }; - toGlobalMatrix.transformPoint(point, nextP); - // 得到 vchart stage const vchartStage = vChart.getStage(); vchartStage.dirtyBounds?.clear(); - const toChartMatrix = vchartStage.window.getViewBoxTransform(); - toChartMatrix.transformPoint(nextP, nextP); - const pick = vchartStage.pick(nextP.x, nextP.y); + // 因为vchart 在 vtable 内始坐标变换始终等于在group中的坐标变换,所以这里不需要再做坐标转换 + const pick = vchartStage.pick(point.x, point.y); // @ts-ignore if (pick.graphic === null && pick.group.name === 'root') { return false; From be1f291a043e0172cabd2ada983e1be67cd32562 Mon Sep 17 00:00:00 2001 From: "lixuefei.1313" Date: Thu, 27 Mar 2025 11:30:02 +0800 Subject: [PATCH 35/51] feat: support customConfig disableBuildInChartActive --- packages/vtable/src/state/hover/update-position.ts | 9 ++++++--- packages/vtable/src/ts-types/base-table.ts | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/vtable/src/state/hover/update-position.ts b/packages/vtable/src/state/hover/update-position.ts index c199b58ac1..843f8875f6 100644 --- a/packages/vtable/src/state/hover/update-position.ts +++ b/packages/vtable/src/state/hover/update-position.ts @@ -43,9 +43,12 @@ export function updateHoverPosition(state: StateManager, col: number, row: numbe if (prevHoverCellCol === col && prevHoverCellRow === row) { return; } - // 将hover单元格的图表实例激活 并将上一个失去焦点 - scenegraph.deactivateChart(prevHoverCellCol, prevHoverCellRow); - scenegraph.activateChart(col, row); + + if (!state.table.options.customConfig?.disableBuildInChartActive) { + // 将hover单元格的图表实例激活 并将上一个失去焦点 + scenegraph.deactivateChart(prevHoverCellCol, prevHoverCellRow); + scenegraph.activateChart(col, row); + } let updateScenegraph = false; const { diff --git a/packages/vtable/src/ts-types/base-table.ts b/packages/vtable/src/ts-types/base-table.ts index 99349eae5b..0206bf9a49 100644 --- a/packages/vtable/src/ts-types/base-table.ts +++ b/packages/vtable/src/ts-types/base-table.ts @@ -569,6 +569,9 @@ export interface BaseTableConstructorOptions { // 开启透视结构缓存 enablePivotPathCache?: boolean; + + // 是否禁用内置图表激活 + disableBuildInChartActive?: boolean; }; // 部分特殊配置,兼容xTable等作用 animationAppear?: boolean | IAnimationAppear; From e824931c51f2ad061f18da40a2067b08b8746f4c Mon Sep 17 00:00:00 2001 From: "lixuefei.1313" Date: Thu, 27 Mar 2025 11:30:20 +0800 Subject: [PATCH 36/51] docs: update changlog of rush --- ...disable-buildin-active-chart_2025-03-27-03-30.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json diff --git a/common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json b/common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json new file mode 100644 index 0000000000..9a53f7fd5b --- /dev/null +++ b/common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "feat: support customConfig disableBuildInChartActive\n\n", + "type": "none", + "packageName": "@visactor/vtable" + } + ], + "packageName": "@visactor/vtable", + "email": "lixuef1313@163.com" +} \ No newline at end of file From c93a93bf5646ace16ab7997f0b12ba34aadb4d3b Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 16 Apr 2025 16:03:48 +0800 Subject: [PATCH 37/51] fix: fix row/column update problem in text-stick #3744 --- .../vtable/fix-stick-row-update_2025-04-16-08-02.json | 10 ++++++++++ packages/vtable/src/scenegraph/layout/update-col.ts | 5 +++++ packages/vtable/src/scenegraph/layout/update-row.ts | 5 +++++ packages/vtable/src/scenegraph/stick-text/index.ts | 7 ++++++- 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json diff --git a/common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json b/common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json new file mode 100644 index 0000000000..3fcf8453dd --- /dev/null +++ b/common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "fix: fix row/column update problem in text-stick #3744", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file diff --git a/packages/vtable/src/scenegraph/layout/update-col.ts b/packages/vtable/src/scenegraph/layout/update-col.ts index f02f6527d0..c90130b368 100644 --- a/packages/vtable/src/scenegraph/layout/update-col.ts +++ b/packages/vtable/src/scenegraph/layout/update-col.ts @@ -6,6 +6,7 @@ import { updateCell } from '../group-creater/cell-helper'; import type { Scenegraph } from '../scenegraph'; import { getCellMergeInfo } from '../utils/get-cell-merge'; import type { IGroup } from '@src/vrender'; +import { checkHaveTextStick, resetTextStick } from '../stick-text'; /** * add and remove rows in scenegraph @@ -16,6 +17,10 @@ export function updateCol( updateCells: CellAddress[], table: BaseTableAPI ) { + if (checkHaveTextStick(table)) { + resetTextStick(table); // reset text stick + } + const scene = table.scenegraph; // deduplication const removeCols = deduplication(removeCells.map(cell => cell.col)).sort((a, b) => b - a); diff --git a/packages/vtable/src/scenegraph/layout/update-row.ts b/packages/vtable/src/scenegraph/layout/update-row.ts index f18bd87dc0..8905123e16 100644 --- a/packages/vtable/src/scenegraph/layout/update-row.ts +++ b/packages/vtable/src/scenegraph/layout/update-row.ts @@ -6,6 +6,7 @@ import { updateCell } from '../group-creater/cell-helper'; import type { Scenegraph } from '../scenegraph'; import { getCellMergeInfo } from '../utils/get-cell-merge'; import { deduplication } from '../../tools/util'; +import { checkHaveTextStick, resetTextStick } from '../stick-text'; /** * add and remove rows in scenegraph @@ -17,6 +18,10 @@ export function updateRow( table: BaseTableAPI, skipUpdateProxy?: boolean ) { + if (checkHaveTextStick(table)) { + resetTextStick(table); // reset text stick + } + const scene = table.scenegraph; // deduplication const removeRows = deduplication(removeCells.map(cell => cell.row)).sort((a, b) => b - a); diff --git a/packages/vtable/src/scenegraph/stick-text/index.ts b/packages/vtable/src/scenegraph/stick-text/index.ts index 0fa2090840..3c09560f7a 100644 --- a/packages/vtable/src/scenegraph/stick-text/index.ts +++ b/packages/vtable/src/scenegraph/stick-text/index.ts @@ -6,7 +6,7 @@ import type { ITextStyleOption, StickCell } from '../../ts-types'; import { isNumber, min } from '@visactor/vutils'; import { getCellMergeRange } from '../../tools/merge-range'; -export function handleTextStick(table: BaseTableAPI) { +export function resetTextStick(table: BaseTableAPI) { // reset const { changedCells } = table.internalProps.stick; // changedCells only cache one time changedCells.forEach((cellPos: StickCell) => { @@ -19,6 +19,11 @@ export function handleTextStick(table: BaseTableAPI) { }); }); changedCells.clear(); + return changedCells; +} + +export function handleTextStick(table: BaseTableAPI) { + const changedCells = resetTextStick(table); const { scrollTop, scrollLeft, frozenRowCount, frozenColCount } = table; const frozenRowsHeight = table.getFrozenRowsHeight(); From 4ae3f9824e71f7d9c55bc205c9f0eee5aed0e552 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 16 Apr 2025 14:43:35 +0800 Subject: [PATCH 38/51] fix: fix image flash problem #3588 --- .../vtable/fix-image-flash_2025-04-16-06-43.json | 10 ++++++++++ .../scenegraph/group-creater/cell-type/image-cell.ts | 3 +++ 2 files changed, 13 insertions(+) create mode 100644 common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json diff --git a/common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json b/common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json new file mode 100644 index 0000000000..955f26695b --- /dev/null +++ b/common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "fix: fix image flash problem #3588", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file diff --git a/packages/vtable/src/scenegraph/group-creater/cell-type/image-cell.ts b/packages/vtable/src/scenegraph/group-creater/cell-type/image-cell.ts index 6cb59600e3..70356a63fd 100644 --- a/packages/vtable/src/scenegraph/group-creater/cell-type/image-cell.ts +++ b/packages/vtable/src/scenegraph/group-creater/cell-type/image-cell.ts @@ -170,7 +170,9 @@ export function createImageCellGroup( image.resources.has(image.attribute.image) && image.resources.get(image.attribute.image).state === 'success' ) { + image.setAttribute('opacity', 0); // hack for image update setTimeout(() => { + image.setAttribute('opacity', 1); // hack for image update; 如果图片资源存在,会先安照单元格大小渲染一次,再异步调整大小,这样可能出现图片闪烁的问题,这里使用opacity来规避 updateAutoSizingAndKeepAspectRatio( imageAutoSizing, keepAspectRatio, @@ -181,6 +183,7 @@ export function createImageCellGroup( cellGroup, table ); + table.scenegraph.updateNextFrame(); }, 0); } else { image.successCallback = () => { From d0cde85847c4d29edd37a67d445ae1e6ce25d214 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 16 Apr 2025 14:52:36 +0800 Subject: [PATCH 39/51] fix: fix validateDragOrderOnEnd judgement in dragOrder option --- packages/vtable/src/layout/pivot-header-layout.ts | 4 ++-- packages/vtable/src/layout/simple-header-layout.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vtable/src/layout/pivot-header-layout.ts b/packages/vtable/src/layout/pivot-header-layout.ts index a4a5439f10..ebe3a2c6f0 100644 --- a/packages/vtable/src/layout/pivot-header-layout.ts +++ b/packages/vtable/src/layout/pivot-header-layout.ts @@ -2939,8 +2939,8 @@ export class PivotHeaderLayoutMap implements LayoutMapAPI { } { // 判断从source地址是否可以移动到target地址 if ( - (this._table.options.dragOrder?.validateDragOrderOnEnd(source, target) || - !this._table.options.dragOrder?.validateDragOrderOnEnd) && + (!this._table.options.dragOrder?.validateDragOrderOnEnd || + this._table.options.dragOrder?.validateDragOrderOnEnd(source, target)) && this.canMoveHeaderPosition(source, target) && !this.isCellRangeEqual(source.col, source.row, target.col, target.row) ) { diff --git a/packages/vtable/src/layout/simple-header-layout.ts b/packages/vtable/src/layout/simple-header-layout.ts index 40c529e298..95444a4989 100644 --- a/packages/vtable/src/layout/simple-header-layout.ts +++ b/packages/vtable/src/layout/simple-header-layout.ts @@ -1203,8 +1203,8 @@ export class SimpleHeaderLayoutMap implements LayoutMapAPI { } { // 判断从source地址是否可以移动到target地址 if ( - (this._table.options.dragOrder?.validateDragOrderOnEnd(source, target) || - !this._table.options.dragOrder?.validateDragOrderOnEnd) && + (!this._table.options.dragOrder?.validateDragOrderOnEnd || + this._table.options.dragOrder?.validateDragOrderOnEnd(source, target)) && this.canMoveHeaderPosition(source, target) ) { let sourceCellRange = this.getCellRange(source.col, source.row); From dcb8cb562999770d852c1b5148f428aa50ff5f96 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Tue, 15 Apr 2025 20:40:19 +0800 Subject: [PATCH 40/51] fix: fix table size in getCellsRect() #3681 --- .../vtable/fix-cell-rect_2025-04-15-12-40.json | 10 ++++++++++ packages/vtable/src/core/BaseTable.ts | 15 +++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json diff --git a/common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json b/common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json new file mode 100644 index 0000000000..aa6aca4778 --- /dev/null +++ b/common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "fix: fix table size in getCellsRect() #3681", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index 35ed9a2ad5..e7f4f20a53 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -1866,6 +1866,9 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { let absoluteLeft = this.getColsWidth(0, startCol - 1) || 0; // startCol为0时,absoluteLeft计算为Nan let width = this.getColsWidth(startCol, endCol); const scrollLeft = this.scrollLeft; + + const tableWidth = Math.min(this.tableNoFrameWidth, this.getAllColsWidth()); + const tableHeight = Math.min(this.tableNoFrameHeight, this.getAllRowsHeight()); if (this.isLeftFrozenColumn(startCol) && this.isRightFrozenColumn(endCol)) { width = this.tableNoFrameWidth - (this.getColsWidth(startCol + 1, this.colCount - 1) ?? 0) - absoluteLeft; // width = @@ -1875,10 +1878,10 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { } else if (this.isLeftFrozenColumn(startCol) && !this.isLeftFrozenColumn(endCol)) { width = Math.max(width - scrollLeft, this.getColsWidth(startCol, this.frozenColCount - 1)); } else if (!this.isRightFrozenColumn(startCol) && this.isRightFrozenColumn(endCol)) { - absoluteLeft = Math.min(absoluteLeft - scrollLeft, this.tableNoFrameWidth - this.getRightFrozenColsWidth()); - width = this.tableNoFrameWidth - (this.getColsWidth(startCol + 1, this.colCount - 1) ?? 0) - absoluteLeft; + absoluteLeft = Math.min(absoluteLeft - scrollLeft, tableWidth - this.getRightFrozenColsWidth()); + width = tableWidth - (this.getColsWidth(startCol + 1, this.colCount - 1) ?? 0) - absoluteLeft; } else if (this.isRightFrozenColumn(startCol)) { - absoluteLeft = this.tableNoFrameWidth - (this.getColsWidth(startCol, this.colCount - 1) ?? 0); + absoluteLeft = tableWidth - (this.getColsWidth(startCol, this.colCount - 1) ?? 0); } else { // 范围全部在整体一块区域 如都在右侧冻结区域 都可以走这块逻辑 // do nothing @@ -1896,10 +1899,10 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { } else if (this.isTopFrozenRow(startRow) && !this.isTopFrozenRow(endRow)) { height = Math.max(height - scrollTop, this.getRowsHeight(startRow, this.frozenRowCount - 1)); } else if (!this.isBottomFrozenRow(startRow) && this.isBottomFrozenRow(endRow)) { - absoluteTop = Math.min(absoluteTop - scrollTop, this.tableNoFrameHeight - this.getBottomFrozenRowsHeight()); - height = this.tableNoFrameHeight - (this.getRowsHeight(startRow + 1, this.rowCount - 1) ?? 0) - absoluteTop; + absoluteTop = Math.min(absoluteTop - scrollTop, tableHeight - this.getBottomFrozenRowsHeight()); + height = tableHeight - (this.getRowsHeight(startRow + 1, this.rowCount - 1) ?? 0) - absoluteTop; } else if (this.isBottomFrozenRow(startRow)) { - absoluteTop = this.tableNoFrameHeight - (this.getRowsHeight(startRow, this.rowCount - 1) ?? 0); + absoluteTop = tableHeight - (this.getRowsHeight(startRow, this.rowCount - 1) ?? 0); } else { // 范围全部在整体一块区域 如都在右侧冻结区域 都可以走这块逻辑 // do nothing From 9e6c4d9734e945a7caa845368ef1db6ca40fb825 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Fri, 28 Mar 2025 16:22:14 +0800 Subject: [PATCH 41/51] fix: fix cell radius set in getCellCornerRadius() --- packages/vtable/src/core/tableHelper.ts | 46 +++++++++++++++++-------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/packages/vtable/src/core/tableHelper.ts b/packages/vtable/src/core/tableHelper.ts index 1a41bccd9c..c8695a2ef1 100644 --- a/packages/vtable/src/core/tableHelper.ts +++ b/packages/vtable/src/core/tableHelper.ts @@ -368,25 +368,43 @@ export function getCellCornerRadius(col: number, row: number, table: BaseTableAP const tableCornerRadius = table.theme.frameStyle.cornerRadius; if (table.theme.cellInnerBorder) { if (Array.isArray(tableCornerRadius)) { + const radius = [0, 0, 0, 0]; if (col === 0 && row === 0) { - return [tableCornerRadius[0], 0, 0, 0]; - } else if (col === table.colCount - 1 && row === 0) { - return [0, tableCornerRadius[1], 0, 0]; - } else if (col === 0 && row === table.rowCount - 1) { - return [0, 0, 0, tableCornerRadius[3]]; - } else if (col === table.colCount - 1 && row === table.rowCount - 1) { - return [0, 0, tableCornerRadius[2], 0]; + // return [tableCornerRadius[0], 0, 0, 0]; + radius[0] = tableCornerRadius[0]; } + if (col === table.colCount - 1 && row === 0) { + // return [0, tableCornerRadius[1], 0, 0]; + radius[1] = tableCornerRadius[1]; + } + if (col === 0 && row === table.rowCount - 1) { + // return [0, 0, 0, tableCornerRadius[3]]; + radius[3] = tableCornerRadius[3]; + } + if (col === table.colCount - 1 && row === table.rowCount - 1) { + // return [0, 0, tableCornerRadius[2], 0]; + radius[2] = tableCornerRadius[2]; + } + return radius; } else if (tableCornerRadius) { + const radius = [0, 0, 0, 0]; if (col === 0 && row === 0) { - return [tableCornerRadius, 0, 0, 0]; - } else if (col === table.colCount - 1 && row === 0) { - return [0, tableCornerRadius, 0, 0]; - } else if (col === 0 && row === table.rowCount - 1) { - return [0, 0, 0, tableCornerRadius]; - } else if (col === table.colCount - 1 && row === table.rowCount - 1) { - return [0, 0, tableCornerRadius, 0]; + // return [tableCornerRadius, 0, 0, 0]; + radius[0] = tableCornerRadius; + } + if (col === table.colCount - 1 && row === 0) { + // return [0, tableCornerRadius, 0, 0]; + radius[1] = tableCornerRadius; + } + if (col === 0 && row === table.rowCount - 1) { + // return [0, 0, 0, tableCornerRadius]; + radius[3] = tableCornerRadius; + } + if (col === table.colCount - 1 && row === table.rowCount - 1) { + // return [0, 0, tableCornerRadius, 0]; + radius[2] = tableCornerRadius; } + return radius; } } return 0; From cddba58361aa05da325cfb1d70d7f732a24a9399 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Fri, 28 Mar 2025 16:35:37 +0800 Subject: [PATCH 42/51] feat: add dynamicUpdateSelectionSize config in theme.selectionStyle --- .../vtable/src/scenegraph/select/update-select-border.ts | 9 +++++---- packages/vtable/src/themes/theme.ts | 3 +++ packages/vtable/src/ts-types/theme.ts | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/vtable/src/scenegraph/select/update-select-border.ts b/packages/vtable/src/scenegraph/select/update-select-border.ts index 10e6e96e57..e7ac811b4c 100644 --- a/packages/vtable/src/scenegraph/select/update-select-border.ts +++ b/packages/vtable/src/scenegraph/select/update-select-border.ts @@ -187,11 +187,12 @@ function updateComponent( } } + const { dynamicUpdateSelectionSize } = table.theme.selectionStyle; if ( - (isNearRowHeader && selectComp.rect.attribute.stroke[3]) || - (isNearRightRowHeader && selectComp.rect.attribute.stroke[1]) || - (isNearColHeader && selectComp.rect.attribute.stroke[0]) || - (isNearBottomColHeader && selectComp.rect.attribute.stroke[2]) + (isNearRowHeader && (selectComp.rect.attribute.stroke[3] || dynamicUpdateSelectionSize)) || + (isNearRightRowHeader && (selectComp.rect.attribute.stroke[1] || dynamicUpdateSelectionSize)) || + (isNearColHeader && (selectComp.rect.attribute.stroke[0] || dynamicUpdateSelectionSize)) || + (isNearBottomColHeader && (selectComp.rect.attribute.stroke[2] || dynamicUpdateSelectionSize)) ) { if (isNearRowHeader && selectComp.rect.attribute.stroke[3]) { scene.tableGroup.insertAfter( diff --git a/packages/vtable/src/themes/theme.ts b/packages/vtable/src/themes/theme.ts index 5f5d42f438..94004a960a 100644 --- a/packages/vtable/src/themes/theme.ts +++ b/packages/vtable/src/themes/theme.ts @@ -719,6 +719,9 @@ export class TableTheme implements ITableThemeDefine { }, get selectionFillMode(): 'overlay' | 'replace' { return selectionStyle?.selectionFillMode ?? 'overlay'; + }, + get dynamicUpdateSelectionSize(): boolean { + return selectionStyle?.dynamicUpdateSelectionSize ?? false; } }; } diff --git a/packages/vtable/src/ts-types/theme.ts b/packages/vtable/src/ts-types/theme.ts index 87a0924630..9c9f22fc57 100644 --- a/packages/vtable/src/ts-types/theme.ts +++ b/packages/vtable/src/ts-types/theme.ts @@ -154,6 +154,7 @@ export interface ITableThemeDefine { inlineRowBgColor?: string; //交互所在整行的背景颜色 inlineColumnBgColor?: string; //交互所在整列的背景颜色 selectionFillMode?: 'overlay' | 'replace'; //选择框填充模式,overlay表示选择框背景色覆盖在表格上(需要配饰透明度),replace表示背景色替换原有单元格的背景色 + dynamicUpdateSelectionSize?: boolean; // 选择框大小随滚动动态变化,用于冻结并且背景透明的场景,默认false,开启后性能会有一定影响 }; // style for axis From 8c3196dbd5adf89b412463ad2411d991fc3cab92 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Fri, 28 Mar 2025 16:48:50 +0800 Subject: [PATCH 43/51] chore: update rush change --- .../fix-selected-border-update_2025-03-28-08-48.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json diff --git a/common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json b/common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json new file mode 100644 index 0000000000..e0ad5a0761 --- /dev/null +++ b/common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "feat: add dynamicUpdateSelectionSize config in theme.selectionStyle", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file From ae06d836074b7f5507a8f63dd7ccad44b9cb346c Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Mon, 31 Mar 2025 19:54:48 +0800 Subject: [PATCH 44/51] fix: fix range cache in _updateSize() --- packages/vtable/src/core/BaseTable.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/vtable/src/core/BaseTable.ts b/packages/vtable/src/core/BaseTable.ts index e7f4f20a53..0d8f0f32f9 100644 --- a/packages/vtable/src/core/BaseTable.ts +++ b/packages/vtable/src/core/BaseTable.ts @@ -1167,6 +1167,9 @@ export abstract class BaseTable extends EventTarget implements BaseTableAPI { height - ((lineWidths[0] ?? 0) + (shadowWidths[0] ?? 0)) - ((lineWidths[2] ?? 0) + (shadowWidths[2] ?? 0)); } } + + this._clearColRangeWidthsMap(); + this._clearRowRangeHeightsMap(); } updateViewBox(newViewBox: IBoundsLike) { From d8ea8e123595c12f16ecf4f7c3052ade3f7d64b9 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 16 Apr 2025 20:47:23 +0800 Subject: [PATCH 45/51] fix: fix chart picker logic --- packages/vtable/examples/pivot-chart/pivotChart.ts | 8 ++++---- .../graphic/contributions/vchart-graphic-picker.ts | 14 ++------------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/packages/vtable/examples/pivot-chart/pivotChart.ts b/packages/vtable/examples/pivot-chart/pivotChart.ts index 1d1d37a040..b7edbcda75 100644 --- a/packages/vtable/examples/pivot-chart/pivotChart.ts +++ b/packages/vtable/examples/pivot-chart/pivotChart.ts @@ -9422,10 +9422,10 @@ export function createTable() { cellBgColor: '' } }, - selectionStyle: { - cellBgColor: '', - cellBorderColor: '' - }, + // selectionStyle: { + // cellBgColor: '', + // cellBorderColor: '' + // }, frameStyle: { borderLineWidth: 0 }, diff --git a/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts index b4b345a336..56d3f5471e 100644 --- a/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts +++ b/packages/vtable/src/scenegraph/graphic/contributions/vchart-graphic-picker.ts @@ -9,19 +9,9 @@ export class VChartPicker implements IGraphicPicker { numberType: number = CHART_NUMBER_TYPE; contains(chart: any, point: any, params?: IPickParams): boolean | any { - const vChart = (chart as VChartGraphic).activeChartInstance; - if (!vChart) { + if (!chart.AABBBounds.containsPoint(point)) { return false; } - // 得到 vchart stage - const vchartStage = vChart.getStage(); - vchartStage.dirtyBounds?.clear(); - // 因为vchart 在 vtable 内始坐标变换始终等于在group中的坐标变换,所以这里不需要再做坐标转换 - const pick = vchartStage.pick(point.x, point.y); - // @ts-ignore - if (pick.graphic === null && pick.group.name === 'root') { - return false; - } - return pick; + return true; } } From c90769ba88f57cd65276645771309d9e3f921652 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Apr 2025 06:36:59 +0000 Subject: [PATCH 46/51] build: prelease version 1.17.7 --- ...eforeCacheChartImage_2025-04-14-09-57.json | 11 ------ ...buildin-active-chart_2025-03-27-03-30.json | 11 ------ .../fix-cell-rect_2025-04-15-12-40.json | 10 ------ ...n-with-series-number_2025-04-16-05-30.json | 11 ------ ...fix-switch-direction_2025-04-02-09-23.json | 10 ------ .../fix-image-flash_2025-04-16-06-43.json | 10 ------ ...lected-border-update_2025-03-28-08-48.json | 10 ------ ...fix-stick-row-update_2025-04-16-08-02.json | 10 ------ common/config/rush/version-policies.json | 2 +- packages/openinula-vtable/package.json | 2 +- packages/react-vtable/package.json | 2 +- packages/vtable-calendar/package.json | 2 +- packages/vtable-editors/package.json | 2 +- packages/vtable-export/package.json | 2 +- packages/vtable-gantt/package.json | 2 +- packages/vtable-plugins/package.json | 4 +-- packages/vtable-search/package.json | 2 +- packages/vtable/CHANGELOG.json | 35 +++++++++++++++++++ packages/vtable/CHANGELOG.md | 25 ++++++++++++- packages/vtable/package.json | 4 +-- packages/vue-vtable/package.json | 2 +- 21 files changed, 72 insertions(+), 97 deletions(-) delete mode 100644 common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json delete mode 100644 common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json delete mode 100644 common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json delete mode 100644 common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json delete mode 100644 common/changes/@visactor/vtable/fix-fix-switch-direction_2025-04-02-09-23.json delete mode 100644 common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json delete mode 100644 common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json delete mode 100644 common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json diff --git a/common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json b/common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json deleted file mode 100644 index 8dfb67199d..0000000000 --- a/common/changes/@visactor/vtable/feat-onBeforeCacheChartImage_2025-04-14-09-57.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "feat: add onBeforeCacheChartImage event\n\n", - "type": "none", - "packageName": "@visactor/vtable" - } - ], - "packageName": "@visactor/vtable", - "email": "892739385@qq.com" -} \ No newline at end of file diff --git a/common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json b/common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json deleted file mode 100644 index 9a53f7fd5b..0000000000 --- a/common/changes/@visactor/vtable/feat-support-disable-buildin-active-chart_2025-03-27-03-30.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "feat: support customConfig disableBuildInChartActive\n\n", - "type": "none", - "packageName": "@visactor/vtable" - } - ], - "packageName": "@visactor/vtable", - "email": "lixuef1313@163.com" -} \ No newline at end of file diff --git a/common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json b/common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json deleted file mode 100644 index aa6aca4778..0000000000 --- a/common/changes/@visactor/vtable/fix-cell-rect_2025-04-15-12-40.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@visactor/vtable", - "comment": "fix: fix table size in getCellsRect() #3681", - "type": "none" - } - ], - "packageName": "@visactor/vtable" -} \ No newline at end of file diff --git a/common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json b/common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json deleted file mode 100644 index b6efc9d319..0000000000 --- a/common/changes/@visactor/vtable/fix-column-index-calculation-with-series-number_2025-04-16-05-30.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "fix: correct column index calculation when rowSeriesNumber is configured\n\n", - "type": "none", - "packageName": "@visactor/vtable" - } - ], - "packageName": "@visactor/vtable", - "email": "zzh7498624@163.com" -} \ No newline at end of file diff --git a/common/changes/@visactor/vtable/fix-fix-switch-direction_2025-04-02-09-23.json b/common/changes/@visactor/vtable/fix-fix-switch-direction_2025-04-02-09-23.json deleted file mode 100644 index 629f20f3ce..0000000000 --- a/common/changes/@visactor/vtable/fix-fix-switch-direction_2025-04-02-09-23.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@visactor/vtable", - "comment": "fix: fix switch default direction #3667", - "type": "minor" - } - ], - "packageName": "@visactor/vtable" -} \ No newline at end of file diff --git a/common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json b/common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json deleted file mode 100644 index 955f26695b..0000000000 --- a/common/changes/@visactor/vtable/fix-image-flash_2025-04-16-06-43.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@visactor/vtable", - "comment": "fix: fix image flash problem #3588", - "type": "none" - } - ], - "packageName": "@visactor/vtable" -} \ No newline at end of file diff --git a/common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json b/common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json deleted file mode 100644 index e0ad5a0761..0000000000 --- a/common/changes/@visactor/vtable/fix-selected-border-update_2025-03-28-08-48.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@visactor/vtable", - "comment": "feat: add dynamicUpdateSelectionSize config in theme.selectionStyle", - "type": "none" - } - ], - "packageName": "@visactor/vtable" -} \ No newline at end of file diff --git a/common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json b/common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json deleted file mode 100644 index 3fcf8453dd..0000000000 --- a/common/changes/@visactor/vtable/fix-stick-row-update_2025-04-16-08-02.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@visactor/vtable", - "comment": "fix: fix row/column update problem in text-stick #3744", - "type": "none" - } - ], - "packageName": "@visactor/vtable" -} \ No newline at end of file diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 7f3d48cab2..7b96897f70 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -1 +1 @@ -[{"definitionName":"lockStepVersion","policyName":"vtableMain","version":"1.17.6","mainProject":"@visactor/vtable","nextBump":"patch"}] +[{"definitionName":"lockStepVersion","policyName":"vtableMain","version":"1.17.7","mainProject":"@visactor/vtable","nextBump":"patch"}] diff --git a/packages/openinula-vtable/package.json b/packages/openinula-vtable/package.json index c63269c6a7..c1562270d2 100644 --- a/packages/openinula-vtable/package.json +++ b/packages/openinula-vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/openinula-vtable", - "version": "1.17.6", + "version": "1.17.7", "description": "The openinula version of VTable", "keywords": [ "openinula", diff --git a/packages/react-vtable/package.json b/packages/react-vtable/package.json index 1a3b7899db..3fb9dd22a6 100644 --- a/packages/react-vtable/package.json +++ b/packages/react-vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/react-vtable", - "version": "1.17.6", + "version": "1.17.7", "description": "The react version of VTable", "keywords": [ "react", diff --git a/packages/vtable-calendar/package.json b/packages/vtable-calendar/package.json index 2beae330c5..2bc2a80bca 100644 --- a/packages/vtable-calendar/package.json +++ b/packages/vtable-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-calendar", - "version": "1.17.6", + "version": "1.17.7", "description": "The calendar component of VTable", "author": { "name": "VisActor", diff --git a/packages/vtable-editors/package.json b/packages/vtable-editors/package.json index 6d098ddc61..e389e84a68 100644 --- a/packages/vtable-editors/package.json +++ b/packages/vtable-editors/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-editors", - "version": "1.17.6", + "version": "1.17.7", "description": "", "sideEffects": false, "main": "cjs/index.js", diff --git a/packages/vtable-export/package.json b/packages/vtable-export/package.json index e74f5de67f..db3aa1ee6f 100644 --- a/packages/vtable-export/package.json +++ b/packages/vtable-export/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-export", - "version": "1.17.6", + "version": "1.17.7", "description": "The export util of VTable", "author": { "name": "VisActor", diff --git a/packages/vtable-gantt/package.json b/packages/vtable-gantt/package.json index 6f90da0999..cf020ffb19 100644 --- a/packages/vtable-gantt/package.json +++ b/packages/vtable-gantt/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-gantt", - "version": "1.17.6", + "version": "1.17.7", "description": "canvas table width high performance", "keywords": [ "vtable-gantt", diff --git a/packages/vtable-plugins/package.json b/packages/vtable-plugins/package.json index 243f1ebad7..14a7060281 100644 --- a/packages/vtable-plugins/package.json +++ b/packages/vtable-plugins/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-plugins", - "version": "1.17.6", + "version": "1.17.7", "description": "The search util of VTable", "author": { "name": "VisActor", @@ -87,4 +87,4 @@ "@types/react-is": "^17.0.3", "rollup-plugin-node-resolve": "5.2.0" } -} \ No newline at end of file +} diff --git a/packages/vtable-search/package.json b/packages/vtable-search/package.json index 46c96076a0..562576bf01 100644 --- a/packages/vtable-search/package.json +++ b/packages/vtable-search/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-search", - "version": "1.17.6", + "version": "1.17.7", "description": "The search util of VTable", "author": { "name": "VisActor", diff --git a/packages/vtable/CHANGELOG.json b/packages/vtable/CHANGELOG.json index b3c55464ef..0a41c48e52 100644 --- a/packages/vtable/CHANGELOG.json +++ b/packages/vtable/CHANGELOG.json @@ -1,6 +1,41 @@ { "name": "@visactor/vtable", "entries": [ + { + "version": "1.17.7", + "tag": "@visactor/vtable_v1.17.7", + "date": "Thu, 17 Apr 2025 06:30:44 GMT", + "comments": { + "none": [ + { + "comment": "feat: add onBeforeCacheChartImage event\n\n" + }, + { + "comment": "feat: support customConfig disableBuildInChartActive\n\n" + }, + { + "comment": "fix: fix table size in getCellsRect() #3681" + }, + { + "comment": "fix: correct column index calculation when rowSeriesNumber is configured\n\n" + }, + { + "comment": "fix: fix image flash problem #3588" + }, + { + "comment": "feat: add dynamicUpdateSelectionSize config in theme.selectionStyle" + }, + { + "comment": "fix: fix row/column update problem in text-stick #3744" + } + ], + "minor": [ + { + "comment": "fix: fix switch default direction #3667" + } + ] + } + }, { "version": "1.17.6", "tag": "@visactor/vtable_v1.17.6", diff --git a/packages/vtable/CHANGELOG.md b/packages/vtable/CHANGELOG.md index ad902f033d..fc2bcd7313 100644 --- a/packages/vtable/CHANGELOG.md +++ b/packages/vtable/CHANGELOG.md @@ -1,6 +1,29 @@ # Change Log - @visactor/vtable -This log was last generated on Thu, 10 Apr 2025 09:18:51 GMT and should not be manually modified. +This log was last generated on Thu, 17 Apr 2025 06:30:44 GMT and should not be manually modified. + +## 1.17.7 +Thu, 17 Apr 2025 06:30:44 GMT + +### Minor changes + +- fix: fix switch default direction #3667 + +### Updates + +- feat: add onBeforeCacheChartImage event + + +- feat: support customConfig disableBuildInChartActive + + +- fix: fix table size in getCellsRect() #3681 +- fix: correct column index calculation when rowSeriesNumber is configured + + +- fix: fix image flash problem #3588 +- feat: add dynamicUpdateSelectionSize config in theme.selectionStyle +- fix: fix row/column update problem in text-stick #3744 ## 1.17.6 Thu, 10 Apr 2025 09:18:51 GMT diff --git a/packages/vtable/package.json b/packages/vtable/package.json index bf25048a35..6de063e8fc 100644 --- a/packages/vtable/package.json +++ b/packages/vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable", - "version": "1.17.6", + "version": "1.17.7", "description": "canvas table width high performance", "keywords": [ "grid", @@ -129,4 +129,4 @@ "url": "https://github.com/VisActor/VTable.git", "directory": "packages/vtable" } -} \ No newline at end of file +} diff --git a/packages/vue-vtable/package.json b/packages/vue-vtable/package.json index 17bb6f86b0..b7164769b0 100644 --- a/packages/vue-vtable/package.json +++ b/packages/vue-vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vue-vtable", - "version": "1.17.6", + "version": "1.17.7", "description": "The vue version of VTable", "keywords": [ "vue", From 672225aad3687a570e62811c9d1348eb17d3a3c2 Mon Sep 17 00:00:00 2001 From: fangsmile Date: Thu, 17 Apr 2025 06:54:21 +0000 Subject: [PATCH 47/51] docs: generate changelog of release v1.17.7 --- docs/assets/changelog/en/release.md | 23 +++++++++++++++++++++++ docs/assets/changelog/zh/release.md | 23 +++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/docs/assets/changelog/en/release.md b/docs/assets/changelog/en/release.md index 71d91e1a83..f493b2e12b 100644 --- a/docs/assets/changelog/en/release.md +++ b/docs/assets/changelog/en/release.md @@ -1,3 +1,26 @@ +# v1.17.7 + +2025-04-17 + + +**🆕 New feature** + +- **@visactor/vtable**: add onBeforeCacheChartImage event +- **@visactor/vtable**: support customConfig disableBuildInChartActive +- **@visactor/vtable**: add dynamicUpdateSelectionSize config in theme.selectionStyle + +**🐛 Bug fix** + +- **@visactor/vtable**: fix table size in getCellsRect() [#3681](https://github.com/VisActor/VTable/issues/3681) +- **@visactor/vtable**: correct column index calculation when rowSeriesNumber is configured +- **@visactor/vtable**: fix image flash problem [#3588](https://github.com/VisActor/VTable/issues/3588) +- **@visactor/vtable**: fix row/column update problem in text-stick [#3744](https://github.com/VisActor/VTable/issues/3744) +- **@visactor/vtable**: fix switch default direction [#3667](https://github.com/VisActor/VTable/issues/3667) + + + +[more detail about v1.17.7](https://github.com/VisActor/VTable/releases/tag/v1.17.7) + # v1.17.6 2025-04-10 diff --git a/docs/assets/changelog/zh/release.md b/docs/assets/changelog/zh/release.md index 0b5da6c5eb..576b0200d6 100644 --- a/docs/assets/changelog/zh/release.md +++ b/docs/assets/changelog/zh/release.md @@ -1,3 +1,26 @@ +# v1.17.7 + +2025-04-17 + + +**🆕 新增功能** + +- **@visactor/vtable**: add onBeforeCacheChartImage event +- **@visactor/vtable**: support customConfig disableBuildInChartActive +- **@visactor/vtable**: add dynamicUpdateSelectionSize config in theme.selectionStyle + +**🐛 功能修复** + +- **@visactor/vtable**: fix table size in getCellsRect() [#3681](https://github.com/VisActor/VTable/issues/3681) +- **@visactor/vtable**: correct column index calculation when rowSeriesNumber is configured +- **@visactor/vtable**: fix image flash problem [#3588](https://github.com/VisActor/VTable/issues/3588) +- **@visactor/vtable**: fix row/column update problem in text-stick [#3744](https://github.com/VisActor/VTable/issues/3744) +- **@visactor/vtable**: fix switch default direction [#3667](https://github.com/VisActor/VTable/issues/3667) + + + +[更多详情请查看 v1.17.7](https://github.com/VisActor/VTable/releases/tag/v1.17.7) + # v1.17.6 2025-04-10 From 08d5d4d84576410ea706f88a9e0af03f0a0df274 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 17 Apr 2025 15:32:16 +0800 Subject: [PATCH 48/51] chore: release 1.18.0 --- .../vtable/chore-release-minor_2025-04-17-07-31.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json diff --git a/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json b/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json new file mode 100644 index 0000000000..425c4841c6 --- /dev/null +++ b/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "chore: release 1.18.0", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file From 624a4b163db7d4f8eaad48d58e2bb6ece4607fdf Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 17 Apr 2025 15:42:29 +0800 Subject: [PATCH 49/51] docs: update release log --- docs/assets/changelog/en/release.md | 119 +++++++++++++++------------- docs/assets/changelog/zh/release.md | 28 ++++--- 2 files changed, 78 insertions(+), 69 deletions(-) diff --git a/docs/assets/changelog/en/release.md b/docs/assets/changelog/en/release.md index f493b2e12b..ce12ec6dfc 100644 --- a/docs/assets/changelog/en/release.md +++ b/docs/assets/changelog/en/release.md @@ -1,22 +1,27 @@ -# v1.17.7 +# v1.18.0 + v1.17.7 same content 2025-04-17 +**💥 Breaking change** + +- **@visactor/vtable**: fix switch default direction [#3667](https://github.com/VisActor/VTable/issues/3667) +- **@visactor/vtable-editors**: fix input editor default style **🆕 New feature** - -- **@visactor/vtable**: add onBeforeCacheChartImage event -- **@visactor/vtable**: support customConfig disableBuildInChartActive -- **@visactor/vtable**: add dynamicUpdateSelectionSize config in theme.selectionStyle + +- **@visactor/vtable**: add onBeforeCacheChartImage event +- **@visactor/vtable**: support customConfig disableBuildInChartActive +- **@visactor/vtable**: add dynamicUpdateSelectionSize config in theme.selectionStyle **🐛 Bug fix** - -- **@visactor/vtable**: fix table size in getCellsRect() [#3681](https://github.com/VisActor/VTable/issues/3681) -- **@visactor/vtable**: correct column index calculation when rowSeriesNumber is configured -- **@visactor/vtable**: fix image flash problem [#3588](https://github.com/VisActor/VTable/issues/3588) -- **@visactor/vtable**: fix row/column update problem in text-stick [#3744](https://github.com/VisActor/VTable/issues/3744) -- **@visactor/vtable**: fix switch default direction [#3667](https://github.com/VisActor/VTable/issues/3667) - + +- **@visactor/vtable**: fix table size in getCellsRect() [#3681](https://github.com/VisActor/VTable/issues/3681) +- **@visactor/vtable**: correct column index calculation when rowSeriesNumber is configured +- **@visactor/vtable**: fix image flash problem [#3588](https://github.com/VisActor/VTable/issues/3588) +- **@visactor/vtable**: fix row/column update problem in text-stick [#3744](https://github.com/VisActor/VTable/issues/3744) +- **@visactor/vtable**: fix switch default direction [#3667](https://github.com/VisActor/VTable/issues/3667) + [more detail about v1.17.7](https://github.com/VisActor/VTable/releases/tag/v1.17.7) @@ -27,20 +32,20 @@ **🆕 New feature** - -- **@visactor/vtable**: listTable added tiggerEvent parameter to changeCellValue -- **@visactor/vtable**: list table header support hierarchy + +- **@visactor/vtable**: listTable added tiggerEvent parameter to changeCellValue +- **@visactor/vtable**: list table header support hierarchy **🐛 Bug fix** - -- **@visactor/vtable**: when move tree node position code occor error [#3645](https://github.com/VisActor/VTable/issues/3645) [#3706](https://github.com/VisActor/VTable/issues/3706) -- **@visactor/vtable**: frame border set array render bottom line position error [#3684](https://github.com/VisActor/VTable/issues/3684) -- **@visactor/vtable**: mobile touch event resize column width [#3693](https://github.com/VisActor/VTable/issues/3693) -- **@visactor/vtable**: when set frozen disableDragSelect not work [#3702](https://github.com/VisActor/VTable/issues/3702) -- **@visactor/vtable**: fix flex layout update in react-custom-layout component [#3696](https://github.com/VisActor/VTable/issues/3696) -- **@visactor/vtable**: updateTaskRecord api [#3639](https://github.com/VisActor/VTable/issues/3639) -- **@visactor/vtable**: repeat call computeColsWidth adaptive mode result error - + +- **@visactor/vtable**: when move tree node position code occor error [#3645](https://github.com/VisActor/VTable/issues/3645) [#3706](https://github.com/VisActor/VTable/issues/3706) +- **@visactor/vtable**: frame border set array render bottom line position error [#3684](https://github.com/VisActor/VTable/issues/3684) +- **@visactor/vtable**: mobile touch event resize column width [#3693](https://github.com/VisActor/VTable/issues/3693) +- **@visactor/vtable**: when set frozen disableDragSelect not work [#3702](https://github.com/VisActor/VTable/issues/3702) +- **@visactor/vtable**: fix flex layout update in react-custom-layout component [#3696](https://github.com/VisActor/VTable/issues/3696) +- **@visactor/vtable**: updateTaskRecord api [#3639](https://github.com/VisActor/VTable/issues/3639) +- **@visactor/vtable**: repeat call computeColsWidth adaptive mode result error + [more detail about v1.17.6](https://github.com/VisActor/VTable/releases/tag/v1.17.6) @@ -51,23 +56,23 @@ **🆕 New feature** - -- **@visactor/vtable**: cell support marked function [#3583](https://github.com/VisActor/VTable/issues/3583) -- **@visactor/vtable**: refactor pivotTable corner with no columns or rows case [#3653](https://github.com/VisActor/VTable/issues/3653) + +- **@visactor/vtable**: cell support marked function [#3583](https://github.com/VisActor/VTable/issues/3583) +- **@visactor/vtable**: refactor pivotTable corner with no columns or rows case [#3653](https://github.com/VisActor/VTable/issues/3653) **🐛 Bug fix** - -- **@visactor/vtable**: gantt scale set quarter parser problem [#3612](https://github.com/VisActor/VTable/issues/3612) -- **@visactor/vtable**: gantt overscrollBehavior none work [#3638](https://github.com/VisActor/VTable/issues/3638) -- **@visactor/vtable**: gantt chart updateRecords error when table is tree mode [#3639](https://github.com/VisActor/VTable/issues/3639) -- **@visactor/vtable**: rowHeight error when set adaptive heightMode [#3640](https://github.com/VisActor/VTable/issues/3640) -- **@visactor/vtable**: when set renderChartAsync setRecords api render error [#3661](https://github.com/VisActor/VTable/issues/3661) -- **@visactor/vtable**: fix merge cell checkbox state update [#3668](https://github.com/VisActor/VTable/issues/3668) + +- **@visactor/vtable**: gantt scale set quarter parser problem [#3612](https://github.com/VisActor/VTable/issues/3612) +- **@visactor/vtable**: gantt overscrollBehavior none work [#3638](https://github.com/VisActor/VTable/issues/3638) +- **@visactor/vtable**: gantt chart updateRecords error when table is tree mode [#3639](https://github.com/VisActor/VTable/issues/3639) +- **@visactor/vtable**: rowHeight error when set adaptive heightMode [#3640](https://github.com/VisActor/VTable/issues/3640) +- **@visactor/vtable**: when set renderChartAsync setRecords api render error [#3661](https://github.com/VisActor/VTable/issues/3661) +- **@visactor/vtable**: fix merge cell checkbox state update [#3668](https://github.com/VisActor/VTable/issues/3668) **🔨 Refactor** - -- **@visactor/vtable**: fillHandle function [#3582](https://github.com/VisActor/VTable/issues/3582) - + +- **@visactor/vtable**: fillHandle function [#3582](https://github.com/VisActor/VTable/issues/3582) + [more detail about v1.17.5](https://github.com/VisActor/VTable/releases/tag/v1.17.5) @@ -78,15 +83,15 @@ **🆕 New feature** - -- **@visactor/vtable**: add barMarkInBar style config in progressbar [#3616](https://github.com/VisActor/VTable/issues/3616) + +- **@visactor/vtable**: add barMarkInBar style config in progressbar [#3616](https://github.com/VisActor/VTable/issues/3616) **🐛 Bug fix** - -- **@visactor/vtable**: fix button style problem [#3614](https://github.com/VisActor/VTable/issues/3614) -- **@visactor/vtable**: fix checkbox state order update [#3606](https://github.com/VisActor/VTable/issues/3606) -- **@visactor/vtable**: add isCustom tag for merge cell range [#3504](https://github.com/VisActor/VTable/issues/3504) -- **@visactor/vtable**: fix tree checkbox state update problem + +- **@visactor/vtable**: fix button style problem [#3614](https://github.com/VisActor/VTable/issues/3614) +- **@visactor/vtable**: fix checkbox state order update [#3606](https://github.com/VisActor/VTable/issues/3606) +- **@visactor/vtable**: add isCustom tag for merge cell range [#3504](https://github.com/VisActor/VTable/issues/3504) +- **@visactor/vtable**: fix tree checkbox state update problem - **@visactor/vtable**: disable group title editor [more detail about v1.17.4](https://github.com/VisActor/VTable/releases/tag/v1.17.4) @@ -97,21 +102,21 @@ **🆕 New feature** - -- **@visactor/vtable**: rowSeriesNumber support cell type radio [#3558](https://github.com/VisActor/VTable/issues/3558) -- **@visactor/vtable**: add custom reactAttributePlugin in react-vtable -- **@visactor/vtable**: add maintainedColumnCount config + +- **@visactor/vtable**: rowSeriesNumber support cell type radio [#3558](https://github.com/VisActor/VTable/issues/3558) +- **@visactor/vtable**: add custom reactAttributePlugin in react-vtable +- **@visactor/vtable**: add maintainedColumnCount config **🐛 Bug fix** - -- **@visactor/vtable**: selection mergeCell extend range [#3529](https://github.com/VisActor/VTable/issues/3529) -- **@visactor/vtable**: set cellInnerBorder false frame border render error [#3574](https://github.com/VisActor/VTable/issues/3574) -- **@visactor/vtable**: fix cell border in cell with corner-radius -- **@visactor/vtable**: fix axis label autosize computation -- **@visactor/vtable**: fix small window size frozen column count -- **@visactor/vtable**: columnWidthConfig match dimension error -- **@visactor/vtable**: fix react component update [#3474](https://github.com/VisActor/VTable/issues/3474) -- **@visactor/vtable**: fix right button select problem + +- **@visactor/vtable**: selection mergeCell extend range [#3529](https://github.com/VisActor/VTable/issues/3529) +- **@visactor/vtable**: set cellInnerBorder false frame border render error [#3574](https://github.com/VisActor/VTable/issues/3574) +- **@visactor/vtable**: fix cell border in cell with corner-radius +- **@visactor/vtable**: fix axis label autosize computation +- **@visactor/vtable**: fix small window size frozen column count +- **@visactor/vtable**: columnWidthConfig match dimension error +- **@visactor/vtable**: fix react component update [#3474](https://github.com/VisActor/VTable/issues/3474) +- **@visactor/vtable**: fix right button select problem - **@visactor/vtable**: fix row update range [#3468](https://github.com/VisActor/VTable/issues/3468) [more detail about v1.17.3](https://github.com/VisActor/VTable/releases/tag/v1.17.3) diff --git a/docs/assets/changelog/zh/release.md b/docs/assets/changelog/zh/release.md index 576b0200d6..002700d3fb 100644 --- a/docs/assets/changelog/zh/release.md +++ b/docs/assets/changelog/zh/release.md @@ -1,22 +1,26 @@ -# v1.17.7 +# v1.18.0 + v1.17.7 版本相同内容 2025-04-17 +**💥 Breaking change** + +- **@visactor/vtable**: 修复 switch 默认方向问题 [#3667](https://github.com/VisActor/VTable/issues/3667) +- **@visactor/vtable-editors**: 修改了input编辑器中的默认样式 **🆕 新增功能** - -- **@visactor/vtable**: add onBeforeCacheChartImage event -- **@visactor/vtable**: support customConfig disableBuildInChartActive -- **@visactor/vtable**: add dynamicUpdateSelectionSize config in theme.selectionStyle +- **@visactor/vtable-plugins**: 新增 行列新增 行列序号 excel键盘对齐等插件 +- **@visactor/vtable**: 新增 onBeforeCacheChartImage 事件 +- **@visactor/vtable**: 支持 customConfig disableBuildInChartActive 配置 +- **@visactor/vtable**: 在 theme.selectionStyle 中新增 dynamicUpdateSelectionSize 配置 **🐛 功能修复** - -- **@visactor/vtable**: fix table size in getCellsRect() [#3681](https://github.com/VisActor/VTable/issues/3681) -- **@visactor/vtable**: correct column index calculation when rowSeriesNumber is configured -- **@visactor/vtable**: fix image flash problem [#3588](https://github.com/VisActor/VTable/issues/3588) -- **@visactor/vtable**: fix row/column update problem in text-stick [#3744](https://github.com/VisActor/VTable/issues/3744) -- **@visactor/vtable**: fix switch default direction [#3667](https://github.com/VisActor/VTable/issues/3667) - + +- **@visactor/vtable**: 修复 getCellsRect() 中表格大小问题 [#3681](https://github.com/VisActor/VTable/issues/3681) +- **@visactor/vtable**: 修复配置 rowSeriesNumber 时列索引计算错误问题 +- **@visactor/vtable**: 修复图片闪烁问题 [#3588](https://github.com/VisActor/VTable/issues/3588) +- **@visactor/vtable**: 修复 text-stick 中行/列更新问题 [#3744](https://github.com/VisActor/VTable/issues/3744) + [更多详情请查看 v1.17.7](https://github.com/VisActor/VTable/releases/tag/v1.17.7) From faca7fcaa2966f616b462e985b05fc6512e048f6 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 17 Apr 2025 15:32:16 +0800 Subject: [PATCH 50/51] chore: release 1.18.0 --- .../vtable/chore-release-minor_2025-04-17-07-31.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json diff --git a/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json b/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json new file mode 100644 index 0000000000..425c4841c6 --- /dev/null +++ b/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vtable", + "comment": "chore: release 1.18.0", + "type": "none" + } + ], + "packageName": "@visactor/vtable" +} \ No newline at end of file From 3c61988580a9616e741696c776be36095c0c5d18 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Apr 2025 07:48:11 +0000 Subject: [PATCH 51/51] build: prelease version 1.18.0 --- .../vtable/chore-release-minor_2025-04-17-07-31.json | 10 ---------- common/config/rush/version-policies.json | 2 +- packages/openinula-vtable/package.json | 2 +- packages/react-vtable/package.json | 2 +- packages/vtable-calendar/package.json | 2 +- packages/vtable-editors/package.json | 2 +- packages/vtable-export/package.json | 2 +- packages/vtable-gantt/package.json | 2 +- packages/vtable-plugins/package.json | 2 +- packages/vtable-search/package.json | 2 +- packages/vtable/CHANGELOG.json | 12 ++++++++++++ packages/vtable/CHANGELOG.md | 9 ++++++++- packages/vtable/package.json | 2 +- packages/vue-vtable/package.json | 2 +- 14 files changed, 31 insertions(+), 22 deletions(-) delete mode 100644 common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json diff --git a/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json b/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json deleted file mode 100644 index 425c4841c6..0000000000 --- a/common/changes/@visactor/vtable/chore-release-minor_2025-04-17-07-31.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@visactor/vtable", - "comment": "chore: release 1.18.0", - "type": "none" - } - ], - "packageName": "@visactor/vtable" -} \ No newline at end of file diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 7b96897f70..f92b8ea905 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -1 +1 @@ -[{"definitionName":"lockStepVersion","policyName":"vtableMain","version":"1.17.7","mainProject":"@visactor/vtable","nextBump":"patch"}] +[{"definitionName":"lockStepVersion","policyName":"vtableMain","version":"1.18.0","mainProject":"@visactor/vtable","nextBump":"minor"}] diff --git a/packages/openinula-vtable/package.json b/packages/openinula-vtable/package.json index c1562270d2..7ac2e0858c 100644 --- a/packages/openinula-vtable/package.json +++ b/packages/openinula-vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/openinula-vtable", - "version": "1.17.7", + "version": "1.18.0", "description": "The openinula version of VTable", "keywords": [ "openinula", diff --git a/packages/react-vtable/package.json b/packages/react-vtable/package.json index 3fb9dd22a6..eff744bdf5 100644 --- a/packages/react-vtable/package.json +++ b/packages/react-vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/react-vtable", - "version": "1.17.7", + "version": "1.18.0", "description": "The react version of VTable", "keywords": [ "react", diff --git a/packages/vtable-calendar/package.json b/packages/vtable-calendar/package.json index 2bc2a80bca..b0a9e4b3ac 100644 --- a/packages/vtable-calendar/package.json +++ b/packages/vtable-calendar/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-calendar", - "version": "1.17.7", + "version": "1.18.0", "description": "The calendar component of VTable", "author": { "name": "VisActor", diff --git a/packages/vtable-editors/package.json b/packages/vtable-editors/package.json index e389e84a68..431030b0ae 100644 --- a/packages/vtable-editors/package.json +++ b/packages/vtable-editors/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-editors", - "version": "1.17.7", + "version": "1.18.0", "description": "", "sideEffects": false, "main": "cjs/index.js", diff --git a/packages/vtable-export/package.json b/packages/vtable-export/package.json index db3aa1ee6f..83be2ea256 100644 --- a/packages/vtable-export/package.json +++ b/packages/vtable-export/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-export", - "version": "1.17.7", + "version": "1.18.0", "description": "The export util of VTable", "author": { "name": "VisActor", diff --git a/packages/vtable-gantt/package.json b/packages/vtable-gantt/package.json index cf020ffb19..efee7f01ce 100644 --- a/packages/vtable-gantt/package.json +++ b/packages/vtable-gantt/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-gantt", - "version": "1.17.7", + "version": "1.18.0", "description": "canvas table width high performance", "keywords": [ "vtable-gantt", diff --git a/packages/vtable-plugins/package.json b/packages/vtable-plugins/package.json index 14a7060281..2751355e80 100644 --- a/packages/vtable-plugins/package.json +++ b/packages/vtable-plugins/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-plugins", - "version": "1.17.7", + "version": "1.18.0", "description": "The search util of VTable", "author": { "name": "VisActor", diff --git a/packages/vtable-search/package.json b/packages/vtable-search/package.json index 562576bf01..442db1412e 100644 --- a/packages/vtable-search/package.json +++ b/packages/vtable-search/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable-search", - "version": "1.17.7", + "version": "1.18.0", "description": "The search util of VTable", "author": { "name": "VisActor", diff --git a/packages/vtable/CHANGELOG.json b/packages/vtable/CHANGELOG.json index 0a41c48e52..753232d089 100644 --- a/packages/vtable/CHANGELOG.json +++ b/packages/vtable/CHANGELOG.json @@ -1,6 +1,18 @@ { "name": "@visactor/vtable", "entries": [ + { + "version": "1.18.0", + "tag": "@visactor/vtable_v1.18.0", + "date": "Thu, 17 Apr 2025 07:40:27 GMT", + "comments": { + "none": [ + { + "comment": "chore: release 1.18.0" + } + ] + } + }, { "version": "1.17.7", "tag": "@visactor/vtable_v1.17.7", diff --git a/packages/vtable/CHANGELOG.md b/packages/vtable/CHANGELOG.md index fc2bcd7313..2669e11f84 100644 --- a/packages/vtable/CHANGELOG.md +++ b/packages/vtable/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log - @visactor/vtable -This log was last generated on Thu, 17 Apr 2025 06:30:44 GMT and should not be manually modified. +This log was last generated on Thu, 17 Apr 2025 07:40:27 GMT and should not be manually modified. + +## 1.18.0 +Thu, 17 Apr 2025 07:40:27 GMT + +### Updates + +- chore: release 1.18.0 ## 1.17.7 Thu, 17 Apr 2025 06:30:44 GMT diff --git a/packages/vtable/package.json b/packages/vtable/package.json index 6de063e8fc..f1664253d8 100644 --- a/packages/vtable/package.json +++ b/packages/vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vtable", - "version": "1.17.7", + "version": "1.18.0", "description": "canvas table width high performance", "keywords": [ "grid", diff --git a/packages/vue-vtable/package.json b/packages/vue-vtable/package.json index b7164769b0..c2158d07bc 100644 --- a/packages/vue-vtable/package.json +++ b/packages/vue-vtable/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vue-vtable", - "version": "1.17.7", + "version": "1.18.0", "description": "The vue version of VTable", "keywords": [ "vue",