Skip to content

Commit

Permalink
perf(sheets-drawing-ui): float dom scroll performance optimize (#3838)
Browse files Browse the repository at this point in the history
  • Loading branch information
weird94 authored Oct 24, 2024
1 parent 7e49171 commit b4b8810
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@
* limitations under the License.
*/

import type { IDisposable, IPosition, ITransformState, Nullable, Serializable, Worksheet } from '@univerjs/core';
import type { IDisposable, IPosition, ITransformState, Nullable, Serializable, Workbook, Worksheet } from '@univerjs/core';
import type { IDrawingJsonUndo1 } from '@univerjs/drawing';
import type { BaseObject, IBoundRectNoAngle, IRectProps, IRender, Scene, SpreadsheetSkeleton } from '@univerjs/engine-render';
import type { ISetFrozenMutationParams } from '@univerjs/sheets';
import type { IFloatDomData, ISheetDrawingPosition, ISheetFloatDom } from '@univerjs/sheets-drawing';
import type { IFloatDomLayout } from '@univerjs/ui';
import type { IInsertDrawingCommandParams } from '../commands/commands/interfaces';
import { Disposable, DisposableCollection, generateRandomId, ICommandService, Inject, IUniverInstanceService } from '@univerjs/core';
import { Disposable, DisposableCollection, fromEventSubject, generateRandomId, ICommandService, Inject, IUniverInstanceService, UniverInstanceType } from '@univerjs/core';
import { DrawingTypeEnum, getDrawingShapeKeyByDrawingSearch, IDrawingManagerService } from '@univerjs/drawing';

import { DRAWING_OBJECT_LAYER_INDEX, IRenderManagerService, Rect, SHEET_VIEWPORT_KEY } from '@univerjs/engine-render';
import { getSheetCommandTarget, SetFrozenMutation } from '@univerjs/sheets';
import { DrawingApplyType, ISheetDrawingService, SetDrawingApplyMutation } from '@univerjs/sheets-drawing';
import { ISheetSelectionRenderService, SetScrollOperation, SetZoomRatioOperation, SheetSkeletonManagerService } from '@univerjs/sheets-ui';
import { ISheetSelectionRenderService, SetZoomRatioOperation, SheetSkeletonManagerService, VIEWPORT_KEY } from '@univerjs/sheets-ui';
import { CanvasFloatDomService } from '@univerjs/ui';
import { BehaviorSubject, Subject } from 'rxjs';
import { BehaviorSubject, filter, map, Subject, switchMap } from 'rxjs';
import { InsertSheetDrawingCommand } from '../commands/commands/insert-sheet-drawing.command';

export interface ICanvasFloatDom {
Expand Down Expand Up @@ -371,29 +371,50 @@ export class SheetCanvasFloatDomManagerService extends Disposable {
}

private _scrollUpdateListener() {
this.disposeWithMe(this._commandService.onCommandExecuted((commandInfo) => {
const updateSheet = (unitId: string, subUnitId: string) => {
const renderObject = this._getSceneAndTransformerByDrawingSearch(unitId);
const map = this._ensureMap(unitId, subUnitId);
const ids = Array.from(map.keys());
const target = getSheetCommandTarget(this._univerInstanceService, { unitId, subUnitId });
const skeleton = this._renderManagerService.getRenderById(unitId)?.with(SheetSkeletonManagerService).getWorksheetSkeleton(subUnitId);
if (!renderObject || !target || !skeleton) {
return;
const updateSheet = (unitId: string, subUnitId: string) => {
const renderObject = this._getSceneAndTransformerByDrawingSearch(unitId);
const map = this._ensureMap(unitId, subUnitId);
const ids = Array.from(map.keys());
const target = getSheetCommandTarget(this._univerInstanceService, { unitId, subUnitId });
const skeleton = this._renderManagerService.getRenderById(unitId)?.with(SheetSkeletonManagerService).getWorksheetSkeleton(subUnitId);
if (!renderObject || !target || !skeleton) {
return;
}
ids.forEach((id) => {
const info = this._domLayerInfoMap.get(id);
if (info) {
const position = calcPosition(info.rect, renderObject.renderObject, skeleton.skeleton, target.worksheet);
info.position$.next(position);
}
ids.forEach((id) => {
const info = this._domLayerInfoMap.get(id);
if (info) {
const position = calcPosition(info.rect, renderObject.renderObject, skeleton.skeleton, target.worksheet);
info.position$.next(position);
}
});
};
if (commandInfo.id === SetScrollOperation.id) {
const params = (commandInfo.params) as any;
const { unitId, sheetId } = params;
updateSheet(unitId, sheetId);
} else if (commandInfo.id === SetZoomRatioOperation.id) {
});
};
let time = 0;

this.disposeWithMe(

this._univerInstanceService.getCurrentTypeOfUnit$<Workbook>(UniverInstanceType.UNIVER_SHEET)
.pipe(
filter((sheet) => !!sheet),
map((sheet) => {
const render = this._renderManagerService.getRenderById(sheet.getUnitId());
return render ? { render, unitId: sheet.getUnitId(), subUnitId: sheet.getActiveSheet().getSheetId() } : null;
}),
filter((render) => !!render),
switchMap((render) => fromEventSubject(render.render.scene.getViewport(VIEWPORT_KEY.VIEW_MAIN)!.onMouseWheel$)
.pipe(
map(() => ({ unitId: render.unitId, subUnitId: render.subUnitId }))
)
)
)
.subscribe(({ unitId, subUnitId }) => {
const now = performance.now();
time = now;
updateSheet(unitId, subUnitId);
})

);
this.disposeWithMe(this._commandService.onCommandExecuted((commandInfo) => {
if (commandInfo.id === SetZoomRatioOperation.id) {
const params = (commandInfo.params) as any;
const { unitId } = params;
const subUnitIds = Array.from(this._domLayerMap.get(unitId)?.keys() ?? []);
Expand Down
142 changes: 99 additions & 43 deletions packages/ui/src/views/components/dom/FloatDom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

import type { IFloatDom } from '../../../services/dom/canvas-dom-layer.service';
import { IUniverInstanceService, UniverInstanceType, useDependency } from '@univerjs/core';
import React, { memo } from 'react';
import React, { memo, useEffect, useMemo, useRef } from 'react';
import { distinctUntilChanged, first } from 'rxjs';
import { ComponentManager } from '../../../common';
import { useObservable } from '../../../components/hooks/observable';
import { CanvasFloatDomService } from '../../../services/dom/canvas-dom-layer.service';
Expand All @@ -25,55 +26,110 @@ import styles from './index.module.less';
const FloatDomSingle = memo((props: { layer: IFloatDom; id: string }) => {
const { layer, id } = props;
const componentManager = useDependency(ComponentManager);
const position = useObservable(layer.position$);
const size$ = useMemo(() => layer.position$.pipe(
distinctUntilChanged(
(prev, curr) => prev.absolute.left === curr.absolute.left &&
prev.absolute.top === curr.absolute.top &&
prev.endX - prev.startX === curr.endX - curr.startX &&
prev.endY - prev.startY === curr.endY - curr.startY
)
), [layer.position$]);

const position = useObservable(useMemo(() => layer.position$.pipe(first()), [layer.position$]));
const domRef = useRef<HTMLDivElement>(null);
const innerDomRef = useRef<HTMLDivElement>(null);
const transformRef = useRef<string>(`transform: rotate(${position?.rotate}deg) translate(${position?.startX}px, ${position?.startY}px)`);
const innerStyle = useRef<React.CSSProperties>({

});
const Component = typeof layer.componentKey === 'string' ? componentManager.get(layer.componentKey) : layer.componentKey;
const layerProps: any = {
const layerProps: any = useMemo(() => ({
data: layer.data,
...layer.props,
};
}), [layer.data, layer.props]);

useEffect(() => {
const subscription = layer.position$.subscribe((position) => {
transformRef.current = `rotate(${position.rotate}deg) translate(${position.startX}px, ${position.startY}px)`;
if (domRef.current) {
domRef.current.style.transform = transformRef.current;
}
});

const sizeSubscription = size$.subscribe((size) => {
if (domRef.current) {
domRef.current.style.width = `${size.endX - size.startX}px`;
domRef.current.style.height = `${size.endY - size.startY}px`;
}

if (innerDomRef.current) {
const style = {
width: `${size.width}px`,
height: `${size.height}px`,
left: `${size.absolute.left ? 0 : 'auto'}`,
top: `${size.absolute.top ? 0 : 'auto'}`,
right: `${size.absolute.left ? 'auto' : 0}`,
bottom: `${size.absolute.top ? 'auto' : 0}`,
};

return position
? (
innerDomRef.current.style.width = style.width;
innerDomRef.current.style.height = style.height;
innerDomRef.current.style.left = style.left;
innerDomRef.current.style.top = style.top;
innerDomRef.current.style.right = style.right;
innerDomRef.current.style.bottom = style.bottom;

innerStyle.current = style;
}
});
return () => {
subscription.unsubscribe();
sizeSubscription.unsubscribe();
};
}, [layer.position$, size$]);

const component = useMemo(() => Component ? <Component {...layerProps} /> : null, [Component, layerProps]);

if (!position) {
return null;
}

return (
<div
ref={domRef}
className={styles.floatDomWrapper}
style={{
position: 'absolute',
top: 0,
left: 0,
width: Math.max(position.endX - position.startX - 2, 0),
height: Math.max(position.endY - position.startY - 2, 0),
transform: transformRef.current,
overflow: 'hidden',
}}
onPointerMove={(e) => {
layer.onPointerMove(e.nativeEvent);
}}
onPointerDown={(e) => {
layer.onPointerDown(e.nativeEvent);
}}
onPointerUp={(e) => {
layer.onPointerUp(e.nativeEvent);
}}
onWheel={(e) => {
layer.onWheel(e.nativeEvent);
}}
>
<div
className={styles.floatDomWrapper}
style={{
position: 'absolute',
top: position.startY,
left: position.startX,
width: Math.max(position.endX - position.startX - 2, 0),
height: Math.max(position.endY - position.startY - 2, 0),
transform: `rotate(${position.rotate}deg)`,
overflow: 'hidden',
}}
onPointerMove={(e) => {
layer.onPointerMove(e.nativeEvent);
}}
onPointerDown={(e) => {
layer.onPointerDown(e.nativeEvent);
}}
onPointerUp={(e) => {
layer.onPointerUp(e.nativeEvent);
}}
onWheel={(e) => {
layer.onWheel(e.nativeEvent);
}}
id={id}
ref={innerDomRef}
className={styles.floatDom}
style={{ position: 'absolute', ...innerStyle.current }}
>
<div
id={id}
className={styles.floatDom}
style={{
width: position.width,
height: position.height,
position: 'absolute',
...(position.absolute.left) ? { left: 0 } : { right: 0 },
...(position.absolute.top) ? { top: 0 } : { bottom: 0 },
}}
>
{Component ? <Component {...layerProps} /> : null}
</div>
{component}
</div>
)
: null;
</div>
);
});

export const FloatDom = ({ unitId }: { unitId?: string }) => {
Expand Down

0 comments on commit b4b8810

Please sign in to comment.