@sequent-org/moodboard 1.2.114 → 1.2.115
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
CHANGED
package/src/tools/ToolManager.js
CHANGED
|
@@ -34,6 +34,7 @@ export class ToolManager {
|
|
|
34
34
|
// Последняя позиция курсора относительно контейнера (CSS-пиксели)
|
|
35
35
|
this.lastMousePos = null;
|
|
36
36
|
this.isMouseOverContainer = false;
|
|
37
|
+
this._originalPixiCursorStyles = null;
|
|
37
38
|
|
|
38
39
|
// Устанавливаем курсор по умолчанию на контейнер, если инструмент ещё не активирован
|
|
39
40
|
if (this.container) {
|
|
@@ -77,6 +78,7 @@ export class ToolManager {
|
|
|
77
78
|
if (typeof this.activeTool.activate === 'function') {
|
|
78
79
|
this.activeTool.activate(this.pixiApp);
|
|
79
80
|
}
|
|
81
|
+
this.syncActiveToolCursor();
|
|
80
82
|
|
|
81
83
|
return true;
|
|
82
84
|
}
|
|
@@ -148,7 +150,9 @@ export class ToolManager {
|
|
|
148
150
|
this.isMouseOverContainer = true;
|
|
149
151
|
if (!this.activeTool) {
|
|
150
152
|
this.container.style.cursor = DEFAULT_CURSOR;
|
|
153
|
+
return;
|
|
151
154
|
}
|
|
155
|
+
this.syncActiveToolCursor();
|
|
152
156
|
});
|
|
153
157
|
this.container.addEventListener('mouseleave', () => { this.isMouseOverContainer = false; });
|
|
154
158
|
// Убираем отдельные слушатели aux-pan на контейнере, чтобы не дублировать mousedown/mouseup
|
|
@@ -305,9 +309,55 @@ export class ToolManager {
|
|
|
305
309
|
// Если временно активирован pan, проксируем движение именно ему
|
|
306
310
|
if (this.temporaryTool === 'pan' && this.activeTool?.name === 'pan') {
|
|
307
311
|
this.activeTool.onMouseMove(event);
|
|
312
|
+
this.syncActiveToolCursor();
|
|
308
313
|
return;
|
|
309
314
|
}
|
|
310
315
|
this.activeTool.onMouseMove(event);
|
|
316
|
+
this.syncActiveToolCursor();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
isCursorLockedToActiveTool() {
|
|
320
|
+
return !!this.activeTool && this.activeTool.name !== 'select';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
getPixiCursorStyles() {
|
|
324
|
+
const renderer = this.pixiApp && this.pixiApp.renderer;
|
|
325
|
+
if (!renderer) return null;
|
|
326
|
+
const events = renderer.events || (renderer.plugins && renderer.plugins.interaction);
|
|
327
|
+
return events && events.cursorStyles ? events.cursorStyles : null;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
getActiveToolCursor() {
|
|
331
|
+
const cursor = this.activeTool && this.activeTool.cursor;
|
|
332
|
+
if (typeof cursor === 'string' && cursor.length > 0) return cursor;
|
|
333
|
+
return DEFAULT_CURSOR;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
syncActiveToolCursor() {
|
|
337
|
+
const cursorStyles = this.getPixiCursorStyles();
|
|
338
|
+
const lockCursor = this.isCursorLockedToActiveTool();
|
|
339
|
+
const activeCursor = this.getActiveToolCursor();
|
|
340
|
+
|
|
341
|
+
if (cursorStyles && !this._originalPixiCursorStyles) {
|
|
342
|
+
this._originalPixiCursorStyles = {
|
|
343
|
+
pointer: cursorStyles.pointer,
|
|
344
|
+
default: cursorStyles.default
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (cursorStyles) {
|
|
349
|
+
if (lockCursor) {
|
|
350
|
+
cursorStyles.pointer = activeCursor;
|
|
351
|
+
cursorStyles.default = activeCursor;
|
|
352
|
+
} else if (this._originalPixiCursorStyles) {
|
|
353
|
+
cursorStyles.pointer = this._originalPixiCursorStyles.pointer;
|
|
354
|
+
cursorStyles.default = this._originalPixiCursorStyles.default;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (lockCursor && this.pixiApp && this.pixiApp.view) {
|
|
359
|
+
this.pixiApp.view.style.cursor = activeCursor;
|
|
360
|
+
}
|
|
311
361
|
}
|
|
312
362
|
|
|
313
363
|
handleMouseUp(e) {
|
|
@@ -329,6 +379,7 @@ export class ToolManager {
|
|
|
329
379
|
return;
|
|
330
380
|
}
|
|
331
381
|
this.activeTool.onMouseUp(event);
|
|
382
|
+
this.syncActiveToolCursor();
|
|
332
383
|
}
|
|
333
384
|
|
|
334
385
|
handleDoubleClick(e) {
|
|
@@ -614,5 +665,12 @@ export class ToolManager {
|
|
|
614
665
|
try { window.removeEventListener('wheel', this._onWindowWheel); } catch (_) {}
|
|
615
666
|
this._onWindowWheel = null;
|
|
616
667
|
}
|
|
668
|
+
|
|
669
|
+
const cursorStyles = this.getPixiCursorStyles();
|
|
670
|
+
if (cursorStyles && this._originalPixiCursorStyles) {
|
|
671
|
+
cursorStyles.pointer = this._originalPixiCursorStyles.pointer;
|
|
672
|
+
cursorStyles.default = this._originalPixiCursorStyles.default;
|
|
673
|
+
}
|
|
674
|
+
this._originalPixiCursorStyles = null;
|
|
617
675
|
}
|
|
618
676
|
}
|
|
@@ -8,8 +8,9 @@ import * as PIXI from 'pixi.js';
|
|
|
8
8
|
export class DrawingTool extends BaseTool {
|
|
9
9
|
constructor(eventBus) {
|
|
10
10
|
super('draw', eventBus);
|
|
11
|
-
this.cursor = 'crosshair';
|
|
12
11
|
this.hotkey = 'd';
|
|
12
|
+
const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><path d='M4 20 L20 4 L28 12 L12 28 L4 28 Z' fill='black'/></svg>`;
|
|
13
|
+
this.cursor = `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}") 4 28, crosshair`;
|
|
13
14
|
|
|
14
15
|
// Состояние рисования
|
|
15
16
|
this.isDrawing = false;
|
|
@@ -50,12 +51,7 @@ export class DrawingTool extends BaseTool {
|
|
|
50
51
|
super.activate();
|
|
51
52
|
this.app = app;
|
|
52
53
|
this.world = this._getWorldLayer();
|
|
53
|
-
|
|
54
|
-
const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><path d='M4 20 L20 4 L28 12 L12 28 L4 28 Z' fill='black'/></svg>`;
|
|
55
|
-
// Горячая точка ставим в реальный нижний левый угол фигуры (x=4, y=28),
|
|
56
|
-
// чтобы линия выходила прямо из карандаша без зазора.
|
|
57
|
-
const url = `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}") 4 28, crosshair`;
|
|
58
|
-
if (this.app && this.app.view) this.app.view.style.cursor = url;
|
|
54
|
+
this.setCursor();
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
deactivate() {
|
|
@@ -70,6 +66,12 @@ export class DrawingTool extends BaseTool {
|
|
|
70
66
|
this.world = null;
|
|
71
67
|
}
|
|
72
68
|
|
|
69
|
+
setCursor() {
|
|
70
|
+
if (this.app && this.app.view) {
|
|
71
|
+
this.app.view.style.cursor = this.cursor;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
73
75
|
onMouseDown(event) {
|
|
74
76
|
super.onMouseDown(event);
|
|
75
77
|
if (!this.world) this.world = this._getWorldLayer();
|
|
@@ -47,6 +47,7 @@ export class PlacementTool extends BaseTool {
|
|
|
47
47
|
// Обновляем курсор в зависимости от pending
|
|
48
48
|
if (this.app && this.app.view) {
|
|
49
49
|
const cur = this._getPendingCursor();
|
|
50
|
+
this.cursor = cur;
|
|
50
51
|
this.app.view.style.cursor = (cur === 'default') ? '' : cur;
|
|
51
52
|
}
|
|
52
53
|
// При выборе текста заставляем pointer вести себя как текстовый курсор
|
|
@@ -147,7 +148,8 @@ export class PlacementTool extends BaseTool {
|
|
|
147
148
|
this.world = this._getWorldLayer();
|
|
148
149
|
// Курсор в зависимости от типа размещаемого объекта
|
|
149
150
|
if (this.app && this.app.view) {
|
|
150
|
-
this.
|
|
151
|
+
this.cursor = this._getPendingCursor();
|
|
152
|
+
this.app.view.style.cursor = this.cursor;
|
|
151
153
|
// Добавляем обработчик движения мыши для "призрака"
|
|
152
154
|
this.app.view.addEventListener('mousemove', this._onMouseMove.bind(this));
|
|
153
155
|
}
|
|
@@ -492,7 +494,8 @@ export class PlacementTool extends BaseTool {
|
|
|
492
494
|
|
|
493
495
|
startFrameDrawMode() {
|
|
494
496
|
// Курсор при рисовании фрейма
|
|
495
|
-
|
|
497
|
+
this.cursor = 'crosshair';
|
|
498
|
+
if (this.app && this.app.view) this.app.view.style.cursor = this.cursor;
|
|
496
499
|
}
|
|
497
500
|
|
|
498
501
|
_onFrameDrawMove(event) {
|
|
@@ -941,13 +944,15 @@ export class PlacementTool extends BaseTool {
|
|
|
941
944
|
const cursorSize = 24;
|
|
942
945
|
const url = encodeURI(src);
|
|
943
946
|
// Используем CSS cursor с изображением, если поддерживается
|
|
944
|
-
this.
|
|
947
|
+
this.cursor = `url(${url}) ${Math.floor(cursorSize/2)} ${Math.floor(cursorSize/2)}, default`;
|
|
948
|
+
this.app.view.style.cursor = this.cursor;
|
|
945
949
|
}
|
|
946
950
|
} catch (_) {}
|
|
947
951
|
} else {
|
|
948
952
|
// Для эмоджи используем стандартный курсор
|
|
949
953
|
if (this.app && this.app.view) {
|
|
950
|
-
this.
|
|
954
|
+
this.cursor = 'crosshair';
|
|
955
|
+
this.app.view.style.cursor = this.cursor;
|
|
951
956
|
}
|
|
952
957
|
}
|
|
953
958
|
}
|