feat: add float-dom update & delete & event api (#5515)

Co-authored-by: 白熱 <sonne@asaki.me>
Co-authored-by: Wpxp123456 <2677556700@qq.com>
This commit is contained in:
WEI ZHANG
2025-07-10 22:13:03 +08:00
committed by GitHub
co-authored by 白熱 Wpxp123456
parent ec740ba578
commit a4e177a140
7 changed files with 802 additions and 31 deletions
@@ -20,6 +20,7 @@ import type { ISheetSelectionRenderService, SheetSkeletonManagerService } from '
import { precisionTo } from '@univerjs/engine-render';
import { convertPositionSheetOverGridToAbsolute } from '@univerjs/sheets-ui';
// eslint-disable-next-line max-lines-per-function
export function drawingPositionToTransform(
position: ISheetDrawingPosition,
selectionRenderService: ISheetSelectionRenderService,
@@ -16,7 +16,7 @@
import type { IDrawingSearch } from '@univerjs/core';
import type { IEventBase } from '@univerjs/core/facade';
import type { ISheetImage } from '@univerjs/sheets-drawing';
import type { ISheetFloatDom, ISheetImage } from '@univerjs/sheets-drawing';
import type { FWorkbook } from '@univerjs/sheets/facade';
import type { FOverGridImage } from './f-over-grid-image';
import { FEventName } from '@univerjs/core/facade';
@@ -25,6 +25,108 @@ import { FEventName } from '@univerjs/core/facade';
* @ignore
*/
interface IFDrawingEventNameMixin {
/**
* Triggered before float dom insertion.
* @see {@link IBeforeFloatDomAddParam}
* @example
* ```ts
* const disposable = univerAPI.addEvent(univerAPI.Event.BeforeFloatDomAdd, (params) => {
* console.log(params);
* // do something
* const { workbook, drawings } = params;
* // Cancel the insertion operation
* params.cancel = true;
* })
*
* // Remove the event listener, use `disposable.dispose()`
* ```
*/
readonly BeforeFloatDomAdd: 'BeforeFloatDomAdd';
/**
* Triggered after float dom insertion.
* @see {@link IFloatDomAddedParam}
* @example
* ```ts
* const disposable = univerAPI.addEvent(univerAPI.Event.FloatDomAdded, (params) => {
* console.log(params);
* // do something
* const { workbook, drawings } = params;
* })
*
* // Remove the event listener, use `disposable.dispose()`
* ```
*/
readonly FloatDomAdded: 'FloatDomAdded';
/**
* Triggered before float dom update.
* @see {@link IBeforeFloatDomUpdateParam}
* @example
* ```ts
* const disposable = univerAPI.addEvent(univerAPI.Event.BeforeFloatDomUpdate, (params) => {
* console.log(params);
* // do something
* const { workbook, drawings } = params;
* // Cancel the update operation
* params.cancel = true;
* })
*
* // Remove the event listener, use `disposable.dispose()`
* ```
*/
readonly BeforeFloatDomUpdate: 'BeforeFloatDomUpdate';
/**
* Triggered after float dom update.
* @see {@link IFloatDomUpdatedParam}
* @example
* ```ts
* const disposable = univerAPI.addEvent(univerAPI.Event.FloatDomUpdated, (params) => {
* console.log(params);
* // do something
* const { workbook, drawings } = params;
* })
*
* // Remove the event listener, use `disposable.dispose()`
* ```
*/
readonly FloatDomUpdated: 'FloatDomUpdated';
/**
* Triggered before float dom deletion.
* @see {@link IBeforeFloatDomDeleteParam}
* @example
* ```ts
* const disposable = univerAPI.addEvent(univerAPI.Event.BeforeFloatDomDelete, (params) => {
* console.log(params);
* // do something
* const { workbook, drawings } = params;
* // Cancel the deletion operation
* params.cancel = true;
* })
*
* // Remove the event listener, use `disposable.dispose()`
* ```
*/
readonly BeforeFloatDomDelete: 'BeforeFloatDomDelete';
/**
* Triggered after float dom deletion.
* @see {@link IFloatDomDeletedParam}
* @example
* ```ts
* const disposable = univerAPI.addEvent(univerAPI.Event.FloatDomDeleted, (params) => {
* console.log(params);
* // do something
* const { workbook, drawings } = params;
* })
*
* // Remove the event listener, use `disposable.dispose()`
* ```
*/
readonly FloatDomDeleted: 'FloatDomDeleted';
/**
* Triggered before floating image insertion.
* @see {@link IBeforeOverGridImageInsertParam}
@@ -163,6 +265,30 @@ interface IFDrawingEventNameMixin {
}
export class FDrawingEventNameMixin extends FEventName implements IFDrawingEventNameMixin {
override get BeforeFloatDomAdd(): 'BeforeFloatDomAdd' {
return 'BeforeFloatDomAdd' as const;
}
override get FloatDomAdded(): 'FloatDomAdded' {
return 'FloatDomAdded' as const;
}
override get BeforeFloatDomUpdate(): 'BeforeFloatDomUpdate' {
return 'BeforeFloatDomUpdate' as const;
}
override get FloatDomUpdated(): 'FloatDomUpdated' {
return 'FloatDomUpdated' as const;
}
override get BeforeFloatDomDelete(): 'BeforeFloatDomDelete' {
return 'BeforeFloatDomDelete' as const;
}
override get FloatDomDeleted(): 'FloatDomDeleted' {
return 'FloatDomDeleted' as const;
}
override get BeforeOverGridImageChange(): 'BeforeOverGridImageChange' {
return 'BeforeOverGridImageChange' as const;
}
@@ -307,6 +433,78 @@ export interface IOverGridImageSelectedParam extends IEventBase {
/**
* @ignore
*/
export interface IBeforeFloatDomAddParam extends IEventBase {
/**
* The workbook instance currently being operated on. {@link FWorkbook}
*/
workbook: FWorkbook;
/**
* Collection of float dom drawings to be added.
*/
drawings: ISheetFloatDom[];
}
export interface IFloatDomAddedParam extends IEventBase {
/**
* The workbook instance currently being operated on. {@link FWorkbook}
*/
workbook: FWorkbook;
/**
* Collection of float dom drawings that were added.
*/
drawings: ISheetFloatDom[];
}
export interface IBeforeFloatDomUpdateParam extends IEventBase {
/**
* The workbook instance currently being operated on. {@link FWorkbook}
*/
workbook: FWorkbook;
/**
* Collection of float dom drawings to be updated.
*/
drawings: ISheetFloatDom[];
}
export interface IFloatDomUpdatedParam extends IEventBase {
/**
* The workbook instance currently being operated on. {@link FWorkbook}
*/
workbook: FWorkbook;
/**
* Collection of float dom drawings that were updated.
*/
drawings: ISheetFloatDom[];
}
export interface IBeforeFloatDomDeleteParam extends IEventBase {
/**
* The workbook instance currently being operated on. {@link FWorkbook}
*/
workbook: FWorkbook;
/**
* Collection of float dom drawings to be deleted.
*/
drawings: ISheetFloatDom[];
}
export interface IFloatDomDeletedParam extends IEventBase {
/**
* The workbook instance currently being operated on. {@link FWorkbook}
*/
workbook: FWorkbook;
/**
* Collection of float dom drawing ids that were deleted.
*/
drawings: string[];
}
interface IFSheetsUIEventParamConfig {
BeforeOverGridImageChange: IBeforeOverGridImageChangeParam;
OverGridImageChanged: IOverGridImageChangedParam;
@@ -319,6 +517,15 @@ interface IFSheetsUIEventParamConfig {
BeforeOverGridImageSelect: IBeforeOverGridImageSelectParam;
OverGridImageSelected: IOverGridImageSelectedParam;
BeforeFloatDomAdd: IBeforeFloatDomAddParam;
FloatDomAdded: IFloatDomAddedParam;
BeforeFloatDomUpdate: IBeforeFloatDomUpdateParam;
FloatDomUpdated: IFloatDomUpdatedParam;
BeforeFloatDomDelete: IBeforeFloatDomDeleteParam;
FloatDomDeleted: IFloatDomDeletedParam;
}
FEventName.extend(FDrawingEventNameMixin);
@@ -16,11 +16,16 @@
import type { IDrawingSearch, Injector } from '@univerjs/core';
import type { IEventBase } from '@univerjs/core/facade';
import type { ISheetImage } from '@univerjs/sheets-drawing';
import type { ISheetFloatDom, ISheetImage } from '@univerjs/sheets-drawing';
import type { IDeleteDrawingCommandParams, IInsertDrawingCommandParams, ISetDrawingCommandParams } from '@univerjs/sheets-drawing-ui';
import type { FWorkbook } from '@univerjs/sheets/facade';
import type { IBeforeOverGridImageChangeParamObject } from './f-event';
import { CanceledError, ICommandService } from '@univerjs/core';
import type {
IBeforeFloatDomAddParam,
IBeforeFloatDomDeleteParam,
IBeforeFloatDomUpdateParam,
IBeforeOverGridImageChangeParamObject,
} from './f-event';
import { CanceledError, DrawingTypeEnum, ICommandService } from '@univerjs/core';
import { FUniver } from '@univerjs/core/facade';
import { IDrawingManagerService, SetDrawingSelectedOperation } from '@univerjs/drawing';
import { InsertSheetDrawingCommand, RemoveSheetDrawingCommand, SetSheetDrawingCommand } from '@univerjs/sheets-drawing-ui';
@@ -58,6 +63,67 @@ export class FUniverDrawingMixin extends FUniver {
override _initialize(injector: Injector): void {
const commandService = injector.get(ICommandService);
// Float DOM Add Events
this.registerEventHandler(
this.Event.BeforeFloatDomAdd,
() => commandService.beforeCommandExecuted((commandInfo) => {
if (commandInfo.id !== InsertSheetDrawingCommand.id) return;
const params = commandInfo.params as IInsertDrawingCommandParams;
const workbook = this.getActiveWorkbook();
if (workbook == null || params == null) {
return;
}
const { drawings } = params;
const floatDomDrawings = drawings.filter(
(drawing) => drawing.drawingType === DrawingTypeEnum.DRAWING_DOM
) as ISheetFloatDom[];
if (floatDomDrawings.length === 0) {
return;
}
const eventParams: IBeforeFloatDomAddParam = {
workbook,
drawings: floatDomDrawings,
};
this.fireEvent(this.Event.BeforeFloatDomAdd, eventParams);
if (eventParams.cancel) {
throw new CanceledError();
}
})
);
this.registerEventHandler(
this.Event.FloatDomAdded,
() => commandService.onCommandExecuted((commandInfo) => {
if (commandInfo.id !== InsertSheetDrawingCommand.id) return;
const params = commandInfo.params as IInsertDrawingCommandParams;
const workbook = this.getActiveWorkbook();
if (workbook == null || params == null) {
return;
}
const { drawings } = params;
const floatDomDrawings = drawings.filter(
(drawing) => drawing.drawingType === DrawingTypeEnum.DRAWING_DOM
) as ISheetFloatDom[];
if (floatDomDrawings.length === 0) {
return;
}
this.fireEvent(this.Event.FloatDomAdded, {
workbook,
drawings: floatDomDrawings,
});
})
);
this.registerEventHandler(
this.Event.BeforeOverGridImageInsert,
() => commandService.beforeCommandExecuted((commandInfo) => {
@@ -155,6 +221,138 @@ export class FUniverDrawingMixin extends FUniver {
})
);
// Float DOM Update Events
this.registerEventHandler(
this.Event.BeforeFloatDomUpdate,
() => commandService.beforeCommandExecuted((commandInfo) => {
if (commandInfo.id !== SetSheetDrawingCommand.id) return;
const params = commandInfo.params as ISetDrawingCommandParams;
const workbook = this.getActiveWorkbook();
if (workbook == null || params == null) {
return;
}
const { drawings } = params;
const drawingManagerService = injector.get(IDrawingManagerService);
const floatDomDrawings: ISheetFloatDom[] = [];
drawings.forEach((drawing) => {
const dom = drawingManagerService.getDrawingByParam(drawing as IDrawingSearch) as ISheetFloatDom;
if (dom?.drawingType === DrawingTypeEnum.DRAWING_DOM) {
floatDomDrawings.push(dom);
}
});
if (floatDomDrawings.length === 0) {
return;
}
const eventParams: IBeforeFloatDomUpdateParam = {
workbook,
drawings: floatDomDrawings,
};
this.fireEvent(this.Event.BeforeFloatDomUpdate, eventParams);
if (eventParams.cancel) {
drawingManagerService.updateNotification(drawings as IDrawingSearch[]);
throw new CanceledError();
}
})
);
this.registerEventHandler(
this.Event.FloatDomUpdated,
() => commandService.onCommandExecuted((commandInfo) => {
if (commandInfo.id !== SetSheetDrawingCommand.id) return;
const params = commandInfo.params as ISetDrawingCommandParams;
const workbook = this.getActiveWorkbook();
if (workbook == null || params == null) {
return;
}
const { drawings } = params;
const drawingManagerService = injector.get(IDrawingManagerService);
const floatDomDrawings: ISheetFloatDom[] = [];
drawings.forEach((drawing) => {
const dom = drawingManagerService.getDrawingByParam(drawing as IDrawingSearch) as ISheetFloatDom;
if (dom?.drawingType === DrawingTypeEnum.DRAWING_DOM) {
floatDomDrawings.push(dom);
}
});
if (floatDomDrawings.length === 0) {
return;
}
this.fireEvent(this.Event.FloatDomUpdated, {
workbook,
drawings: floatDomDrawings,
});
})
);
// Float DOM Delete Events
this.registerEventHandler(
this.Event.BeforeFloatDomDelete,
() => commandService.beforeCommandExecuted((commandInfo) => {
if (commandInfo.id !== RemoveSheetDrawingCommand.id) return;
const params = commandInfo.params as IDeleteDrawingCommandParams;
const workbook = this.getActiveWorkbook();
if (workbook == null || params == null) {
return;
}
const drawingManagerService = injector.get(IDrawingManagerService);
const { drawings } = params;
const floatDomDrawings = drawings
.map((drawing) => drawingManagerService.getDrawingByParam(drawing))
.filter((drawing): drawing is ISheetFloatDom =>
drawing?.drawingType === DrawingTypeEnum.DRAWING_DOM
);
if (floatDomDrawings.length === 0) {
return;
}
const eventParams: IBeforeFloatDomDeleteParam = {
workbook,
drawings: floatDomDrawings,
};
this.fireEvent(this.Event.BeforeFloatDomDelete, eventParams);
if (eventParams.cancel) {
throw new CanceledError();
}
})
);
this.registerEventHandler(
this.Event.FloatDomDeleted,
() => commandService.onCommandExecuted((commandInfo) => {
if (commandInfo.id !== RemoveSheetDrawingCommand.id) return;
const params = commandInfo.params as IDeleteDrawingCommandParams;
const workbook = this.getActiveWorkbook();
if (workbook == null || params == null) {
return;
}
const { drawings } = params;
this.fireEvent(this.Event.FloatDomDeleted, {
workbook,
drawings: drawings.filter((i) => i.drawingType === DrawingTypeEnum.DRAWING_DOM).map((i) => i.drawingId),
});
})
);
this.registerEventHandler(
this.Event.BeforeOverGridImageSelect,
() => commandService.beforeCommandExecuted((commandInfo) => {
@@ -14,27 +14,164 @@
* limitations under the License.
*/
import type { IDisposable, Nullable } from '@univerjs/core';
import type { IDisposable, ITransformState, Nullable } from '@univerjs/core';
import type { IFBlobSource } from '@univerjs/core/facade';
import type { ISheetImage } from '@univerjs/sheets-drawing';
import type { ICanvasFloatDom, IDOMAnchor } from '@univerjs/sheets-drawing-ui';
import type { ISheetFloatDom, ISheetImage } from '@univerjs/sheets-drawing';
import type { ICanvasFloatDom, ICanvasFloatDomInfo, IDOMAnchor } from '@univerjs/sheets-drawing-ui';
import type { IFComponentKey } from '@univerjs/sheets-ui/facade';
import type { FRange } from '@univerjs/sheets/facade';
import { DrawingTypeEnum, ImageSourceType, toDisposable } from '@univerjs/core';
import { IRenderManagerService } from '@univerjs/engine-render';
import { ISheetDrawingService } from '@univerjs/sheets-drawing';
import { InsertSheetDrawingCommand, RemoveSheetDrawingCommand, SetSheetDrawingCommand, SheetCanvasFloatDomManagerService } from '@univerjs/sheets-drawing-ui';
import { InsertSheetDrawingCommand, RemoveSheetDrawingCommand, SetSheetDrawingCommand, SheetCanvasFloatDomManagerService, transformToDrawingPosition } from '@univerjs/sheets-drawing-ui';
import { ISheetSelectionRenderService } from '@univerjs/sheets-ui';
import { transformComponentKey } from '@univerjs/sheets-ui/facade';
import { FWorksheet } from '@univerjs/sheets/facade';
import { ComponentManager } from '@univerjs/ui';
import { FOverGridImage, FOverGridImageBuilder } from './f-over-grid-image';
// why omit this key? if componentKey is missing, then which component should be used?
export interface IFICanvasFloatDom extends Omit<ICanvasFloatDom, 'componentKey' | 'unitId' | 'subUnitId'>, IFComponentKey {}
export interface IFICanvasFloatDom extends Omit<ICanvasFloatDom, 'componentKey' | 'unitId' | 'subUnitId'>, IFComponentKey { }
export interface IFCanvasFloatDomResult extends Omit<ICanvasFloatDom, 'componentKey' | 'unitId' | 'subUnitId' | 'initPosition'>,
IFComponentKey,
Pick<ICanvasFloatDomInfo, 'id'> {
position: ITransformState;
id: string;
}
/**
* @ignore
*/
export interface IFWorksheetLegacy {
/**
* Get float dom by id
* @param {string} id - float dom id
* @returns {IFCanvasFloatDomResult | null} float dom info or null if not found
* @example
* ```ts
* const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet();
* const floatDom = fWorksheet.getFloatDomById('myFloatDomId');
* if (floatDom) {
* console.log('Float dom position:', floatDom.position);
* console.log('Component key:', floatDom.componentKey);
* console.log('Custom data:', floatDom.data);
* }
* ```
*/
getFloatDomById(id: string): Nullable<IFCanvasFloatDomResult>;
/**
* Get all float doms in current worksheet
* @returns {IFCanvasFloatDomResult[]} array of float dom info
* @example
* ```ts
* const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet();
* const allFloatDoms = fWorksheet.getAllFloatDoms();
* allFloatDoms.forEach(floatDom => {
* console.log('Float dom ID:', floatDom.id);
* console.log('Position:', floatDom.position);
* });
* ```
*/
getAllFloatDoms(): IFCanvasFloatDomResult[];
/**
* Update float dom position and properties
* @param {string} id - float dom id
* @param {Partial<IFCanvasFloatDomResult>} config - new float dom config
* @returns {FWorksheet} The worksheet instance for chaining
* @example
* ```ts
* const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet();
* const firstFloatDom = fWorksheet.getAllFloatDoms()[0];
*
* if (!firstFloatDom) return;
*
* // Update first float dom position and size
* fWorksheet.updateFloatDom(firstFloatDom.id, {
* position: {
* left: 100,
* top: 100,
* width: 200,
* height: 150,
* angle: 45, // rotate 45 degrees
* }
* });
*
* // Update first float dom data
* fWorksheet.updateFloatDom(firstFloatDom.id, {
* data: {
* label: 'Updated Label',
* color: '#ff0000'
* }
* });
*
* // Disable the first float dom from transform
* fWorksheet.updateFloatDom(firstFloatDom.id, {
* allowTransform: false
* });
* ```
*/
updateFloatDom(id: string, config: Partial<IFCanvasFloatDomResult>): this;
/**
* Batch update float doms
* @param {Array<{id: string, config: Partial<IFCanvasFloatDomResult>}>} updates - array of update configs
* @returns {FWorksheet} The worksheet instance for chaining
* @example
* ```ts
* const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet();
*
* // Update multiple float doms at once
* const allFloatDoms = fWorksheet.getAllFloatDoms();
* fWorksheet.batchUpdateFloatDoms(allFloatDoms.map((floatDom, index) => {
* if (floatDom.id === 'MyFloatDomId') {
* return {
* id: floatDom.id,
* config: {
* position: {
* left: 100,
* top: 100
* },
* data: {
* label: 'Updated'
* }
* }
* }
* }
*
* return {
* id: floatDom.id,
* config: {
* position: {
* left: 300,
* top: 100
* }
* }
* }
* }));
* ```
*/
batchUpdateFloatDoms(updates: Array<{ id: string; config: Partial<IFCanvasFloatDomResult> }>): this;
/**
* Remove float dom by id
* @param {string} id - float dom id
* @returns {FWorksheet} The worksheet instance for chaining
* @example
* ```ts
* const fWorksheet = univerAPI.getActiveWorkbook().getActiveSheet();
* const firstFloatDom = fWorksheet.getAllFloatDoms()[0];
*
* if (!firstFloatDom) return;
*
* // Remove the first float dom
* fWorksheet.removeFloatDom(firstFloatDom.id);
* ```
*/
removeFloatDom(id: string): this;
/**
* Add a float dom to position.
* @param {IFICanvasFloatDom} layer - The float dom layer configuration.
@@ -59,7 +196,7 @@ export interface IFWorksheetLegacy {
*
* // Add a floating DOM
* // If disposable is null, floating DOM addition failed
* const disposeable = fWorksheet.addFloatDomToPosition({
* const disposable = fWorksheet.addFloatDomToPosition({
* componentKey: 'myFloatDom',
* initPosition: {
* startX: 100,
@@ -73,10 +210,11 @@ export interface IFWorksheetLegacy {
* label: 'hahah',
* },
* });
* console.log(disposable?.id); // The id of the floating DOM
*
* // Remove the floating DOM after 2 seconds
* setTimeout(() => {
* disposeable?.dispose();
* disposable?.dispose();
* }, 2000);
* ```
*/
@@ -121,11 +259,12 @@ export interface IFWorksheetLegacy {
*
* // Add the range loading component covering the range A1:C3
* const fRange = fWorksheet.getRange('A1:C3');
* const disposeable = fWorksheet.addFloatDomToRange(fRange, { componentKey: 'RangeLoading' }, {}, 'myRangeLoading');
* const disposable = fWorksheet.addFloatDomToRange(fRange, { componentKey: 'RangeLoading' }, {}, 'myRangeLoading');
* console.log(disposable?.id); // The id of the floating DOM
*
* // Remove the floating DOM after 2 seconds
* setTimeout(() => {
* disposeable?.dispose();
* disposable?.dispose();
* }, 2000);
*
* // another example-------------------
@@ -158,7 +297,7 @@ export interface IFWorksheetLegacy {
*
* // Add the float button to the range A5:C7, position is start from A5 cell, and width is 100px, height is 30px, margin is 100% of range width and height
* const fRange2 = fWorksheet.getRange('A5:C7');
* const disposeable2 = fWorksheet.addFloatDomToRange(
* const disposable2 = fWorksheet.addFloatDomToRange(
* fRange2,
* {
* componentKey: 'FloatButton',
@@ -171,6 +310,7 @@ export interface IFWorksheetLegacy {
* },
* 'myFloatButton'
* );
* console.log(disposable2?.id); // The id of the floating DOM
* ```
*/
addFloatDomToRange(range: FRange, layer: Partial<IFICanvasFloatDom>, domLayout: Partial<IDOMAnchor>, id?: string): Nullable<{
@@ -217,7 +357,7 @@ export interface IFWorksheetLegacy {
* univerAPI.registerComponent('FloatButton', FloatButton);
*
* // Add the float button to the column D header, position is right align, width is 100px, height is 30px, margin is 0
* const disposeable = fWorksheet.addFloatDomToColumnHeader(
* const disposable = fWorksheet.addFloatDomToColumnHeader(
* 3,
* {
* componentKey: 'FloatButton',
@@ -232,10 +372,11 @@ export interface IFWorksheetLegacy {
* },
* 'myFloatButton'
* );
* console.log(disposable?.id); // The id of the floating DOM
*
* // Remove the float button after 2 seconds
* setTimeout(() => {
* disposeable?.dispose();
* disposable?.dispose();
* }, 2000);
* ```
*/
@@ -450,6 +591,212 @@ export interface IFWorksheetLegacy {
}
export class FWorksheetLegacy extends FWorksheet implements IFWorksheetLegacy {
override getFloatDomById(id: string): Nullable<IFCanvasFloatDomResult> {
const floatDomService = this._injector.get(SheetCanvasFloatDomManagerService);
const info = floatDomService.getFloatDomInfo(id);
if (!info) return null;
const { unitId, subUnitId } = info;
const { rect } = info;
const state = rect.getState();
const { left = 0, top = 0, width = 0, height = 0, flipX = false, flipY = false, angle = 0, skewX = 0, skewY = 0 } = state;
const drawingParm = this._injector.get(ISheetDrawingService).getDrawingByParam({
drawingId: info.id,
unitId,
subUnitId,
})! as ISheetFloatDom;
if (!drawingParm) return null;
return {
position: {
left,
top,
width,
height,
flipX,
flipY,
angle,
skewX,
skewY,
},
componentKey: drawingParm.componentKey,
allowTransform: drawingParm.allowTransform,
data: drawingParm.data,
id: info.id,
};
}
override getAllFloatDoms(): IFCanvasFloatDomResult[] {
const floatDomService = this._injector.get(SheetCanvasFloatDomManagerService);
const unitId = this._workbook.getUnitId();
const subUnitId = this._worksheet.getSheetId();
return Array.from(floatDomService.getFloatDomsBySubUnitId(unitId, subUnitId).values())
.map((info) => {
const { rect } = info;
const drawingParm = this._injector.get(ISheetDrawingService).getDrawingByParam({
drawingId: info.id,
unitId,
subUnitId,
})! as ISheetFloatDom;
const { left, top, width, height, flipX, flipY, angle, skewX, skewY } = rect.getState();
return {
position: {
left,
top,
width,
height,
flipX,
flipY,
angle,
skewX,
skewY,
},
componentKey: drawingParm.componentKey,
allowTransform: drawingParm.allowTransform,
data: drawingParm.data,
id: info.id,
};
});
}
override updateFloatDom(id: string, config: Partial<Omit<IFCanvasFloatDomResult, 'id'>>): this {
const floatDomService = this._injector.get(SheetCanvasFloatDomManagerService);
const info = floatDomService.getFloatDomInfo(id);
if (!info) return this;
const { unitId, subUnitId } = info;
const drawingParm = this._injector.get(ISheetDrawingService).getDrawingByParam({
unitId,
subUnitId,
drawingId: id,
})! as ISheetFloatDom;
const renderManagerService = this._injector.get(IRenderManagerService);
const render = renderManagerService.getRenderById(unitId);
if (!render) return this;
const skeleton = this.getSkeleton();
if (!skeleton) return this;
const selectionRenderService = renderManagerService.getRenderById(this.getWorkbook().getUnitId())?.with(ISheetSelectionRenderService);
if (!selectionRenderService) return this;
const newParam: ISheetFloatDom = {
...drawingParm,
componentKey: config.componentKey || drawingParm.componentKey,
allowTransform: config.allowTransform !== undefined ? config.allowTransform : drawingParm.allowTransform,
data: config.data || drawingParm.data,
sheetTransform: config.position
? transformToDrawingPosition(
config.position,
selectionRenderService
) ?? drawingParm.sheetTransform
: drawingParm.sheetTransform,
transform: {
...drawingParm.transform,
...config.position, // Merge with existing transform
},
};
const res = this._commandService.syncExecuteCommand(SetSheetDrawingCommand.id, { unitId, subUnitId, drawings: [newParam] });
if (!res) {
throw new Error('updateFloatDom failed');
}
return this;
}
override batchUpdateFloatDoms(updates: Array<{ id: string; config: Partial<Omit<IFCanvasFloatDomResult, 'id'>> }>): this {
const floatDomService = this._injector.get(SheetCanvasFloatDomManagerService);
const drawingService = this._injector.get(ISheetDrawingService);
const renderManagerService = this._injector.get(IRenderManagerService);
const drawings: ISheetFloatDom[] = [];
for (const update of updates) {
const info = floatDomService.getFloatDomInfo(update.id);
if (!info) continue;
const { unitId, subUnitId } = info;
const drawingParm = drawingService.getDrawingByParam({
unitId,
subUnitId,
drawingId: update.id,
}) as ISheetFloatDom;
if (!drawingParm) continue;
const render = renderManagerService.getRenderById(unitId);
if (!render) continue;
const skeleton = this.getSkeleton();
if (!skeleton) continue;
const selectionRenderService = render.with(ISheetSelectionRenderService);
if (!selectionRenderService) return this;
const newParam: ISheetFloatDom = {
...drawingParm,
componentKey: update.config.componentKey || drawingParm.componentKey,
allowTransform: update.config.allowTransform !== undefined ? update.config.allowTransform : drawingParm.allowTransform,
data: update.config.data || drawingParm.data,
sheetTransform: update.config.position
? transformToDrawingPosition(
update.config.position,
selectionRenderService
) ?? drawingParm.sheetTransform
: drawingParm.sheetTransform,
transform: {
...drawingParm.transform,
...update.config.position, // Merge with existing transform
},
};
drawings.push(newParam);
}
if (drawings.length > 0) {
const unitId = this._workbook.getUnitId();
const subUnitId = this._worksheet.getSheetId();
const res = this._commandService.syncExecuteCommand(SetSheetDrawingCommand.id, { unitId, subUnitId, drawings });
if (!res) {
throw new Error('batchUpdateFloatDoms failed');
}
}
return this;
}
override removeFloatDom(id: string): this {
const floatDomService = this._injector.get(SheetCanvasFloatDomManagerService);
const info = floatDomService.getFloatDomInfo(id);
if (!info) return this;
const { unitId, subUnitId } = info;
const drawingService = this._injector.get(ISheetDrawingService);
const drawing = drawingService.getDrawingByParam({
unitId,
subUnitId,
drawingId: id,
});
if (!drawing) return this;
// Then delete it
const res = this._commandService.syncExecuteCommand(RemoveSheetDrawingCommand.id, {
unitId,
drawings: [drawing],
});
if (!res) {
throw new Error('removeFloatDom failed');
}
return this;
}
override addFloatDomToPosition(layer: IFICanvasFloatDom, id?: string): Nullable<{
id: string;
dispose: () => void;
@@ -669,5 +1016,5 @@ export class FWorksheetLegacy extends FWorksheet implements IFWorksheetLegacy {
FWorksheet.extend(FWorksheetLegacy);
declare module '@univerjs/sheets/facade' {
// eslint-disable-next-line ts/naming-convention
interface FWorksheet extends IFWorksheetLegacy {}
interface FWorksheet extends IFWorksheetLegacy { }
}
+3 -1
View File
@@ -16,6 +16,7 @@
import './global.css';
export { drawingPositionToTransform, transformToDrawingPosition } from './basics/transform-position';
export { DeleteDrawingsCommand } from './commands/commands/delete-drawings.command';
export { GroupSheetDrawingCommand } from './commands/commands/group-sheet-drawing.command';
export { type IInsertImageCommandParams, InsertFloatImageCommand } from './commands/commands/insert-image.command';
@@ -32,5 +33,6 @@ export { SidebarSheetDrawingOperation } from './commands/operations/open-drawing
export type { IUniverSheetsDrawingUIConfig } from './controllers/config.schema';
export { SheetDrawingUpdateController } from './controllers/sheet-drawing-update.controller';
export { UniverSheetsDrawingUIPlugin } from './plugin';
export { type ICanvasFloatDom, type IDOMAnchor, SheetCanvasFloatDomManagerService } from './services/canvas-float-dom-manager.service';
export { calcSheetFloatDomPosition, type ICanvasFloatDom, type ICanvasFloatDomInfo, type IDOMAnchor, SheetCanvasFloatDomManagerService } from './services/canvas-float-dom-manager.service';
export { SHEETS_IMAGE_MENU_ID } from './views/menu/image.menu';
@@ -613,6 +613,22 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
...sheetDrawing.transform,
};
this._transformChange$.next({ id: data.drawingId, value: newValue });
this._canvasFloatDomService.updateFloatDom(data.drawingId, {
...sheetDrawing,
});
const renderObject = this._getSceneAndTransformerByDrawingSearch(data.unitId);
if (renderObject) {
const { scene } = renderObject;
const floatDomInfo = this._domLayerInfoMap.get(data.drawingId);
if (floatDomInfo?.rect) {
if (sheetDrawing.allowTransform === false) {
scene.detachTransformerFrom(floatDomInfo.rect);
} else {
scene.attachTransformerTo(floatDomInfo.rect);
}
}
}
});
})
);
@@ -628,19 +644,6 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
);
}
updateFloatDomProps(unitId: string, subUnitId: string, id: string, props: Record<string, any>) {
const info = this._domLayerInfoMap.get(id);
const renderObject = this._getSceneAndTransformerByDrawingSearch(unitId);
if (info && renderObject) {
const { scene } = renderObject;
const rectShapeKey = getDrawingShapeKeyByDrawingSearch({ unitId, subUnitId, drawingId: id });
const rectShape = scene.getObject(rectShapeKey);
if (rectShape && rectShape instanceof Rect) {
rectShape.setProps(props);
}
}
}
// CreateFloatDomCommand --> floatDomService.addFloatDomToPosition
addFloatDomToPosition(layer: ICanvasFloatDom, propId?: string) {
const target = getSheetCommandTarget(this._univerInstanceService, {
@@ -56,6 +56,19 @@ export class CanvasFloatDomService {
this._domLayers$.next(Array.from(this._domLayerMap.entries()));
}
updateFloatDom(id: string, item: Partial<IFloatDom>) {
const current = this._domLayerMap.get(id);
if (!current) {
return;
}
this._domLayerMap.set(id, {
...current,
...item,
});
this._notice();
}
addFloatDom(item: IFloatDom) {
this._domLayerMap.set(item.id, item);
this._notice();