From 438c7b661561cae255c948b9583bfc48140b5b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A5=D0=B0=D0=BB=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=A0=D1=83?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BC?= Date: Sun, 11 Jan 2026 13:42:33 +0300 Subject: [PATCH] 2 --- src/components/LayoutStep.tsx | 84 ++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/components/LayoutStep.tsx b/src/components/LayoutStep.tsx index 0155872..65f1872 100644 --- a/src/components/LayoutStep.tsx +++ b/src/components/LayoutStep.tsx @@ -67,13 +67,12 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { let maxLimit = 1; parts.forEach(p => { - // Если стенка параллельна нашей, мы ищем, не является ли она барьером + // Если стенка параллельна нашей if (p.axis === axis) { const pMin = p.min ?? 0; const pMax = p.max ?? 1; - // Проверяем, пересекаются ли они "в проекции" - // crossPos - это середина нашей стенки. Попадает ли она в диапазон соседки? + // Проверяем пересечение проекций if (crossPos > pMin && crossPos < pMax) { if (p.offset < currentOffset) minLimit = Math.max(minLimit, p.offset); if (p.offset > currentOffset) maxLimit = Math.min(maxLimit, p.offset); @@ -83,7 +82,7 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { return { min: minLimit, max: maxLimit }; }; - // Поиск границ для НОВОЙ стенки (чтобы обрезать её до T-соединения) + // Поиск границ для НОВОЙ стенки (T-соединения) const getHoveredBoundaries = (lx: number, ly: number, parts: Partition[]) => { let minX = 0, maxX = 1; let minY = 0, maxY = 1; @@ -93,13 +92,13 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { const pMax = p.max ?? 1; if (p.axis === 'x') { - // Вертикальная стенка. Блокирует горизонтальное движение? + // Вертикальная стенка. Ограничивает по X. if (ly >= pMin && ly <= pMax) { if (p.offset < lx) minX = Math.max(minX, p.offset); if (p.offset > lx) maxX = Math.min(maxX, p.offset); } } else { - // Горизонтальная стенка + // Горизонтальная стенка. Ограничивает по Y. if (lx >= pMin && lx <= pMax) { if (p.offset < ly) minY = Math.max(minY, p.offset); if (p.offset > ly) maxY = Math.min(maxY, p.offset); @@ -164,6 +163,7 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { newSplits[dragging.axis][dragging.index] = val; onChange(newSplits); } else { + // Dragging Partition const [iStr, jStr] = dragging.cellKey.split('-'); const i = parseInt(iStr); const j = parseInt(jStr); const cellX1 = sortedX[i]; const cellX2 = sortedX[i+1]; @@ -175,7 +175,11 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { } else { newOffset = (ny - cellY1) / (cellY2 - cellY1); } + + // Ограничиваем перетаскивание. + // В идеале нужно динамически считать соседей, но для скорости пока ограничим ячейкой (2%-98%) newOffset = Math.max(0.02, Math.min(0.98, newOffset)); + if (!isNaN(newOffset)) { updatePartition(dragging.cellKey, dragging.id, { offset: newOffset }); } @@ -240,18 +244,23 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { if (found) { setHoveredPartition({ id: found.id, cellKey: key }); } else { - // Calculate Phantom Partition + // Calculate Phantom Partition with T-junctions const bounds = getHoveredBoundaries(lx, ly, parts); - const distL = lx - bounds.minX; const distR = bounds.maxX - lx; - const distT = ly - bounds.minY; const distB = bounds.maxY - ly; + + const distL = lx - bounds.minX; + const distR = bounds.maxX - lx; + const distT = ly - bounds.minY; + const distB = bounds.maxY - ly; const minX = Math.min(distL, distR); const minY = Math.min(distT, distB); const axis = minX < minY ? 'y' : 'x'; + const width = bounds.maxX - bounds.minX; const height = bounds.maxY - bounds.minY; + // Рисуем фантом только если есть место (>10% ячейки) if ((axis === 'y' && height > 0.1) || (axis === 'x' && width > 0.1)) { const offset = axis === 'x' ? lx : ly; const min = axis === 'x' ? bounds.minY : bounds.minX; @@ -308,7 +317,6 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { const x1 = sortedX[i]; const x2 = sortedX[i + 1]; const y1 = sortedY[j]; const y2 = sortedY[j + 1]; - // !!! FIX: Проверка y2 if (y2 === undefined || x2 === undefined) continue; const cellX = x1 * viewBoxW; const cellY = y1 * viewBoxH; @@ -322,15 +330,16 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { const realW = (x2 - x1) * drawerW; const realD = (y2 - y1) * drawerD; - // Label if empty + // --- LABEL FOR EMPTY CELL --- if (parts.length === 0) { const labelX = cellX + cellW / 2; const labelY = cellY + cellH / 2; const textW = Math.max(0, realW - wallThick).toFixed(0); const textD = Math.max(0, realD - wallThick).toFixed(0); + // Увеличен шрифт до 16px if (cellH > 40 && cellW > 60) { elements.push( - + {textW} × {textD} ); @@ -344,36 +353,34 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { {parts.map(p => { const pMin = p.min ?? 0; const pMax = p.max ?? 1; - let lx1, ly1, lx2, ly2; - let tx, ty; - let dist1 = 0, dist2 = 0; - - // Ищем границы для размеров + let lx1, ly1, lx2, ly2; // Координаты линии + let dist1 = 0, dist2 = 0; // Расстояния + + // Ищем соседей для расчета размеров const neighbors = getNeighborOffsets(p.offset, (pMin + pMax)/2, p.axis, parts); + const isVertical = p.axis === 'x'; - if (p.axis === 'x') { + if (isVertical) { const px = cellX + (cellW * p.offset); lx1 = px; lx2 = px; ly1 = cellY + (cellH * pMin); ly2 = cellY + (cellH * pMax); - - // Дистанция = (Мой Оффсет - Оффсет Соседа) * Ширину Ячейки - Толщина стенки + // Расчет расстояний по горизонтали dist1 = Math.abs((p.offset - neighbors.min) * realW) - wallThick; dist2 = Math.abs((neighbors.max - p.offset) * realW) - wallThick; - - tx = px; ty = (ly1 + ly2) / 2; } else { const py = cellY + (cellH * p.offset); ly1 = py; ly2 = py; lx1 = cellX + (cellW * pMin); lx2 = cellX + (cellW * pMax); - + // Расчет расстояний по вертикали dist1 = Math.abs((p.offset - neighbors.min) * realD) - wallThick; dist2 = Math.abs((neighbors.max - p.offset) * realD) - wallThick; - - tx = (lx1 + lx2) / 2; ty = py; } const isSel = selectedPartitionId === p.id; const isHov = hoveredPartition?.id === p.id; + const midX = (lx1 + lx2) / 2; + const midY = (ly1 + ly2) / 2; + const textOffset = 8; // Отступ текста от линии return ( @@ -382,24 +389,31 @@ export const LayoutStep: React.FC = ({ config, splits, onChange }) => { - {/* DIMENSIONS */} - - {p.axis === 'x' ? ( + {/* DIMENSIONS - Увеличен шрифт до 14px */} + + {isVertical ? ( + // Для вертикальных линий: два отдельных текста слева и справа, выровненных по центру высоты <> - {Math.max(0, dist1).toFixed(0)} - {Math.max(0, dist2).toFixed(0)} + + {Math.max(0, dist1).toFixed(0)} + + + {Math.max(0, dist2).toFixed(0)} + ) : ( - <> - {Math.max(0, dist1).toFixed(0)} - {Math.max(0, dist2).toFixed(0)} - + // Для горизонтальных линий: один текст по центру с tspan сверху и снизу + + {Math.max(0, dist1).toFixed(0)} + {Math.max(0, dist2).toFixed(0)} + )} - + ); })} + {/* Phantom Line */} {isHovered && phantomPartition && !hoveredPartition && !dragging && ( {(() => {