mirror of
https://github.com/idrawjs/idraw
synced 2026-05-22 17:18:24 +00:00
Merge pull request #360 from idrawjs/dev-v0.4
feat: add features of undo and redo
This commit is contained in:
commit
e952f6c190
46 changed files with 385 additions and 62 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"private": false,
|
||||
"version": "0.4.0-beta.45",
|
||||
"version": "0.4.0-rc.0",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import {
|
|||
} from '@idraw/util';
|
||||
import { Board, Sharer, Calculator } from './board';
|
||||
import { createBoardContent, validateElements } from '@idraw/util';
|
||||
import { Cursor } from './lib/cursor';
|
||||
import { Cursor } from './cursor/cursor';
|
||||
import { getModifyElementRecord } from './record';
|
||||
|
||||
export { coreEventKeys } from './config';
|
||||
|
|
@ -43,15 +43,15 @@ export type { CoreEventKeys } from './config';
|
|||
export { Board, Sharer, Calculator };
|
||||
|
||||
// export { MiddlewareSelector } from './middleware/selector';
|
||||
export { MiddlewareSelector } from './middleware/selector';
|
||||
export { MiddlewareScroller } from './middleware/scroller';
|
||||
export { MiddlewareScaler } from './middleware/scaler';
|
||||
export { MiddlewareRuler } from './middleware/ruler';
|
||||
export { MiddlewareTextEditor } from './middleware/text-editor';
|
||||
export { MiddlewareDragger } from './middleware/dragger';
|
||||
export { MiddlewareInfo } from './middleware/info';
|
||||
export { MiddlewareLayoutSelector } from './middleware/layout-selector';
|
||||
export { MiddlewarePointer } from './middleware/pointer';
|
||||
export { MiddlewareSelector } from './middlewares/selector';
|
||||
export { MiddlewareScroller } from './middlewares/scroller';
|
||||
export { MiddlewareScaler } from './middlewares/scaler';
|
||||
export { MiddlewareRuler } from './middlewares/ruler';
|
||||
export { MiddlewareTextEditor } from './middlewares/text-editor';
|
||||
export { MiddlewareDragger } from './middlewares/dragger';
|
||||
export { MiddlewareInfo } from './middlewares/info';
|
||||
export { MiddlewareLayoutSelector } from './middlewares/layout-selector';
|
||||
export { MiddlewarePointer } from './middlewares/pointer';
|
||||
|
||||
export class Core<E extends CoreEventMap = CoreEventMap> {
|
||||
#board: Board<E>;
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ export const MiddlewareLayoutSelector: Middleware<
|
|||
};
|
||||
}
|
||||
eventHub.trigger(coreEventKeys.CHANGE, {
|
||||
type: 'dragLayout',
|
||||
type: 'resizeLayout',
|
||||
data,
|
||||
modifyRecord
|
||||
});
|
||||
|
|
@ -120,6 +120,9 @@ export const MiddlewareSelector: Middleware<
|
|||
devicePixelRatio: sharer.getActiveViewSizeInfo().devicePixelRatio
|
||||
});
|
||||
|
||||
let startResizeGroupRecord: ModifyRecord<'resizeElements'> | null = null;
|
||||
let endResizeGroupRecord: ModifyRecord<'resizeElements'> | null = null;
|
||||
|
||||
sharer.setSharedStorage(keyActionType, null);
|
||||
sharer.setSharedStorage(keyEnableSnapToGrid, true);
|
||||
|
||||
|
|
@ -213,6 +216,8 @@ export const MiddlewareSelector: Middleware<
|
|||
};
|
||||
|
||||
const clear = () => {
|
||||
startResizeGroupRecord = null;
|
||||
endResizeGroupRecord = null;
|
||||
sharer.setSharedStorage(keyActionType, null);
|
||||
sharer.setSharedStorage(keyResizeType, null);
|
||||
sharer.setSharedStorage(keyAreaStart, null);
|
||||
|
|
@ -419,6 +424,8 @@ export const MiddlewareSelector: Middleware<
|
|||
prevPoint = e.point;
|
||||
moveOriginalStartPoint = e.point;
|
||||
|
||||
startResizeGroupRecord = null;
|
||||
endResizeGroupRecord = null;
|
||||
sharer.setSharedStorage(keyActionType, null);
|
||||
sharer.setSharedStorage(keyResizeType, null);
|
||||
sharer.setSharedStorage(keyAreaStart, null);
|
||||
|
|
@ -674,7 +681,7 @@ export const MiddlewareSelector: Middleware<
|
|||
const gridW = calculator.toGridNum(resizedElemSize.w, calcOpts);
|
||||
const gridH = calculator.toGridNum(resizedElemSize.h, calcOpts);
|
||||
if (elems[0].type === 'group') {
|
||||
resizeEffectGroupElement(
|
||||
endResizeGroupRecord = resizeEffectGroupElement(
|
||||
elems[0] as Element<'group'>,
|
||||
{
|
||||
x: gridX,
|
||||
|
|
@ -684,6 +691,9 @@ export const MiddlewareSelector: Middleware<
|
|||
},
|
||||
{ resizeEffect: elems[0].operations?.resizeEffect }
|
||||
);
|
||||
if (!startResizeGroupRecord) {
|
||||
startResizeGroupRecord = endResizeGroupRecord;
|
||||
}
|
||||
elems[0].x = gridX;
|
||||
elems[0].y = gridY;
|
||||
} else {
|
||||
|
|
@ -791,16 +801,16 @@ export const MiddlewareSelector: Middleware<
|
|||
}
|
||||
|
||||
if (data && (['drag', 'drag-list', 'drag-list-end', 'resize'] as ActionType[]).includes(actionType)) {
|
||||
let type: any = 'dragElement';
|
||||
let type: any = 'resizeElement';
|
||||
if (type === 'resize') {
|
||||
type = 'resizeElement';
|
||||
}
|
||||
if (hasChangedData) {
|
||||
const startSize = pointStartElementSizeList[0] as ElementSize & { uuid: string };
|
||||
let modifyRecord: ModifyRecord | undefined = undefined;
|
||||
let modifyRecord: ModifyRecord | null | undefined = null;
|
||||
if (selectedElements.length === 1) {
|
||||
modifyRecord = {
|
||||
type: 'dragElement',
|
||||
type: 'resizeElement',
|
||||
time: 0,
|
||||
content: {
|
||||
method: 'modifyElement',
|
||||
|
|
@ -809,9 +819,18 @@ export const MiddlewareSelector: Middleware<
|
|||
after: toFlattenElement(getElementSize(selectedElements[0]))
|
||||
}
|
||||
};
|
||||
if (selectedElements[0].type === 'group' && startResizeGroupRecord && endResizeGroupRecord) {
|
||||
modifyRecord = {
|
||||
...endResizeGroupRecord,
|
||||
content: {
|
||||
...endResizeGroupRecord.content,
|
||||
before: startResizeGroupRecord.content.before
|
||||
}
|
||||
};
|
||||
}
|
||||
} else if (selectedElements.length > 1) {
|
||||
modifyRecord = {
|
||||
type: 'dragElements',
|
||||
type: 'resizeElements',
|
||||
time: 0,
|
||||
content: {
|
||||
method: 'modifyElements',
|
||||
|
|
@ -238,15 +238,15 @@ export class iDraw {
|
|||
return this.#core.forceRender();
|
||||
}
|
||||
|
||||
// getHistoryHandler() {
|
||||
// return this.#historyHandler;
|
||||
// }
|
||||
getHistoryHandler() {
|
||||
return this.#historyHandler;
|
||||
}
|
||||
|
||||
// redo() {
|
||||
// this.#historyHandler?.redo();
|
||||
// }
|
||||
redo() {
|
||||
this.#historyHandler?.redo();
|
||||
}
|
||||
|
||||
// undo() {
|
||||
// this.#historyHandler?.undo();
|
||||
// }
|
||||
undo() {
|
||||
this.#historyHandler?.undo();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ const supportRecordTypes = [
|
|||
'deleteElement',
|
||||
'moveElement',
|
||||
'addElement',
|
||||
'dragElement',
|
||||
'resizeElement',
|
||||
'dragLayout',
|
||||
'resizeElements',
|
||||
'resizeLayout',
|
||||
'modifyLayout',
|
||||
'modifyGlobal'
|
||||
];
|
||||
|
|
@ -90,7 +90,7 @@ export const useHistory = (opts: { core: Core; limit?: number }) => {
|
|||
undoRecord = core.modifyGlobal(info) as ModifyRecord;
|
||||
} else if (record.content.method === 'modifyElements') {
|
||||
undoRecord = core.modifyElements(
|
||||
record.content.before.forEach((item) => unflatObject(item)) as unknown as Array<
|
||||
record.content.before.map((item) => unflatObject(item)) as unknown as Array<
|
||||
RecursivePartial<Omit<Element, 'uuid'>> & Pick<Element, 'uuid'>
|
||||
>
|
||||
) as ModifyRecord;
|
||||
|
|
@ -153,7 +153,7 @@ export const useHistory = (opts: { core: Core; limit?: number }) => {
|
|||
redoRecord = core.modifyGlobal(info) as ModifyRecord;
|
||||
} else if (record.content.method === 'modifyElements') {
|
||||
redoRecord = core.modifyElements(
|
||||
record.content.before.forEach((item) => unflatObject(item)) as unknown as Array<
|
||||
record.content.before.map((item) => unflatObject(item)) as unknown as Array<
|
||||
RecursivePartial<Omit<Element, 'uuid'>> & Pick<Element, 'uuid'>
|
||||
>
|
||||
) as ModifyRecord;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
|
||||
import { rotateElement, calcViewElementSize, enhanceFontFamliy } from '@idraw/util';
|
||||
import { is, isColorStr, getDefaultElementDetailConfig } from '@idraw/util';
|
||||
import { drawBox, drawBoxShadow } from './box';
|
||||
import { drawBox, drawBoxShadow, getOpacity } from './box';
|
||||
|
||||
const detailConfig = getDefaultElementDetailConfig();
|
||||
|
||||
|
|
@ -35,6 +35,9 @@ export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: Render
|
|||
return;
|
||||
}
|
||||
|
||||
const { parentOpacity } = opts;
|
||||
const opacity = getOpacity(elem) * parentOpacity;
|
||||
ctx.globalAlpha = opacity;
|
||||
ctx.fillStyle = elem.detail.color || detailConfig.color;
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.$setFont({
|
||||
|
|
@ -64,6 +67,8 @@ export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: Render
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
ctx.globalAlpha = parentOpacity;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
import type { ElementBaseDetail, ElementTextDetail, ElementGroupDetail } from './element';
|
||||
|
||||
export type DefaultElementDetailConfig = Required<Omit<ElementBaseDetail, 'clipPath' | 'background'>> &
|
||||
Required<Pick<ElementTextDetail, 'color' | 'textAlign' | 'verticalAlign' | 'fontSize' | 'fontFamily' | 'fontWeight' | 'minInlineSize' | 'wordBreak'>> &
|
||||
export type DefaultElementDetailConfig = Required<
|
||||
Omit<ElementBaseDetail, 'clipPath' | 'clipPathStrokeWidth' | 'clipPathStrokeColor' | 'background'>
|
||||
> &
|
||||
Required<
|
||||
Pick<
|
||||
ElementTextDetail,
|
||||
'color' | 'textAlign' | 'verticalAlign' | 'fontSize' | 'fontFamily' | 'fontWeight' | 'minInlineSize' | 'wordBreak'
|
||||
>
|
||||
> &
|
||||
Required<Pick<ElementGroupDetail, 'overflow'>>;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export interface CoreEventChange<T extends ModifyType = ModifyType> {
|
|||
type: T | 'setData' | 'other' | string;
|
||||
selectedElements?: Element[] | null;
|
||||
hoverElement?: Element | null;
|
||||
modifyRecord?: ModifyRecord<T>;
|
||||
modifyRecord?: ModifyRecord<T> | null;
|
||||
}
|
||||
export interface CoreEventScale {
|
||||
scale: number;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ export type ModifyMethod =
|
|||
| 'deleteElement'
|
||||
| 'moveElement'
|
||||
| 'addElement'
|
||||
| 'dragElement'
|
||||
| 'dragElements'
|
||||
| 'resizeElement'
|
||||
| 'resizeElements'
|
||||
| 'modifyElements'
|
||||
| 'dragLayout'
|
||||
| 'resizeLayout'
|
||||
| 'modifyLayout'
|
||||
| 'modifyGlobal';
|
||||
|
||||
|
|
@ -92,19 +92,19 @@ export interface ModifyContentMap {
|
|||
from: ElementPosition;
|
||||
to: ElementPosition;
|
||||
};
|
||||
dragElement: {
|
||||
resizeElement: {
|
||||
method: 'modifyElement';
|
||||
uuid: string;
|
||||
before: FlattenElement | null;
|
||||
after: FlattenElement | null;
|
||||
};
|
||||
dragElements: {
|
||||
resizeElements: {
|
||||
method: 'modifyElements';
|
||||
before: (FlattenLayout & { uuid: string })[];
|
||||
after: (FlattenLayout & { uuid: string })[];
|
||||
};
|
||||
dragLayout: {
|
||||
method: 'modifyElement';
|
||||
resizeLayout: {
|
||||
method: 'modifyLayout';
|
||||
before: FlattenLayout;
|
||||
after: FlattenLayout;
|
||||
};
|
||||
|
|
@ -151,13 +151,13 @@ export interface ModifyRecordMap {
|
|||
time: number;
|
||||
content: ModifyContentMap['moveElement'];
|
||||
};
|
||||
dragElement: {
|
||||
type: 'dragElement';
|
||||
resizeElement: {
|
||||
type: 'resizeElement';
|
||||
time: number;
|
||||
content: ModifyContentMap['modifyElement'];
|
||||
};
|
||||
dragElements: {
|
||||
type: 'dragElements';
|
||||
resizeElements: {
|
||||
type: 'resizeElements';
|
||||
time: number;
|
||||
content: ModifyContentMap['modifyElements'];
|
||||
};
|
||||
|
|
@ -166,10 +166,10 @@ export interface ModifyRecordMap {
|
|||
time: number;
|
||||
content: ModifyContentMap['modifyElements'];
|
||||
};
|
||||
dragLayout: {
|
||||
type: 'dragLayout';
|
||||
resizeLayout: {
|
||||
type: 'resizeLayout';
|
||||
time: number;
|
||||
content: ModifyContentMap['dragLayout'];
|
||||
content: ModifyContentMap['resizeLayout'];
|
||||
};
|
||||
modifyLayout: {
|
||||
type: 'modifyLayout';
|
||||
|
|
|
|||
292
packages/util/__tests__/lib/resize-element.test.ts
Normal file
292
packages/util/__tests__/lib/resize-element.test.ts
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
import { createElement, resizeEffectGroupElement } from '@idraw/util';
|
||||
import type { Element } from '@idraw/types';
|
||||
|
||||
const createGroupByRatio = (opts?: { xRatio?: number; yRatio?: number }) => {
|
||||
const { xRatio = 1, yRatio = 1 } = opts || {};
|
||||
const minRatio = Math.min(xRatio, yRatio);
|
||||
const maxRatio = Math.max(xRatio, yRatio);
|
||||
const midRatio = (minRatio + maxRatio) / 2;
|
||||
|
||||
const group: Element<'group'> = createElement('group', {
|
||||
uuid: 'test-001',
|
||||
x: 10,
|
||||
y: 10,
|
||||
w: 2000 * xRatio,
|
||||
h: 2000 * yRatio,
|
||||
detail: {
|
||||
children: [
|
||||
createElement('rect', { uuid: 'test-002', x: 20 * xRatio, y: 20 * yRatio, w: 20 * xRatio, h: 20 * yRatio }),
|
||||
createElement('circle', { uuid: 'test-003', x: 40 * xRatio, y: 40 * yRatio, w: 40 * xRatio, h: 40 * yRatio }),
|
||||
createElement('text', {
|
||||
uuid: 'test-004',
|
||||
x: 60 * xRatio,
|
||||
y: 60 * yRatio,
|
||||
w: 60 * xRatio,
|
||||
h: 60 * yRatio,
|
||||
detail: {
|
||||
fontSize: 16 * midRatio,
|
||||
// lineHeight: 32 * midRatio,
|
||||
text: 'Text in Group'
|
||||
}
|
||||
}),
|
||||
createElement('image', {
|
||||
uuid: 'test-005',
|
||||
x: 80 * xRatio,
|
||||
y: 80 * yRatio,
|
||||
w: 80 * xRatio,
|
||||
h: 80 * yRatio,
|
||||
detail: { src: 'https://example.com/002.png' }
|
||||
}),
|
||||
createElement('group', {
|
||||
uuid: 'test-100',
|
||||
x: 500 * xRatio,
|
||||
y: 500 * yRatio,
|
||||
w: 1000 * xRatio,
|
||||
h: 1000 * yRatio,
|
||||
detail: {
|
||||
children: [
|
||||
createElement('rect', {
|
||||
uuid: 'test-101',
|
||||
x: 20 * xRatio,
|
||||
y: 20 * yRatio,
|
||||
w: 20 * xRatio,
|
||||
h: 20 * yRatio
|
||||
}),
|
||||
createElement('circle', {
|
||||
uuid: 'test-102',
|
||||
x: 40 * xRatio,
|
||||
y: 40 * yRatio,
|
||||
w: 40 * xRatio,
|
||||
h: 40 * yRatio
|
||||
}),
|
||||
createElement('text', {
|
||||
uuid: 'test-103',
|
||||
x: 60 * xRatio,
|
||||
y: 60 * yRatio,
|
||||
w: 60 * xRatio,
|
||||
h: 60 * yRatio,
|
||||
detail: {
|
||||
fontSize: 16 * midRatio,
|
||||
text: 'Text in Group'
|
||||
}
|
||||
}),
|
||||
createElement('image', {
|
||||
uuid: 'test-104',
|
||||
x: 80 * xRatio,
|
||||
y: 80 * yRatio,
|
||||
w: 80 * xRatio,
|
||||
h: 80 * yRatio,
|
||||
detail: { src: 'https://example.com/002.png' }
|
||||
})
|
||||
]
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
operations: {
|
||||
resizeEffect: 'deepResize'
|
||||
}
|
||||
});
|
||||
return group;
|
||||
};
|
||||
|
||||
const createGroupByFixed = (opts: { moveX: number; moveY: number; moveW: number; moveH: number }) => {
|
||||
const { moveX, moveY, moveW, moveH } = opts || {};
|
||||
|
||||
const group: Element<'group'> = createElement('group', {
|
||||
uuid: 'test-001',
|
||||
x: 10 + moveX,
|
||||
y: 10 + moveY,
|
||||
w: 2000 + moveW,
|
||||
h: 2000 + moveH,
|
||||
detail: {
|
||||
children: [
|
||||
createElement('rect', { uuid: 'test-002', x: 20 - moveX, y: 20 - moveY, w: 20, h: 20 }),
|
||||
createElement('circle', { uuid: 'test-003', x: 40 - moveX, y: 40 - moveY, w: 40, h: 40 }),
|
||||
createElement('text', {
|
||||
uuid: 'test-004',
|
||||
x: 60 - moveX,
|
||||
y: 60 - moveY,
|
||||
w: 60,
|
||||
h: 60,
|
||||
detail: {
|
||||
fontSize: 16,
|
||||
text: 'Text in Group'
|
||||
}
|
||||
}),
|
||||
createElement('image', {
|
||||
uuid: 'test-005',
|
||||
x: 80 - moveX,
|
||||
y: 80 - moveY,
|
||||
w: 80,
|
||||
h: 80,
|
||||
detail: { src: 'https://example.com/002.png' }
|
||||
}),
|
||||
createElement('group', {
|
||||
uuid: 'test-100',
|
||||
x: 500 - moveX,
|
||||
y: 500 - moveY,
|
||||
w: 1000,
|
||||
h: 1000,
|
||||
detail: {
|
||||
children: [
|
||||
createElement('rect', {
|
||||
uuid: 'test-101',
|
||||
x: 20,
|
||||
y: 20,
|
||||
w: 20,
|
||||
h: 20
|
||||
}),
|
||||
createElement('circle', {
|
||||
uuid: 'test-102',
|
||||
x: 40,
|
||||
y: 40,
|
||||
w: 40,
|
||||
h: 40
|
||||
}),
|
||||
createElement('text', {
|
||||
uuid: 'test-103',
|
||||
x: 60,
|
||||
y: 60,
|
||||
w: 60,
|
||||
h: 60,
|
||||
detail: {
|
||||
fontSize: 16,
|
||||
text: 'Text in Group'
|
||||
}
|
||||
}),
|
||||
createElement('image', {
|
||||
uuid: 'test-104',
|
||||
x: 80,
|
||||
y: 80,
|
||||
w: 80,
|
||||
h: 80,
|
||||
detail: { src: 'https://example.com/002.png' }
|
||||
})
|
||||
]
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
operations: {
|
||||
resizeEffect: 'deepResize'
|
||||
}
|
||||
});
|
||||
return group;
|
||||
};
|
||||
|
||||
describe('resizeEffectGroupElement', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers().setSystemTime(new Date('2025-01-01'));
|
||||
});
|
||||
|
||||
test('deepSize', () => {
|
||||
const group = createGroupByRatio();
|
||||
const xRatio = 2;
|
||||
const yRatio = 3;
|
||||
|
||||
const record = resizeEffectGroupElement(
|
||||
group,
|
||||
{
|
||||
w: group.w * xRatio,
|
||||
h: group.h * yRatio
|
||||
},
|
||||
{
|
||||
resizeEffect: 'deepResize'
|
||||
}
|
||||
);
|
||||
|
||||
expect(group).toStrictEqual(
|
||||
createGroupByRatio({
|
||||
xRatio,
|
||||
yRatio
|
||||
})
|
||||
);
|
||||
|
||||
expect(record).toStrictEqual({
|
||||
type: 'resizeElements',
|
||||
time: 1735689600000,
|
||||
content: {
|
||||
method: 'modifyElements',
|
||||
before: [
|
||||
{ uuid: 'test-001', x: 10, y: 10, w: 2000, h: 2000 },
|
||||
{ x: 20, y: 20, w: 20, h: 20, uuid: 'test-002' },
|
||||
{ x: 40, y: 40, w: 40, h: 40, uuid: 'test-003' },
|
||||
{ x: 60, y: 60, w: 60, h: 60, uuid: 'test-004', 'detail.fontSize': 16 },
|
||||
{ x: 80, y: 80, w: 80, h: 80, uuid: 'test-005' },
|
||||
{ x: 500, y: 500, w: 1000, h: 1000, uuid: 'test-100' },
|
||||
{ x: 20, y: 20, w: 20, h: 20, uuid: 'test-101' },
|
||||
{ x: 40, y: 40, w: 40, h: 40, uuid: 'test-102' },
|
||||
{ x: 60, y: 60, w: 60, h: 60, uuid: 'test-103', 'detail.fontSize': 16 },
|
||||
{ x: 80, y: 80, w: 80, h: 80, uuid: 'test-104' }
|
||||
],
|
||||
after: [
|
||||
{ uuid: 'test-001', x: 10, y: 10, w: 4000, h: 6000 },
|
||||
{ x: 40, y: 60, w: 40, h: 60, uuid: 'test-002' },
|
||||
{ x: 80, y: 120, w: 80, h: 120, uuid: 'test-003' },
|
||||
{ x: 120, y: 180, w: 120, h: 180, uuid: 'test-004', 'detail.fontSize': 40 },
|
||||
{ x: 160, y: 240, w: 160, h: 240, uuid: 'test-005' },
|
||||
{ x: 1000, y: 1500, w: 2000, h: 3000, uuid: 'test-100' },
|
||||
{ x: 40, y: 60, w: 40, h: 60, uuid: 'test-101' },
|
||||
{ x: 80, y: 120, w: 80, h: 120, uuid: 'test-102' },
|
||||
{ x: 120, y: 180, w: 120, h: 180, uuid: 'test-103', 'detail.fontSize': 40 },
|
||||
{ x: 160, y: 240, w: 160, h: 240, uuid: 'test-104' }
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('fixed', () => {
|
||||
const group = createGroupByRatio();
|
||||
const moveX = 99;
|
||||
const moveY = 88;
|
||||
const moveW = 77;
|
||||
const moveH = 66;
|
||||
|
||||
const record = resizeEffectGroupElement(
|
||||
group,
|
||||
{
|
||||
x: group.x + moveX,
|
||||
y: group.y + moveY,
|
||||
w: group.w + moveW,
|
||||
h: group.h + moveH
|
||||
},
|
||||
{
|
||||
resizeEffect: 'fixed'
|
||||
}
|
||||
);
|
||||
|
||||
expect(group).toStrictEqual(
|
||||
createGroupByFixed({
|
||||
moveX,
|
||||
moveY,
|
||||
moveW,
|
||||
moveH
|
||||
})
|
||||
);
|
||||
|
||||
expect(record).toStrictEqual({
|
||||
type: 'resizeElements',
|
||||
time: 1735689600000,
|
||||
content: {
|
||||
method: 'modifyElements',
|
||||
before: [
|
||||
{ uuid: 'test-001', x: 10, y: 10, w: 2000, h: 2000 },
|
||||
{ uuid: 'test-002', x: 20, y: 20 },
|
||||
{ uuid: 'test-003', x: 40, y: 40 },
|
||||
{ uuid: 'test-004', x: 60, y: 60 },
|
||||
{ uuid: 'test-005', x: 80, y: 80 },
|
||||
{ uuid: 'test-100', x: 500, y: 500 }
|
||||
],
|
||||
after: [
|
||||
{ uuid: 'test-001', x: 109, y: 98, w: 2077, h: 2066 },
|
||||
{ uuid: 'test-002', x: -79, y: -68 },
|
||||
{ uuid: 'test-003', x: -59, y: -48 },
|
||||
{ uuid: 'test-004', x: -39, y: -28 },
|
||||
{ uuid: 'test-005', x: -19, y: -8 },
|
||||
{ uuid: 'test-100', x: 401, y: 412 }
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -61,7 +61,7 @@ export function getDefaultElementTextDetail(elementSize: ElementSize): ElementTe
|
|||
color: detailConfig.color,
|
||||
fontFamily: detailConfig.fontFamily,
|
||||
fontWeight: detailConfig.fontWeight,
|
||||
lineHeight: elementSize.w / defaultText.length,
|
||||
// lineHeight: elementSize.w / defaultText.length,
|
||||
fontSize: elementSize.w / defaultText.length,
|
||||
textAlign: 'center',
|
||||
verticalAlign: 'middle'
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ function resizeElementBaseDetailByRatio(elem: Element, opts: DeepResizeRatioOpti
|
|||
function resizeElementBaseByRatio(elem: Element, opts: DeepResizeRatioOptions): ModifyRecord<'modifyElement'> {
|
||||
const { xRatio, yRatio } = opts;
|
||||
const { uuid, x, y, w, h } = elem;
|
||||
elem.x = doNum(x * xRatio);
|
||||
elem.y = doNum(y * yRatio);
|
||||
elem.w = doNum(w * xRatio);
|
||||
elem.h = doNum(h * yRatio);
|
||||
const record: ModifyRecord<'modifyElement'> = {
|
||||
type: 'modifyElement',
|
||||
time: Date.now(),
|
||||
|
|
@ -112,13 +116,10 @@ function resizeElementBaseByRatio(elem: Element, opts: DeepResizeRatioOptions):
|
|||
method: 'modifyElement',
|
||||
uuid: uuid,
|
||||
before: { x, y, w, h },
|
||||
after: { x, y, w, h }
|
||||
after: { x: elem.x, y: elem.y, w: elem.w, h: elem.h }
|
||||
}
|
||||
};
|
||||
elem.x = doNum(x * xRatio);
|
||||
elem.y = doNum(y * yRatio);
|
||||
elem.w = doNum(w * xRatio);
|
||||
elem.h = doNum(h * yRatio);
|
||||
|
||||
const detailRecord = resizeElementBaseDetailByRatio(elem, opts);
|
||||
record.content.before = {
|
||||
...record.content.before,
|
||||
|
|
@ -170,7 +171,7 @@ function resizeTextElementDetailByRatio(
|
|||
function deepResizeElementByRatio(
|
||||
elem: Element,
|
||||
opts: DeepResizeRatioOptions,
|
||||
record?: ModifyRecord<'modifyElements'>
|
||||
record?: ModifyRecord<'resizeElements'>
|
||||
) {
|
||||
const { type, uuid } = elem;
|
||||
|
||||
|
|
@ -210,7 +211,7 @@ function deepResizeElementByRatio(
|
|||
function fixedResizeGroupElementChildren(
|
||||
elem: Element<'group'>,
|
||||
opts: FixedResizeOptions,
|
||||
record?: ModifyRecord<'modifyElements'>
|
||||
record?: ModifyRecord<'resizeElements'>
|
||||
) {
|
||||
if (!(elem.type === 'group' && Array.isArray(elem.detail.children))) {
|
||||
return;
|
||||
|
|
@ -250,12 +251,9 @@ export function resizeEffectGroupElement(
|
|||
opts?: {
|
||||
resizeEffect?: ElementOperations['resizeEffect'];
|
||||
}
|
||||
): ModifyRecord<'modifyElements'> | null {
|
||||
if (!istype.number(size.x) && !istype.number(size.y)) {
|
||||
return null;
|
||||
}
|
||||
const record: ModifyRecord<'modifyElements'> = {
|
||||
type: 'modifyElements',
|
||||
): ModifyRecord<'resizeElements'> | null {
|
||||
const record: ModifyRecord<'resizeElements'> = {
|
||||
type: 'resizeElements',
|
||||
time: Date.now(),
|
||||
content: {
|
||||
method: 'modifyElements',
|
||||
|
|
@ -279,6 +277,8 @@ export function resizeEffectGroupElement(
|
|||
const afterGroupElem: FlattenLayout & { uuid: string } = { uuid, x: resizeX, y: resizeY, w: resizeW, h: resizeH };
|
||||
|
||||
if (opts?.resizeEffect === 'deepResize') {
|
||||
record.content.before.push(beforeGroupElem);
|
||||
record.content.after.push(afterGroupElem);
|
||||
const xRatio = resizeW / elem.w;
|
||||
const yRatio = resizeH / elem.h;
|
||||
if (xRatio === yRatio && xRatio === 1) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue