@sequent-org/moodboard 1.2.85 → 1.2.87

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sequent-org/moodboard",
3
- "version": "1.2.85",
3
+ "version": "1.2.87",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
@@ -1,21 +1,4 @@
1
1
  import { BaseTool } from '../BaseTool.js';
2
- import iCursorSvg from '../../assets/icons/i-cursor.svg?raw';
3
-
4
- // Масштабируем I-курсор в 2 раза меньше (примерно 16x32 с сохранением пропорций 1:2)
5
- const _scaledICursorSvg = (() => {
6
- try {
7
- if (!/\bwidth="/i.test(iCursorSvg)) {
8
- return iCursorSvg.replace('<svg ', '<svg width="16px" height="32px" ');
9
- }
10
- return iCursorSvg
11
- .replace(/width="[^"]+"/i, 'width="16px"')
12
- .replace(/height="[^"]+"/i, 'height="32px"');
13
- } catch (_) {
14
- return iCursorSvg;
15
- }
16
- })();
17
-
18
- const TEXT_CURSOR = `url("data:image/svg+xml;charset=utf-8,${encodeURIComponent(_scaledICursorSvg)}") 0 0, text`;
19
2
 
20
3
  /**
21
4
  * Инструмент для создания и редактирования текстовых объектов
@@ -23,7 +6,7 @@ const TEXT_CURSOR = `url("data:image/svg+xml;charset=utf-8,${encodeURIComponent(
23
6
  export class TextTool extends BaseTool {
24
7
  constructor(eventBus) {
25
8
  super('text', eventBus);
26
- this.cursor = 'text';
9
+ this.cursor = 'text';
27
10
  this.hotkey = 't';
28
11
  this.container = null;
29
12
 
@@ -49,13 +32,35 @@ export class TextTool extends BaseTool {
49
32
  onMouseDown(event) {
50
33
  super.onMouseDown(event);
51
34
 
35
+ // Учитываем масштаб браузера для корректных координат
36
+ const zoomFactor = this._getBrowserZoomFactor();
37
+ const correctedX = event.x * zoomFactor;
38
+ const correctedY = event.y * zoomFactor;
39
+
40
+ // Диагностика координат для решения проблемы с масштабом браузера
41
+ console.log('🔍 TextTool onMouseDown диагностика:', {
42
+ 'исходные event.x/y': { x: event.x, y: event.y },
43
+ 'zoomFactor': zoomFactor,
44
+ 'исправленные x/y': { x: correctedX, y: correctedY },
45
+ 'window.devicePixelRatio': window.devicePixelRatio,
46
+ 'масштаб браузера': window.outerWidth / window.innerWidth
47
+ });
48
+
49
+ // Преобразуем экранные координаты в мировые координаты PIXI
50
+ const worldPoint = this._toWorld(correctedX, correctedY);
51
+
52
+ console.log('🔍 Преобразование координат:', {
53
+ 'исправленные': { x: correctedX, y: correctedY },
54
+ 'мировые': worldPoint
55
+ });
56
+
52
57
  // Проверяем, кликнули ли на существующий текстовый объект
53
- const hitObject = this.getTextObjectAt(event.x, event.y);
58
+ const hitObject = this.getTextObjectAt(correctedX, correctedY);
54
59
 
55
60
  if (hitObject) {
56
61
  this.startEditing(hitObject, event);
57
62
  } else {
58
- this.createNewText(event.x, event.y);
63
+ this.createNewText(worldPoint.x, worldPoint.y);
59
64
  }
60
65
  }
61
66
 
@@ -132,10 +137,19 @@ export class TextTool extends BaseTool {
132
137
  /**
133
138
  * Создание HTML input для редактирования текста
134
139
  */
135
- createTextInput(x, y, initialText) {
140
+ createTextInput(worldX, worldY, initialText) {
136
141
  // Удаляем предыдущий input если есть
137
142
  this.removeTextInput();
138
143
 
144
+ // Преобразуем мировые координаты в экранные для HTML элемента
145
+ const screenPos = this._toScreen(worldX, worldY);
146
+
147
+ console.log('🔍 Позиционирование input:', {
148
+ 'мировые координаты': { x: worldX, y: worldY },
149
+ 'экранные координаты': screenPos,
150
+ 'container': this.getContainer()
151
+ });
152
+
139
153
  // Создаем новый input
140
154
  this.textInput = document.createElement('textarea');
141
155
  this.textInput.value = initialText;
@@ -144,8 +158,8 @@ export class TextTool extends BaseTool {
144
158
  // Стили input
145
159
  Object.assign(this.textInput.style, {
146
160
  position: 'absolute',
147
- left: `${x}px`,
148
- top: `${y}px`,
161
+ left: `${screenPos.x}px`,
162
+ top: `${screenPos.y}px`,
149
163
  border: '2px solid #007bff',
150
164
  borderRadius: '4px',
151
165
  padding: '4px 8px',
@@ -401,14 +415,15 @@ export class TextTool extends BaseTool {
401
415
  */
402
416
  activate(pixiApp) {
403
417
  super.activate();
418
+ this.pixiApp = pixiApp;
404
419
 
405
420
  // Устанавливаем контейнер для размещения input
406
421
  if (pixiApp && pixiApp.view && pixiApp.view.parentElement) {
407
422
  this.setContainer(pixiApp.view.parentElement);
408
423
  }
409
- // Устанавливаем кастомный курсор на холст
424
+ // Устанавливаем стандартный текстовый курсор
410
425
  if (pixiApp && pixiApp.view) {
411
- pixiApp.view.style.cursor = (this.cursor && this.cursor !== 'default') ? this.cursor : '';
426
+ pixiApp.view.style.cursor = 'text';
412
427
  }
413
428
  }
414
429
 
@@ -421,6 +436,50 @@ export class TextTool extends BaseTool {
421
436
  }
422
437
  }
423
438
 
439
+ /**
440
+ * Преобразование экранных координат в мировые (worldLayer)
441
+ */
442
+ _toWorld(x, y) {
443
+ if (!this.pixiApp || !this.pixiApp.stage) return { x, y };
444
+ const world = this.pixiApp.stage.getChildByName && this.pixiApp.stage.getChildByName('worldLayer');
445
+ if (!world || !world.toLocal) return { x, y };
446
+ const p = new PIXI.Point(x, y);
447
+ const local = world.toLocal(p);
448
+ return { x: local.x, y: local.y };
449
+ }
450
+
451
+ /**
452
+ * Преобразование мировых координат в экранные для HTML элементов
453
+ */
454
+ _toScreen(worldX, worldY) {
455
+ if (!this.pixiApp || !this.pixiApp.stage) return { x: worldX, y: worldY };
456
+ const world = this.pixiApp.stage.getChildByName && this.pixiApp.stage.getChildByName('worldLayer');
457
+ if (!world || !world.toGlobal) return { x: worldX, y: worldY };
458
+ const p = new PIXI.Point(worldX, worldY);
459
+ const global = world.toGlobal(p);
460
+
461
+ // Обратная коррекция для HTML элементов с учетом масштаба браузера
462
+ const zoomFactor = this._getBrowserZoomFactor();
463
+ return {
464
+ x: global.x / zoomFactor,
465
+ y: global.y / zoomFactor
466
+ };
467
+ }
468
+
469
+ /**
470
+ * Получение коэффициента масштабирования браузера
471
+ */
472
+ _getBrowserZoomFactor() {
473
+ // Определяем масштаб браузера разными способами
474
+ const outerInnerRatio = window.outerWidth / window.innerWidth;
475
+ const devicePixelRatio = window.devicePixelRatio || 1;
476
+
477
+ // Используемый подход: соотношение размеров окна браузера
478
+ const zoomFactor = outerInnerRatio;
479
+
480
+ return Math.max(0.1, Math.min(5, zoomFactor)); // Ограничиваем разумными пределами
481
+ }
482
+
424
483
  /**
425
484
  * Установка настроек текста по умолчанию
426
485
  */