diff --git a/packages/lb-annotation/src/core/pointCloud/annotation.ts b/packages/lb-annotation/src/core/pointCloud/annotation.ts index c97aa8c3..138e6436 100644 --- a/packages/lb-annotation/src/core/pointCloud/annotation.ts +++ b/packages/lb-annotation/src/core/pointCloud/annotation.ts @@ -230,7 +230,11 @@ export class PointCloudAnnotation implements IPointCloudAnnotationOperation { this.updatePointList(sphereList); } - public updatePolygonList = (pointCloudDataList: IPointCloudBox[], extraList?: IPolygonData[]) => { + public updatePolygonList = ( + pointCloudDataList: IPointCloudBox[], + extraList?: IPolygonData[], + isDeleteSelectedID: boolean = true, + ) => { let polygonList = pointCloudDataList.map((v: IPointCloudBox) => { const { polygon2d: pointList } = this.pointCloudInstance.getBoxTopPolygon2DCoordinate(v); return { @@ -256,10 +260,10 @@ export class PointCloudAnnotation implements IPointCloudAnnotationOperation { ); } - this.toolScheduler.updateDataByToolName(EToolName.PointCloudPolygon, polygonList); + this.toolScheduler.updateDataByToolName(EToolName.PointCloudPolygon, polygonList, isDeleteSelectedID); }; - public updatePointList = (sphereList: IPointCloudSphere[]) => { + public updatePointList = (sphereList: IPointCloudSphere[], isDeleteSelectedID: boolean = true) => { const pointList = sphereList?.map((v: IPointCloudSphere) => { const { point2d } = this.pointCloudInstance.getSphereTopPoint2DCoordinate(v); return { @@ -271,7 +275,7 @@ export class PointCloudAnnotation implements IPointCloudAnnotationOperation { textAttribute: '', }; }) as IPointUnit[]; - this.toolScheduler.updateDataByToolName(EToolName.Point, pointList); + this.toolScheduler.updateDataByToolName(EToolName.Point, pointList, isDeleteSelectedID); }; /** diff --git a/packages/lb-annotation/src/core/scheduler.ts b/packages/lb-annotation/src/core/scheduler.ts index c5f43ae0..479e8814 100644 --- a/packages/lb-annotation/src/core/scheduler.ts +++ b/packages/lb-annotation/src/core/scheduler.ts @@ -350,11 +350,11 @@ export class ToolScheduler implements IToolSchedulerOperation { * there is no more specific instance like pointCloud2dOperation you can reach, * so if you need to update result in specific operation instance, you can try this. */ - public updateDataByToolName(toolName: EToolName, result: any) { + public updateDataByToolName(toolName: EToolName, result: any, isDeleteSelectedID: boolean = true) { const operationIndex = this.toolOperationNameList.indexOf(toolName); if (operationIndex >= 0) { const operationInstance = this.toolOperationList[operationIndex]; - operationInstance.setResult(result); + operationInstance.setResult(result, isDeleteSelectedID); } } diff --git a/packages/lb-annotation/src/core/toolOperation/basicToolOperation.ts b/packages/lb-annotation/src/core/toolOperation/basicToolOperation.ts index 68d2a5e3..4c2ca7e1 100644 --- a/packages/lb-annotation/src/core/toolOperation/basicToolOperation.ts +++ b/packages/lb-annotation/src/core/toolOperation/basicToolOperation.ts @@ -239,11 +239,13 @@ class BasicToolOperation extends EventListener { // 阻止右键菜单栏 this.onMouseDown = this.onMouseDown.bind(this); this.onMouseMove = this.onMouseMove.bind(this); + this.optimizeMouseMove = this.optimizeMouseMove.bind(this); this.onMouseLeave = this.onMouseLeave.bind(this); this.onMouseUp = this.onMouseUp.bind(this); this.onKeyDown = this.onKeyDown.bind(this); this.onKeyUp = this.onKeyUp.bind(this); this.onWheel = this.onWheel.bind(this); + this.optimizeWheel = this.optimizeWheel.bind(this); this.onLeftDblClick = this.onLeftDblClick.bind(this); this.onRightDblClick = this.onRightDblClick.bind(this); this.onClick = this.onClick.bind(this); @@ -251,7 +253,7 @@ class BasicToolOperation extends EventListener { this.clearImgDrag = this.clearImgDrag.bind(this); // 初始化监听事件 - this.dblClickListener = new DblClickEventListener(this.container, 200); + this.dblClickListener = new DblClickEventListener(this.container, 300); this.coordUtils = new CoordinateUtils(this); this.coordUtils.setBasicImgInfo(this.basicImgInfo); @@ -861,11 +863,14 @@ class BasicToolOperation extends EventListener { public eventBinding() { this.dblClickListener.addEvent(() => {}, this.onLeftDblClick, this.onRightDblClick); this.container.addEventListener('mousedown', this.onMouseDown); - this.container.addEventListener('mousemove', this.onMouseMove); + this.container.addEventListener('mousemove', this.optimizeMouseMove); + this.container.addEventListener('mouseup', this.onMouseUp); this.container.addEventListener('mouseleave', this.onMouseLeave); this.container.addEventListener('click', this.onClick); - this.container.addEventListener('wheel', this.onWheel); + + this.container.addEventListener('wheel', this.optimizeWheel); + document.addEventListener('keydown', this.onKeyDown); document.addEventListener('keyup', this.onKeyUp); window.parent.document.addEventListener('contextmenu', this.onContextmenu, false); @@ -873,10 +878,10 @@ class BasicToolOperation extends EventListener { public eventUnbinding() { this.container.removeEventListener('mousedown', this.onMouseDown); - this.container.removeEventListener('mousemove', this.onMouseMove); + this.container.removeEventListener('mousemove', this.optimizeMouseMove); this.container.removeEventListener('mouseup', this.onMouseUp); this.container.removeEventListener('mouseleave', this.onMouseLeave); - this.container.removeEventListener('wheel', this.onWheel); + this.container.removeEventListener('wheel', this.optimizeWheel); this.container.removeEventListener('click', this.onClick); document.removeEventListener('keydown', this.onKeyDown); document.removeEventListener('keyup', this.onKeyUp); @@ -901,6 +906,28 @@ class BasicToolOperation extends EventListener { }; } + private moveAnimationFrameId: number | null = null; + + private onWheelAnimationFrameId: number | null = null; + + public optimizeMouseMove(event: MouseEvent): boolean | void { + if (this.moveAnimationFrameId) return; + + this.moveAnimationFrameId = requestAnimationFrame(() => { + this.onMouseMove(event); + this.moveAnimationFrameId = null; + }); + } + + public optimizeWheel(event: MouseEvent): boolean | void { + if (this.onWheelAnimationFrameId) return; + + this.onWheelAnimationFrameId = requestAnimationFrame(() => { + this.onWheel(event); + this.onWheelAnimationFrameId = null; + }); + } + public onMouseDown(e: MouseEvent): void | boolean { // e.stopPropagation(); if (!this.canvas || this.isImgError) { diff --git a/packages/lb-annotation/src/core/toolOperation/polygonOperation.ts b/packages/lb-annotation/src/core/toolOperation/polygonOperation.ts index 0c125496..816235af 100644 --- a/packages/lb-annotation/src/core/toolOperation/polygonOperation.ts +++ b/packages/lb-annotation/src/core/toolOperation/polygonOperation.ts @@ -259,8 +259,8 @@ class PolygonOperation extends BasicToolOperation { this.render(); } - public setResult(polygonList: IPolygonData[]) { - this.clearActiveStatus(); + public setResult(polygonList: IPolygonData[], isDeleteSelectedID: boolean = true) { + this.clearActiveStatus(isDeleteSelectedID); this.setPolygonList(polygonList); this.render(); } @@ -350,7 +350,6 @@ class PolygonOperation extends BasicToolOperation { } this.rectToolMode = localStorage.getItem(RECT_TOOL_MODE_NAME) as ERectToolModeType; - this.deleteSelectedID(); const coordinateZoom = this.getCoordinateUnderZoom(e); const coordinate = AxisUtils.changeDrawOutsideTarget( coordinateZoom, @@ -440,9 +439,11 @@ class PolygonOperation extends BasicToolOperation { /** * 清楚所有的中间状态 */ - public clearActiveStatus() { + public clearActiveStatus(isDeleteSelectedID: boolean = true) { this.clearPolygonDrag(); - this.deleteSelectedID(); + if (isDeleteSelectedID) { + this.deleteSelectedID(); + } } public clearDrawingStatus() { diff --git a/packages/lb-annotation/src/core/toolOperation/rectOperation.ts b/packages/lb-annotation/src/core/toolOperation/rectOperation.ts index 8316debb..a555a223 100644 --- a/packages/lb-annotation/src/core/toolOperation/rectOperation.ts +++ b/packages/lb-annotation/src/core/toolOperation/rectOperation.ts @@ -74,7 +74,7 @@ class RectOperation extends BasicToolOperation { public renderPointCloud2DHighlight(): void {} constructor(props: IRectOperationProps) { - super(props); + super({ ...props, isOffscreenCanvas: true }); this._drawOutSideTarget = props.drawOutSideTarget || false; this.rectList = []; this.isFlow = true; @@ -875,8 +875,7 @@ class RectOperation extends BasicToolOperation { return; } this.lastMouseMoveTime = now; - - if (super.onMouseMove(e) || this.forbidMouseOperation || !this.imgInfo) { + if (super.onMouseMove(e, false) || this.forbidMouseOperation || !this.imgInfo) { return; } @@ -893,6 +892,7 @@ class RectOperation extends BasicToolOperation { if (this.selectedIDs.length > 0 && this.dragInfo) { this.onDragMove(coordinate); + this.render(); return; } @@ -984,6 +984,13 @@ class RectOperation extends BasicToolOperation { }; this.render(); } + // When dragging the canvas + if (this.isDrag && !this.dragInfo) { + this.render('drag'); + return; + } + // At present, the hover effect of 2D views has little impact and will not be processed temporarily. The default is mouse movement interaction + this.render('move'); return undefined; }); @@ -1864,21 +1871,38 @@ class RectOperation extends BasicToolOperation { /** * 渲染矩形框体 */ - public renderRect() { - this.renderStaticRect(); + public renderRect(trigger?: string) { + if (trigger !== 'move') { + this.renderStaticRect(); + } this.renderCreatingRect(); } - public render() { + public render(trigger?: string) { if (!this.ctx) { return; } - super.render(); - this.renderRect(); + if (trigger !== 'move') { + super.render(); + } + if (trigger !== 'drag') { + this.renderRect(trigger); + } this.renderCursorLine(this.getLineColor(this.defaultAttribute)); } + // Rendering Crosslines + public renderCursorLine(lineColor: string) { + // Clear Extra Canvas + this.clearOffscreenCanvas(); + const { x, y } = this.coord; + + DrawUtils.drawLine(this.offscreenCanvas, { x: 0, y }, { x: 10000, y }, { color: lineColor }); + DrawUtils.drawLine(this.offscreenCanvas, { x, y: 0 }, { x, y: 10000 }, { color: lineColor }); + DrawUtils.drawCircleWithFill(this.offscreenCanvas, { x, y }, 1, { color: 'white' }); + } + public setDefaultAttribute(defaultAttribute?: string) { const oldDefault = this.defaultAttribute; this.defaultAttribute = defaultAttribute ?? ''; diff --git a/packages/lb-components/src/components/pointCloud2DRectOperationView/index.tsx b/packages/lb-components/src/components/pointCloud2DRectOperationView/index.tsx index 285e53cc..c09c6daf 100644 --- a/packages/lb-components/src/components/pointCloud2DRectOperationView/index.tsx +++ b/packages/lb-components/src/components/pointCloud2DRectOperationView/index.tsx @@ -270,8 +270,17 @@ const PointCloud2DRectOperationView = (props: IPointCloud2DRectOperationViewProp const onRightClick = ({ targetId, id }: { targetId: string; id: string }) => { setNeedUpdateCenter(false); - setSelectedIDs(targetId); - setRightClickRectId(id); + requestAnimationFrame(() => { + updateSelectedIDs(targetId); + setRightClickRectId(id); + }); + }; + + const updateSelectedIDs = (newID: string) => { + const currentIDs = Array.isArray(selectedIDs) ? selectedIDs : []; + if (!currentIDs.includes(newID)) { + setSelectedIDs(newID); + } }; useEffect(() => { @@ -416,7 +425,7 @@ const PointCloud2DRectOperationView = (props: IPointCloud2DRectOperationViewProp // Center the view by selectedID if (!selectedID || !needUpdateCenter) { setNeedUpdateCenter(true); - // during disconnection + // during disconnection if (shouldExcludePointCloudBoxListUpdate) { operation.current.setHoverRectID(''); operation.current.render(); @@ -431,7 +440,7 @@ const PointCloud2DRectOperationView = (props: IPointCloud2DRectOperationViewProp setNeedUpdateCenter(true); return; } - // during disconnection + // during disconnection if (shouldExcludePointCloudBoxListUpdate) { operation.current.setHoverRectID(rect.id); } diff --git a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts index 4b501b7a..c0a49503 100644 --- a/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts +++ b/packages/lb-components/src/components/pointCloudView/hooks/usePointCloudViews.ts @@ -834,7 +834,7 @@ export const usePointCloudViews = (params?: IUsePointCloudViewsParams) => { config?.secondaryAttributeConfigurable ? config?.inputList ?? [] : [], ); - topViewInstance?.updatePolygonList(newPointCloudList ?? [], polygonList); + topViewInstance?.updatePolygonList(newPointCloudList ?? [], polygonList, false); /** If new box is hidden will not active target point box */ if (isBoxHidden) { setSelectedIDs([]);