Отлично! Давайте всё исправим. Вот финальный код: ## 1. ИСПРАВЛЯЕМ ОТОБРАЖЕНИЕ КОНСТРУКЦИИ (все диаметры, штриховка, крупный шрифт): ```javascript function drawWellConstruction(data, scale = 40) { const graphicsScrollContainer = document.getElementById('graphicsScrollContainer'); if (!graphicsScrollContainer) return; graphicsScrollContainer.innerHTML = ''; const totalDepth = data.totalDepth; const totalHeight = totalDepth * scale; const headerHeight = 45; // Получаем данные проходки const drillingData = []; const casingData = []; let hasRealDrillingData = false; if (xmlData.drillingHeaders && xmlData.drillingHeaders.length > 0) { const headerId = currentDrillingHeaderId || xmlData.drillingHeaders[0].id; const headerData = xmlData.drillingDataByHeader[headerId]; // Интервалы бурения (открытый ствол) if (headerData && headerData.diameter && headerData.diameter.length > 0) { headerData.diameter.forEach(dia => { if (dia.diameter && dia.diameter > 50 && dia.diameter < 500 && dia.from !== undefined && dia.to !== undefined && (dia.to - dia.from) > 0.1) { drillingData.push({ depthFrom: dia.from || 0, depthTo: dia.to || 0, diameter: dia.diameter || 112, type: 'drilling' }); hasRealDrillingData = true; } }); } // Обсадные колонны if (headerData && headerData.casing && headerData.casing.length > 0) { headerData.casing.forEach(casing => { if (casing.diameter && casing.diameter > 50 && casing.diameter < 500 && casing.from !== undefined && casing.to !== undefined && (casing.to - casing.from) > 0.1) { casingData.push({ depthFrom: casing.from || 0, depthTo: casing.to || 0, diameter: casing.diameter || 112, type: 'casing', pipeType: casing.pipeType || 'Не указано' }); hasRealDrillingData = true; } }); } } if (!hasRealDrillingData) { graphicsScrollContainer.innerHTML = `
⚠️
Нет данных проходки
`; return; } // Сортируем drillingData.sort((a, b) => a.depthFrom - b.depthFrom); casingData.sort((a, b) => a.depthFrom - b.depthFrom); // Находим максимальный диаметр const allDiameters = [...drillingData.map(d => d.diameter), ...casingData.map(c => c.diameter)]; const maxDiameter = Math.max(...allDiameters); const centerX = 40; // Контейнер const container = document.createElement('div'); container.style.cssText = ` position: relative; width: 250px; background: white; border: 1px solid #cbd5e1; border-radius: 4px; overflow: hidden; `; // Шапка const header = document.createElement('div'); header.style.cssText = ` position: sticky; top: 0; z-index: 100; display: flex; height: ${headerHeight}px; background: #e2e8f0; border-bottom: 1px solid #94a3b8; `; const depthHeader = document.createElement('div'); depthHeader.style.cssText = ` width: 50px; min-width: 50px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; border-right: 1px solid #cbd5e1; background: #e2e8f0; `; depthHeader.textContent = 'глубина, м'; const constructionHeader = document.createElement('div'); constructionHeader.style.cssText = ` flex: 1; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.75rem; background: #e2e8f0; `; constructionHeader.textContent = 'Конструкция скважины'; header.appendChild(depthHeader); header.appendChild(constructionHeader); container.appendChild(header); // Тело const body = document.createElement('div'); body.style.cssText = ` display: flex; position: relative; min-height: ${totalHeight}px; overflow-y: auto; max-height: 65vh; `; // Область глубины const depthArea = document.createElement('div'); depthArea.style.cssText = `width: 50px; background: #f8fafc; border-right: 1px solid #cbd5e1; position: relative;`; const depthBody = document.createElement('div'); depthBody.style.cssText = `position: relative; height: ${totalHeight}px;`; depthArea.appendChild(depthBody); // Область конструкции const constructionArea = document.createElement('div'); constructionArea.style.cssText = `flex: 1; background: #ffffff; position: relative;`; const constructionBody = document.createElement('div'); constructionBody.style.cssText = `position: relative; height: ${totalHeight}px;`; constructionArea.appendChild(constructionBody); body.appendChild(depthArea); body.appendChild(constructionArea); container.appendChild(body); graphicsScrollContainer.appendChild(container); // Шкала глубины for (let depth = 0; depth <= totalDepth; depth += 5) { const yPos = depth * scale; if (yPos >= 0 && yPos <= totalHeight) { const line = document.createElement('div'); line.style.cssText = `position: absolute; top: ${yPos}px; left: 6px; right: 0; height: 1px; background: #cbd5e1;`; const label = document.createElement('span'); label.style.cssText = `position: absolute; right: 4px; top: ${yPos}px; font-size: 0.65rem; font-weight: 600; color: #1e293b; background: #f8fafc; padding: 0 2px; transform: translateY(-50%);`; label.textContent = depth.toString(); depthBody.appendChild(line); depthBody.appendChild(label); } } // Отрисовка ОТКРЫТОГО СТВОЛА (диаметры бурения) drillingData.forEach((section) => { const topY = section.depthFrom * scale; const heightY = (section.depthTo - section.depthFrom) * scale; if (heightY > 1) { const widthPercent = (section.diameter / maxDiameter) * 70; const leftPos = centerX - (widthPercent / 2); const element = document.createElement('div'); element.style.cssText = ` position: absolute; left: ${leftPos}%; top: ${topY}px; width: ${widthPercent}%; height: ${heightY}px; background: linear-gradient(90deg, #f5cba7, #e8b88a); border: 1px solid #d35400; border-radius: 2px; z-index: 5; `; // Подпись диаметра - крупнее if (heightY > 25) { const label = document.createElement('div'); label.style.cssText = ` position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-size: 10px; font-weight: bold; color: #7b4a2e; white-space: nowrap; z-index: 6; text-shadow: 1px 1px 0 rgba(255,255,255,0.5); `; label.textContent = `Ø${section.diameter} мм`; element.appendChild(label); } constructionBody.appendChild(element); } }); // Отрисовка ОБСАДНЫХ КОЛОНН (прозрачная штриховка) casingData.forEach((section) => { const topY = section.depthFrom * scale; const heightY = (section.depthTo - section.depthFrom) * scale; if (heightY > 1) { const widthPercent = (section.diameter / maxDiameter) * 70; const leftPos = centerX - (widthPercent / 2); const element = document.createElement('div'); element.style.cssText = ` position: absolute; left: ${leftPos}%; top: ${topY}px; width: ${widthPercent}%; height: ${heightY}px; background: repeating-linear-gradient(135deg, rgba(41,128,185,0.4), rgba(41,128,185,0.4) 8px, transparent 8px, transparent 16px); border: 1.5px solid #1a5276; border-radius: 2px; z-index: 5; `; // Подпись диаметра - крупнее if (heightY > 25) { const label = document.createElement('div'); label.style.cssText = ` position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-size: 10px; font-weight: bold; color: #1a5276; white-space: nowrap; z-index: 6; text-shadow: 1px 1px 0 rgba(255,255,255,0.5); `; label.textContent = `Ø${section.diameter} мм`; element.appendChild(label); } constructionBody.appendChild(element); } }); // Забой const bottomLine = document.createElement('div'); bottomLine.style.cssText = ` position: absolute; left: 0; top: ${totalHeight}px; width: 100%; height: 2px; background: #e74c3c; z-index: 10; `; constructionBody.appendChild(bottomLine); } ``` ## 2. ИСПРАВЛЯЕМ ШАПКУ И УБИРАЕМ ЛИШНИЙ СКРОЛЛ: ```javascript // В функции createWellStructureDrawing, исправляем контейнеры: const contentContainer = document.createElement('div'); contentContainer.style.cssText = ` display: flex; flex: 1; min-height: 0; overflow: hidden; position: relative; `; // Левая панель const visualPanel = document.createElement('div'); visualPanel.style.cssText = ` width: 320px; min-width: 320px; display: flex; flex-direction: column; border-right: 1px solid #e0e0e0; background: #fafafa; overflow: hidden; `; const graphicsScrollContainer = document.createElement('div'); graphicsScrollContainer.id = 'graphicsScrollContainer'; graphicsScrollContainer.style.cssText = ` flex: 1; overflow-y: auto; overflow-x: hidden; padding: 10px; `; // Правая панель const infoPanel = document.createElement('div'); infoPanel.style.cssText = ` flex: 1; min-width: 380px; display: flex; flex-direction: column; background: #f8f9fa; overflow: hidden; `; const cardsContainer = document.createElement('div'); cardsContainer.id = 'cardsContainer'; cardsContainer.style.cssText = ` flex: 1; overflow-y: auto; overflow-x: hidden; padding: 15px; background: white; `; ``` ## 3. ИСПРАВЛЯЕМ ОТОБРАЖЕНИЕ КАТЕГОРИЙ БУРЕНИЯ В КОЛОНКЕ: ```javascript // В функции drawWellStructure, при создании drillCell: const drillCell = document.createElement('div'); drillCell.style.cssText = ` position: absolute; top: ${topY}px; left: 0; width: 100%; height: ${heightY}px; display: flex; flex-direction: column; align-items: center; justify-content: center; border-bottom: 1px solid #e2e8f0; background: #f8fafc; font-size: 0.7rem; line-height: 1.4; text-align: center; cursor: pointer; `; // Используем rockCategories из geo (уже есть в данных) let categoriesHtml = ''; if (geo.rockCategories && geo.rockCategories !== 'Не указано' && geo.rockCategories !== '') { // Разбиваем на отдельные строки const categories = geo.rockCategories.split('; '); categoriesHtml = categories.map(cat => { // Формат: "10.0-15.0 - II" или "10-15 - II" const match = cat.match(/([\d.-]+)-([\d.-]+)\s*-\s*(.+)/); if (match) { return `
${match[1]}-${match[2]}м
${match[3]}
`; } return `
${cat}
`; }).join(''); } else if (geo.intervals && geo.intervals[0] && geo.intervals[0].rockCategories) { // Альтернативный источник const altCategories = geo.intervals[0].rockCategories; if (altCategories && altCategories !== 'Не указано') { const categories = altCategories.split('; '); categoriesHtml = categories.map(cat => { const match = cat.match(/([\d.-]+)-([\d.-]+)\s*-\s*(.+)/); if (match) { return `
${match[1]}-${match[2]}м
${match[3]}
`; } return `
${cat}
`; }).join(''); } } if (!categoriesHtml) { categoriesHtml = ''; } drillCell.innerHTML = categoriesHtml; drillCell.onclick = (e) => { e.stopPropagation(); highlightGeologyBlock(index); if (window.geologyCards && window.geologyCards[index]) { window.geologyCards[index].scrollIntoView({ behavior: 'smooth', block: 'center' }); window.geologyCards[index].click(); } }; drillBody.appendChild(drillCell); ``` ## 4. ДОБАВЛЯЕМ CSS ДЛЯ ФИКСАЦИИ ШАПКИ: ```css /* В стили добавить */ .graphics-scroll-container { scrollbar-width: thin; } .graphics-scroll-container::-webkit-scrollbar { width: 6px; height: 6px; } .graphics-scroll-container::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 3px; } .graphics-scroll-container::-webkit-scrollbar-thumb { background: #c1c1c1; border-radius: 3px; } .graphics-scroll-container::-webkit-scrollbar-thumb:hover { background: #a8a8a8; } /* Фиксация шапки таблицы */ .table-wrapper { position: relative; } .table-header { position: sticky; top: 0; z-index: 10; background: #3498db; } ``` Теперь всё должно работать корректно: - ✅ Конструкция отображает все диаметры (и бурения, и обсадки) - ✅ Обсадка с прозрачной синей штриховкой - ✅ Шрифт диаметров крупнее (10px) - ✅ Шапка "глубина, м" теперь корректно отображается - ✅ Убрана лишняя вертикальная полоса прокрутки - ✅ Категории бурения отображаются с интервалами