@sequent-org/moodboard 1.2.118 → 1.2.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/events/Events.js +1 -0
- package/src/core/index.js +14 -6
- package/src/ui/HtmlHandlesLayer.js +25 -2
package/package.json
CHANGED
|
@@ -28,6 +28,7 @@ export const Events = {
|
|
|
28
28
|
GroupResizeStart: 'tool:group:resize:start',
|
|
29
29
|
GroupResizeUpdate: 'tool:group:resize:update',
|
|
30
30
|
GroupResizeEnd: 'tool:group:resize:end',
|
|
31
|
+
RotateStart: 'tool:rotate:start',
|
|
31
32
|
RotateUpdate: 'tool:rotate:update',
|
|
32
33
|
RotateEnd: 'tool:rotate:end',
|
|
33
34
|
GroupRotateStart: 'tool:group:rotate:start',
|
package/src/core/index.js
CHANGED
|
@@ -1042,8 +1042,8 @@ export class CoreMoodBoard {
|
|
|
1042
1042
|
if (!obj || !pixiObj) continue;
|
|
1043
1043
|
this._groupResizeSnapshot.set(id, {
|
|
1044
1044
|
size: { width: obj.width, height: obj.height },
|
|
1045
|
-
//
|
|
1046
|
-
position: { x:
|
|
1045
|
+
// В snapshot фиксируем top-left как в state, чтобы не смешивать системы координат.
|
|
1046
|
+
position: { x: obj.position.x, y: obj.position.y },
|
|
1047
1047
|
type: obj.type || null
|
|
1048
1048
|
});
|
|
1049
1049
|
}
|
|
@@ -1343,7 +1343,6 @@ export class CoreMoodBoard {
|
|
|
1343
1343
|
if (!newPos) newPos = calcNew;
|
|
1344
1344
|
}
|
|
1345
1345
|
const command = new ResizeObjectCommand(
|
|
1346
|
-
this,
|
|
1347
1346
|
this,
|
|
1348
1347
|
data.object,
|
|
1349
1348
|
data.oldSize,
|
|
@@ -1402,7 +1401,8 @@ export class CoreMoodBoard {
|
|
|
1402
1401
|
|
|
1403
1402
|
this.eventBus.on(Events.Tool.GroupRotateUpdate, (data) => {
|
|
1404
1403
|
// Поворачиваем каждый объект вокруг общего центра с сохранением относительного смещения
|
|
1405
|
-
const center = this._groupRotateCenter
|
|
1404
|
+
const center = this._groupRotateCenter;
|
|
1405
|
+
if (!center) return;
|
|
1406
1406
|
const rad = (data.angle || 0) * Math.PI / 180;
|
|
1407
1407
|
const cos = Math.cos(rad);
|
|
1408
1408
|
const sin = Math.sin(rad);
|
|
@@ -1431,14 +1431,22 @@ export class CoreMoodBoard {
|
|
|
1431
1431
|
|
|
1432
1432
|
this.eventBus.on(Events.Tool.GroupRotateEnd, (data) => {
|
|
1433
1433
|
// Оформляем как батч-команду GroupRotateCommand
|
|
1434
|
-
const center = this._groupRotateCenter
|
|
1434
|
+
const center = this._groupRotateCenter;
|
|
1435
|
+
if (!center) return;
|
|
1435
1436
|
const changes = [];
|
|
1436
1437
|
for (const id of data.objects) {
|
|
1437
1438
|
const start = this._groupRotateStart?.get(id);
|
|
1438
1439
|
const pixiObject = this.pixi.objects.get(id);
|
|
1439
1440
|
if (!start || !pixiObject) continue;
|
|
1440
1441
|
const toAngle = pixiObject.rotation * 180 / Math.PI;
|
|
1441
|
-
const
|
|
1442
|
+
const objState = this.state.state.objects.find(o => o.id === id);
|
|
1443
|
+
const toPos = objState?.position
|
|
1444
|
+
? { x: objState.position.x, y: objState.position.y }
|
|
1445
|
+
: (() => {
|
|
1446
|
+
const halfW = (pixiObject.width || 0) / 2;
|
|
1447
|
+
const halfH = (pixiObject.height || 0) / 2;
|
|
1448
|
+
return { x: pixiObject.x - halfW, y: pixiObject.y - halfH };
|
|
1449
|
+
})();
|
|
1442
1450
|
if (Math.abs(start.angle - toAngle) > 0.1 || Math.abs(start.position.x - toPos.x) > 0.1 || Math.abs(start.position.y - toPos.y) > 0.1) {
|
|
1443
1451
|
changes.push({ id, fromAngle: start.angle, toAngle, fromPos: start.position, toPos });
|
|
1444
1452
|
}
|
|
@@ -691,7 +691,7 @@ export class HtmlHandlesLayer {
|
|
|
691
691
|
el.style.width = `${Math.max(1, Math.round(endCSS.width))}px`;
|
|
692
692
|
el.style.height = 'auto';
|
|
693
693
|
const measured = Math.max(1, Math.round(el.scrollHeight));
|
|
694
|
-
const worldH2 = (measured *
|
|
694
|
+
const worldH2 = (measured * rendererRes) / s;
|
|
695
695
|
const fixData = {
|
|
696
696
|
object: id,
|
|
697
697
|
size: { width: worldW, height: worldH2 },
|
|
@@ -981,7 +981,30 @@ export class HtmlHandlesLayer {
|
|
|
981
981
|
const req = { selection: [] };
|
|
982
982
|
this.eventBus.emit(Events.Tool.GetSelection, req);
|
|
983
983
|
const objects = req.selection || [];
|
|
984
|
-
|
|
984
|
+
// Центр поворота должен передаваться в world-координатах.
|
|
985
|
+
// При отсутствии core/pixi (например, в изолированных тестах) используем CSS-центр как fallback.
|
|
986
|
+
let centerWorldX = centerX;
|
|
987
|
+
let centerWorldY = centerY;
|
|
988
|
+
try {
|
|
989
|
+
const world = this.core?.pixi?.worldLayer || this.core?.pixi?.app?.stage;
|
|
990
|
+
const s = world?.scale?.x || 1;
|
|
991
|
+
const tx = world?.x || 0;
|
|
992
|
+
const ty = world?.y || 0;
|
|
993
|
+
const rendererRes = (this.core?.pixi?.app?.renderer?.resolution) || 1;
|
|
994
|
+
const containerRect = this.container?.getBoundingClientRect ? this.container.getBoundingClientRect() : { left: 0, top: 0 };
|
|
995
|
+
const view = this.core?.pixi?.app?.view || null;
|
|
996
|
+
const viewRect = view && view.getBoundingClientRect ? view.getBoundingClientRect() : { left: 0, top: 0 };
|
|
997
|
+
const offsetLeft = viewRect.left - containerRect.left;
|
|
998
|
+
const offsetTop = viewRect.top - containerRect.top;
|
|
999
|
+
const screenX = centerX - offsetLeft;
|
|
1000
|
+
const screenY = centerY - offsetTop;
|
|
1001
|
+
centerWorldX = ((screenX * rendererRes) - tx) / s;
|
|
1002
|
+
centerWorldY = ((screenY * rendererRes) - ty) / s;
|
|
1003
|
+
} catch (_) {}
|
|
1004
|
+
this.eventBus.emit(Events.Tool.GroupRotateStart, {
|
|
1005
|
+
objects,
|
|
1006
|
+
center: { x: centerWorldX, y: centerWorldY },
|
|
1007
|
+
});
|
|
985
1008
|
}
|
|
986
1009
|
|
|
987
1010
|
const onRotateMove = (ev) => {
|