@sequent-org/moodboard 1.2.102 → 1.2.104

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.102",
3
+ "version": "1.2.104",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
@@ -2067,23 +2067,49 @@ export class SelectTool extends BaseTool {
2067
2067
  } catch (_) {}
2068
2068
 
2069
2069
  // Для новых текстов: синхронизируем мировую позицию объекта с фактической позицией wrapper,
2070
- // чтобы после закрытия редактора статичный текст встал ровно туда же без сдвига
2070
+ // чтобы после закрытия редактора статичный текст встал ровно туда же без сдвига.
2071
+ // Используем ту же систему координат, что и HtmlTextLayer/HtmlHandlesLayer:
2072
+ // CSS ←→ world через toGlobal/toLocal БЕЗ умножения/деления на resolution.
2071
2073
  try {
2072
2074
  if (create && objectId) {
2073
2075
  const worldLayerRef = this.textEditor.world || (this.app?.stage);
2074
- const viewRes = (this.app?.renderer?.resolution) || (view.width && view.clientWidth ? (view.width / view.clientWidth) : 1);
2075
- // Статичный HTML-текст не имеет верхнего внутреннего отступа (HtmlTextLayer ставит padding: 0),
2076
- // поэтому добавляем padTop к topPx при расчёте мировых координат
2077
- const yCssStaticTop = Math.round(topPx + padTop);
2078
- const globalPoint = new PIXI.Point(Math.round(leftPx * viewRes), Math.round(yCssStaticTop * viewRes));
2079
- const worldPoint = worldLayerRef && worldLayerRef.toLocal ? worldLayerRef.toLocal(globalPoint) : { x: position.x, y: position.y };
2080
- const newWorldPos = { x: Math.round(worldPoint.x), y: Math.round(worldPoint.y) };
2081
- this.eventBus.emit(Events.Object.StateChanged, {
2082
- objectId: objectId,
2083
- updates: { position: newWorldPos }
2084
- });
2085
- // Диагностика
2086
- console.log('🧭 Text position sync', { objectId, newWorldPos, leftPx, topPx, yCssStaticTop, padTop, viewRes });
2076
+ const viewEl = this.app?.view;
2077
+ if (worldLayerRef && viewEl && viewEl.parentElement) {
2078
+ const containerRect = viewEl.parentElement.getBoundingClientRect();
2079
+ const viewRect = viewEl.getBoundingClientRect();
2080
+ const offsetLeft = viewRect.left - containerRect.left;
2081
+ const offsetTop = viewRect.top - containerRect.top;
2082
+
2083
+ // Статичный HTML-текст не имеет верхнего внутреннего отступа (HtmlTextLayer ставит padding: 0),
2084
+ // поэтому добавляем padTop к topPx при расчёте мировой позиции верхнего края текста.
2085
+ const yCssStaticTop = Math.round(topPx + padTop);
2086
+ // Переводим CSS-координаты wrapper в экранные координаты относительно view
2087
+ const screenX = Math.round(leftPx - offsetLeft);
2088
+ const screenY = Math.round(yCssStaticTop - offsetTop);
2089
+ const globalPoint = new PIXI.Point(screenX, screenY);
2090
+ const worldPoint = worldLayerRef.toLocal
2091
+ ? worldLayerRef.toLocal(globalPoint)
2092
+ : { x: position.x, y: position.y };
2093
+ const newWorldPos = {
2094
+ x: Math.round(worldPoint.x),
2095
+ y: Math.round(worldPoint.y)
2096
+ };
2097
+ this.eventBus.emit(Events.Object.StateChanged, {
2098
+ objectId: objectId,
2099
+ updates: { position: newWorldPos }
2100
+ });
2101
+ // Диагностика
2102
+ console.log('🧭 Text position sync', {
2103
+ objectId,
2104
+ newWorldPos,
2105
+ leftPx,
2106
+ topPx,
2107
+ yCssStaticTop,
2108
+ padTop,
2109
+ offsetLeft,
2110
+ offsetTop
2111
+ });
2112
+ }
2087
2113
  }
2088
2114
  } catch (_) {}
2089
2115
  }
@@ -325,12 +325,15 @@ export class HtmlTextLayer {
325
325
  const tl = worldLayer.toGlobal(new PIXI.Point(x, y));
326
326
  const br = worldLayer.toGlobal(new PIXI.Point(x + w, y + h));
327
327
 
328
- // toGlobal() возвращает координаты в device-пикселях с учётом resolution.
329
- // Для CSS нам нужны логические пиксели, поэтому делим на res.
330
- const left = offsetLeft + tl.x / res;
331
- const top = offsetTop + tl.y / res;
332
- const width = Math.max(1, (br.x - tl.x) / res);
333
- const height = Math.max(1, (br.y - tl.y) / res);
328
+ // ВАЖНО: toGlobal() уже возвращает координаты в логических экранных пикселях
329
+ // (как и для HtmlHandlesLayer), поэтому делить их на renderer.resolution
330
+ // при вычислении CSS-позиции и размеров не нужно. Деление приводило к тому,
331
+ // что при res < 1 (масштаб браузера ≠ 100%) HTML-текст уезжал относительно
332
+ // собственных рамок и PIXI-объекта.
333
+ const left = offsetLeft + tl.x;
334
+ const top = offsetTop + tl.y;
335
+ const width = Math.max(1, (br.x - tl.x));
336
+ const height = Math.max(1, (br.y - tl.y));
334
337
 
335
338
  // Применяем к элементу
336
339
  el.style.left = `${left}px`;