mirror of
https://github.com/idrawjs/idraw
synced 2026-05-24 10:08:34 +00:00
feat: improve snapping to grid in selector middleware
This commit is contained in:
parent
ee87f3c2e6
commit
9ea6699e3f
10 changed files with 375 additions and 62 deletions
|
|
@ -307,12 +307,6 @@ export class Board<T extends BoardExtendEventMap = BoardExtendEventMap> {
|
|||
extend: true
|
||||
});
|
||||
if (modifiedOptions) {
|
||||
// TODO
|
||||
// this.#viewer.modifyViewVisibleInfoMap(data, {
|
||||
// viewSizeInfo,
|
||||
// viewScaleInfo,
|
||||
// modifyOptions: modifiedOptions
|
||||
// });
|
||||
this.#viewer.resetViewVisibleInfoMap(data, {
|
||||
viewSizeInfo,
|
||||
viewScaleInfo
|
||||
|
|
|
|||
|
|
@ -188,30 +188,53 @@ export class Calculator implements ViewCalculator {
|
|||
const viewVisibleInfoMap = this.#store.get('viewVisibleInfoMap');
|
||||
if (type === 'deleteElement') {
|
||||
const { element } = content as ModifyOptions<'deleteElement'>['content'];
|
||||
delete viewVisibleInfoMap[element.uuid];
|
||||
} else if (type === 'addElement' || type === 'updateElement') {
|
||||
const uuids: string[] = [];
|
||||
const _walk = (e: Element) => {
|
||||
uuids.push(e.uuid);
|
||||
if (e.type === 'group' && Array.isArray((e as Element<'group'>).detail.children)) {
|
||||
(e as Element<'group'>).detail.children.forEach((child) => {
|
||||
_walk(child);
|
||||
});
|
||||
}
|
||||
};
|
||||
_walk(element);
|
||||
uuids.forEach((uuid) => {
|
||||
delete viewVisibleInfoMap[uuid];
|
||||
});
|
||||
this.#store.set('viewVisibleInfoMap', viewVisibleInfoMap);
|
||||
}
|
||||
// else if (type === 'updateElement') {
|
||||
// // TODO
|
||||
// this.resetViewVisibleInfoMap(data, { viewScaleInfo, viewSizeInfo });
|
||||
// }
|
||||
else if (type === 'addElement' || type === 'updateElement') {
|
||||
const { position } = content as ModifyOptions<'addElement'>['content'];
|
||||
const element = findElementFromListByPosition(position, data.elements);
|
||||
const groupQueue = getGroupQueueByElementPosition(list, position);
|
||||
if (element) {
|
||||
const originRectInfo = calcElementOriginRectInfo(element, {
|
||||
groupQueue: groupQueue || []
|
||||
});
|
||||
const newViewVisibleInfo: ViewVisibleInfo = {
|
||||
originRectInfo,
|
||||
rangeRectInfo: is.angle(element.angle) ? originRectInfoToRangeRectInfo(originRectInfo) : originRectInfo,
|
||||
isVisibleInView: true,
|
||||
isGroup: element?.type === 'group',
|
||||
position: [...position]
|
||||
};
|
||||
viewVisibleInfoMap[element.uuid] = newViewVisibleInfo;
|
||||
if (type === 'updateElement') {
|
||||
this.updateVisiableStatus({ viewScaleInfo, viewSizeInfo });
|
||||
if (type === 'updateElement' && element.type === 'group') {
|
||||
// TODO
|
||||
this.resetViewVisibleInfoMap(data, { viewScaleInfo, viewSizeInfo });
|
||||
} else {
|
||||
const originRectInfo = calcElementOriginRectInfo(element, {
|
||||
groupQueue: groupQueue || []
|
||||
});
|
||||
const newViewVisibleInfo: ViewVisibleInfo = {
|
||||
originRectInfo,
|
||||
rangeRectInfo: is.angle(element.angle) ? originRectInfoToRangeRectInfo(originRectInfo) : originRectInfo,
|
||||
isVisibleInView: true,
|
||||
isGroup: element?.type === 'group',
|
||||
position: [...position]
|
||||
};
|
||||
viewVisibleInfoMap[element.uuid] = newViewVisibleInfo;
|
||||
this.#store.set('viewVisibleInfoMap', viewVisibleInfoMap);
|
||||
if (type === 'updateElement') {
|
||||
this.updateVisiableStatus({ viewScaleInfo, viewSizeInfo });
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type === 'moveElement') {
|
||||
this.resetViewVisibleInfoMap(data, { viewScaleInfo, viewSizeInfo });
|
||||
}
|
||||
this.#store.set('viewVisibleInfoMap', viewVisibleInfoMap);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ export const keySelectedElementList = Symbol(`${key}_selectedElementList`); // A
|
|||
export const keySelectedElementListVertexes = Symbol(`${key}_selectedElementListVertexes`); // ViewRectVertexes | null
|
||||
export const keySelectedElementController = Symbol(`${key}_selectedElementController`); // ElementSizeController
|
||||
export const keySelectedElementPosition = Symbol(`${key}_selectedElementPosition`); // ElementPosition | []
|
||||
export const keySelectedReferenceXLines = Symbol(`${key}_selectedReferenceXLines`); // Array<PointSize[]>
|
||||
export const keySelectedReferenceYLines = Symbol(`${key}_selectedReferenceYLines`); // Array<PointSize[]>
|
||||
export const keyGroupQueue = Symbol(`${key}_groupQueue`); // Array<Element<'group'>> | []
|
||||
export const keyGroupQueueVertexesList = Symbol(`${key}_groupQueueVertexesList`); // Array<ViewRectVertexes> | []
|
||||
export const keyIsMoving = Symbol(`${key}_isMoving`); // boolean | null
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
getElementPositionFromList,
|
||||
deepResizeGroupElement
|
||||
} from '@idraw/util';
|
||||
import type { ViewRectVertexes, CoreEventMap, ElementPosition, ViewScaleInfo, ViewSizeInfo, ElementSizeController } from '@idraw/types';
|
||||
import type { Data, ViewRectVertexes, CoreEventMap, ElementPosition, ViewScaleInfo, ViewSizeInfo, ElementSizeController } from '@idraw/types';
|
||||
import type {
|
||||
Point,
|
||||
PointSize,
|
||||
|
|
@ -61,8 +61,6 @@ import {
|
|||
keySelectedElementListVertexes,
|
||||
keySelectedElementController,
|
||||
keySelectedElementPosition,
|
||||
keySelectedReferenceXLines,
|
||||
keySelectedReferenceYLines,
|
||||
keyIsMoving,
|
||||
keyEnableSelectInGroup,
|
||||
keyEnableSnapToGrid,
|
||||
|
|
@ -175,8 +173,6 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
sharer.setSharedStorage(keySelectedElementListVertexes, null);
|
||||
sharer.setSharedStorage(keySelectedElementController, null);
|
||||
sharer.setSharedStorage(keySelectedElementPosition, []);
|
||||
sharer.setSharedStorage(keySelectedReferenceXLines, []);
|
||||
sharer.setSharedStorage(keySelectedReferenceYLines, []);
|
||||
sharer.setSharedStorage(keyIsMoving, null);
|
||||
sharer.setSharedStorage(keyEnableSelectInGroup, null);
|
||||
};
|
||||
|
|
@ -430,8 +426,6 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
},
|
||||
|
||||
pointMove: (e: PointWatcherEvent) => {
|
||||
sharer.setSharedStorage(keySelectedReferenceXLines, []);
|
||||
sharer.setSharedStorage(keySelectedReferenceYLines, []);
|
||||
sharer.setSharedStorage(keyIsMoving, true);
|
||||
const data = sharer.getActiveStorage('data');
|
||||
const elems = getActiveElements();
|
||||
|
|
@ -470,8 +464,6 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
if (is.y(referenceInfo.offsetY) && referenceInfo.offsetY !== null) {
|
||||
totalMoveY = calculator.toGridNum(totalMoveY + referenceInfo.offsetY);
|
||||
}
|
||||
sharer.setSharedStorage(keySelectedReferenceXLines, referenceInfo.xLines);
|
||||
sharer.setSharedStorage(keySelectedReferenceYLines, referenceInfo.yLines);
|
||||
}
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
|
@ -518,10 +510,6 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
});
|
||||
}
|
||||
});
|
||||
// calculator.updateVisiableStatus({
|
||||
// viewSizeInfo,
|
||||
// viewScaleInfo
|
||||
// });
|
||||
|
||||
sharer.setActiveStorage('data', data);
|
||||
}
|
||||
|
|
@ -613,10 +601,10 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
|
||||
pointEnd(e: PointWatcherEvent) {
|
||||
inBusyMode = null;
|
||||
sharer.setSharedStorage(keySelectedReferenceXLines, []);
|
||||
sharer.setSharedStorage(keySelectedReferenceYLines, []);
|
||||
sharer.setSharedStorage(keyIsMoving, false);
|
||||
const data = sharer.getActiveStorage('data');
|
||||
const selectedElements = sharer.getSharedStorage(keySelectedElementList);
|
||||
const hoverElement = sharer.getSharedStorage(keyHoverElement);
|
||||
const resizeType = sharer.getSharedStorage(keyResizeType);
|
||||
const actionType = sharer.getSharedStorage(keyActionType);
|
||||
// const viewScaleInfo = sharer.getActiveViewScaleInfo();
|
||||
|
|
@ -684,7 +672,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
if (type === 'resize') {
|
||||
type = 'resizeElement';
|
||||
}
|
||||
eventHub.trigger(eventChange, { data, type });
|
||||
eventHub.trigger(eventChange, { data, type, selectedElements, hoverElement });
|
||||
}
|
||||
viewer.drawFrame();
|
||||
};
|
||||
|
|
@ -787,13 +775,23 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
hideControllers: !!isMoving && actionType === 'drag'
|
||||
});
|
||||
if (actionType === 'drag') {
|
||||
const xLines = sharer.getSharedStorage(keySelectedReferenceXLines);
|
||||
const yLines = sharer.getSharedStorage(keySelectedReferenceYLines);
|
||||
if (enableSnapToGrid === true) {
|
||||
drawReferenceLines(overlayContext, {
|
||||
xLines,
|
||||
yLines
|
||||
const referenceInfo = calcReferenceInfo(elem.uuid, {
|
||||
calculator,
|
||||
data: activeStore.data as Data,
|
||||
groupQueue,
|
||||
viewScaleInfo,
|
||||
viewSizeInfo
|
||||
});
|
||||
if (referenceInfo) {
|
||||
const { offsetX, offsetY, xLines, yLines } = referenceInfo;
|
||||
if (offsetX === 0 || offsetY === 0) {
|
||||
drawReferenceLines(overlayContext, {
|
||||
xLines,
|
||||
yLines
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -821,13 +819,23 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
hideControllers: !!isMoving && actionType === 'drag'
|
||||
});
|
||||
if (actionType === 'drag') {
|
||||
const xLines = sharer.getSharedStorage(keySelectedReferenceXLines);
|
||||
const yLines = sharer.getSharedStorage(keySelectedReferenceYLines);
|
||||
if (enableSnapToGrid === true) {
|
||||
drawReferenceLines(overlayContext, {
|
||||
xLines,
|
||||
yLines
|
||||
const referenceInfo = calcReferenceInfo(elem.uuid, {
|
||||
calculator,
|
||||
data: activeStore.data as Data,
|
||||
groupQueue,
|
||||
viewScaleInfo,
|
||||
viewSizeInfo
|
||||
});
|
||||
if (referenceInfo) {
|
||||
const { offsetX, offsetY, xLines, yLines } = referenceInfo;
|
||||
if (offsetX === 0 || offsetY === 0) {
|
||||
drawReferenceLines(overlayContext, {
|
||||
xLines,
|
||||
yLines
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (actionType === 'area' && areaStart && areaEnd) {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,154 @@ const getClosestNumInSortedKeys = (sortedKeys: number[], target: number) => {
|
|||
|
||||
const isEqualNum = (a: number, b: number) => Math.abs(a - b) < 0.00001;
|
||||
|
||||
// export function calcSnapOffsetInfo(
|
||||
// uuid: string,
|
||||
// opts: {
|
||||
// data: Data;
|
||||
// groupQueue: Element<'group'>[];
|
||||
// calculator: ViewCalculator;
|
||||
// viewScaleInfo: ViewScaleInfo;
|
||||
// viewSizeInfo: ViewSizeInfo;
|
||||
// }
|
||||
// ) {
|
||||
// const { data, groupQueue, calculator, viewScaleInfo, viewSizeInfo } = opts;
|
||||
// let targetElements: Element[] = data.elements || [];
|
||||
// if (groupQueue?.length > 0) {
|
||||
// targetElements = (groupQueue[groupQueue.length - 1] as Element<'group'>)?.detail?.children || [];
|
||||
// }
|
||||
// const siblingViewRectInfoList: ViewRectInfo[] = [];
|
||||
// targetElements.forEach((elem: Element) => {
|
||||
// if (elem.uuid !== uuid) {
|
||||
// const info = calculator.calcViewRectInfoFromRange(elem.uuid, { checkVisible: true, viewScaleInfo, viewSizeInfo });
|
||||
// if (info) {
|
||||
// siblingViewRectInfoList.push(info);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// const targetRectInfo = calculator.calcViewRectInfoFromRange(uuid, { viewScaleInfo, viewSizeInfo });
|
||||
|
||||
// if (!targetRectInfo) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// const vTargetLineDotMap: DotMap = {}; // target vertical line dots
|
||||
// const hTargetLineDotMap: DotMap = {}; // target horizontal line dots
|
||||
|
||||
// const vRefLineDotMap: DotMap = {}; // reference vertical line dots
|
||||
// const hRefLineDotMap: DotMap = {}; // reference horizontal line dots
|
||||
|
||||
// let sortedRefXKeys: number[] = []; // hRefLineDotMap key nums
|
||||
// let sortedRefYKeys: number[] = []; // vRefLineDotMap key nums
|
||||
|
||||
// const targetBox = getViewBoxInfo(targetRectInfo);
|
||||
|
||||
// vTargetLineDotMap[targetBox.minX] = [targetBox.minY, targetBox.midY, targetBox.maxY];
|
||||
// vTargetLineDotMap[targetBox.midX] = [targetBox.minY, targetBox.midY, targetBox.maxY];
|
||||
// vTargetLineDotMap[targetBox.maxX] = [targetBox.minY, targetBox.midY, targetBox.maxY];
|
||||
|
||||
// hTargetLineDotMap[targetBox.minY] = [targetBox.minX, targetBox.midX, targetBox.maxX];
|
||||
// hTargetLineDotMap[targetBox.midY] = [targetBox.minX, targetBox.midX, targetBox.maxX];
|
||||
// hTargetLineDotMap[targetBox.maxY] = [targetBox.minX, targetBox.midX, targetBox.maxX];
|
||||
|
||||
// siblingViewRectInfoList.forEach((info) => {
|
||||
// const box = getViewBoxInfo(info);
|
||||
// if (!vRefLineDotMap[box.minX]) {
|
||||
// vRefLineDotMap[box.minX] = [];
|
||||
// }
|
||||
// if (!vRefLineDotMap[box.midX]) {
|
||||
// vRefLineDotMap[box.midX] = [];
|
||||
// }
|
||||
// if (!vRefLineDotMap[box.maxX]) {
|
||||
// vRefLineDotMap[box.maxX] = [];
|
||||
// }
|
||||
// if (!hRefLineDotMap[box.minY]) {
|
||||
// hRefLineDotMap[box.minY] = [];
|
||||
// }
|
||||
// if (!hRefLineDotMap[box.midY]) {
|
||||
// hRefLineDotMap[box.midY] = [];
|
||||
// }
|
||||
// if (!hRefLineDotMap[box.maxY]) {
|
||||
// hRefLineDotMap[box.maxY] = [];
|
||||
// }
|
||||
|
||||
// vRefLineDotMap[box.minX] = [box.minY, box.midY, box.maxY];
|
||||
// vRefLineDotMap[box.midX] = [box.minY, box.midY, box.maxY];
|
||||
// vRefLineDotMap[box.maxX] = [box.minY, box.midY, box.maxY];
|
||||
|
||||
// sortedRefXKeys.push(box.minX);
|
||||
// sortedRefXKeys.push(box.midX);
|
||||
// sortedRefXKeys.push(box.maxX);
|
||||
|
||||
// hRefLineDotMap[box.minY] = [box.minX, box.midX, box.maxX];
|
||||
// hRefLineDotMap[box.midY] = [box.minX, box.midX, box.maxX];
|
||||
// hRefLineDotMap[box.maxY] = [box.minX, box.midX, box.maxX];
|
||||
|
||||
// sortedRefYKeys.push(box.minY);
|
||||
// sortedRefYKeys.push(box.midY);
|
||||
// sortedRefYKeys.push(box.maxY);
|
||||
// });
|
||||
|
||||
// sortedRefXKeys = sortedRefXKeys.sort((a, b) => a - b);
|
||||
// sortedRefYKeys = sortedRefYKeys.sort((a, b) => a - b);
|
||||
|
||||
// let offsetX: number | null = null;
|
||||
// let offsetY: number | null = null;
|
||||
// let closestMinX: number | null = null;
|
||||
// let closestMidX: number | null = null;
|
||||
// let closestMaxX: number | null = null;
|
||||
// let closestMinY: number | null = null;
|
||||
// let closestMidY: number | null = null;
|
||||
// let closestMaxY: number | null = null;
|
||||
|
||||
// if (sortedRefXKeys.length > 0) {
|
||||
// closestMinX = getClosestNumInSortedKeys(sortedRefXKeys, targetBox.minX);
|
||||
// closestMidX = getClosestNumInSortedKeys(sortedRefXKeys, targetBox.midX);
|
||||
// closestMaxX = getClosestNumInSortedKeys(sortedRefXKeys, targetBox.maxX);
|
||||
|
||||
// const distMinX = Math.abs(closestMinX - targetBox.minX);
|
||||
// const distMidX = Math.abs(closestMidX - targetBox.midX);
|
||||
// const distMaxX = Math.abs(closestMaxX - targetBox.maxX);
|
||||
// const closestXDist = Math.min(distMinX, distMidX, distMaxX);
|
||||
|
||||
// if (closestXDist <= unitSize / viewScaleInfo.scale) {
|
||||
// if (isEqualNum(closestXDist, distMinX)) {
|
||||
// offsetX = closestMinX - targetBox.minX;
|
||||
// } else if (isEqualNum(closestXDist, distMidX)) {
|
||||
// offsetX = closestMidX - targetBox.midX;
|
||||
// } else if (isEqualNum(closestXDist, distMaxX)) {
|
||||
// offsetX = closestMaxX - targetBox.maxX;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (sortedRefYKeys.length > 0) {
|
||||
// closestMinY = getClosestNumInSortedKeys(sortedRefYKeys, targetBox.minY);
|
||||
// closestMidY = getClosestNumInSortedKeys(sortedRefYKeys, targetBox.midY);
|
||||
// closestMaxY = getClosestNumInSortedKeys(sortedRefYKeys, targetBox.maxY);
|
||||
|
||||
// const distMinY = Math.abs(closestMinY - targetBox.minY);
|
||||
// const distMidY = Math.abs(closestMidY - targetBox.midY);
|
||||
// const distMaxY = Math.abs(closestMaxY - targetBox.maxY);
|
||||
// const closestYDist = Math.min(distMinY, distMidY, distMaxY);
|
||||
|
||||
// if (closestYDist <= unitSize / viewScaleInfo.scale) {
|
||||
// if (isEqualNum(closestYDist, distMinY)) {
|
||||
// offsetY = closestMinY - targetBox.minY;
|
||||
// } else if (isEqualNum(closestYDist, distMidY)) {
|
||||
// offsetY = closestMidY - targetBox.midY;
|
||||
// } else if (isEqualNum(closestYDist, distMaxY)) {
|
||||
// offsetY = closestMaxY - targetBox.maxY;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return {
|
||||
// offsetX,
|
||||
// offsetY
|
||||
// };
|
||||
// }
|
||||
|
||||
export function calcReferenceInfo(
|
||||
uuid: string,
|
||||
opts: {
|
||||
|
|
@ -235,7 +383,7 @@ export function calcReferenceInfo(
|
|||
yList: []
|
||||
};
|
||||
vLine.yList.push(newTargetBox.minY);
|
||||
vLine.yList.push(newTargetBox.midY);
|
||||
// vLine.yList.push(newTargetBox.midY);
|
||||
vLine.yList.push(newTargetBox.maxY);
|
||||
vLine.yList.push(...(hRefLineDotMap?.[closestMinX] || []));
|
||||
vHelperLineDotMapList.push(vLine);
|
||||
|
|
@ -247,7 +395,7 @@ export function calcReferenceInfo(
|
|||
yList: []
|
||||
};
|
||||
vLine.yList.push(newTargetBox.minY);
|
||||
vLine.yList.push(newTargetBox.midY);
|
||||
// vLine.yList.push(newTargetBox.midY);
|
||||
vLine.yList.push(newTargetBox.maxY);
|
||||
vLine.yList.push(...(hRefLineDotMap?.[closestMidX] || []));
|
||||
vHelperLineDotMapList.push(vLine);
|
||||
|
|
@ -259,7 +407,7 @@ export function calcReferenceInfo(
|
|||
yList: []
|
||||
};
|
||||
vLine.yList.push(newTargetBox.minY);
|
||||
vLine.yList.push(newTargetBox.midY);
|
||||
// vLine.yList.push(newTargetBox.midY);
|
||||
vLine.yList.push(newTargetBox.maxY);
|
||||
vLine.yList.push(...(hRefLineDotMap?.[closestMaxX] || []));
|
||||
vHelperLineDotMapList.push(vLine);
|
||||
|
|
@ -273,7 +421,7 @@ export function calcReferenceInfo(
|
|||
xList: []
|
||||
};
|
||||
hLine.xList.push(newTargetBox.minX);
|
||||
hLine.xList.push(newTargetBox.midX);
|
||||
// hLine.xList.push(newTargetBox.midX);
|
||||
hLine.xList.push(newTargetBox.maxX);
|
||||
hLine.xList.push(...(vRefLineDotMap?.[closestMinY] || []));
|
||||
hHelperLineDotMapList.push(hLine);
|
||||
|
|
@ -284,7 +432,7 @@ export function calcReferenceInfo(
|
|||
xList: []
|
||||
};
|
||||
hLine.xList.push(newTargetBox.minX);
|
||||
hLine.xList.push(newTargetBox.midX);
|
||||
// hLine.xList.push(newTargetBox.midX);
|
||||
hLine.xList.push(newTargetBox.maxX);
|
||||
hLine.xList.push(...(vRefLineDotMap?.[closestMinY] || []));
|
||||
hHelperLineDotMapList.push(hLine);
|
||||
|
|
@ -295,7 +443,7 @@ export function calcReferenceInfo(
|
|||
xList: []
|
||||
};
|
||||
hLine.xList.push(newTargetBox.minX);
|
||||
hLine.xList.push(newTargetBox.midX);
|
||||
// hLine.xList.push(newTargetBox.midX);
|
||||
hLine.xList.push(newTargetBox.maxX);
|
||||
hLine.xList.push(...(vRefLineDotMap?.[closestMaxY] || []));
|
||||
hHelperLineDotMapList.push(hLine);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ import {
|
|||
keySelectedElementListVertexes,
|
||||
keySelectedElementController,
|
||||
keySelectedElementPosition,
|
||||
keySelectedReferenceXLines,
|
||||
keySelectedReferenceYLines,
|
||||
keyIsMoving,
|
||||
keyEnableSelectInGroup,
|
||||
keyEnableSnapToGrid,
|
||||
|
|
@ -104,8 +102,6 @@ export type DeepSelectorSharedStorage = {
|
|||
[keySelectedElementListVertexes]: ViewRectVertexes | null;
|
||||
[keySelectedElementController]: ElementSizeController | null;
|
||||
[keySelectedElementPosition]: ElementPosition;
|
||||
[keySelectedReferenceXLines]: Array<PointSize[]>;
|
||||
[keySelectedReferenceYLines]: Array<PointSize[]>;
|
||||
[keyIsMoving]: boolean | null;
|
||||
[keyEnableSelectInGroup]: boolean | null;
|
||||
[keyEnableSnapToGrid]: boolean | null;
|
||||
|
|
|
|||
|
|
@ -253,9 +253,9 @@ export class iDraw {
|
|||
core.trigger(eventKeys.change, { data, type: 'moveElement' });
|
||||
}
|
||||
|
||||
async getImageBlobURL(opts: ExportImageFileBaseOptions): Promise<ExportImageFileResult> {
|
||||
async getImageBlobURL(opts?: ExportImageFileBaseOptions): Promise<ExportImageFileResult> {
|
||||
const data = this.getData() || { elements: [] };
|
||||
const { devicePixelRatio } = opts;
|
||||
const { devicePixelRatio } = opts || { devicePixelRatio: 1 };
|
||||
|
||||
const outputSize = calcElementListSize(data.elements);
|
||||
const { viewSizeInfo } = this.getViewInfo();
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ export interface CoreEventSelect {
|
|||
export interface CoreEventChange {
|
||||
type: string;
|
||||
data: Data;
|
||||
selectedElements?: Element[] | null;
|
||||
hoverElement?: Element | null;
|
||||
}
|
||||
export interface CoreEventScale {
|
||||
scale: number;
|
||||
|
|
|
|||
|
|
@ -88,3 +88,4 @@ export { calcViewCenterContent, calcViewCenter } from './lib/view-content';
|
|||
export { modifyElement, getModifiedElement } from './lib/modify';
|
||||
// export { ModifyRecorder } from './lib/modify-recorder';
|
||||
export { enhanceFontFamliy } from './lib/text';
|
||||
export { flatElementList } from './lib/flat';
|
||||
|
|
|
|||
143
packages/util/src/lib/flat.ts
Normal file
143
packages/util/src/lib/flat.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import type { Element, ElementSize, Elements, ViewRectVertexes } from '@idraw/types';
|
||||
import { calcElementVertexesInGroup } from './vertex';
|
||||
import { limitAngle, parseAngleToRadian, calcElementCenterFromVertexes, rotatePoint } from './rotate';
|
||||
|
||||
function flatElementSize(
|
||||
elemSize: ElementSize,
|
||||
opts: {
|
||||
groupQueue: Element<'group'>[];
|
||||
}
|
||||
): ElementSize {
|
||||
const { groupQueue } = opts;
|
||||
let { x, y, w, h, angle = 0 } = elemSize;
|
||||
let totalAngle = 0;
|
||||
groupQueue.forEach((group) => {
|
||||
x += group.x;
|
||||
y += group.y;
|
||||
totalAngle += group.angle || 0;
|
||||
});
|
||||
totalAngle = limitAngle(totalAngle);
|
||||
if (totalAngle === 0) {
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
angle
|
||||
};
|
||||
}
|
||||
totalAngle += elemSize.angle || 0;
|
||||
totalAngle = limitAngle(totalAngle);
|
||||
|
||||
const vertexes = calcElementVertexesInGroup(elemSize, { groupQueue }) as ViewRectVertexes;
|
||||
const center = calcElementCenterFromVertexes(vertexes);
|
||||
const start = rotatePoint(center, vertexes[0], parseAngleToRadian(0 - totalAngle));
|
||||
x = start.x;
|
||||
y = start.y;
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
w,
|
||||
h,
|
||||
angle: totalAngle
|
||||
};
|
||||
}
|
||||
|
||||
function isValidElement(elem: Element) {
|
||||
if (['rect', 'circle'].includes(elem.type)) {
|
||||
const detail = (elem as Element<'rect'>).detail;
|
||||
if (!detail.background && !detail.borderWidth) {
|
||||
return false;
|
||||
}
|
||||
if (detail.background === 'transparent' && !detail.borderWidth) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (['group'].includes(elem.type)) {
|
||||
const detail = (elem as Element<'group'>).detail || {};
|
||||
const { children } = detail;
|
||||
|
||||
if (!(children.length > 0) && !detail.background && !detail.borderWidth) {
|
||||
return false;
|
||||
}
|
||||
if (!(children.length > 0) && detail.background === 'transparent' && !detail.borderWidth) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (elem.type === 'text') {
|
||||
if (!(elem as Element<'text'>).detail.text) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (elem.type === 'image') {
|
||||
if (!(elem as Element<'image'>).detail.src) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (elem.type === 'html') {
|
||||
if (!(elem as Element<'html'>).detail.html) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (elem.type === 'svg') {
|
||||
if (!(elem as Element<'svg'>).detail.svg) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (elem.type === 'path') {
|
||||
const detail = (elem as Element<'path'>).detail;
|
||||
if (!(detail?.commands?.length > 0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function flatElementList(list: Elements): Elements {
|
||||
const elemeList: Elements = [];
|
||||
const currentGroupQueue: Array<Element<'group'>> = [];
|
||||
|
||||
const _resetElemSize = (elem: Element) => {
|
||||
if (!isValidElement(elem)) {
|
||||
return;
|
||||
}
|
||||
const newSize = flatElementSize(elem, { groupQueue: currentGroupQueue });
|
||||
const resizeElem = {
|
||||
...elem,
|
||||
...newSize
|
||||
};
|
||||
|
||||
elemeList.push(resizeElem);
|
||||
};
|
||||
|
||||
const _walk = (elem: Element) => {
|
||||
if (elem?.operations?.invisible === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (elem.type === 'group') {
|
||||
const { detail } = elem as Element<'group'>;
|
||||
const { children, ...restDetail } = detail;
|
||||
_resetElemSize({ ...elem, ...{ detail: { ...restDetail, children: [] } } });
|
||||
|
||||
currentGroupQueue.push(elem as Element<'group'>);
|
||||
children.forEach((child) => {
|
||||
_walk(child);
|
||||
});
|
||||
currentGroupQueue.pop();
|
||||
} else {
|
||||
_resetElemSize(elem);
|
||||
}
|
||||
};
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const elem = list[i];
|
||||
_walk(elem);
|
||||
}
|
||||
|
||||
return elemeList;
|
||||
}
|
||||
Loading…
Reference in a new issue