@sequent-org/moodboard 1.0.0

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.
Files changed (123) hide show
  1. package/package.json +44 -0
  2. package/src/assets/icons/README.md +105 -0
  3. package/src/assets/icons/attachments.svg +3 -0
  4. package/src/assets/icons/clear.svg +5 -0
  5. package/src/assets/icons/comments.svg +3 -0
  6. package/src/assets/icons/emoji.svg +6 -0
  7. package/src/assets/icons/frame.svg +3 -0
  8. package/src/assets/icons/image.svg +3 -0
  9. package/src/assets/icons/note.svg +3 -0
  10. package/src/assets/icons/pan.svg +3 -0
  11. package/src/assets/icons/pencil.svg +3 -0
  12. package/src/assets/icons/redo.svg +3 -0
  13. package/src/assets/icons/select.svg +9 -0
  14. package/src/assets/icons/shapes.svg +3 -0
  15. package/src/assets/icons/text-add.svg +3 -0
  16. package/src/assets/icons/topbar/README.md +39 -0
  17. package/src/assets/icons/topbar/grid-cross.svg +6 -0
  18. package/src/assets/icons/topbar/grid-dot.svg +3 -0
  19. package/src/assets/icons/topbar/grid-line.svg +3 -0
  20. package/src/assets/icons/topbar/grid-off.svg +3 -0
  21. package/src/assets/icons/topbar/paint.svg +3 -0
  22. package/src/assets/icons/undo.svg +3 -0
  23. package/src/core/ApiClient.js +309 -0
  24. package/src/core/EventBus.js +42 -0
  25. package/src/core/HistoryManager.js +261 -0
  26. package/src/core/KeyboardManager.js +710 -0
  27. package/src/core/PixiEngine.js +439 -0
  28. package/src/core/SaveManager.js +381 -0
  29. package/src/core/StateManager.js +64 -0
  30. package/src/core/commands/BaseCommand.js +68 -0
  31. package/src/core/commands/CopyObjectCommand.js +44 -0
  32. package/src/core/commands/CreateObjectCommand.js +46 -0
  33. package/src/core/commands/DeleteObjectCommand.js +146 -0
  34. package/src/core/commands/EditFileNameCommand.js +107 -0
  35. package/src/core/commands/GroupMoveCommand.js +47 -0
  36. package/src/core/commands/GroupReorderZCommand.js +74 -0
  37. package/src/core/commands/GroupResizeCommand.js +37 -0
  38. package/src/core/commands/GroupRotateCommand.js +41 -0
  39. package/src/core/commands/MoveObjectCommand.js +89 -0
  40. package/src/core/commands/PasteObjectCommand.js +103 -0
  41. package/src/core/commands/ReorderZCommand.js +45 -0
  42. package/src/core/commands/ResizeObjectCommand.js +135 -0
  43. package/src/core/commands/RotateObjectCommand.js +70 -0
  44. package/src/core/commands/index.js +14 -0
  45. package/src/core/events/Events.js +147 -0
  46. package/src/core/index.js +1632 -0
  47. package/src/core/rendering/GeometryUtils.js +89 -0
  48. package/src/core/rendering/HitTestManager.js +186 -0
  49. package/src/core/rendering/LayerManager.js +137 -0
  50. package/src/core/rendering/ObjectRenderer.js +363 -0
  51. package/src/core/rendering/PixiRenderer.js +140 -0
  52. package/src/core/rendering/index.js +9 -0
  53. package/src/grid/BaseGrid.js +164 -0
  54. package/src/grid/CrossGrid.js +75 -0
  55. package/src/grid/DotGrid.js +148 -0
  56. package/src/grid/GridFactory.js +173 -0
  57. package/src/grid/LineGrid.js +115 -0
  58. package/src/index.js +2 -0
  59. package/src/moodboard/ActionHandler.js +114 -0
  60. package/src/moodboard/DataManager.js +114 -0
  61. package/src/moodboard/MoodBoard.js +359 -0
  62. package/src/moodboard/WorkspaceManager.js +103 -0
  63. package/src/objects/BaseObject.js +1 -0
  64. package/src/objects/CommentObject.js +115 -0
  65. package/src/objects/DrawingObject.js +114 -0
  66. package/src/objects/EmojiObject.js +98 -0
  67. package/src/objects/FileObject.js +318 -0
  68. package/src/objects/FrameObject.js +127 -0
  69. package/src/objects/ImageObject.js +72 -0
  70. package/src/objects/NoteObject.js +227 -0
  71. package/src/objects/ObjectFactory.js +61 -0
  72. package/src/objects/ShapeObject.js +134 -0
  73. package/src/objects/StampObject.js +0 -0
  74. package/src/objects/StickerObject.js +0 -0
  75. package/src/objects/TextObject.js +123 -0
  76. package/src/services/BoardService.js +85 -0
  77. package/src/services/FileUploadService.js +398 -0
  78. package/src/services/FrameService.js +138 -0
  79. package/src/services/ImageUploadService.js +246 -0
  80. package/src/services/ZOrderManager.js +50 -0
  81. package/src/services/ZoomPanController.js +78 -0
  82. package/src/src.7z +0 -0
  83. package/src/src.zip +0 -0
  84. package/src/src2.zip +0 -0
  85. package/src/tools/AlignmentGuides.js +326 -0
  86. package/src/tools/BaseTool.js +257 -0
  87. package/src/tools/ResizeHandles.js +381 -0
  88. package/src/tools/ToolManager.js +580 -0
  89. package/src/tools/board-tools/PanTool.js +43 -0
  90. package/src/tools/board-tools/ZoomTool.js +393 -0
  91. package/src/tools/object-tools/DrawingTool.js +404 -0
  92. package/src/tools/object-tools/PlacementTool.js +1005 -0
  93. package/src/tools/object-tools/SelectTool.js +2183 -0
  94. package/src/tools/object-tools/TextTool.js +416 -0
  95. package/src/tools/object-tools/selection/BoxSelectController.js +105 -0
  96. package/src/tools/object-tools/selection/GeometryUtils.js +101 -0
  97. package/src/tools/object-tools/selection/GroupDragController.js +61 -0
  98. package/src/tools/object-tools/selection/GroupResizeController.js +90 -0
  99. package/src/tools/object-tools/selection/GroupRotateController.js +61 -0
  100. package/src/tools/object-tools/selection/HandlesSync.js +96 -0
  101. package/src/tools/object-tools/selection/ResizeController.js +68 -0
  102. package/src/tools/object-tools/selection/RotateController.js +58 -0
  103. package/src/tools/object-tools/selection/SelectionModel.js +42 -0
  104. package/src/tools/object-tools/selection/SimpleDragController.js +45 -0
  105. package/src/ui/CommentPopover.js +187 -0
  106. package/src/ui/ContextMenu.js +340 -0
  107. package/src/ui/FilePropertiesPanel.js +298 -0
  108. package/src/ui/FramePropertiesPanel.js +462 -0
  109. package/src/ui/HtmlHandlesLayer.js +778 -0
  110. package/src/ui/HtmlTextLayer.js +279 -0
  111. package/src/ui/MapPanel.js +290 -0
  112. package/src/ui/NotePropertiesPanel.js +502 -0
  113. package/src/ui/SaveStatus.js +250 -0
  114. package/src/ui/TextPropertiesPanel.js +911 -0
  115. package/src/ui/Toolbar.js +1118 -0
  116. package/src/ui/Topbar.js +220 -0
  117. package/src/ui/ZoomPanel.js +116 -0
  118. package/src/ui/styles/workspace.css +854 -0
  119. package/src/utils/colors.js +0 -0
  120. package/src/utils/geometry.js +0 -0
  121. package/src/utils/iconLoader.js +270 -0
  122. package/src/utils/objectIdGenerator.js +17 -0
  123. package/src/utils/topbarIconLoader.js +114 -0
@@ -0,0 +1,381 @@
1
+ /**
2
+ * Система отображения ручек для изменения размера объектов
3
+ *
4
+ * ⚠️ ВНИМАНИЕ: ДАННЫЙ МОМЕНТ НЕ ИСПОЛЬЗУЕТСЯ ⚠️
5
+ * Сейчас используются HTML-ручки из HtmlHandlesLayer.js
6
+ * Этот файл оставлен для совместимости и возможного использования в будущем
7
+ */
8
+ import * as PIXI from 'pixi.js';
9
+
10
+ export class ResizeHandles {
11
+ constructor(app) {
12
+ this.app = app;
13
+ this.container = new PIXI.Container();
14
+ this.container.name = 'resize-handles';
15
+ this.container.zIndex = 100000; // Поверх всех объектов в worldLayer
16
+ // Размещаем контейнер ручек в worldLayer, чтобы он масштабировался вместе с доской
17
+ const worldLayer = this.app.stage.getChildByName && this.app.stage.getChildByName('worldLayer');
18
+ if (worldLayer) {
19
+ worldLayer.addChild(this.container);
20
+ worldLayer.sortableChildren = true;
21
+ } else {
22
+ this.app.stage.addChild(this.container);
23
+ this.app.stage.sortableChildren = true;
24
+ }
25
+
26
+ this.handles = [];
27
+ this.targetObject = null;
28
+ this.targetBounds = null;
29
+
30
+ // Настройки внешнего вида ручек
31
+ this.handleSize = 12; // Увеличиваем размер для лучшего клика
32
+ this.handleColor = 0x007ACC;
33
+ this.handleHoverColor = 0x0099FF;
34
+ this.borderColor = 0x007ACC;
35
+ this.borderWidth = 1;
36
+
37
+ // Настройки ручки вращения
38
+ this.rotateHandleSize = 20; // Увеличиваем размер фона
39
+ this.rotateHandleColor = 0x28A745; // Зеленый цвет
40
+ this.rotateHandleHoverColor = 0x34CE57;
41
+ this.rotateHandleOffset = 25; // Смещение от угла объекта
42
+ }
43
+
44
+ /**
45
+ * Показать ручки для объекта
46
+ */
47
+ showHandles(pixiObject, objectId) {
48
+ console.log(`👁️ showHandles вызван для ${objectId}`);
49
+ this.hideHandles();
50
+
51
+ this.targetObject = pixiObject;
52
+ this.targetObjectId = objectId;
53
+ this.updateHandles();
54
+ this.container.visible = true;
55
+ console.log(`👁️ Контейнер установлен как visible: ${this.container.visible}`);
56
+ }
57
+
58
+ /**
59
+ * Скрыть ручки
60
+ */
61
+ hideHandles() {
62
+ this.container.visible = false;
63
+ this.targetObject = null;
64
+ this.targetObjectId = null;
65
+ this.clearHandles();
66
+ }
67
+
68
+ /**
69
+ * Обновить позицию ручек
70
+ */
71
+ updateHandles() {
72
+ if (!this.targetObject) return;
73
+
74
+ this.clearHandles();
75
+
76
+ // Получаем локальные границы объекта (без учета трансформации)
77
+ const localBounds = this.targetObject.getLocalBounds();
78
+
79
+ // Синхронизируем поворот контейнера ручек с объектом
80
+ if (this.targetObject.rotation !== undefined && this.targetObject.rotation !== 0) {
81
+ this.container.rotation = this.targetObject.rotation;
82
+
83
+ // Вычисляем позицию левого верхнего угла объекта в мировых координатах
84
+ // Учитываем, что объект имеет pivot в центре
85
+ const objectCenterX = this.targetObject.x;
86
+ const objectCenterY = this.targetObject.y;
87
+ const objectPivotX = this.targetObject.pivot ? this.targetObject.pivot.x : 0;
88
+ const objectPivotY = this.targetObject.pivot ? this.targetObject.pivot.y : 0;
89
+
90
+ // Позиция левого верхнего угла объекта = центр - pivot
91
+ const objectTopLeftX = objectCenterX - objectPivotX;
92
+ const objectTopLeftY = objectCenterY - objectPivotY;
93
+
94
+ // Устанавливаем контейнер ручек так, чтобы он поворачивался вокруг центра объекта
95
+ this.container.x = objectCenterX;
96
+ this.container.y = objectCenterY;
97
+ this.container.pivot.set(objectPivotX, objectPivotY);
98
+
99
+ console.log(`🔄 Поворот ручек: ${(this.targetObject.rotation * 180 / Math.PI).toFixed(1)}°, центр: (${objectCenterX}, ${objectCenterY}), pivot: (${objectPivotX}, ${objectPivotY})`);
100
+
101
+ // Используем локальные границы для создания ручек
102
+ this.workingBounds = {
103
+ x: localBounds.x,
104
+ y: localBounds.y,
105
+ width: localBounds.width,
106
+ height: localBounds.height
107
+ };
108
+ } else {
109
+ // Сбрасываем поворот если объект не повернут
110
+ this.container.rotation = 0;
111
+ const pivotX = this.targetObject.pivot ? this.targetObject.pivot.x : 0;
112
+ const pivotY = this.targetObject.pivot ? this.targetObject.pivot.y : 0;
113
+ // Если это специальная рамка группы — её x/y уже заданы как левый-верх в worldLayer
114
+ if (this.targetObject.name === 'group-bounds') {
115
+ this.container.x = this.targetObject.x;
116
+ this.container.y = this.targetObject.y;
117
+ this.container.pivot.set(0, 0);
118
+ this.workingBounds = {
119
+ x: 0,
120
+ y: 0,
121
+ width: localBounds.width,
122
+ height: localBounds.height
123
+ };
124
+ } else {
125
+ // Обычный объект: левый-верх = центр - pivot (в координатах worldLayer)
126
+ const topLeftX = this.targetObject.x - pivotX;
127
+ const topLeftY = this.targetObject.y - pivotY;
128
+ this.container.x = topLeftX;
129
+ this.container.y = topLeftY;
130
+ this.container.pivot.set(0, 0);
131
+ // Рабочие границы начинаются от (0,0) контейнера, размеры из локальных границ
132
+ this.workingBounds = {
133
+ x: 0,
134
+ y: 0,
135
+ width: localBounds.width,
136
+ height: localBounds.height
137
+ };
138
+ }
139
+ }
140
+
141
+ // Создаем рамку выделения
142
+ this.createSelectionBorder(this.workingBounds);
143
+
144
+ // Создаем ручки по углам и сторонам относительно workingBounds (локальные координаты контейнера)
145
+ const bounds = this.workingBounds;
146
+ const x0 = bounds.x;
147
+ const y0 = bounds.y;
148
+ const x1 = bounds.x + bounds.width;
149
+ const y1 = bounds.y + bounds.height;
150
+ const cx = bounds.x + bounds.width / 2;
151
+ const cy = bounds.y + bounds.height / 2;
152
+ const handlePositions = [
153
+ { type: 'nw', x: x0, y: y0, cursor: 'nw-resize' },
154
+ { type: 'n', x: cx, y: y0, cursor: 'n-resize' },
155
+ { type: 'ne', x: x1, y: y0, cursor: 'ne-resize' },
156
+ { type: 'e', x: x1, y: cy, cursor: 'e-resize' },
157
+ { type: 'se', x: x1, y: y1, cursor: 'se-resize' },
158
+ { type: 's', x: cx, y: y1, cursor: 's-resize' },
159
+ { type: 'sw', x: x0, y: y1, cursor: 'sw-resize' },
160
+ { type: 'w', x: x0, y: cy, cursor: 'w-resize' }
161
+ ];
162
+
163
+ handlePositions.forEach(pos => {
164
+ const handle = this.createHandle(pos.type, pos.x, pos.y, pos.cursor);
165
+ this.handles.push(handle);
166
+ this.container.addChild(handle);
167
+ });
168
+
169
+ // Создаем ручку вращения возле левого НИЖНЕГО угла рамки
170
+ const rotateHandle = this.createRotateHandle(
171
+ bounds.x,
172
+ bounds.y + bounds.height + this.rotateHandleOffset
173
+ );
174
+ this.handles.push(rotateHandle);
175
+ this.container.addChild(rotateHandle);
176
+
177
+ console.log(`🔄 Ручка вращения создана: x=${rotateHandle.x}, y=${rotateHandle.y}, visible=${rotateHandle.visible}, eventMode=${rotateHandle.eventMode}`);
178
+ console.log(`📦 Контейнер ручек: zIndex=${this.container.zIndex}, visible=${this.container.visible}, children=${this.container.children.length}`);
179
+ }
180
+
181
+ /**
182
+ * Создать рамку выделения
183
+ */
184
+ createSelectionBorder(bounds) {
185
+ const border = new PIXI.Graphics();
186
+ border.lineStyle(this.borderWidth, this.borderColor, 0.8);
187
+ border.drawRect(0, 0, bounds.width, bounds.height);
188
+ border.x = bounds.x;
189
+ border.y = bounds.y;
190
+ border.name = 'selection-border';
191
+
192
+ this.container.addChild(border);
193
+ }
194
+
195
+ /**
196
+ * Создать ручку изменения размера
197
+ */
198
+ createHandle(type, x, y, cursor) {
199
+ const handle = new PIXI.Graphics();
200
+
201
+ // Рисуем круглую ручку - синий круг с белой серединой
202
+ this.drawCircularHandle(handle, this.handleColor);
203
+
204
+ // Позиционируем
205
+ handle.x = x;
206
+ handle.y = y;
207
+
208
+ // Настраиваем интерактивность
209
+ handle.eventMode = 'static';
210
+ handle.cursor = cursor;
211
+ handle.name = `resize-handle-${type}`;
212
+ handle.zIndex = 2000; // Еще выше чем контейнер
213
+
214
+ // Сохраняем тип ручки
215
+ handle.handleType = type;
216
+ handle.targetObjectId = this.targetObjectId;
217
+
218
+ // Эффекты при наведении
219
+ handle.on('pointerover', () => {
220
+ handle.clear();
221
+ this.drawCircularHandle(handle, this.handleHoverColor);
222
+ });
223
+
224
+ handle.on('pointerout', () => {
225
+ handle.clear();
226
+ this.drawCircularHandle(handle, this.handleColor);
227
+ });
228
+
229
+ return handle;
230
+ }
231
+
232
+ /**
233
+ * Рисует круглую ручку с синей обводкой и белой серединой
234
+ */
235
+ drawCircularHandle(graphics, outerColor) {
236
+ const radius = this.handleSize / 2;
237
+ const innerRadius = radius - 2; // Внутренний радиус меньше на 2 пикселя
238
+
239
+ // Рисуем внешний синий круг
240
+ graphics.beginFill(outerColor);
241
+ graphics.drawCircle(0, 0, radius);
242
+ graphics.endFill();
243
+
244
+ // Рисуем внутренний белый круг
245
+ graphics.beginFill(0xFFFFFF);
246
+ graphics.drawCircle(0, 0, innerRadius);
247
+ graphics.endFill();
248
+ }
249
+
250
+ /**
251
+ * Создать ручку вращения с иконкой круговой стрелки
252
+ */
253
+ createRotateHandle(x, y) {
254
+ const container = new PIXI.Container();
255
+
256
+ // Создаем круглый фон
257
+ const background = new PIXI.Graphics();
258
+ background.beginFill(this.rotateHandleColor);
259
+ background.lineStyle(1, 0xFFFFFF, 1);
260
+ background.drawCircle(0, 0, this.rotateHandleSize / 2);
261
+ background.endFill();
262
+
263
+ // Создаем текстовую иконку (Unicode символ)
264
+ const icon = new PIXI.Text('↻', {
265
+ fontFamily: 'Arial, sans-serif',
266
+ fontSize: this.rotateHandleSize - 4,
267
+ fill: 0xFFFFFF,
268
+ align: 'center'
269
+ });
270
+
271
+ // Центрируем иконку
272
+ icon.anchor.set(0.5, 0.5);
273
+ icon.x = 0;
274
+ icon.y = 0;
275
+
276
+ // Добавляем элементы в контейнер
277
+ container.addChild(background);
278
+ container.addChild(icon);
279
+
280
+ // Позиционируем
281
+ container.x = x;
282
+ container.y = y;
283
+
284
+ // Настраиваем интерактивность
285
+ container.eventMode = 'static';
286
+ container.cursor = 'grab';
287
+ container.name = 'rotate-handle';
288
+ container.zIndex = 2000;
289
+
290
+ // Сохраняем тип ручки
291
+ container.handleType = 'rotate';
292
+ container.targetObjectId = this.targetObjectId;
293
+
294
+ // Сохраняем ссылки на элементы для изменения цвета
295
+ container._background = background;
296
+ container._icon = icon;
297
+
298
+ // Эффекты при наведении
299
+ container.on('pointerover', () => {
300
+ background.clear();
301
+ background.beginFill(this.rotateHandleHoverColor);
302
+ background.lineStyle(1, 0xFFFFFF, 1);
303
+ background.drawCircle(0, 0, this.rotateHandleSize / 2);
304
+ background.endFill();
305
+ container.cursor = 'grab';
306
+ });
307
+
308
+ container.on('pointerout', () => {
309
+ background.clear();
310
+ background.beginFill(this.rotateHandleColor);
311
+ background.lineStyle(1, 0xFFFFFF, 1);
312
+ background.drawCircle(0, 0, this.rotateHandleSize / 2);
313
+ background.endFill();
314
+ });
315
+
316
+ return container;
317
+ }
318
+
319
+
320
+
321
+ /**
322
+ * Очистить все ручки
323
+ */
324
+ clearHandles() {
325
+ this.container.removeChildren();
326
+ this.handles = [];
327
+ this.targetBounds = null;
328
+ }
329
+
330
+ /**
331
+ * Проверить, является ли объект ручкой изменения размера или вращения
332
+ */
333
+ isResizeHandle(pixiObject) {
334
+ return pixiObject && pixiObject.name &&
335
+ (pixiObject.name.startsWith('resize-handle-') || pixiObject.name === 'rotate-handle');
336
+ }
337
+
338
+ /**
339
+ * Получить информацию о ручке
340
+ */
341
+ getHandleInfo(pixiObject) {
342
+ if (!this.isResizeHandle(pixiObject)) {
343
+ return null;
344
+ }
345
+
346
+ return {
347
+ type: pixiObject.handleType,
348
+ targetObjectId: pixiObject.targetObjectId,
349
+ handle: pixiObject
350
+ };
351
+ }
352
+
353
+ /**
354
+ * Временно скрыть ручки (например, во время перетаскивания)
355
+ */
356
+ temporaryHide() {
357
+ console.log(`🙈 temporaryHide вызван`);
358
+ this.container.visible = false;
359
+ }
360
+
361
+ /**
362
+ * Показать ручки снова
363
+ */
364
+ temporaryShow() {
365
+ console.log(`👁️ temporaryShow вызван, targetObject: ${!!this.targetObject}`);
366
+ if (this.targetObject) {
367
+ this.container.visible = true;
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Уничтожить систему ручек
373
+ */
374
+ destroy() {
375
+ this.hideHandles();
376
+ if (this.container.parent) {
377
+ this.container.parent.removeChild(this.container);
378
+ }
379
+ this.container.destroy();
380
+ }
381
+ }