Skip to content

Commit

Permalink
feat(sheets-ui): support drawing print (#2418)
Browse files Browse the repository at this point in the history
* feat: printing support drawing

* feat: update

* feat: update

* feat: update

* feat: update

* fix: review issue
  • Loading branch information
weird94 authored Jun 6, 2024
1 parent d4a0929 commit f24cace
Show file tree
Hide file tree
Showing 14 changed files with 306 additions and 68 deletions.
77 changes: 15 additions & 62 deletions packages/drawing-ui/src/controllers/image-update.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,24 @@
*/

import type { ICommandInfo, Nullable } from '@univerjs/core';
import { Disposable,
import {
Disposable,
ICommandService,
IUniverInstanceService,
LifecycleStages,
OnLifecycle,
toDisposable,
} from '@univerjs/core';
import type { IImageProps, Scene } from '@univerjs/engine-render';
import { CURSOR_TYPE, DRAWING_OBJECT_LAYER_INDEX, Image, IRenderManagerService } from '@univerjs/engine-render';
import type { Image, Scene } from '@univerjs/engine-render';
import { CURSOR_TYPE, IRenderManagerService } from '@univerjs/engine-render';
import type { IDrawingSearch, IImageData } from '@univerjs/drawing';
import { DrawingTypeEnum, getDrawingShapeKeyByDrawingSearch, IDrawingManagerService, IImageIoService, ImageSourceType } from '@univerjs/drawing';
import { DrawingTypeEnum, getDrawingShapeKeyByDrawingSearch, IDrawingManagerService, IImageIoService } from '@univerjs/drawing';
import { IDialogService } from '@univerjs/ui';
import { Inject } from '@wendellhu/redi';
import { COMPONENT_IMAGE_VIEWER } from '../views/image-viewer/component-name';
import { ImageResetSizeOperation } from '../commands/operations/image-reset-size.operation';
import { getCurrentUnitInfo, insertGroupObject } from './utils';
import { DrawingRenderService } from '../services/drawing-render.service';
import { getCurrentUnitInfo } from './utils';

const IMAGE_VIEWER_DROPDOWN_PADDING = 50;

Expand All @@ -41,7 +44,8 @@ export class ImageUpdateController extends Disposable {
@IDrawingManagerService private readonly _drawingManagerService: IDrawingManagerService,
@IDialogService private readonly _dialogService: IDialogService,
@IImageIoService private readonly _imageIoService: IImageIoService,
@IUniverInstanceService private readonly _currentUniverService: IUniverInstanceService
@IUniverInstanceService private readonly _currentUniverService: IUniverInstanceService,
@Inject(DrawingRenderService) private readonly _drawingRenderService: DrawingRenderService
) {
super();

Expand Down Expand Up @@ -193,72 +197,21 @@ export class ImageUpdateController extends Disposable {
private _insertImages(params: IDrawingSearch[]) {
(params).forEach(async (param) => {
const { unitId, subUnitId, drawingId } = param;
const imageParam = this._drawingManagerService.getDrawingByParam(param) as IImageData;
if (imageParam == null) {
return;
}

const { transform, drawingType, source, imageSourceType, srcRect, prstGeom, groupId } = imageParam;
if (drawingType !== DrawingTypeEnum.DRAWING_IMAGE) {
return;
}
const renderObject = this._getSceneAndTransformerByDrawingSearch(unitId);

if (renderObject == null) {
return;
}
const { scene, transformer } = renderObject;
if (transform == null) {
return true;
}

const { left, top, width, height, angle, flipX, flipY, skewX, skewY } = transform;
const imageShapeKey = getDrawingShapeKeyByDrawingSearch({ unitId, subUnitId, drawingId });
const imageShape = scene.getObject(imageShapeKey);

if (imageShape != null) {
imageShape.transformByState({ left, top, width, height, angle, flipX, flipY, skewX, skewY });
const imageParam = this._drawingManagerService.getDrawingByParam(param) as IImageData;
if (imageParam == null) {
return;
}

const orders = this._drawingManagerService.getDrawingOrder(unitId, subUnitId);
const zIndex = orders.indexOf(drawingId);
const imageConfig: IImageProps = { ...transform, zIndex: zIndex === -1 ? (orders.length - 1) : zIndex };
const imageNativeCache = this._imageIoService.getImageSourceCache(source, imageSourceType);

let shouldBeCache = false;
if (imageNativeCache != null) {
imageConfig.image = imageNativeCache;
} else {
if (imageSourceType === ImageSourceType.UUID) {
try {
imageConfig.url = await this._imageIoService.getImage(source);
} catch (error) {
console.error(error);
return;
}
} else {
imageConfig.url = source;
}
shouldBeCache = true;
}

const image = new Image(imageShapeKey, imageConfig);
if (shouldBeCache) {
this._imageIoService.addImageSourceCache(source, imageSourceType, image.getNative());
}

scene.addObject(image, DRAWING_OBJECT_LAYER_INDEX).attachTransformerTo(image);

groupId && insertGroupObject({ drawingId: groupId, unitId, subUnitId }, image, scene, this._drawingManagerService);

if (prstGeom != null) {
image.setPrstGeom(prstGeom);
}
if (srcRect != null) {
image.setSrcRect(srcRect);
const image = await this._drawingRenderService.renderImage(imageParam, renderObject.scene);
if (!image) {
return;
}

this._addHoverForImage(image);
this._addDialogForImage(image);
});
Expand Down
1 change: 1 addition & 0 deletions packages/drawing-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

export { DrawingRenderService } from './services/drawing-render.service';
export { getUpdateParams } from './utils/get-update-params';
export { ImageResetSizeOperation } from './commands/operations/image-reset-size.operation';
export { CloseImageCropOperation, OpenImageCropOperation } from './commands/operations/image-crop.operation';
Expand Down
3 changes: 2 additions & 1 deletion packages/drawing-ui/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { DrawingUpdateController } from './controllers/drawing-update.controller
import { DrawingUIController } from './controllers/drawing-ui.controller';
import { ImageCropperController } from './controllers/image-cropper.controller';
import { ImageUpdateController } from './controllers/image-update.controller';
import { DrawingRenderService } from './services/drawing-render.service';

const PLUGIN_NAME = 'DRAWING_UI_PLUGIN';

Expand All @@ -43,7 +44,7 @@ export class UniverDrawingUIPlugin extends Plugin {
const dependencies: Dependency[] = [

// services

[DrawingRenderService],
// controllers
[DrawingUpdateController],
[DrawingUIController],
Expand Down
102 changes: 102 additions & 0 deletions packages/drawing-ui/src/services/drawing-render.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { IDrawingSearch, IImageData } from '@univerjs/drawing';
import { DrawingTypeEnum, getDrawingShapeKeyByDrawingSearch, IDrawingManagerService, IImageIoService, ImageSourceType } from '@univerjs/drawing';
import type { IImageProps, Scene } from '@univerjs/engine-render';
import { DRAWING_OBJECT_LAYER_INDEX, Image } from '@univerjs/engine-render';
import { insertGroupObject } from '../controllers/utils';

export class DrawingRenderService {
constructor(
@IDrawingManagerService private readonly _drawingManagerService: IDrawingManagerService,
@IImageIoService private readonly _imageIoService: IImageIoService
) { }

async renderImage(imageParam: IImageData, scene: Scene) {
const { transform, drawingType, source, imageSourceType, srcRect, prstGeom, groupId, unitId, subUnitId, drawingId } = imageParam;
if (drawingType !== DrawingTypeEnum.DRAWING_IMAGE) {
return;
}

if (transform == null) {
return;
}

const { left, top, width, height, angle, flipX, flipY, skewX, skewY } = transform;
const imageShapeKey = getDrawingShapeKeyByDrawingSearch({ unitId, subUnitId, drawingId });
const imageShape = scene.getObject(imageShapeKey);

if (imageShape != null) {
imageShape.transformByState({ left, top, width, height, angle, flipX, flipY, skewX, skewY });
return;
}

const orders = this._drawingManagerService.getDrawingOrder(unitId, subUnitId);
const zIndex = orders.indexOf(drawingId);
const imageConfig: IImageProps = { ...transform, zIndex: zIndex === -1 ? (orders.length - 1) : zIndex };
const imageNativeCache = this._imageIoService.getImageSourceCache(source, imageSourceType);

let shouldBeCache = false;
if (imageNativeCache != null) {
imageConfig.image = imageNativeCache;
} else {
if (imageSourceType === ImageSourceType.UUID) {
try {
imageConfig.url = await this._imageIoService.getImage(source);
} catch (error) {
console.error(error);
return;
}
} else {
imageConfig.url = source;
}
shouldBeCache = true;
}

imageConfig.printable = true;
const image = new Image(imageShapeKey, imageConfig);
if (shouldBeCache) {
this._imageIoService.addImageSourceCache(source, imageSourceType, image.getNative());
}

scene.addObject(image, DRAWING_OBJECT_LAYER_INDEX).attachTransformerTo(image);

groupId && insertGroupObject({ drawingId: groupId, unitId, subUnitId }, image, scene, this._drawingManagerService);

if (prstGeom != null) {
image.setPrstGeom(prstGeom);
}
if (srcRect != null) {
image.setSrcRect(srcRect);
}

return image;
}

renderDrawing(param: IDrawingSearch, scene: Scene) {
const drawingParam = this._drawingManagerService.getDrawingByParam(param);
if (drawingParam == null) {
return;
}

switch (drawingParam.drawingType) {
case DrawingTypeEnum.DRAWING_IMAGE:
return this.renderImage(drawingParam as IImageData, scene);
default:
}
}
}
6 changes: 6 additions & 0 deletions packages/engine-render/src/base-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export abstract class BaseObject extends Disposable {
protected _dirty: boolean = true;
protected _forceDirty: boolean = true;

private _printable: boolean = false;

private _top: number = 0;
private _topOrigin: number | string = 0;

Expand Down Expand Up @@ -155,6 +157,10 @@ export abstract class BaseObject extends Disposable {
return transform;
}

get printable() {
return this._printable;
}

get topOrigin() {
return this._topOrigin;
}
Expand Down
1 change: 1 addition & 0 deletions packages/engine-render/src/basics/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export interface IObjectFullState extends ITransformState {
forceRender?: boolean;
debounceParentDirty?: boolean;
transformerConfig?: ITransformerConfig;
printable?: boolean;
}

export interface IRect extends ISize, IOffset {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export class Marker extends SheetExtension {

// eslint-disable-next-line max-lines-per-function
override draw(ctx: UniverRenderingContext, parentScale: IScale, skeleton: SpreadsheetSkeleton, diffRanges: IRange[]): void {
if (ctx.__mode === 'printing') {
return;
}

const { worksheet, rowColumnSegment } = skeleton;
if (!worksheet) {
return;
Expand Down
6 changes: 5 additions & 1 deletion packages/engine-render/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -965,9 +965,13 @@ export class UniverRenderingContextWebGL { }
*/
export class UniverRenderingContextWebGPU { }

export class UniverRenderingContext extends UniverRenderingContext2D { }
export class UniverRenderingContext extends UniverRenderingContext2D {
__mode = 'rendering';
}

export class UniverPrintingContext extends UniverRenderingContext2D {
__mode = 'printing';

private __getScale() {
const m = this.getTransform();
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { BooleanNumber, DataValidationRenderMode, DEFAULT_EMPTY_DOCUMENT_VALUE, DocumentDataModel, HorizontalAlign, ICommandService, LocaleService, Tools, VerticalAlign, WrapStrategy } from '@univerjs/core';
import type { ICellRenderContext, IDocumentData, IPaddingData, IStyleData, Nullable } from '@univerjs/core';
import { Documents, DocumentSkeleton, DocumentViewModel, getDocsSkeletonPageSize, Rect } from '@univerjs/engine-render';
import type { IMouseEvent, IPointerEvent, ISheetFontRenderExtension, SpreadsheetSkeleton, UniverRenderingContext2D } from '@univerjs/engine-render';
import type { IMouseEvent, IPointerEvent, ISheetFontRenderExtension, SpreadsheetSkeleton, UniverRenderingContext, UniverRenderingContext2D } from '@univerjs/engine-render';
import { Inject } from '@wendellhu/redi';
import type { IBaseDataValidationWidget } from '@univerjs/data-validation';
import { getCellValueOrigin } from '../utils/get-cell-data-origin';
Expand Down Expand Up @@ -270,7 +270,7 @@ export class DropdownWidget implements IBaseDataValidationWidget {
ctx.beginPath();
ctx.rect(0, 0, realWidth, fontHeight);
ctx.clip();
documents.render(ctx);
documents.render(ctx as UniverRenderingContext);
ctx.translateWithPrecision(paddingLeft, 0);
ctx.restore();

Expand Down Expand Up @@ -330,7 +330,7 @@ export class DropdownWidget implements IBaseDataValidationWidget {
ctx.translate(MARGIN_H, paddingTop);
const rectWidth = Math.max(cellWidth - MARGIN_H * 2, 1);
const rectHeight = fontHeight;
Rect.drawWith(ctx, {
Rect.drawWith(ctx as UniverRenderingContext, {
width: rectWidth,
height: rectHeight,
fill: activeItem?.color || DROP_DOWN_DEFAULT_COLOR,
Expand All @@ -342,7 +342,7 @@ export class DropdownWidget implements IBaseDataValidationWidget {
ctx.rect(0, 0, realWidth, fontHeight);
ctx.clip();
ctx.translateWithPrecision(paddingLeft, 0);
documents.render(ctx);
documents.render(ctx as UniverRenderingContext);
ctx.restore();
ctx.translate(realWidth + PADDING_H + 4, (fontHeight - ICON_SIZE) / 2);
ctx.fillStyle = DROP_DOWN_ICON_COLOR;
Expand Down
Loading

0 comments on commit f24cace

Please sign in to comment.