Skip to content

Commit

Permalink
Merge pull request #339 from idrawjs/dev-v0.4
Browse files Browse the repository at this point in the history
feat: add utils of group
  • Loading branch information
chenshenhai authored Jul 27, 2024
2 parents 25c10a7 + 4cf487d commit dec40ac
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 4 deletions.
15 changes: 13 additions & 2 deletions packages/core/src/middleware/selector/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
findElementsFromList,
findElementsFromListByPositions,
getElementPositionFromList,
getElementPositionMapFromList,
deepResizeGroupElement,
getElementSize
} from '@idraw/util';
Expand Down Expand Up @@ -99,6 +100,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
let moveOriginalStartPoint: Point | null = null;
let moveOriginalStartElementSize: ElementSize | null = null;
let inBusyMode: 'resize' | 'drag' | 'drag-list' | 'area' | null = null;
let hasChangedData: boolean | null = null;

sharer.setSharedStorage(keyActionType, null);
sharer.setSharedStorage(keyEnableSnapToGrid, true);
Expand Down Expand Up @@ -154,7 +156,10 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
}

if (opts?.triggerEvent === true) {
eventHub.trigger(coreEventKeys.SELECT, { uuids: list.map((elem) => elem.uuid), positions: [] });
const uuids = list.map((elem) => elem.uuid);
const data = sharer.getActiveStorage('data');
const positionMap = getElementPositionMapFromList(uuids, data?.elements || []);
eventHub.trigger(coreEventKeys.SELECT, { uuids, positions: list.map((elem) => [...positionMap[elem.uuid]]) });
}
};

Expand Down Expand Up @@ -471,6 +476,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
const enableSnapToGrid = sharer.getSharedStorage(keyEnableSnapToGrid);

if (actionType === 'drag') {
hasChangedData = true;
inBusyMode = 'drag';
if (data && elems?.length === 1 && moveOriginalStartElementSize && originalStart && end && elems[0]?.operations?.locked !== true) {
const { moveX, moveY } = calcMoveInGroup(originalStart, end, groupQueue);
Expand Down Expand Up @@ -518,6 +524,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
}
viewer.drawFrame();
} else if (actionType === 'drag-list') {
hasChangedData = true;
inBusyMode = 'drag-list';
if (data && originalStart && start && end && elems?.length > 1) {
const moveX = (end.x - start.x) / scale;
Expand Down Expand Up @@ -546,6 +553,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
viewer.drawFrame();
} else if (actionType === 'resize') {
if (data && elems?.length === 1 && originalStart && moveOriginalStartElementSize && resizeType?.startsWith('resize-')) {
hasChangedData = true;
inBusyMode = 'resize';
const pointGroupQueue: Element<'group'>[] = [];
groupQueue.forEach((group) => {
Expand Down Expand Up @@ -700,7 +708,10 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
if (type === 'resize') {
type = 'resizeElement';
}
eventHub.trigger(coreEventKeys.CHANGE, { data, type, selectedElements, hoverElement });
if (hasChangedData) {
eventHub.trigger(coreEventKeys.CHANGE, { data, type, selectedElements, hoverElement });
hasChangedData = false;
}
}
viewer.drawFrame();
};
Expand Down
1 change: 1 addition & 0 deletions packages/idraw/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export {
findElementsFromListByPositions,
findElementQueueFromListByPosition,
getElementPositionFromList,
getElementPositionMapFromList,
updateElementInList,
getGroupQueueFromList,
getElementSize,
Expand Down
2 changes: 2 additions & 0 deletions packages/util/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export {
filterElementAsset,
isResourceElement,
getElementPositionFromList,
getElementPositionMapFromList,
calcElementListSize
} from './lib/element';
export { checkRectIntersect } from './lib/rect';
Expand Down Expand Up @@ -89,3 +90,4 @@ export { modifyElement, getModifiedElement } from './lib/modify';
// export { ModifyRecorder } from './lib/modify-recorder';
export { enhanceFontFamliy } from './lib/text';
export { flatElementList } from './lib/flat';
export { groupElementsByPosition, ungroupElementsByPosition } from './lib/group';
39 changes: 39 additions & 0 deletions packages/util/src/lib/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,3 +465,42 @@ export function getElementPositionFromList(uuid: string, elements: Element<Eleme
_loop(elements);
return result;
}

export function getElementPositionMapFromList(
uuids: string[],
elements: Element<ElementType>[]
): {
[uuid: string]: ElementPosition;
} {
const currentPosition: ElementPosition = [];
const positionMap: {
[uuid: string]: ElementPosition;
} = {};

let over = false;
const _loop = (list: Element<ElementType>[]) => {
for (let i = 0; i < list.length; i++) {
if (over === true) {
break;
}
currentPosition.push(i);
const elem = list[i];
if (uuids.includes(elem.uuid)) {
positionMap[elem.uuid] = [...currentPosition];

if (Object.keys(positionMap).length === uuids.length) {
over = true;
break;
}
} else if (elem.type === 'group') {
_loop((elem as Element<'group'>)?.detail?.children || []);
}
if (over) {
break;
}
currentPosition.pop();
}
};
_loop(elements);
return positionMap;
}
97 changes: 97 additions & 0 deletions packages/util/src/lib/group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { Elements, Element, ElementPosition } from '@idraw/types';
import { findElementFromListByPosition, calcElementListSize } from './element';
import { deleteElementInListByPosition, insertElementToListByPosition } from './handle-element';
import { createUUID } from './uuid';

export function groupElementsByPosition(list: Elements, positions: ElementPosition[]): Elements {
if (positions.length > 1) {
let isValidPositions: boolean = true;
let lastIndexs: number[] = [];
for (let i = 1; i < positions.length; i++) {
const prevPosition = positions[i - 1];
const position = positions[i];
if (!(prevPosition.length > 0 && position.length > 0)) {
isValidPositions = false;
break;
}

if (prevPosition.length !== position.length) {
isValidPositions = false;
break;
}

const temp1 = [...prevPosition];
const temp2 = [...position];
const lastIndex1 = temp1.pop();
const lastIndex2 = temp2.pop();
if (i === 1 && typeof lastIndex1 === 'number' && lastIndex1 >= 0) {
lastIndexs.push(lastIndex1 as number);
}
if (typeof lastIndex2 === 'number' && lastIndex2 >= 0) {
lastIndexs.push(lastIndex2 as number);
}
}
if (isValidPositions !== true) {
console.error('[idraw]: The grouped elements are not siblings!');
return list;
}
lastIndexs.sort((a, b) => a - b);
const groupParentPosition = [...positions[0]].splice(0, positions[0].length - 1);
const groupChildren: Elements = [];

const groupPosition = [...groupParentPosition, lastIndexs[0]];
for (let i = 0; i < lastIndexs.length; i++) {
const position = [...groupParentPosition, lastIndexs[i]];
const elem = findElementFromListByPosition(position, list);
if (elem) {
groupChildren.push(elem);
}
}

const groupSize = calcElementListSize(groupChildren);
for (let i = 0; i < groupChildren.length; i++) {
const elem = groupChildren[i];
if (elem) {
elem.x -= groupSize.x;
elem.y -= groupSize.y;
}
}

for (let i = lastIndexs.length - 1; i >= 0; i--) {
const position = [...groupParentPosition, lastIndexs[i]];
deleteElementInListByPosition(position, list);
}

const group: Element<'group'> = {
name: 'Group',
uuid: createUUID(),
type: 'group',
...groupSize,
detail: {
children: groupChildren
}
};
insertElementToListByPosition(group, groupPosition, list);
}
return list;
}

export function ungroupElementsByPosition(list: Elements, position: ElementPosition): Elements {
const elem = findElementFromListByPosition(position, list) as Element<'group'>;
if (!(elem && elem?.type === 'group' && Array.isArray(elem?.detail?.children))) {
console.error('[idraw]: The ungrouped element is not a group element!');
}
const groupParentPosition = [...position].splice(0, position.length - 1);
const groupLastIndex = position[position.length - 1];

const { x, y } = elem;
deleteElementInListByPosition(position, list);
elem.detail.children.forEach((child, i) => {
child.x += x;
child.y += y;
const elemPosition = [...groupParentPosition, groupLastIndex + i];
insertElementToListByPosition(child, elemPosition, list);
});

return list;
}
19 changes: 17 additions & 2 deletions packages/util/src/lib/store.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import type { RecursivePartial } from '@idraw/types';
import { deepClone } from './data';

export class Store<T extends Record<string | symbol, any> = Record<string | symbol, any>> {
export class Store<
T extends Record<string | symbol, any> = Record<string | symbol, any>,
S extends Record<string | symbol, any> = Record<string | symbol, any>
> {
#temp: T;
#backUpDefaultStorage: T;
#static: RecursivePartial<S>;

constructor(opts: { defaultStorage: T }) {
constructor(opts: { defaultStorage: T; defaultStatic?: S }) {
this.#backUpDefaultStorage = deepClone(opts.defaultStorage);
this.#temp = this.#createTempStorage();
this.#static = opts.defaultStatic || {};
}

set<K extends keyof T>(name: K, value: T[K]) {
Expand All @@ -17,6 +23,14 @@ export class Store<T extends Record<string | symbol, any> = Record<string | symb
return this.#temp[name];
}

setStatic<K extends keyof S>(name: K, value: S[K]) {
this.#static[name] = value;
}

getStatic<K extends keyof S>(name: K): S[K] | undefined {
return this.#static[name] as S[K] | undefined;
}

getSnapshot(opts?: { deepClone?: boolean }): T {
if (opts?.deepClone === true) {
return deepClone(this.#temp);
Expand All @@ -30,6 +44,7 @@ export class Store<T extends Record<string | symbol, any> = Record<string | symb

destroy() {
this.#temp = null as any;
this.#static = null as any;
}

#createTempStorage() {
Expand Down

0 comments on commit dec40ac

Please sign in to comment.