Font size for sizes
This commit is contained in:
@@ -61,37 +61,40 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
};
|
||||
const selectedData = getSelectedPartition();
|
||||
|
||||
// Найти ближайшие границы для перегородки (или точки)
|
||||
const getNearestNeighbors = (lx: number, ly: number, axis: Axis, parts: Partition[]) => {
|
||||
// --- ИСПРАВЛЕННЫЙ РАСЧЕТ СОСЕДЕЙ ДЛЯ РАЗМЕРОВ ---
|
||||
// targetOffset: позиция стенки (0..1) по её основной оси
|
||||
// crossPos: позиция центра стенки по перпендикулярной оси (чтобы понять, пересекаются ли они)
|
||||
// axis: ось самой стенки ('x' или 'y')
|
||||
const getNearestNeighbors = (targetOffset: number, crossPos: number, axis: Axis, parts: Partition[]) => {
|
||||
let min = 0;
|
||||
let max = 1;
|
||||
|
||||
parts.forEach(p => {
|
||||
// Игнорируем саму себя, если это проверка для существующей стенки (но здесь мы передаем lx/ly точки)
|
||||
|
||||
const pMin = p.min ?? 0;
|
||||
const pMax = p.max ?? 1;
|
||||
|
||||
// Если мы ищем границы по X (для вертикальной стенки или пространства слева/справа)
|
||||
// То нас интересуют другие ВЕРТИКАЛЬНЫЕ стенки (axis === 'x'), которые перекрывают нас по Y
|
||||
if (axis === 'x') {
|
||||
// Мы - вертикальная стенка (X). Ищем другие ВЕРТИКАЛЬНЫЕ стенки слева/справа.
|
||||
if (p.axis === 'x') {
|
||||
// Перекрываются ли диапазоны высоты?
|
||||
// ly для точки - это просто координата. Для стенки это min-max.
|
||||
// Здесь мы ищем границы для точки (lx, ly).
|
||||
// Стенка P идет от pMin до pMax по Y.
|
||||
if (ly > pMin && ly < pMax) {
|
||||
if (p.offset < lx) min = Math.max(min, p.offset);
|
||||
if (p.offset > lx) max = Math.min(max, p.offset);
|
||||
// Они должны перекрываться с нами по высоте (Y)
|
||||
// Наша "высота" - это точка crossPos (середина).
|
||||
// Стенка P занимает по Y от pMin до pMax.
|
||||
if (crossPos > pMin && crossPos < pMax) {
|
||||
// Стенка P находится слева от нас?
|
||||
if (p.offset < targetOffset) min = Math.max(min, p.offset);
|
||||
// Стенка P находится справа от нас?
|
||||
if (p.offset > targetOffset) max = Math.min(max, p.offset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Ищем границы по Y (для горизонтальной стенки)
|
||||
// Нас интересуют ГОРИЗОНТАЛЬНЫЕ стенки
|
||||
// Мы - горизонтальная стенка (Y). Ищем другие ГОРИЗОНТАЛЬНЫЕ стенки сверху/снизу.
|
||||
if (p.axis === 'y') {
|
||||
if (lx > pMin && lx < pMax) {
|
||||
if (p.offset < ly) min = Math.max(min, p.offset);
|
||||
if (p.offset > ly) max = Math.min(max, p.offset);
|
||||
// Они должны перекрываться с нами по ширине (X)
|
||||
// Наша "ширина" - это точка crossPos (середина).
|
||||
// Стенка P занимает по X от pMin до pMax.
|
||||
if (crossPos > pMin && crossPos < pMax) {
|
||||
if (p.offset < targetOffset) min = Math.max(min, p.offset);
|
||||
if (p.offset > targetOffset) max = Math.min(max, p.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +102,7 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
return { min, max };
|
||||
};
|
||||
|
||||
// Расчет границ для НОВОЙ линии (перпендикулярной)
|
||||
// Расчет границ для НОВОЙ линии (T-соединения)
|
||||
const getHoveredBoundaries = (lx: number, ly: number, parts: Partition[]) => {
|
||||
let minX = 0, maxX = 1;
|
||||
let minY = 0, maxY = 1;
|
||||
@@ -181,9 +184,8 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
const cellY1 = sortedY[j]; const cellY2 = sortedY[j+1];
|
||||
|
||||
let newOffset = 0;
|
||||
// Текущие границы перетаскиваемой стенки (чтобы не выехать за пределы соседей)
|
||||
// Для простоты пока используем границы ячейки (0-1), так как сложный пересчет соседей в реалтайме - это дорого
|
||||
// Но визуально мы ограничим 2-98%
|
||||
// Ограничиваем перетаскивание пределами "родительской" зоны
|
||||
// Для T-соединений это сложнее, но пока ограничим ячейкой (0-1)
|
||||
if (dragging.axis === 'x') {
|
||||
newOffset = (nx - cellX1) / (cellX2 - cellX1);
|
||||
} else {
|
||||
@@ -330,24 +332,19 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
const parts = safePartitions[key] || [];
|
||||
const isSelected = parts.some(p => p.id === selectedPartitionId);
|
||||
|
||||
// Реальные размеры ячейки в мм
|
||||
// Реальные размеры
|
||||
const realW = (x2 - x1) * drawerW;
|
||||
const realD = (y2 - y1) * drawerD;
|
||||
|
||||
// --- ЛЕЙБЛ РАЗМЕРА ---
|
||||
// Если перегородок нет, показываем общий размер по центру
|
||||
// Если перегородок нет - размер по центру
|
||||
if (parts.length === 0) {
|
||||
const labelX = cellX + cellW / 2;
|
||||
const labelY = cellY + cellH / 2;
|
||||
// Учитываем толщину внешних стенок (или соседних)
|
||||
// Упрощенно: вычитаем толщину (1 раз, т.к. 0.5 с каждой стороны)
|
||||
const textW = Math.max(0, realW - thickness).toFixed(0);
|
||||
const textD = Math.max(0, realD - thickness).toFixed(0);
|
||||
|
||||
// Рисуем текст только если есть место
|
||||
if (cellH > 40 && cellW > 60) {
|
||||
elements.push(
|
||||
<text key={`label-${key}`} x={labelX} y={labelY} textAnchor="middle" dominantBaseline="middle" className="fill-slate-400 font-mono text-[10px] pointer-events-none select-none opacity-60">
|
||||
<text key={`label-${key}`} x={labelX} y={labelY} textAnchor="middle" dominantBaseline="middle" className="fill-slate-300 font-mono text-[12px] font-bold pointer-events-none select-none opacity-80" style={{ textShadow: '1px 1px 2px rgba(0,0,0,0.8)' }}>
|
||||
{textW} × {textD}
|
||||
</text>
|
||||
);
|
||||
@@ -360,11 +357,13 @@ export const LayoutStep: React.FC<Props> = ({ 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 tx, ty;
|
||||
let dist1 = 0, dist2 = 0;
|
||||
|
||||
// Находим соседей для расчета размеров
|
||||
// Используем правильные координаты для поиска соседей
|
||||
// axis='x' -> offset - это X, center - это Y
|
||||
// axis='y' -> offset - это Y, center - это X
|
||||
const neighbors = getNearestNeighbors(p.offset, (pMin + pMax)/2, p.axis, parts);
|
||||
|
||||
if (p.axis === 'x') {
|
||||
@@ -372,27 +371,23 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
lx1 = px; lx2 = px;
|
||||
ly1 = cellY + (cellH * pMin); ly2 = cellY + (cellH * pMax);
|
||||
|
||||
// Размеры слева и справа
|
||||
const leftRatio = p.offset - neighbors.min;
|
||||
const rightRatio = neighbors.max - p.offset;
|
||||
dist1 = (leftRatio * realW) - thickness; // Left
|
||||
dist2 = (rightRatio * realW) - thickness; // Right
|
||||
// Distances Left/Right
|
||||
// p.offset is 0..1. neighbor.min is 0..1.
|
||||
// Distance = (current - neighbor) * width
|
||||
dist1 = (p.offset - neighbors.min) * realW - thickness;
|
||||
dist2 = (neighbors.max - p.offset) * realW - thickness;
|
||||
|
||||
tx = px;
|
||||
ty = (ly1 + ly2) / 2;
|
||||
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);
|
||||
|
||||
// Размеры сверху и снизу
|
||||
const topRatio = p.offset - neighbors.min;
|
||||
const botRatio = neighbors.max - p.offset;
|
||||
dist1 = (topRatio * realD) - thickness; // Top
|
||||
dist2 = (botRatio * realD) - thickness; // Bottom
|
||||
// Distances Top/Bottom
|
||||
dist1 = (p.offset - neighbors.min) * realD - thickness;
|
||||
dist2 = (neighbors.max - p.offset) * realD - thickness;
|
||||
|
||||
tx = (lx1 + lx2) / 2;
|
||||
ty = py;
|
||||
tx = (lx1 + lx2) / 2; ty = py;
|
||||
}
|
||||
|
||||
const isSel = selectedPartitionId === p.id;
|
||||
@@ -400,23 +395,22 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
|
||||
return (
|
||||
<g key={p.id}>
|
||||
{/* Сама линия */}
|
||||
<g onDoubleClick={(e) => { e.stopPropagation(); removePartition(key, p.id); }}>
|
||||
<line x1={lx1} y1={ly1} x2={lx2} y2={ly2} stroke="transparent" strokeWidth="40" />
|
||||
<line x1={lx1} y1={ly1} x2={lx2} y2={ly2} stroke={isSel ? "#a855f7" : (isHov ? "#d8b4fe" : "#7e22ce")} strokeWidth={isSel ? 6 : 4} strokeLinecap="round" />
|
||||
</g>
|
||||
|
||||
{/* Текст размеров (Слева/Справа или Сверху/Снизу) */}
|
||||
<text x={tx} y={ty} className="pointer-events-none select-none font-mono text-[9px] fill-white font-bold" textAnchor="middle" dominantBaseline="middle">
|
||||
{/* Размеры (только если есть место) */}
|
||||
<text x={tx} y={ty} className="pointer-events-none select-none font-mono text-[11px] font-bold fill-white" textAnchor="middle" dominantBaseline="middle" style={{ textShadow: '0px 0px 4px #000' }}>
|
||||
{p.axis === 'x' ? (
|
||||
<>
|
||||
<tspan dx="-12" fill="#94a3b8">{dist1.toFixed(0)}</tspan>
|
||||
<tspan dx="24" fill="#94a3b8">{dist2.toFixed(0)}</tspan>
|
||||
<tspan dx="-16" fill="#cbd5e1">{Math.max(0, dist1).toFixed(0)}</tspan>
|
||||
<tspan dx="32" fill="#cbd5e1">{Math.max(0, dist2).toFixed(0)}</tspan>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<tspan x={tx} dy="-8" fill="#94a3b8">{dist1.toFixed(0)}</tspan>
|
||||
<tspan x={tx} dy="16" fill="#94a3b8">{dist2.toFixed(0)}</tspan>
|
||||
<tspan x={tx} dy="-10" fill="#cbd5e1">{Math.max(0, dist1).toFixed(0)}</tspan>
|
||||
<tspan x={tx} dy="20" fill="#cbd5e1">{Math.max(0, dist2).toFixed(0)}</tspan>
|
||||
</>
|
||||
)}
|
||||
</text>
|
||||
@@ -480,7 +474,7 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
>
|
||||
<svg ref={svgRef} viewBox={`0 0 ${viewBoxW} ${viewBoxH}`} className="w-full h-full touch-none block"
|
||||
preserveAspectRatio="none"
|
||||
onMouseMove={handleMouseMove} onMouseDown={handleMouseDown} onMouseUp={() => setDragging(null)} onMouseLeave={() => setDragging(null)} onContextMenu={(e) => e.preventDefault()}
|
||||
onMouseMove={handleGlobalMouseMove} onMouseDown={handleMouseDown} onMouseUp={() => setDragging(null)} onMouseLeave={() => setDragging(null)} onContextMenu={(e) => e.preventDefault()}
|
||||
>
|
||||
<defs><pattern id="grid" width="50" height="50" patternUnits="userSpaceOnUse"><path d="M 50 0 L 0 0 0 50" fill="none" stroke="rgba(255,255,255,0.03)" strokeWidth="1"/></pattern></defs>
|
||||
<rect width="100%" height="100%" fill="url(#grid)" />
|
||||
@@ -500,9 +494,8 @@ export const LayoutStep: React.FC<Props> = ({ config, splits, onChange }) => {
|
||||
</g>
|
||||
))}
|
||||
{/* Phantoms */}
|
||||
{mode === 'lines' && !hoveredMainSplit && !dragging && phantomMainAxis && (
|
||||
<line x1={phantomMainAxis === 'x' ? mousePos.x * viewBoxW : 0} y1={phantomMainAxis === 'y' ? mousePos.y * viewBoxH : 0} x2={phantomMainAxis === 'x' ? mousePos.x * viewBoxW : '100%'} y2={phantomMainAxis === 'y' ? mousePos.y * viewBoxH : '100%'} stroke="#3b82f6" strokeWidth="4" strokeDasharray="8,8" className="pointer-events-none opacity-50"/>
|
||||
)}
|
||||
{mode === 'lines' && !hoveredMainSplit && !dragging && phantomMainAxis === 'x' && <line x1={mousePos.x * viewBoxW} y1="0" x2={mousePos.x * viewBoxW} y2="100%" stroke="#3b82f6" strokeWidth="4" strokeDasharray="8,8" className="pointer-events-none opacity-50"/>}
|
||||
{mode === 'lines' && !hoveredMainSplit && !dragging && phantomMainAxis === 'y' && <line x1="0" y1={mousePos.y * viewBoxH} x2="100%" y2={mousePos.y * viewBoxH} stroke="#3b82f6" strokeWidth="4" strokeDasharray="8,8" className="pointer-events-none opacity-50"/>}
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user