diff --git a/packages/s2-core/__tests__/spreadsheet/spread-sheet-resize-spec.ts b/packages/s2-core/__tests__/spreadsheet/spread-sheet-resize-spec.ts index 43969361fc..a193347ade 100644 --- a/packages/s2-core/__tests__/spreadsheet/spread-sheet-resize-spec.ts +++ b/packages/s2-core/__tests__/spreadsheet/spread-sheet-resize-spec.ts @@ -118,4 +118,46 @@ describe('SpreadSheet Resize Active Tests', () => { expect(group.findById(KEY_GROUP_COL_RESIZE_AREA)).toBeDefined(); }); + + test('should disable all cell resize area by visible', () => { + const s2 = renderSheet({ + interaction: { + resize: { + visible: () => false, + }, + }, + } as S2Options); + + const group = s2.facet.foregroundGroup; + + [ + KEY_GROUP_CORNER_RESIZE_AREA, + KEY_GROUP_COL_RESIZE_AREA, + KEY_GROUP_ROW_RESIZE_AREA, + ].forEach((key) => { + expect(group.findById(key)).toBeNull(); + }); + }); + + test('should only show col cell resize area by visible', () => { + const s2 = renderSheet({ + interaction: { + resize: { + visible: (cell) => { + const meta = cell.getMeta(); + return meta.id === 'root[&]笔[&]price'; + }, + }, + }, + } as S2Options); + + const group = s2.facet.foregroundGroup; + const colResizeGroups = group + .getChildren() + .filter((element) => element.cfg.id === KEY_GROUP_COL_RESIZE_AREA); + + expect(colResizeGroups).toHaveLength(1); + expect(group.findById(KEY_GROUP_ROW_RESIZE_AREA)).toBeNull(); + expect(group.findById(KEY_GROUP_CORNER_RESIZE_AREA)).toBeNull(); + }); }); diff --git a/packages/s2-core/__tests__/unit/interaction/row-column-resize-spec.ts b/packages/s2-core/__tests__/unit/interaction/row-column-resize-spec.ts index 3f6bfc77f5..bc14438738 100644 --- a/packages/s2-core/__tests__/unit/interaction/row-column-resize-spec.ts +++ b/packages/s2-core/__tests__/unit/interaction/row-column-resize-spec.ts @@ -54,19 +54,19 @@ describe('Interaction Row Column Resize Tests', () => { }; const getStartGuideLine = () => { - return rowColumnResizeInstance.resizeReferenceGroup.findById( + return rowColumnResizeInstance.resizeReferenceGroup?.findById( RESIZE_START_GUIDE_LINE_ID, ) as IShape; }; const getEndGuideLine = () => { - return rowColumnResizeInstance.resizeReferenceGroup.findById( + return rowColumnResizeInstance.resizeReferenceGroup?.findById( RESIZE_END_GUIDE_LINE_ID, ) as IShape; }; const getResizeMask = () => { - return rowColumnResizeInstance.resizeReferenceGroup.findById( + return rowColumnResizeInstance.resizeReferenceGroup?.findById( RESIZE_MASK_ID, ) as IShape; }; @@ -502,4 +502,84 @@ describe('Interaction Row Column Resize Tests', () => { ); expect(s2.interaction.reset).toHaveBeenCalledTimes(1); }); + + test('should not update col width after resized if resize disabled', () => { + s2.setOptions({ + interaction: { + resize: { + disable: () => true, + }, + }, + }); + + const resizeInfo = emitResize( + ResizeDirectionType.Horizontal, + ResizeAreaEffect.Field, + ); + + expect(s2.options.style.rowCfg.widthByField).toEqual({ + [resizeInfo.id]: resizeInfo.width, + }); + }); + + test('should set no drop cursor and gray guide line if disable resize', () => { + const disable = jest.fn(() => true); + + s2.setOptions({ + interaction: { + resize: { + disable, + }, + }, + }); + + const resizeInfo = { + theme: {}, + type: ResizeDirectionType.Vertical, + offsetX: 2, + offsetY: 2, + width: 5, + height: 2, + isResizeArea: true, + effect: ResizeAreaEffect.Cell, + id: '', + } as ResizeInfo; + + emitResizeEvent( + S2Event.LAYOUT_RESIZE_MOUSE_DOWN, + { + offsetX: 10, + offsetY: 20, + }, + resizeInfo, + ); + + emitResizeEvent( + S2Event.LAYOUT_RESIZE_MOUSE_MOVE, + { + offsetX: 20, + offsetY: 20, + }, + resizeInfo, + ); + + expect(getResizeMask().attr('cursor')).toEqual('no-drop'); + expect(getEndGuideLine().attr('stroke')).toEqual('rgba(0,0,0,0.25)'); + expect(disable).toHaveBeenCalledWith({ + ...resizeInfo, + resizedWidth: 0, + resizedHeight: 16, + }); + + emitResizeEvent( + S2Event.GLOBAL_MOUSE_UP, + { + offsetX: 20, + offsetY: 20, + }, + resizeInfo, + ); + + expect(getResizeMask()).toBeFalsy(); + }); }); diff --git a/packages/s2-core/src/cell/base-cell.ts b/packages/s2-core/src/cell/base-cell.ts index d675b12463..7dec33e242 100644 --- a/packages/s2-core/src/cell/base-cell.ts +++ b/packages/s2-core/src/cell/base-cell.ts @@ -1,6 +1,15 @@ import type { BBox, IShape, Point, SimpleBBox } from '@antv/g-canvas'; import { Group } from '@antv/g-canvas'; -import { each, get, includes, isBoolean, isNumber, keys, pickBy } from 'lodash'; +import { + each, + get, + includes, + isBoolean, + isFunction, + isNumber, + keys, + pickBy, +} from 'lodash'; import { CellTypes, InteractionStateName, @@ -11,7 +20,7 @@ import type { CellThemes, DefaultCellTheme, FormatResult, - ResizeActiveOptions, + ResizeInteractionOptions, ResizeArea, S2CellType, S2Theme, @@ -154,12 +163,20 @@ export abstract class BaseCell extends Group { return this.getStyle('resizeArea') as ResizeArea; } - protected shouldDrawResizeAreaByType(type: keyof ResizeActiveOptions) { - const resize = this.spreadsheet.options?.interaction?.resize; + protected shouldDrawResizeAreaByType( + type: keyof ResizeInteractionOptions, + cell: S2CellType, + ) { + const { resize } = this.spreadsheet.options.interaction; + if (isBoolean(resize)) { return resize; } + if (isFunction(resize.visible)) { + return resize.visible(cell); + } + return resize[type]; } diff --git a/packages/s2-core/src/cell/col-cell.ts b/packages/s2-core/src/cell/col-cell.ts index 4899627012..1a331126e5 100644 --- a/packages/s2-core/src/cell/col-cell.ts +++ b/packages/s2-core/src/cell/col-cell.ts @@ -256,7 +256,7 @@ export class ColCell extends HeaderCell { } protected drawHorizontalResizeArea() { - if (!this.shouldDrawResizeAreaByType('colCellVertical')) { + if (!this.shouldDrawResizeAreaByType('colCellVertical', this)) { return; } @@ -289,6 +289,7 @@ export class ColCell extends HeaderCell { offsetY: y, width: resizeAreaWidth, height, + meta: this.meta, }), name: resizeAreaName, x: 0, @@ -343,7 +344,7 @@ export class ColCell extends HeaderCell { protected drawVerticalResizeArea() { if ( !this.meta.isLeaf || - !this.shouldDrawResizeAreaByType('colCellHorizontal') + !this.shouldDrawResizeAreaByType('colCellHorizontal', this) ) { return; } @@ -372,6 +373,7 @@ export class ColCell extends HeaderCell { offsetY, width, height, + meta: this.meta, }), x: offsetX + width - resizeStyle.size / 2, y: offsetY, diff --git a/packages/s2-core/src/cell/corner-cell.ts b/packages/s2-core/src/cell/corner-cell.ts index 1db03399f2..7bdaff60d8 100644 --- a/packages/s2-core/src/cell/corner-cell.ts +++ b/packages/s2-core/src/cell/corner-cell.ts @@ -237,7 +237,7 @@ export class CornerCell extends HeaderCell { } protected drawResizeArea() { - if (!this.shouldDrawResizeAreaByType('cornerCellHorizontal')) { + if (!this.shouldDrawResizeAreaByType('cornerCellHorizontal', this)) { return; } @@ -296,6 +296,7 @@ export class CornerCell extends HeaderCell { offsetY, width, height, + meta: this.meta, }), x: offsetX + width - resizeStyle.size / 2, y: offsetY, diff --git a/packages/s2-core/src/cell/row-cell.ts b/packages/s2-core/src/cell/row-cell.ts index 57788ef3d4..62acb30d5c 100644 --- a/packages/s2-core/src/cell/row-cell.ts +++ b/packages/s2-core/src/cell/row-cell.ts @@ -245,7 +245,7 @@ export class RowCell extends HeaderCell { protected drawResizeAreaInLeaf() { if ( !this.meta.isLeaf || - !this.shouldDrawResizeAreaByType('rowCellVertical') + !this.shouldDrawResizeAreaByType('rowCellVertical', this) ) { return; } @@ -307,6 +307,7 @@ export class RowCell extends HeaderCell { offsetY, width, height, + meta: this.meta, }), x: offsetX, y: offsetY + height - resizeStyle.size / 2, diff --git a/packages/s2-core/src/cell/table-series-cell.ts b/packages/s2-core/src/cell/table-series-cell.ts index 4ffbe54f11..9b600531a4 100644 --- a/packages/s2-core/src/cell/table-series-cell.ts +++ b/packages/s2-core/src/cell/table-series-cell.ts @@ -78,6 +78,7 @@ export class TableSeriesCell extends DataCell { offsetY: yOffset, width, height, + meta: this.meta, }), x, y: yOffset + height - resizeStyle.size / 2, diff --git a/packages/s2-core/src/common/interface/interaction.ts b/packages/s2-core/src/common/interface/interaction.ts index 8c2123db08..976eb53a61 100644 --- a/packages/s2-core/src/common/interface/interaction.ts +++ b/packages/s2-core/src/common/interface/interaction.ts @@ -17,7 +17,7 @@ import type { HeaderCell } from '../../cell/header-cell'; import type { Node } from '../../facet/layout/node'; import type { BaseEvent } from '../../interaction/base-event'; import type { SpreadSheet } from '../../sheet-type'; -import type { ResizeActiveOptions } from './resize'; +import type { ResizeInteractionOptions } from './resize'; import type { ViewMeta } from './basic'; export type S2CellType = @@ -127,7 +127,7 @@ export interface InteractionOptions { // the ratio to control scroll speed, default set to 1 scrollSpeedRatio?: ScrollSpeedRatio; // enable resize area, default set to all enable - resize?: boolean | ResizeActiveOptions; + resize?: boolean | ResizeInteractionOptions; // enable mouse drag brush selection brushSelection?: boolean; // enable Command / Ctrl + click multi selection @@ -141,7 +141,7 @@ export interface InteractionOptions { // An object that specifies characteristics about the event listener // https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener eventListenerOptions?: boolean | AddEventListenerOptions; - // hightlight col and row header for selected cell + // highlight col and row header for selected cell selectedCellHighlight?: boolean; // https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior overscrollBehavior?: 'auto' | 'none' | 'contain'; diff --git a/packages/s2-core/src/common/interface/resize.ts b/packages/s2-core/src/common/interface/resize.ts index 9683d96fcc..abd0f0f0bc 100644 --- a/packages/s2-core/src/common/interface/resize.ts +++ b/packages/s2-core/src/common/interface/resize.ts @@ -4,7 +4,9 @@ import type { ResizeDirectionType, ResizeType, } from '../../common/constant/resize'; -import type { Style } from './basic'; +import type { Node } from '../../facet/layout/node'; +import type { Style, ViewMeta } from './basic'; +import type { S2CellType } from './interaction'; import type { ResizeArea } from './theme'; export type ResizeGuideLinePath = [operation: 'M' | 'L', x: number, y: number]; @@ -58,12 +60,22 @@ export interface ResizeInfo { isResizeArea?: boolean; /** 字段id */ id?: string; + /** 当前拖拽热区对应的节点信息 */ + meta: Node | ViewMeta; + /** 拖拽后的宽度 */ + resizedWidth?: number; + /** 拖拽后的高度 */ + resizedHeight?: number; } -export interface ResizeActiveOptions { +export interface ResizeInteractionOptions { rowCellVertical?: boolean; // 行头垂直方向resize -> 针对行头叶子节点 cornerCellHorizontal?: boolean; // 角头水平方向resize -> 针对角头CornerNodeType为Series和Row colCellHorizontal?: boolean; // 列头水平方向resize -> 针对列头叶子节点 colCellVertical?: boolean; // 列头垂直方向resize -> 针对列头各层级节点 rowResizeType?: ResizeType; // 行高调整时,影响当前行还是全部行 + // 是否允许调整, 返回 false 时拖拽的宽高无效 + disable?: (resizeInfo: ResizeInfo) => boolean; + // 是否显示热区 + visible?: (cell: S2CellType) => boolean; } diff --git a/packages/s2-core/src/common/interface/theme.ts b/packages/s2-core/src/common/interface/theme.ts index 34227ba7d0..b66708f9b7 100644 --- a/packages/s2-core/src/common/interface/theme.ts +++ b/packages/s2-core/src/common/interface/theme.ts @@ -161,6 +161,8 @@ export interface ResizeArea { background?: string; /* 参考线颜色 */ guideLineColor?: string; + /* 参考线不可用颜色 */ + guideLineDisableColor?: string; /* 参考线间隔 */ guideLineDash?: number[]; /* 热区背景色透明度 */ diff --git a/packages/s2-core/src/facet/table-facet.ts b/packages/s2-core/src/facet/table-facet.ts index 261fcb4033..31ba3486cf 100644 --- a/packages/s2-core/src/facet/table-facet.ts +++ b/packages/s2-core/src/facet/table-facet.ts @@ -15,7 +15,7 @@ import { FrozenCellGroupMap } from '../common/constant/frozen'; import { DebuggerUtil } from '../common/debug'; import type { LayoutResult, - ResizeActiveOptions, + ResizeInteractionOptions, S2CellType, SplitLine, SpreadSheetFacetCfg, @@ -866,7 +866,7 @@ export class TableFacet extends BaseFacet { const shouldDrawResize = isBoolean(resize) ? resize - : (resize as ResizeActiveOptions)?.rowCellVertical; + : (resize as ResizeInteractionOptions)?.rowCellVertical; if (!shouldDrawResize) { return; } diff --git a/packages/s2-core/src/interaction/row-column-resize.ts b/packages/s2-core/src/interaction/row-column-resize.ts index 4de31fe099..6faaaefa41 100644 --- a/packages/s2-core/src/interaction/row-column-resize.ts +++ b/packages/s2-core/src/interaction/row-column-resize.ts @@ -4,7 +4,8 @@ import type { IShape, ShapeAttrs, } from '@antv/g-canvas'; -import { clone, get, isEmpty, throttle } from 'lodash'; +import { clone, isEmpty, throttle } from 'lodash'; +import type { ResizeInteractionOptions, Style } from '../common'; import { InterceptType, MIN_CELL_HEIGHT, @@ -100,21 +101,31 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { }; } + private getResizeShapes(): IShape[] { + return this.resizeReferenceGroup?.get('children') || []; + } + + private setResizeMaskCursor(cursor: string) { + const [, , resizeMask] = this.getResizeShapes(); + resizeMask?.attr('cursor', cursor); + } + private updateResizeGuideLinePosition( event: MouseEvent, resizeInfo: ResizeInfo, ) { - const resizeShapes: IShape[] = this.resizeReferenceGroup.get('children'); + const resizeShapes = this.getResizeShapes(); + if (isEmpty(resizeShapes)) { return; } - const [startResizeGuideLineShape, endResizeGuideLineShape, resizeMask] = - resizeShapes; + + const [startResizeGuideLineShape, endResizeGuideLineShape] = resizeShapes; const { type, offsetX, offsetY, width, height } = resizeInfo; const { width: guideLineMaxWidth, height: guideLineMaxHeight } = this.getGuideLineWidthAndHeight(); - resizeMask.attr('cursor', `${type}-resize`); + this.setResizeMaskCursor(`${type}-resize`); if (type === ResizeDirectionType.Horizontal) { startResizeGuideLineShape.attr('path', [ @@ -190,10 +201,35 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { }; } - private getResizeWidthDetail(): ResizeDetail { + private getDisAllowResizeInfo() { + const resizeInfo = this.getResizeInfo(); + const { resize } = this.spreadsheet.options.interaction; const { start, end } = this.getResizeGuideLinePosition(); - const width = Math.floor(end.x - start.x); + const resizedWidth = Math.floor(end.x - start.x); + const resizedHeight = Math.floor(end.y - start.y); + + const originalWidth = resizeInfo.width; + const originalHeight = resizeInfo.height; + + const isDisabled = (resize as ResizeInteractionOptions)?.disable?.({ + ...resizeInfo, + resizedWidth, + resizedHeight, + }); + + const displayWidth = isDisabled ? originalWidth : resizedWidth; + const displayHeight = isDisabled ? originalHeight : resizedHeight; + + return { + displayWidth, + displayHeight, + isDisabled, + }; + } + + private getResizeWidthDetail(): ResizeDetail { const resizeInfo = this.getResizeInfo(); + const { displayWidth } = this.getDisAllowResizeInfo(); switch (resizeInfo.effect) { case ResizeAreaEffect.Field: @@ -202,27 +238,29 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { style: { rowCfg: { widthByField: { - [resizeInfo.id]: width, + [resizeInfo.id]: displayWidth, }, }, }, }; + case ResizeAreaEffect.Tree: return { eventType: S2Event.LAYOUT_RESIZE_TREE_WIDTH, style: { rowCfg: { - treeRowsWidth: width, + treeRowsWidth: displayWidth, }, }, }; + case ResizeAreaEffect.Cell: return { eventType: S2Event.LAYOUT_RESIZE_COL_WIDTH, style: { colCfg: { widthByFieldValue: { - [resizeInfo.id]: width, + [resizeInfo.id]: displayWidth, }, }, }, @@ -231,8 +269,9 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { case ResizeAreaEffect.Series: return { eventType: S2Event.LAYOUT_RESIZE_SERIES_WIDTH, - seriesNumberWidth: width, + seriesNumberWidth: displayWidth, }; + default: return null; } @@ -248,12 +287,11 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { }, } = this.spreadsheet; const { padding: rowCellPadding } = this.spreadsheet.theme.rowCell.cell; - const { start, end } = this.getResizeGuideLinePosition(); - const baseHeight = Math.floor(end.y - start.y); - const height = baseHeight - rowCellPadding.top - rowCellPadding.bottom; const resizeInfo = this.getResizeInfo(); + const { displayHeight } = this.getDisAllowResizeInfo(); + const height = displayHeight - rowCellPadding.top - rowCellPadding.bottom; - let rowCellStyle; + let rowCellStyle: Style; switch (resizeInfo.effect) { case ResizeAreaEffect.Field: return { @@ -261,7 +299,7 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { style: { colCfg: { heightByField: { - [resizeInfo.id]: baseHeight, + [resizeInfo.id]: displayHeight, }, }, }, @@ -269,7 +307,8 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { case ResizeAreaEffect.Cell: if ( heightByField[String(resizeInfo.id)] || - get(resize, 'rowResizeType') === ResizeType.CURRENT + (resize as ResizeInteractionOptions)?.rowResizeType === + ResizeType.CURRENT ) { rowCellStyle = { rowCfg: { @@ -313,6 +352,8 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { private bindMouseUp() { this.spreadsheet.on(S2Event.GLOBAL_MOUSE_UP, () => { + this.setResizeMaskCursor('default'); + if ( !this.resizeReferenceGroup || isEmpty(this.resizeReferenceGroup?.getChildren()) @@ -333,7 +374,8 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { const originalEvent = event.originalEvent as MouseEvent; const resizeInfo = this.getResizeInfo(); - const resizeShapes = this.resizeReferenceGroup.get('children') as IShape[]; + const resizeShapes = + (this.resizeReferenceGroup.getChildren() as IShape[]) || []; if (isEmpty(resizeShapes)) { return; @@ -359,9 +401,21 @@ export class RowColumnResize extends BaseEvent implements BaseEventImplement { guideLineEnd, ); } + + this.updateResizeGuideLineTheme(endGuideLineShape); endGuideLineShape.attr('path', [guideLineStart, guideLineEnd]); }; + private updateResizeGuideLineTheme(endGuideLineShape: IShape) { + const { guideLineColor, guideLineDisableColor } = this.getResizeAreaTheme(); + const { isDisabled } = this.getDisAllowResizeInfo(); + endGuideLineShape.attr( + 'stroke', + isDisabled ? guideLineDisableColor : guideLineColor, + ); + this.setResizeMaskCursor(isDisabled ? 'no-drop' : 'default'); + } + private updateHorizontalResizingEndGuideLinePosition( originalEvent: MouseEvent, resizeInfo: ResizeInfo, diff --git a/packages/s2-core/src/theme/index.ts b/packages/s2-core/src/theme/index.ts index f62813f6b1..5833e5cd3a 100644 --- a/packages/s2-core/src/theme/index.ts +++ b/packages/s2-core/src/theme/index.ts @@ -404,6 +404,7 @@ export const getTheme = ( background: basicColors[7], backgroundOpacity: 0, guideLineColor: basicColors[7], + guideLineDisableColor: 'rgba(0,0,0,0.25)', guideLineDash: [3, 3], /* ---------- interaction state ----------- */ interactionState: { diff --git a/packages/s2-react/__tests__/data/strategy-data.ts b/packages/s2-react/__tests__/data/strategy-data.ts index ecf7db22a6..e77503a574 100644 --- a/packages/s2-react/__tests__/data/strategy-data.ts +++ b/packages/s2-react/__tests__/data/strategy-data.ts @@ -363,6 +363,16 @@ export const StrategyOptions: S2Options = { const placeholder = v?.fieldValue ? '-' : ''; return placeholder; }, + interaction: { + resize: { + disable: (resizeInfo) => { + return ( + resizeInfo.meta.label === '净增完成度' && + resizeInfo.resizedWidth < resizeInfo.width + ); + }, + }, + }, headerActionIcons: [ { iconNames: ['Trend'], diff --git a/s2-site/docs/api/components/sheet-component.zh.md b/s2-site/docs/api/components/sheet-component.zh.md index 3ffb599b38..14330daa40 100644 --- a/s2-site/docs/api/components/sheet-component.zh.md +++ b/s2-site/docs/api/components/sheet-component.zh.md @@ -246,12 +246,15 @@ order: 0 | :-- | :-- | :-- | :-- | :-: | | theme | resize 热区配置 | [ResizeArea](#resizearea) | | ✓ | | type | resize 方向 | `Horizontal` \| `Vertical` | | ✓ | -| offsetX | 横向偏移量 | number | | ✓ | -| offsetY | 纵向偏移量 | number | | ✓ | -| offsetX | 横向偏移量 | number | | ✓ | -| width | 拖拽的宽度 | number | | ✓ | -| height | 拖拽 | number | | ✓ | -| size | 热区尺寸 | number | | ✓ | +| offsetX | 横向偏移量 | `number` | | ✓ | +| offsetY | 纵向偏移量 | `number` | | ✓ | +| offsetX | 横向偏移量 | `number` | | ✓ | +| width | 拖拽的宽度 | `number` | | ✓ | +| height | 拖拽 | `number` | | ✓ | +| size | 热区尺寸 | `number` | | ✓ | | effect | 拖拽更改影响的区域 | `Field` \| `Cell` \| `Tree` \| `Series` | | ✓ | | isResizeArea | 是否属于 resize 热区 | [style](/zh/docs/api/general/S2Options#style) | | | -| id | 字段 id | | | | +| id | 字段 id | `string` | | | +| meta | resize 热区对应单元格节点信息 | [Node](/zh/docs/api/basic-class/node) | | | +| resizedWidth | 拖拽后的宽度 | `number` | | | +| resizedHeight | 拖拽后的高度 | `number` | | | diff --git a/s2-site/docs/common/interaction.zh.md b/s2-site/docs/common/interaction.zh.md index e0a779fa91..0f667532aa 100644 --- a/s2-site/docs/common/interaction.zh.md +++ b/s2-site/docs/common/interaction.zh.md @@ -15,9 +15,9 @@ order: 5 | enableCopy | 是否允许复制 | `boolean` | `false` | | | copyWithFormat | 是否使用 field format 格式复制 | `boolean` | `false` | | | customInteractions | 自定义交互 [详情](/zh/docs/manual/advanced/interaction/custom) | [CustomInteraction[]](#custominteraction) | | | -| scrollSpeedRatio | 用于控制滚动速率,分水平和垂直两个方向,默认为 1 | [ScrollSpeedRatio](/zh/docs/api/general/S2Options#scrollspeedratio) | | | +| scrollSpeedRatio | 用于控制滚动速率,分水平和垂直两个方向,默认为 1 | [ScrollSpeedRatio](#scrollspeedratio) | | | | autoResetSheetStyle | 用于控制点击表格外区域和按下 esc 键时是否重置交互状态 | `boolean` | `true` | | -| resize | 用于控制 resize 热区是否显示 | `boolean` \| [ResizeActiveOptions](/zh/docs/api/general/S2Options#resizeactiveoptions) | `true` | | +| resize | 用于控制 resize 热区是否显示 | `boolean` \| [ResizeInteractionOptions](#resizeinteractionoptions) | `true` | | | brushSelection | 是否允许刷选 | `boolean` | `true` | | | multiSelection | 是否允许多选 (包含行头,列头,数值单元格) | `boolean` | `true` | | | rangeSelection | 是否允许区间快捷多选 | `boolean` | `true` | | @@ -44,7 +44,7 @@ interface ScrollSpeedRatio { } ``` -### ResizeActiveOptions +### ResizeInteractionOptions | 参数 | 说明 | 类型 | 默认值 | 必选 | | -------------------- | ---------------------------------------------------------------------------------- | ----------------- | ------ | :---: | @@ -53,3 +53,5 @@ interface ScrollSpeedRatio { | colCellHorizontal | 是否开启列头水平方向 resize 热区 | `boolean` | true | | | colCellVertical | 是否开启列头垂直方向 resize 热区 | `boolean` | true | | | rowResizeType | 用于控制行高 resize 时是同时对所有 Cell 生效,还是只对当前行生效。默认对所有行生效 | `all`\| `current` | `all` | | +| disable | 用于控制行高 resize 是否生效 查看例子 | (resizeInfo: [S2CellType](/zh/docs/api/components/sheet-component#resizeinfo)) => boolean | | | +| visible | 自定义当前单元格是否显示 resize 热区 | (cell: [S2CellType](/zh/docs/api/basic-class/base-cell)) => boolean | | | diff --git a/s2-site/docs/manual/advanced/interaction/basic.zh.md b/s2-site/docs/manual/advanced/interaction/basic.zh.md index e78a46561b..bc64d45343 100644 --- a/s2-site/docs/manual/advanced/interaction/basic.zh.md +++ b/s2-site/docs/manual/advanced/interaction/basic.zh.md @@ -337,7 +337,7 @@ const s2Options = { S2 默认提供 `列等宽布局` `行列等宽布局`和 `紧凑布局` 三种布局方式 ([预览](https://s2.antv.vision/zh/examples/layout/basic#compact)), 也可以拖拽行/列头进行动态调整 -可配置 `resize` 控制需要开启的单元格宽高调整热区范围,分为 角头,行头,列头三个部分,默认为全部开启。可以通过设置`boolean` 类型值快捷开启或关闭所有 `resize` 热区,也可以通过对象类型配置各个区域的热区开启或关闭。[查看具体例子](/zh/examples/interaction/advanced#resize) +可配置 `resize` 控制需要开启的单元格宽高调整热区范围,分为 角头,行头,列头三个部分,默认为全部开启。可以通过设置`boolean` 类型值快捷开启或关闭所有 `resize` 热区,也可以通过对象类型配置各个区域的热区开启或关闭。[查看具体例子](/zh/examples/interaction/advanced#resize-active) ```ts const s2Options = { @@ -345,9 +345,10 @@ const s2Options = { resize: true }, }; + // 等价于 // const s2Options = { -// interaction: { +// interaction: { // resize: { // rowCellVertical:true, // cornerCellHorizontal:true, @@ -358,6 +359,37 @@ const s2Options = { // }; ``` +还可以配置 `resize.visible` 和 `resize.disable` 两个属性,分别用于控制 `resize` 热区的显示和自定义拖拽校验逻辑。[查看具体例子](/zh/examples/interaction/advanced#resize-disable) + +preview + +> 例:不允许调小单元格宽度 + +```ts +const s2Options = { + interaction: { + resize: { + disable: (resizeInfo) => resizeInfo.resizedWidth <= resizeInfo.width; + } + }, +}; +``` + +> 例:只有前 4 个单元格显示 resize 热区 + +```ts +const s2Options = { + interaction: { + resize: { + visible: (cell) => { + const meta = cell.getMeta(); + return meta.colIndex < 3 + } + } + }, +}; +``` + ### 合并单元格 preview diff --git a/s2-site/examples/interaction/advanced/demo/meta.json b/s2-site/examples/interaction/advanced/demo/meta.json index e2402ad5f8..a271f0d106 100644 --- a/s2-site/examples/interaction/advanced/demo/meta.json +++ b/s2-site/examples/interaction/advanced/demo/meta.json @@ -47,11 +47,19 @@ { "filename": "resize-active.ts", "title": { - "zh": "自定义resize热区", + "zh": "自定义行列宽度调整热区", "en": "Custom resize area" }, "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/HEfCpSTRO/2021-12-06%25252011.39.15.gif" }, + { + "filename": "resize-disable.ts", + "title": { + "zh": "自定义行列宽度调整规则", + "en": "Custom resize disable" + }, + "screenshot": "https://gw.alipayobjects.com/zos/antfincdn/64tnK5%263K/Kapture%2525202022-07-19%252520at%25252015.40.15.gif" + }, { "filename": "merge-cell.ts", "title": { diff --git a/s2-site/examples/interaction/advanced/demo/resize-disable.ts b/s2-site/examples/interaction/advanced/demo/resize-disable.ts new file mode 100644 index 0000000000..aa064393a7 --- /dev/null +++ b/s2-site/examples/interaction/advanced/demo/resize-disable.ts @@ -0,0 +1,29 @@ +import { PivotSheet } from '@antv/s2'; + +fetch( + 'https://gw.alipayobjects.com/os/bmw-prod/2a5dbbc8-d0a7-4d02-b7c9-34f6ca63cff6.json', +) + .then((res) => res.json()) + .then((dataCfg) => { + const container = document.getElementById('container'); + + const s2Options = { + width: 600, + height: 480, + interaction: { + resize: { + disable: (resizeInfo) => { + console.log('resizeInfo: ', resizeInfo); + // 不允许调小宽度 + return resizeInfo.resizedWidth <= resizeInfo.width; + // 不允许调小高度 + // return resizeInfo.resizedHeight <= resizeInfo.height; + }, + }, + }, + }; + + const s2 = new PivotSheet(container, dataCfg, s2Options); + + s2.render(); + });