Skip to content

Commit

Permalink
feat: optimize rotate action
Browse files Browse the repository at this point in the history
  • Loading branch information
F-star committed Jun 12, 2024
1 parent 3863378 commit 3487f62
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 135 deletions.
10 changes: 5 additions & 5 deletions packages/core/src/clipboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,19 @@ export class ClipboardManager {
);
editor.selectedElements.setItems(pastedGraphs);

const bbox = editor.selectedElements.getBbox()!;
const boundingRect = editor.selectedElements.getBoundingRect()!;
if (
(x === undefined || y === undefined) &&
pastedData.paperId !== editor.paperId
) {
const vwCenter = this.editor.viewportManager.getCenter();
x = vwCenter.x - bbox.width / 2;
y = vwCenter.y - bbox.height / 2;
x = vwCenter.x - boundingRect.width / 2;
y = vwCenter.y - boundingRect.height / 2;
}

if (x !== undefined && y !== undefined) {
const dx = x - bbox.x;
const dy = y - bbox.y;
const dx = x - boundingRect.x;
const dy = y - boundingRect.y;
if (dx || dy) {
SuikaGraphics.dMove(pastedGraphs, dx, dy);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/ref_line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export class RefLine {
];
} else {
const targetBbox = bboxToBboxWithMid(
rectToBox(this.editor.selectedElements.getBbox()!),
rectToBox(this.editor.selectedElements.getBoundingRect()!),
);
targetPoints = [
{ x: targetBbox.minX, y: targetBbox.minY },
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/selected_box.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class SelectedBox {
transform: selectedGraph.getWorldTransform(),
};
} else {
const rect = selectedElements.getBbox()!;
const rect = selectedElements.getBoundingRect()!;
this.box = {
width: rect.width,
height: rect.height,
Expand Down
10 changes: 1 addition & 9 deletions packages/core/src/selected_elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { type Editor } from './editor';
import { isGroupGraphics, type SuikaGraphics } from './graphs';
import { getParentIdSet } from './service/group_and_record';
import { removeGraphicsAndRecord } from './service/remove_service';
import { getRectCenterPoint } from './utils';

interface Events {
itemsChange(items: SuikaGraphics[]): void;
Expand Down Expand Up @@ -111,20 +110,13 @@ export class SelectedElements {
}
this.toggleItems([toggledElement]);
}
getCenterPoint() {
const bbox = this.getBbox();
if (!bbox) {
throw new Error('no selected elements');
}
return getRectCenterPoint(bbox);
}
size() {
return this.items.length;
}
isEmpty() {
return this.items.length === 0;
}
getBbox(): IRect | null {
getBoundingRect(): IRect | null {
if (this.isEmpty()) {
return null;
}
Expand Down
9 changes: 4 additions & 5 deletions packages/core/src/tools/tool_select/tool_select_move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import { type IBaseTool } from '../type';

/**
* select tool
*
* move selected elements
* sub case: move selected elements
*/
export class SelectMoveTool implements IBaseTool {
private originWorldTfMap = new Map<string, IMatrixArr>();
Expand Down Expand Up @@ -57,13 +56,13 @@ export class SelectMoveTool implements IBaseTool {
this.originWorldTfMap.set(item.attrs.id, item.getWorldTransform());
}

const bBox = this.editor.selectedElements.getBbox();
if (!bBox) {
const boundingRect = this.editor.selectedElements.getBoundingRect();
if (!boundingRect) {
console.error(
"selected elements should't be empty when moving, please report us issue",
);
} else {
this.prevBBoxPos = { x: bBox.x, y: bBox.y };
this.prevBBoxPos = { x: boundingRect.x, y: boundingRect.y };
}

this.editor.refLine.cacheXYToBbox();
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/tools/tool_select/tool_select_resize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { updateParentSize } from './utils';
export class SelectResizeTool implements IBaseTool {
private startPoint: IPoint = { x: -1, y: -1 };
private handleName!: string;
private startSelectBbox: IRect | null = null;
private startSelectBRect: IRect | null = null;

private originAttrsMap = new Map<string, GraphicsAttrs>();
private originWorldTransforms = new Map<string, IMatrixArr>();
Expand Down Expand Up @@ -86,11 +86,11 @@ export class SelectResizeTool implements IBaseTool {
]);
}

const startSelectBbox = this.editor.selectedElements.getBbox();
if (!startSelectBbox) {
const startSelectBRect = this.editor.selectedElements.getBoundingRect();
if (!startSelectBRect) {
throw new Error('startSelectBbox should not be null, please issue to us');
}
this.startSelectBbox = startSelectBbox;
this.startSelectBRect = startSelectBRect;

if (isTransformHandle(handleInfo.handleName)) {
this.editor.controlHandleManager.hideCustomHandles();
Expand Down Expand Up @@ -241,7 +241,7 @@ export class SelectResizeTool implements IBaseTool {

this.updateControls(selectedElements[0]);
} else {
const startSelectBbox = this.startSelectBbox!;
const startSelectBbox = this.startSelectBRect!;
const startSelectedBoxTf = new Matrix().translate(
startSelectBbox.x,
startSelectBbox.y,
Expand Down
154 changes: 70 additions & 84 deletions packages/core/src/tools/tool_select/tool_select_rotation.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { getClosestTimesVal } from '@suika/common';
import { cloneDeep, getClosestTimesVal } from '@suika/common';
import {
getSweepAngle,
type IMatrixArr,
type IPoint,
rad2Deg,
} from '@suika/geo';

import { UpdateGraphicsAttrsCmd } from '../../commands';
import { getRotationCursor } from '../../control_handle_manager';
import { type Editor } from '../../editor';
import { type GraphicsAttrs } from '../../graphs';
import { type SuikaGraphics } from '../../graphs';
import { Transaction } from '../../transaction';
import { type IBaseTool } from '../type';
import { updateParentSize } from './utils';

/**
* select tool
Expand All @@ -20,22 +19,25 @@ import { updateParentSize } from './utils';
*/
export class SelectRotationTool implements IBaseTool {
private originWorldTfMap = new Map<string, IMatrixArr>();
private originAttrsMap = new Map<string, Partial<GraphicsAttrs>>();
private updatedAttrsMap = new Map<string, Partial<GraphicsAttrs>>();

private transaction: Transaction;
private selectedItems: SuikaGraphics[] = [];

private lastPoint: IPoint | null = null;
private startRotation = 0;
private startBboxRotation = 0;
private dRotation = 0; // 按下,然后释放的整个过程中,产生的相对角度
/** center of selected graphs */
private selectedBoxCenter: [x: number, y: number] | null = null;
private selectedBoxCenter: IPoint | null = null;
handleType = '';

private shiftPressHandler = () => {
this.rotateSelectedElements();
this.rotateSelectedGraphics();
};

constructor(private editor: Editor) {}
constructor(private editor: Editor) {
this.transaction = new Transaction(editor);
}

onActive() {
this.editor.hostEventManager.on('shiftToggle', this.shiftPressHandler);
Expand All @@ -44,119 +46,103 @@ export class SelectRotationTool implements IBaseTool {
this.editor.hostEventManager.off('shiftToggle', this.shiftPressHandler);
}
onStart(e: PointerEvent) {
const selectedElements = this.editor.selectedElements.getItems({
this.selectedItems = this.editor.selectedElements.getItems({
excludeLocked: true,
});

for (const graphics of selectedElements) {
this.originAttrsMap.set(graphics.attrs.id, {
transform: [...graphics.attrs.transform],
for (const graphics of this.selectedItems) {
this.transaction.recordOld(graphics.attrs.id, {
transform: cloneDeep(graphics.attrs.transform),
});

this.originWorldTfMap.set(
graphics.attrs.id,
graphics.getWorldTransform(),
);
}

this.selectedBoxCenter = this.editor.selectedElements.getCenterPoint();
const boundingRect = this.editor.selectedElements.getBoundingRect()!;
this.selectedBoxCenter = {
x: boundingRect.x + boundingRect.width / 2,
y: boundingRect.y + boundingRect.height / 2,
};

const mousePoint = this.editor.getSceneCursorXY(e);
this.startRotation = getSweepAngle(
{ x: 0, y: -1 },
{
x: mousePoint.x - this.selectedBoxCenter[0],
y: mousePoint.y - this.selectedBoxCenter[1],
x: mousePoint.x - this.selectedBoxCenter.x,
y: mousePoint.y - this.selectedBoxCenter.y,
},
);
this.startBboxRotation = this.editor.selectedElements.getRotation();
}
onDrag(e: PointerEvent) {
this.lastPoint = this.editor.getSceneCursorXY(e);
this.rotateSelectedElements();
this.rotateSelectedGraphics();
}
private rotateSelectedElements() {
private rotateSelectedGraphics() {
const lastPoint = this.lastPoint;
if (!lastPoint) return;

const editor = this.editor;
const selectedElements = editor.selectedElements.getItems();
/**** 旋转多个元素 ****/
const selectedElementsBBox = editor.selectedElements.getBbox();
if (selectedElementsBBox) {
const [cxInSelectedElementsBBox, cyInSelectedElementsBBox] = this
.selectedBoxCenter as [number, number];

const lastMouseRotation = getSweepAngle(
{ x: 0, y: -1 },
const selectedItems = this.selectedItems;

const { x: cxInSelectedElementsBBox, y: cyInSelectedElementsBBox } =
this.selectedBoxCenter!;

const lastMouseRotation = getSweepAngle(
{ x: 0, y: -1 },
{
x: lastPoint.x - cxInSelectedElementsBBox,
y: lastPoint.y - cyInSelectedElementsBBox,
},
);

this.dRotation = lastMouseRotation - this.startRotation;
if (editor.hostEventManager.isShiftPressing) {
const lockRotation = editor.setting.get('lockRotation');
const bboxRotation = this.startBboxRotation + this.dRotation;
this.dRotation =
getClosestTimesVal(bboxRotation, lockRotation) - this.startBboxRotation;
}

// update cursor
if (editor.selectedElements.size() === 1) {
editor.setCursor(
getRotationCursor(this.handleType, editor.selectedBox.getBox()!),
);
} else {
editor.setCursor({
type: 'rotation',
degree: rad2Deg(lastMouseRotation),
});
}

for (const graphics of selectedItems) {
graphics.dRotate(
this.dRotation,
this.originWorldTfMap.get(graphics.attrs.id)!,
{
x: lastPoint.x - cxInSelectedElementsBBox,
y: lastPoint.y - cyInSelectedElementsBBox,
x: cxInSelectedElementsBBox,
y: cyInSelectedElementsBBox,
},
);

this.dRotation = lastMouseRotation - this.startRotation;
if (editor.hostEventManager.isShiftPressing) {
const lockRotation = editor.setting.get('lockRotation');
const bboxRotation = this.startBboxRotation + this.dRotation;
this.dRotation =
getClosestTimesVal(bboxRotation, lockRotation) -
this.startBboxRotation;
}

if (editor.selectedElements.size() === 1) {
editor.setCursor(
getRotationCursor(this.handleType, editor.selectedBox.getBox()!),
);
} else {
editor.setCursor({
type: 'rotation',
degree: rad2Deg(lastMouseRotation),
});
}

for (const graphics of selectedElements) {
graphics.dRotate(
this.dRotation,
this.originWorldTfMap.get(graphics.attrs.id)!,
{
x: cxInSelectedElementsBBox,
y: cyInSelectedElementsBBox,
},
);

this.updatedAttrsMap.set(graphics.attrs.id, {
transform: [...graphics.attrs.transform],
});
}

updateParentSize(
this.editor,
this.editor.selectedElements.getParentIdSet(),
this.originAttrsMap,
this.updatedAttrsMap,
);
} else {
throw new Error('no selected elements, please report issue');
this.transaction.update(graphics.attrs.id, {
transform: [...graphics.attrs.transform],
});
}

this.transaction.updateParentSize(this.selectedItems);
editor.render();
}
onEnd() {
const commandDesc = 'Rotate Elements';
if (this.dRotation !== 0) {
this.editor.commandManager.pushCommand(
new UpdateGraphicsAttrsCmd(
commandDesc,
this.editor,
this.originAttrsMap,
this.updatedAttrsMap,
),
);
this.transaction.commit('Rotate Elements');
}
}
afterEnd() {
this.originAttrsMap = new Map();
this.updatedAttrsMap = new Map();
this.transaction = new Transaction(this.editor);
this.lastPoint = null;
this.dRotation = 0;
this.selectedBoxCenter = null;
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export class Transaction {
}

commit(desc: string) {
console.log(this);
this.editor.commandManager.pushCommand(
new UpdateGraphicsAttrsCmd(
desc,
Expand Down
12 changes: 0 additions & 12 deletions packages/core/src/utils/geo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,6 @@ import { getSweepAngle, type IBox, type IPoint, type IRect } from '@suika/geo';

import { HALF_PI } from '../constant';

/**
* rect 中心点
*/
export function getRectCenterPoint({
x,
y,
width,
height,
}: IRect): [cx: number, cy: number] {
return [x + width / 2, y + height / 2];
}

/**
* 计算绝对坐标
*/
Expand Down
Loading

0 comments on commit 3487f62

Please sign in to comment.