Я проанализировал вашу программу и пример. Я заменю отображение геологической колонки на новый стиль из примера, сохранив весь существующий функционал (модальные окна проб, категории бурения, крап литологии и т.д.). Вот код для замены функций отображения геологической колонки - нужно заменить следующие функции в вашем существующем коде: ## 1. Замените функцию `drawGeologyColumn` на новую: ```javascript function drawGeologyColumn(mergedGeology, data, drawingContainer, topReserve, scale) { if (mergedGeology.length === 0) return; const columnWidth = 100; const headerHeight = 50; const totalDepth = data.totalDepth; const totalHeight = totalDepth * scale; // Создаем контейнер для колонки с новой структурой const columnContainer = document.createElement('div'); columnContainer.style.cssText = ` position: absolute; top: ${topReserve - headerHeight}px; left: 100px; width: ${columnWidth + 250}px; height: ${totalHeight + headerHeight}px; background: white; border: 1px solid #cbd5e1; border-radius: 4px; overflow: hidden; z-index: 15; display: flex; flex-direction: column; `; // Шапка колонки const columnHeader = document.createElement('div'); columnHeader.style.cssText = ` height: ${headerHeight}px; background: #e2e8f0; border-bottom: 1px solid #94a3b8; display: flex; flex-shrink: 0; `; const depthHeader = document.createElement('div'); depthHeader.style.cssText = ` width: 60px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; text-transform: uppercase; color: #0f172a; border-right: 1px solid #cbd5e1; writing-mode: vertical-rl; text-orientation: mixed; transform: rotate(180deg); `; depthHeader.textContent = 'глуб, м'; const coreHeader = document.createElement('div'); coreHeader.style.cssText = ` width: ${columnWidth}px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; text-transform: uppercase; color: #0f172a; border-right: 1px solid #cbd5e1; `; coreHeader.textContent = 'Колонка'; const infoHeader = document.createElement('div'); infoHeader.style.cssText = ` flex: 1; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; text-transform: uppercase; color: #0f172a; `; const drillHeader = document.createElement('div'); drillHeader.style.cssText = ` width: 70px; display: flex; align-items: center; justify-content: center; border-right: 1px solid #cbd5e1; `; drillHeader.textContent = 'Кат. бур.'; const assaysHeader = document.createElement('div'); assaysHeader.style.cssText = ` width: 120px; display: flex; align-items: center; justify-content: center; border-right: 1px solid #cbd5e1; `; assaysHeader.textContent = 'Пробы'; const descHeader = document.createElement('div'); descHeader.style.cssText = ` flex: 1; display: flex; align-items: center; justify-content: center; `; descHeader.textContent = 'Описание пород'; infoHeader.appendChild(drillHeader); infoHeader.appendChild(assaysHeader); infoHeader.appendChild(descHeader); columnHeader.appendChild(depthHeader); columnHeader.appendChild(coreHeader); columnHeader.appendChild(infoHeader); columnContainer.appendChild(columnHeader); // Тело колонки const columnBody = document.createElement('div'); columnBody.style.cssText = ` display: flex; flex: 1; overflow-y: auto; position: relative; min-height: 0; `; // Область глубины const depthArea = document.createElement('div'); depthArea.style.cssText = ` width: 60px; min-width: 60px; background: #f8fafc; border-right: 1px solid #cbd5e1; position: relative; flex-shrink: 0; `; // Область колонки const coreArea = document.createElement('div'); coreArea.style.cssText = ` width: ${columnWidth}px; min-width: ${columnWidth}px; background: #ffffff; border-right: 1px solid #cbd5e1; position: relative; flex-shrink: 0; `; // Информационная область const infoArea = document.createElement('div'); infoArea.style.cssText = ` flex: 1; background: #ffffff; position: relative; min-width: 0; `; columnBody.appendChild(depthArea); columnBody.appendChild(coreArea); columnBody.appendChild(infoArea); columnContainer.appendChild(columnBody); drawingContainer.appendChild(columnContainer); // Отрисовка глубины const depthBody = document.createElement('div'); depthBody.style.cssText = ` position: relative; height: ${totalHeight}px; `; depthArea.appendChild(depthBody); // Отрисовка отметок глубины for (let depth = 0; depth <= totalDepth; depth += 5) { const yPos = depth * scale; if (yPos >= 0 && yPos <= totalHeight) { const markDiv = document.createElement('div'); markDiv.style.cssText = ` position: absolute; top: ${yPos}px; left: 0; width: 100%; height: 0; `; const line = document.createElement('div'); line.style.cssText = ` position: absolute; left: 8px; right: 0; height: 1px; background: #cbd5e1; `; const label = document.createElement('span'); label.style.cssText = ` position: absolute; right: 6px; font-weight: 600; font-size: 0.65rem; color: #1e293b; background: #f8fafc; padding: 0 2px; transform: translateY(-50%); `; label.textContent = depth.toString(); markDiv.appendChild(line); markDiv.appendChild(label); depthBody.appendChild(markDiv); } } // Отрисовка интервалов const coreBody = document.createElement('div'); coreBody.style.cssText = ` position: relative; height: ${totalHeight}px; `; coreArea.appendChild(coreBody); const infoBodyDiv = document.createElement('div'); infoBodyDiv.style.cssText = ` position: relative; height: ${totalHeight}px; `; infoArea.appendChild(infoBodyDiv); // Сохраняем элементы для взаимодействия const geologyBlocks = []; mergedGeology.forEach((geo, index) => { const topY = geo.from * scale; const heightY = (geo.to - geo.from) * scale; if (heightY > 0) { // Блок колонки const block = document.createElement('div'); const bgColor = getStratigraphyBackground({ stratigraphy: geo.stratigraphy, originalStratigraphy: geo.originalStratigraphy }); block.style.cssText = ` position: absolute; top: ${topY}px; left: 0; width: 100%; height: ${heightY}px; background: ${bgColor}; border: 1px solid rgba(0,0,0,0.25); cursor: pointer; transition: all 0.15s ease; display: flex; align-items: center; justify-content: center; `; // Возраст на блоке const ageSpan = document.createElement('span'); ageSpan.style.cssText = ` font-weight: 700; font-size: 0.7rem; color: ${isColorDark(bgColor) ? '#ffffff' : '#0f172a'}; background: rgba(255,255,255,0.8); padding: 2px 6px; border-radius: 2px; text-align: center; `; ageSpan.textContent = geo.originalStratigraphy || geo.stratigraphy || ''; block.appendChild(ageSpan); // Крап литологии if (geo.lcode && window.LITHOLOGY_PATTERNS && window.LITHOLOGY_PATTERNS[geo.lcode]) { const patternOverlay = document.createElement('div'); const patternSize = getPatternSize(scale); const fileName = window.LITHOLOGY_PATTERNS[geo.lcode]; const patternUrl = `litology/${fileName}`; patternOverlay.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: url("${patternUrl}"); background-repeat: repeat; background-size: ${patternSize.width}px ${patternSize.height}px; opacity: 0.7; pointer-events: none; `; block.appendChild(patternOverlay); } block.dataset.layerId = index; block.addEventListener('click', (e) => { e.stopPropagation(); highlightGeologyBlock(index); if (window.geologyCards && window.geologyCards[index]) { window.geologyCards[index].scrollIntoView({ behavior: 'smooth', block: 'center' }); } }); coreBody.appendChild(block); geologyBlocks.push(block); // Информационная строка const infoRow = document.createElement('div'); infoRow.style.cssText = ` position: absolute; top: ${topY}px; left: 0; width: 100%; height: ${heightY}px; display: flex; border-bottom: 1px solid #e2e8f0; transition: background 0.2s; `; // Категория бурения const drillCell = document.createElement('div'); drillCell.style.cssText = ` width: 70px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.78rem; background: #f1f5f9; border-right: 1px solid #e2e8f0; `; drillCell.textContent = geo.rockCategories && geo.rockCategories !== 'Не указано' ? geo.rockCategories.split(';')[0].split('-')[1]?.trim() || '—' : '—'; // Ячейка проб const assaysCell = document.createElement('div'); assaysCell.style.cssText = ` width: 120px; position: relative; background: #ffffff; border-right: 1px solid #e2e8f0; overflow: visible; `; // Контейнер для проб const assaysContainer = document.createElement('div'); assaysContainer.style.cssText = ` position: absolute; left: 5px; right: 5px; top: 0; bottom: 0; overflow: visible; pointer-events: none; `; assaysCell.appendChild(assaysContainer); // Ячейка описания const descCell = document.createElement('div'); descCell.style.cssText = ` flex: 1; display: flex; align-items: center; padding: 0.15rem 0.3rem; font-size: 0.68rem; color: #1e293b; line-height: 1.3; cursor: pointer; `; descCell.textContent = geo.intervals && geo.intervals[0] ? (geo.intervals[0].description || 'Нет описания') : 'Нет описания'; descCell.addEventListener('click', (e) => { e.stopPropagation(); highlightGeologyBlock(index); }); infoRow.appendChild(drillCell); infoRow.appendChild(assaysCell); infoRow.appendChild(descCell); infoBodyDiv.appendChild(infoRow); // Сохраняем ссылку на информационную строку geo.infoRow = infoRow; } }); // Функция подсветки блока function highlightGeologyBlock(index) { geologyBlocks.forEach((block, i) => { if (i === index) { block.style.border = '2px solid #b91c1c'; block.style.boxShadow = '0 0 0 3px rgba(185, 28, 28, 0.25)'; block.style.zIndex = '6'; } else { block.style.border = '1px solid rgba(0,0,0,0.25)'; block.style.boxShadow = 'none'; block.style.zIndex = '1'; } }); if (window.geologyCards && window.geologyCards[index]) { document.querySelectorAll('.geology-card').forEach(card => { card.style.background = 'white'; card.style.borderLeft = '4px solid #e9ecef'; }); window.geologyCards[index].style.background = '#fff7ed'; window.geologyCards[index].style.borderLeft = '4px solid #c2410c'; } } // Отрисовка проб в колонке if (window.assaysVisible !== false && xmlData && xmlData.assays) { drawAssaysInNewColumn(infoBodyDiv, mergedGeology, scale, totalDepth); } // Сохраняем ссылки window.geologyBlocks = geologyBlocks; } function drawAssaysInNewColumn(infoBodyDiv, mergedGeology, scale, totalDepth) { const assays = xmlData?.assays || []; if (assays.length === 0) return; // Фильтруем пробы по типу документации let filteredAssays = assays; if (window.assayFilter && window.assayFilter !== 'all') { filteredAssays = assays.filter(assay => { if (window.assayFilter === 'primary') { return assay.documentationType === 'Первичное документирование'; } else if (window.assayFilter === 'final') { return assay.documentationType === 'Итоговое документирование'; } return true; }); } const pointAssays = []; const intervalAssays = []; filteredAssays.forEach(assay => { const from = assay.from || 0; const to = assay.to || from; const isPoint = Math.abs(to - from) < 0.1; if (isPoint) { pointAssays.push({ depth: from, docType: assay.documentationType === 'Итоговое документирование' ? 'final' : 'primary', number: assay.number, type: assay.type, description: assay.description, value: assay.value, unit: assay.unit, barcode: assay.barcode, author: assay.author, samplingDate: assay.samplingDate }); } else { intervalAssays.push({ top: from, bottom: to, docType: assay.documentationType === 'Итоговое документирование' ? 'final' : 'primary', number: assay.number, type: assay.type, description: assay.description, value: assay.value, unit: assay.unit, barcode: assay.barcode, author: assay.author, samplingDate: assay.samplingDate }); } }); // Находим все информационные строки const infoRows = infoBodyDiv.querySelectorAll('div[style*="position: absolute"]'); infoRows.forEach((row, rowIndex) => { const assaysContainer = row.querySelector('div[style*="left: 5px; right: 5px"]'); if (!assaysContainer) return; const rowTop = parseFloat(row.style.top); const rowHeight = parseFloat(row.style.height); const layerFrom = rowTop / scale; const layerTo = (rowTop + rowHeight) / scale; // Пробы для этого слоя const layerPointAssays = pointAssays.filter(p => p.depth >= layerFrom && p.depth <= layerTo); const layerIntervalAssays = intervalAssays.filter(i => (i.top >= layerFrom && i.top <= layerTo) || (i.bottom >= layerFrom && i.bottom <= layerTo) || (i.top <= layerFrom && i.bottom >= layerTo) ); // Отрисовка точечных проб layerPointAssays.forEach((assay, idx) => { const yPos = (assay.depth - layerFrom) * scale; if (yPos >= 0 && yPos <= rowHeight) { const pointEl = document.createElement('div'); pointEl.className = `assay-point ${assay.docType}`; const offset = assay.docType === 'primary' ? -20 : 20; pointEl.style.cssText = ` position: absolute; left: calc(50% + ${offset}px); top: ${yPos}px; width: 10px; height: 10px; border-radius: 50%; background: ${assay.docType === 'primary' ? '#2c3e50' : '#e74c3c'}; border: 2px solid #000000; cursor: pointer; pointer-events: auto; z-index: 54; transition: all 0.3s ease; transform: translateX(-50%); `; pointEl.addEventListener('mouseenter', function() { this.style.transform = 'translateX(-50%) scale(1.8)'; this.style.boxShadow = '0 0 8px rgba(231, 76, 60, 0.6)'; this.style.zIndex = '55'; }); pointEl.addEventListener('mouseleave', function() { this.style.transform = 'translateX(-50%) scale(1)'; this.style.boxShadow = 'none'; this.style.zIndex = '54'; }); pointEl.addEventListener('click', (e) => { e.stopPropagation(); showAssayModal({ number: assay.number, type: assay.type, from: assay.depth, to: assay.depth, value: assay.value, unit: assay.unit, barcode: assay.barcode, author: assay.author, samplingDate: assay.samplingDate, description: assay.description, documentationType: assay.docType === 'primary' ? 'Первичное документирование' : 'Итоговое документирование' }); }); assaysContainer.appendChild(pointEl); // Метка для точечной пробы const label = document.createElement('div'); label.className = `assay-label ${assay.docType}`; const labelOffset = assay.docType === 'primary' ? -35 : 35; label.style.cssText = ` position: absolute; left: calc(50% + ${labelOffset}px); top: ${Math.max(yPos, 10)}px; font-size: 8px; font-weight: bold; background: rgba(255,255,255,0.95); padding: 1px 4px; border-radius: 2px; white-space: nowrap; border: 0.5px solid #bdc3c7; cursor: pointer; pointer-events: auto; transform: translateY(-50%); color: ${assay.docType === 'primary' ? '#2c3e50' : '#c0392b'}; z-index: 53; `; label.textContent = assay.depth.toFixed(1); label.addEventListener('click', (e) => { e.stopPropagation(); pointEl.click(); }); assaysContainer.appendChild(label); } }); // Отрисовка интервальных проб layerIntervalAssays.forEach((assay) => { const assayTop = Math.max(assay.top, layerFrom); const assayBottom = Math.min(assay.bottom, layerTo); const topY = (assayTop - layerFrom) * scale; const heightY = (assayBottom - assayTop) * scale; if (heightY > 2) { const intervalEl = document.createElement('div'); intervalEl.className = `assay-interval ${assay.docType}`; const offset = assay.docType === 'primary' ? -25 : 25; intervalEl.style.cssText = ` position: absolute; left: calc(50% + ${offset}px); top: ${topY}px; width: 6px; height: ${heightY}px; background: ${assay.docType === 'primary' ? 'repeating-linear-gradient(45deg, #2c3e50, #2c3e50 3px, transparent 3px, transparent 6px)' : 'repeating-linear-gradient(45deg, #e74c3c, #e74c3c 3px, #fadbd8 3px, #fadbd8 6px)'}; border: 1px solid ${assay.docType === 'primary' ? '#000000' : '#c0392b'}; border-radius: 1px; cursor: pointer; pointer-events: auto; transition: all 0.3s ease; z-index: 52; `; intervalEl.addEventListener('mouseenter', function() { this.style.transform = 'scale(1.05)'; this.style.boxShadow = '0 2px 8px rgba(231, 76, 60, 0.4)'; this.style.zIndex = '53'; }); intervalEl.addEventListener('mouseleave', function() { this.style.transform = 'scale(1)'; this.style.boxShadow = 'none'; this.style.zIndex = '52'; }); intervalEl.addEventListener('click', (e) => { e.stopPropagation(); showAssayModal({ number: assay.number, type: assay.type, from: assay.top, to: assay.bottom, value: assay.value, unit: assay.unit, barcode: assay.barcode, author: assay.author, samplingDate: assay.samplingDate, description: assay.description, documentationType: assay.docType === 'primary' ? 'Первичное документирование' : 'Итоговое документирование' }); }); assaysContainer.appendChild(intervalEl); // Метка для интервальной пробы (верхняя граница) if (assay.top >= layerFrom && heightY > 15) { const topLabel = document.createElement('div'); topLabel.className = `assay-label ${assay.docType}`; const labelOffset = assay.docType === 'primary' ? -35 : 35; topLabel.style.cssText = ` position: absolute; left: calc(50% + ${labelOffset}px); top: ${topY}px; font-size: 7px; font-weight: bold; background: rgba(255,255,255,0.95); padding: 1px 3px; border-radius: 2px; white-space: nowrap; border: 0.5px solid #bdc3c7; cursor: pointer; pointer-events: auto; transform: translateY(-50%); color: ${assay.docType === 'primary' ? '#2c3e50' : '#c0392b'}; z-index: 53; `; topLabel.textContent = assay.top.toFixed(1); topLabel.addEventListener('click', (e) => { e.stopPropagation(); intervalEl.click(); }); assaysContainer.appendChild(topLabel); } } }); }); } ``` ## 2. Замените функцию `createWellStructureDrawing` на новую (упрощенную для геологии): ```javascript function createWellStructureDrawing(structureData) { const drawing = document.getElementById('wellStructureDrawing'); if (!drawing) { console.log('❌ Элемент wellStructureDrawing не найден!'); return; } drawing.innerHTML = ''; const container = document.createElement('div'); container.style.cssText = ` display: flex; flex-direction: column; height: 100%; background: white; border-radius: 8px; border: 1px solid #ddd; overflow: hidden; `; // Заголовок const mainHeader = document.createElement('div'); mainHeader.style.cssText = ` padding: 12px 20px; background: linear-gradient(135deg, #34495e 0%, #2c3e50 100%); color: white; border-bottom: 1px solid #2c3e50; flex-shrink: 0; display: flex; justify-content: space-between; align-items: center; `; const title = document.createElement('h3'); const docTypeNames = { 'primary': 'Первичное', 'final': 'Итоговое', 'gis': 'ГИС' }; const activeDocType = structureData.documentationType; title.textContent = `Геологическая колонка • Глубина: ${structureData.totalDepth} м • ${docTypeNames[activeDocType] || activeDocType}`; title.style.cssText = `margin: 0; color: white; font-size: 18px; font-weight: 600;`; const controlsDiv = document.createElement('div'); controlsDiv.style.cssText = `display: flex; gap: 15px; align-items: center;`; // Переключатель проб const assaysToggle = document.createElement('div'); assaysToggle.style.cssText = ` display: flex; align-items: center; gap: 8px; cursor: pointer; `; const switchEl = document.createElement('div'); switchEl.style.cssText = ` width: 40px; height: 20px; background: ${window.assaysVisible !== false ? '#27ae60' : '#95a5a6'}; border-radius: 10px; position: relative; transition: all 0.3s; border: 2px solid ${window.assaysVisible !== false ? '#27ae60' : '#7f8c8d'}; `; const knob = document.createElement('div'); knob.style.cssText = ` width: 16px; height: 16px; background: white; border-radius: 50%; position: absolute; top: 2px; left: ${window.assaysVisible !== false ? '22px' : '2px'}; transition: all 0.3s; box-shadow: 0 1px 3px rgba(0,0,0,0.3); `; switchEl.appendChild(knob); const labelEl = document.createElement('span'); labelEl.textContent = 'Пробы'; labelEl.style.cssText = `font-size: 12px; color: white; font-weight: 500;`; assaysToggle.appendChild(switchEl); assaysToggle.appendChild(labelEl); assaysToggle.onclick = () => { const newState = window.assaysVisible === false; window.assaysVisible = newState; switchEl.style.background = newState ? '#27ae60' : '#95a5a6'; switchEl.style.borderColor = newState ? '#27ae60' : '#7f8c8d'; knob.style.left = newState ? '22px' : '2px'; updateWellStructureByDocType(activeDocType); }; controlsDiv.appendChild(assaysToggle); mainHeader.appendChild(title); mainHeader.appendChild(controlsDiv); container.appendChild(mainHeader); // Контент 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: 500px; min-width: 500px; display: flex; flex-direction: column; border-right: 1px solid #e0e0e0; background: #fafafa; flex-shrink: 0; overflow: hidden; `; const graphicsScrollContainer = document.createElement('div'); graphicsScrollContainer.id = 'graphicsScrollContainer'; graphicsScrollContainer.style.cssText = ` flex: 1; overflow: auto; padding: 20px; position: relative; min-height: 200px; `; visualPanel.appendChild(graphicsScrollContainer); // Правая панель с карточками const infoPanel = document.createElement('div'); infoPanel.style.cssText = ` flex: 1; min-width: 400px; display: flex; flex-direction: column; background: #f8f9fa; overflow: hidden; `; const infoHeader = document.createElement('div'); infoHeader.style.cssText = ` padding: 10px 20px; background: #2c3e50; color: white; font-size: 14px; font-weight: 600; flex-shrink: 0; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #34495e; `; const headerLeft = document.createElement('div'); headerLeft.style.cssText = 'display: flex; align-items: center; gap: 10px;'; const infoTitle = document.createElement('span'); infoTitle.textContent = 'Интервалы документирования'; const countBadge = document.createElement('span'); countBadge.id = 'intervalsCount'; countBadge.style.cssText = ` background: #e74c3c; color: white; padding: 2px 8px; border-radius: 12px; font-size: 12px; font-weight: 600; `; headerLeft.appendChild(infoTitle); headerLeft.appendChild(countBadge); const headerRight = document.createElement('div'); headerRight.style.cssText = 'display: flex; align-items: center; gap: 5px;'; const docTypeSelector = createDocTypeSelector(activeDocType); headerRight.appendChild(docTypeSelector); infoHeader.appendChild(headerLeft); infoHeader.appendChild(headerRight); infoPanel.appendChild(infoHeader); const cardsContainer = document.createElement('div'); cardsContainer.id = 'cardsContainer'; cardsContainer.style.cssText = ` flex: 1; overflow-y: auto; padding: 15px; background: white; `; infoPanel.appendChild(cardsContainer); contentContainer.appendChild(visualPanel); contentContainer.appendChild(infoPanel); container.appendChild(contentContainer); drawing.appendChild(container); // Инициализация window.currentScale = window.currentScale || 40; window.assaysVisible = window.assaysVisible !== undefined ? window.assaysVisible : true; window.assayFilter = window.assayFilter || 'all'; updateWellStructureByDocType(activeDocType); } ``` ## 3. Добавьте функцию `isColorDark` (если её нет): ```javascript function isColorDark(color) { if (color.startsWith('#')) { const hex = color.replace('#', ''); const r = parseInt(hex.substr(0, 2), 16); const g = parseInt(hex.substr(2, 2), 16); const b = parseInt(hex.substr(4, 2), 16); const brightness = (r * 299 + g * 587 + b * 114) / 1000; return brightness < 128; } const lightColors = ['#ffffff', '#FEF0C5', '#F8F5DB', '#FFE7C9', '#E4F8C5', '#DCE5F8', '#EED2F5', '#AEE7D4', '#A8D2CD']; return !lightColors.includes(color.toLowerCase()); } ``` ## 4. Обновите функцию `updateGeologyCards` для сохранения ссылок: ```javascript function updateGeologyCards(docType) { const cardsContainer = document.getElementById('cardsContainer'); const countBadge = document.getElementById('intervalsCount'); if (!cardsContainer) return; const groupedGeology = createMergedGeologyFromDocumentation(docType); const assays = xmlData?.assays || []; const intervalsWithAssays = groupAssaysByInterval(groupedGeology, assays, docType); if (countBadge) { countBadge.textContent = intervalsWithAssays.length; } if (intervalsWithAssays.length === 0) { cardsContainer.innerHTML = createNoDataMessage(); window.geologyCards = []; } else { cardsContainer.innerHTML = ''; const cards = []; intervalsWithAssays.forEach((group, index) => { const card = createGeologyCard(group, index); cardsContainer.appendChild(card); cards.push(card); }); window.geologyCards = cards; } window.currentSelectedCard = null; window.currentSelectedInterval = null; } ``` Эти изменения полностью заменят старую геологическую колонку на новый стиль из примера, сохранив весь функционал: - Отображение стратиграфии с цветами из `specific_stratigraphy.js` - Крап литологии из ваших паттернов - Категории бурения из `xmlData` - Модальные окна проб (`showAssayModal`) - Карточки интервалов справа