From 5b79be6f1e152ade7639db617aeafbd1e5e2cfee Mon Sep 17 00:00:00 2001 From: chenshenhai Date: Sun, 11 Jun 2023 22:54:06 +0800 Subject: [PATCH] feat: improve deep-selector logic for group --- packages/board/src/lib/calculator.ts | 14 ++--- .../middleware/deep-selector/draw-wrapper.ts | 10 +-- .../src/middleware/deep-selector/index.ts | 7 ++- .../core/src/middleware/deep-selector/util.ts | 28 +++++++-- packages/types/src/lib/view.ts | 5 +- packages/util/src/lib/view-calc.ts | 61 +++++++++++++++++-- 6 files changed, 97 insertions(+), 28 deletions(-) diff --git a/packages/board/src/lib/calculator.ts b/packages/board/src/lib/calculator.ts index 9fbe6d4..5484c3f 100644 --- a/packages/board/src/lib/calculator.ts +++ b/packages/board/src/lib/calculator.ts @@ -1,4 +1,4 @@ -import type { Data, Point, Element, ElementType, ViewCalculator, ViewCalculatorOptions, ViewScaleInfo, ElementSize, ViewSizeInfo } from '@idraw/types'; +import type { Point, Data, Element, ElementType, ViewCalculator, ViewCalculatorOptions, ViewScaleInfo, ElementSize, ViewSizeInfo } from '@idraw/types'; import { calcElementSize, isViewPointInElement, getViewPointAtElement, isElementInView } from '@idraw/util'; export class Calculator implements ViewCalculator { @@ -26,13 +26,11 @@ export class Calculator implements ViewCalculator { }); } - getPointElement(p: Point, data: Data, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): { index: number; element: null | Element } { + getPointElement( + p: Point, + opts: { data: Data; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo } + ): { index: number; element: null | Element; groupQueueIndex: number } { const context2d = this._opts.viewContent.boardContext; - return getViewPointAtElement(p, { - data, - context2d, - viewScaleInfo, - viewSizeInfo - }); + return getViewPointAtElement(p, { ...opts, ...{ context2d } }); } } diff --git a/packages/core/src/middleware/deep-selector/draw-wrapper.ts b/packages/core/src/middleware/deep-selector/draw-wrapper.ts index ed45847..baff9ec 100644 --- a/packages/core/src/middleware/deep-selector/draw-wrapper.ts +++ b/packages/core/src/middleware/deep-selector/draw-wrapper.ts @@ -177,11 +177,11 @@ export function drawGroupsWrapper(ctx: ViewContext2D, elemList: ElementSize[]) { ctx.lineWidth = 2; ctx.strokeStyle = wrapperColor; ctx.beginPath(); - ctx.moveTo(x - bw, y - bw); - ctx.lineTo(x + w + bw, y - bw); - ctx.lineTo(x + w + bw, y + h + bw); - ctx.lineTo(x - bw, y + h + bw); - ctx.lineTo(x - bw, y - bw); + ctx.moveTo(totalX - bw, totalY - bw); + ctx.lineTo(totalX + w + bw, totalY - bw); + ctx.lineTo(totalX + w + bw, totalY + h + bw); + ctx.lineTo(totalX - bw, totalY + h + bw); + ctx.lineTo(totalX - bw, totalY - bw); ctx.closePath(); ctx.stroke(); }); diff --git a/packages/core/src/middleware/deep-selector/index.ts b/packages/core/src/middleware/deep-selector/index.ts index 238d70e..ecf6e86 100644 --- a/packages/core/src/middleware/deep-selector/index.ts +++ b/packages/core/src/middleware/deep-selector/index.ts @@ -134,7 +134,7 @@ export const MiddlewareSelector: BoardMiddleware = (o groupQueue: sharer.getSharedStorage(keyGroupQueue) }); - console.log('pointStart target ====== ', target); + // console.log('pointStart target ====== ', target); if (sharer.getSharedStorage(keyInGroup) === true) { if (target.type === 'in-group-element' && target?.elements?.length > 0) { @@ -266,7 +266,7 @@ export const MiddlewareSelector: BoardMiddleware = (o sharer.setSharedStorage(keyActionType, 'drag-list-end'); needDrawFrame = true; } else if (data) { - const result = calculator.getPointElement(e.point, data, sharer.getActiveScaleInfo(), sharer.getActiveViewSizeInfo()); + const result = calculator.getPointElement(e.point, { data, viewScaleInfo: sharer.getActiveScaleInfo(), viewSizeInfo: sharer.getActiveViewSizeInfo() }); if (result.element) { sharer.setSharedStorage(keyActionType, 'select'); needDrawFrame = true; @@ -317,6 +317,8 @@ export const MiddlewareSelector: BoardMiddleware = (o areaSize: null, groupQueue: sharer.getSharedStorage(keyGroupQueue) }); + // console.log('doubleClick target ======= ', target); + if (target.type === 'in-group-element' && target.elements.length > 0) { sharer.setSharedStorage(keyGroupQueue, target.elements as Element<'group'>[]); sharer.setSharedStorage(keyInGroup, true); @@ -329,7 +331,6 @@ export const MiddlewareSelector: BoardMiddleware = (o } } sharer.setSharedStorage(keyActionType, null); - console.log('doubleClick target ======= ', target); }, beforeDrawFrame({ snapshot }) { diff --git a/packages/core/src/middleware/deep-selector/util.ts b/packages/core/src/middleware/deep-selector/util.ts index 3eecd23..ab78313 100644 --- a/packages/core/src/middleware/deep-selector/util.ts +++ b/packages/core/src/middleware/deep-selector/util.ts @@ -54,23 +54,39 @@ export function getPointTarget( // in-group-element if (groupQueue && Array.isArray(groupQueue) && groupQueue.length > 0 && data) { - const { index, element } = calculator.getPointElement(p as Point, data, viewScaleInfo, viewSizeInfo); - if (index >= 0 && element) { + const { element, groupQueueIndex } = calculator.getPointElement(p as Point, { data, viewScaleInfo, viewSizeInfo, groupQueue }); + if (groupQueueIndex >= 0) { + const newQueue: Element<'group'>[] = groupQueue.splice(0, groupQueueIndex + 1); + target.indexes = []; + target.elements = newQueue; + target.uuids = []; + target.type = 'in-group-element'; + return target; + } else if (element) { const newQueue: Element<'group'>[] = []; for (let i = 0; i < groupQueue.length; i++) { const group = groupQueue[i]; if (group.type !== 'group') { break; } + newQueue.push(group); if (element.uuid === group.uuid) { - // isElementInGroup(element, group) - // TODO check in group - newQueue.push(group); target.indexes = []; target.elements = newQueue; target.uuids = []; target.type = 'in-group-element'; return target; + } else if (Array.isArray(group.detail.children) && group.detail.children.length > 0) { + for (let j = 0; j < group.detail.children.length; j++) { + const child = group.detail.children[j]; + if (element.uuid === child.uuid && element.type === 'group') { + newQueue.push(element as Element<'group'>); + target.indexes = []; + target.elements = newQueue; + target.uuids = []; + target.type = 'in-group-element'; + } + } } } } @@ -117,7 +133,7 @@ export function getPointTarget( // over-element if (data) { - const { index, element } = calculator.getPointElement(p as Point, data, viewScaleInfo, viewSizeInfo); + const { index, element } = calculator.getPointElement(p as Point, { data, viewScaleInfo, viewSizeInfo }); if (index >= 0 && element) { target.indexes = [index]; target.elements = [element]; diff --git a/packages/types/src/lib/view.ts b/packages/types/src/lib/view.ts index 85afc8e..9990838 100644 --- a/packages/types/src/lib/view.ts +++ b/packages/types/src/lib/view.ts @@ -38,5 +38,8 @@ export interface ViewCalculator { isElementInView(elem: Element, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean; isPointInElement(p: Point, elem: Element, viewScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): boolean; elementSize(size: ElementSize, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ElementSize; - getPointElement(p: Point, data: Data, viewScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): { index: number; element: null | Element }; + getPointElement( + p: Point, + opts: { data: Data; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; groupQueue?: Element<'group'>[] } + ): { index: number; element: null | Element; groupQueueIndex: number }; } diff --git a/packages/util/src/lib/view-calc.ts b/packages/util/src/lib/view-calc.ts index 1d6d3c1..6beb7ee 100644 --- a/packages/util/src/lib/view-calc.ts +++ b/packages/util/src/lib/view-calc.ts @@ -111,7 +111,7 @@ export function calcElementSize(size: ElementSize, opts: { viewScaleInfo: ViewSc export function isViewPointInElement( p: Point, - opts: { context2d: ViewContext2D; element: Element; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo } + opts: { context2d: ViewContext2D; element: ElementSize; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo } ): boolean { const { context2d: ctx, element: elem, viewScaleInfo, viewSizeInfo } = opts; @@ -139,13 +139,64 @@ export function getViewPointAtElement( data: Data; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; + groupQueue?: Element<'group'>[]; } -): { index: number; element: null | Element } { - const { context2d: ctx, data, viewScaleInfo, viewSizeInfo } = opts; - const result: { index: number; element: null | Element } = { +): { index: number; element: null | Element; groupQueueIndex: number } { + const { context2d: ctx, data, viewScaleInfo, viewSizeInfo, groupQueue } = opts; + + const result: { index: number; element: null | Element; groupQueueIndex: number } = { index: -1, - element: null + element: null, + groupQueueIndex: -1 }; + + if (groupQueue && Array.isArray(groupQueue) && groupQueue?.length > 0) { + // const lastGroup = groupQueue[groupQueue.length - 1]; + + for (let gIdx = groupQueue.length - 1; gIdx >= 0; gIdx--) { + let totalX = 0; + let totalY = 0; + let totalAngle = 0; + for (let i = 0; i <= gIdx; i++) { + totalX += groupQueue[i].x; + totalY += groupQueue[i].y; + totalAngle += groupQueue[i].angle || 0; + } + + const lastGroup = groupQueue[gIdx]; + + if (lastGroup && lastGroup.type === 'group' && Array.isArray(lastGroup.detail?.children)) { + for (let i = 0; i < lastGroup.detail.children.length; i++) { + const child = lastGroup.detail.children[i]; + if (child) { + const elemSize = { + x: totalX + child.x, + y: totalY + child.y, + w: child.w, + h: child.h, + angle: totalAngle + (child.angle || 0) + }; + if (isViewPointInElement(p, { context2d: ctx, element: elemSize, viewScaleInfo, viewSizeInfo })) { + result.element = child; + if (gIdx < groupQueue.length - 1 || child.type !== 'group') { + result.groupQueueIndex = gIdx; + } + break; + } + } else { + break; + } + } + } + if (result.element) { + break; + } + } + } + if (result.element) { + return result; + } + for (let i = data.elements.length - 1; i >= 0; i--) { const elem = data.elements[i]; if (isViewPointInElement(p, { context2d: ctx, element: elem, viewScaleInfo, viewSizeInfo })) {