Понял проблему! Из консоли видно, что изначально было **11 интервалов категорий**, но при обработке некоторые объединились.
Смотри, в исходных данных есть интервал `1.6-17 - VIII; 17-85 - IX` - это **ДВА разных интервала** (1.6-17м категория VIII и 17-85м категория IX), но при парсинге они объединились в один `1.6-85м - VIII`.
Нужно правильно разбирать строку с несколькими категориями, разделенными точкой с запятой.
Вот исправленный блок сбора категорий:
```javascript
// СОБИРАЕМ КАТЕГОРИИ ПОРОД - ПРАВИЛЬНО РАЗБИРАЕМ СОСТАВНЫЕ ИНТЕРВАЛЫ
const rockCategoriesList = [];
originalIntervals.forEach(interval => {
if (interval.rockCategories && interval.rockCategories !== 'Не указано' && interval.rockCategories !== '') {
// Разбиваем строку по точке с запятой (может быть несколько интервалов в одной строке)
const parts = interval.rockCategories.split(';');
for (const part of parts) {
const trimmedPart = part.trim();
// Ищем римскую цифру в конце
const romanMatch = trimmedPart.match(/([IVX]+)$/i);
if (romanMatch) {
// Ищем границы интервала (формат "X.X-Y.Y")
const rangeMatch = trimmedPart.match(/(\d+(?:\.\d+)?)-(\d+(?:\.\d+)?)/);
if (rangeMatch) {
const from = parseFloat(rangeMatch[1]);
const to = parseFloat(rangeMatch[2]);
if (!isNaN(from) && !isNaN(to) && from >= 0 && to > from) {
rockCategoriesList.push({
from: from,
to: to,
category: romanMatch[1].toUpperCase()
});
console.log(`📊 Категория из составного интервала: ${from}-${to}м → ${romanMatch[1].toUpperCase()}`);
}
} else {
// Если нет явных границ, используем границы интервала документирования
rockCategoriesList.push({
from: interval.from,
to: interval.to,
category: romanMatch[1].toUpperCase()
});
console.log(`📊 Категория из интервала: ${interval.from}-${interval.to}м → ${romanMatch[1].toUpperCase()}`);
}
}
}
}
});
```
А вот **полная исправленная функция** `drawWellStructure` с правильным разбором категорий:
```javascript
function drawWellStructure(data, scale = 40) {
const graphicsScrollContainer = document.getElementById('graphicsScrollContainer');
if (!graphicsScrollContainer) {
console.error('graphicsScrollContainer не найден');
return;
}
graphicsScrollContainer.innerHTML = '';
graphicsScrollContainer.style.cssText = '';
graphicsScrollContainer.style.overflow = 'auto';
graphicsScrollContainer.style.overflowX = 'auto';
graphicsScrollContainer.style.overflowY = 'scroll';
graphicsScrollContainer.style.height = '100%';
graphicsScrollContainer.style.maxHeight = '100%';
graphicsScrollContainer.style.position = 'relative';
graphicsScrollContainer.style.display = 'block';
graphicsScrollContainer.style.flex = '1';
const activeDocType = data.documentationType || 'primary';
const mergedGeology = createMergedGeologyFromDocumentation(activeDocType);
// ПОЛУЧАЕМ ИСХОДНЫЕ ИНТЕРВАЛЫ
let originalIntervals = [];
switch (activeDocType) {
case 'primary': originalIntervals = xmlData?.primaryDocumentation || []; break;
case 'final': originalIntervals = xmlData?.finalDocumentation || []; break;
case 'gis': originalIntervals = xmlData?.gisDocumentation || []; break;
default: originalIntervals = xmlData?.primaryDocumentation || [];
}
// ========== КАТЕГОРИИ ПОРОД - ПРАВИЛЬНЫЙ РАЗБОР ==========
const rockCategoriesList = [];
originalIntervals.forEach(interval => {
if (interval.rockCategories && interval.rockCategories !== 'Не указано' && interval.rockCategories !== '') {
// Разбиваем строку по точке с запятой (несколько интервалов в одной строке)
const parts = interval.rockCategories.split(';');
for (const part of parts) {
const trimmedPart = part.trim();
// Ищем римскую цифру в конце
const romanMatch = trimmedPart.match(/([IVX]+)$/i);
if (romanMatch) {
// Ищем границы интервала (формат "X.X-Y.Y")
const rangeMatch = trimmedPart.match(/(\d+(?:\.\d+)?)-(\d+(?:\.\d+)?)/);
if (rangeMatch) {
const from = parseFloat(rangeMatch[1]);
const to = parseFloat(rangeMatch[2]);
if (!isNaN(from) && !isNaN(to) && from >= 0 && to > from) {
rockCategoriesList.push({
from: from,
to: to,
category: romanMatch[1].toUpperCase()
});
console.log(`📊 Категория (составной): ${from}-${to}м → ${romanMatch[1].toUpperCase()}`);
}
} else {
// Если нет явных границ, используем границы интервала документирования
rockCategoriesList.push({
from: interval.from,
to: interval.to,
category: romanMatch[1].toUpperCase()
});
console.log(`📊 Категория (из интервала): ${interval.from}-${interval.to}м → ${romanMatch[1].toUpperCase()}`);
}
}
}
}
});
// Сортируем по глубине
rockCategoriesList.sort((a, b) => a.from - b.from);
console.log('📊 ИТОГО КАТЕГОРИЙ ПОРОД:', rockCategoriesList.length, rockCategoriesList);
const assays = xmlData?.assays || [];
const realTotalDepth = xmlData?.wellDepth || data.totalDepth;
const totalDepth = realTotalDepth;
// Отступы
const topReserve = 15;
const bottomReserve = 50;
const contentHeight = totalDepth * scale + topReserve;
const totalHeight = contentHeight + bottomReserve;
const columnWidth = 70;
const drillWidth = 70;
const assaysWidth = 150;
const headerHeight = 45;
function decodeHtmlEntities(text) {
if (!text) return '';
const textarea = document.createElement('textarea');
textarea.innerHTML = text;
return textarea.value;
}
// СОЗДАЕМ ОСНОВНОЙ КОНТЕЙНЕР
const scrollContent = document.createElement('div');
scrollContent.style.cssText = `
display: block;
width: 100%;
min-height: ${totalHeight + headerHeight + 20}px;
height: auto;
position: relative;
`;
const columnContainer = document.createElement('div');
columnContainer.style.cssText = `
position: relative;
width: 100%;
background: white;
border: 1px solid #cbd5e1;
border-radius: 4px;
margin-bottom: 20px;
`;
// ШАПКА
const header = document.createElement('div');
header.style.cssText = `
position: sticky;
top: 0;
z-index: 200;
display: flex;
height: ${headerHeight}px;
background: #e2e8f0;
border-bottom: 2px solid #94a3b8;
flex-shrink: 0;
`;
const depthHeader = document.createElement('div');
depthHeader.style.cssText = `width: 60px; min-width: 60px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; color: #0f172a; border-right: 1px solid #cbd5e1; background: #e2e8f0;`;
depthHeader.textContent = 'глубина, м';
const coreHeader = document.createElement('div');
coreHeader.style.cssText = `width: ${columnWidth}px; min-width: ${columnWidth}px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; color: #0f172a; border-right: 1px solid #cbd5e1; background: #e2e8f0;`;
coreHeader.textContent = 'Колонка';
const drillHeader = document.createElement('div');
drillHeader.style.cssText = `width: ${drillWidth}px; min-width: ${drillWidth}px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; color: #0f172a; border-right: 1px solid #cbd5e1; background: #e2e8f0;`;
drillHeader.textContent = 'Кат. бур.';
const assaysHeader = document.createElement('div');
assaysHeader.style.cssText = `width: ${assaysWidth}px; min-width: ${assaysWidth}px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.7rem; color: #0f172a; background: #e2e8f0;`;
assaysHeader.textContent = 'Пробы';
header.appendChild(depthHeader);
header.appendChild(coreHeader);
header.appendChild(drillHeader);
header.appendChild(assaysHeader);
columnContainer.appendChild(header);
// ТЕЛО
const bodyContainer = document.createElement('div');
bodyContainer.style.cssText = `
position: relative;
min-height: ${contentHeight}px;
height: auto;
`;
const body = document.createElement('div');
body.style.cssText = `display: flex; position: relative; min-height: ${contentHeight}px;`;
const depthBody = document.createElement('div');
depthBody.style.cssText = `
position: relative;
width: 60px;
min-width: 60px;
min-height: ${contentHeight}px;
padding-top: ${topReserve}px;
padding-bottom: ${bottomReserve}px;
box-sizing: border-box;
background: #ffffff;
border-right: 1px solid #cbd5e1;
flex-shrink: 0;
`;
const coreBody = document.createElement('div');
coreBody.style.cssText = `
position: relative;
width: ${columnWidth}px;
min-width: ${columnWidth}px;
min-height: ${contentHeight}px;
padding-top: ${topReserve}px;
padding-bottom: ${bottomReserve}px;
box-sizing: border-box;
background: #ffffff;
border-right: 1px solid #cbd5e1;
flex-shrink: 0;
`;
const drillBody = document.createElement('div');
drillBody.style.cssText = `
position: relative;
width: ${drillWidth}px;
min-width: ${drillWidth}px;
min-height: ${contentHeight}px;
padding-top: ${topReserve}px;
padding-bottom: ${bottomReserve}px;
box-sizing: border-box;
background: #ffffff;
border-right: 1px solid #cbd5e1;
flex-shrink: 0;
`;
const assaysBody = document.createElement('div');
assaysBody.style.cssText = `
position: relative;
width: ${assaysWidth}px;
min-width: ${assaysWidth}px;
min-height: ${contentHeight}px;
padding-top: ${topReserve}px;
padding-bottom: ${bottomReserve}px;
box-sizing: border-box;
background: #ffffff;
flex-shrink: 0;
`;
body.appendChild(depthBody);
body.appendChild(coreBody);
body.appendChild(drillBody);
body.appendChild(assaysBody);
bodyContainer.appendChild(body);
columnContainer.appendChild(bodyContainer);
scrollContent.appendChild(columnContainer);
graphicsScrollContainer.appendChild(scrollContent);
// === ШКАЛА ГЛУБИНЫ ===
const finalDepthY = totalDepth * scale + topReserve;
const docBoundaries = new Set();
originalIntervals.forEach(interval => {
const from = parseFloat(interval.from);
const to = parseFloat(interval.to);
if (!isNaN(from) && from > 0 && from < totalDepth) {
docBoundaries.add(Math.round(from * 10) / 10);
}
if (!isNaN(to) && to > 0 && to < totalDepth) {
docBoundaries.add(Math.round(to * 10) / 10);
}
});
// Основные 5-метровые отметки
for (let depth = 0; depth <= totalDepth; depth += 5) {
const yPos = depth * scale + topReserve;
const line = document.createElement('div');
line.style.cssText = `position: absolute; top: ${yPos}px; left: 8px; right: 0; height: 1px; background: #cbd5e1; z-index: 10;`;
depthBody.appendChild(line);
const label = document.createElement('span');
label.style.cssText = `position: absolute; right: 6px; top: ${yPos}px; font-weight: 600; font-size: 0.65rem; color: #1e293b; background: #ffffff; padding: 0 2px; transform: translateY(-50%); z-index: 150; white-space: nowrap;`;
label.textContent = depth.toString();
depthBody.appendChild(label);
}
// КРАСНЫЕ МЕТКИ
docBoundaries.forEach(depth => {
if (depth > 0 && depth < totalDepth) {
const yPos = depth * scale + topReserve;
const isOnFiveMeter = Math.abs(depth % 5) < 0.01;
if (!isOnFiveMeter) {
const redLine = document.createElement('div');
redLine.style.cssText = `position: absolute; top: ${yPos}px; left: 8px; right: 0; height: 2px; background: #e74c3c; z-index: 12;`;
depthBody.appendChild(redLine);
const redLabel = document.createElement('span');
redLabel.style.cssText = `position: absolute; right: 6px; top: ${yPos}px; font-weight: 700; font-size: 0.65rem; color: #e74c3c; background: #ffffff; padding: 0 2px; transform: translateY(-50%); z-index: 150; white-space: nowrap; border-left: 2px solid #e74c3c;`;
redLabel.textContent = depth.toString();
depthBody.appendChild(redLabel);
} else {
const existingLabels = depthBody.querySelectorAll('span');
existingLabels.forEach(label => {
if (parseFloat(label.textContent) === depth && label.style.color !== 'rgb(231, 76, 60)') {
label.style.color = '#e74c3c';
label.style.fontWeight = '700';
label.style.borderLeft = '2px solid #e74c3c';
label.style.paddingLeft = '4px';
}
});
}
}
});
// Промежуточные линии
for (let depth = 0; depth < totalDepth; depth += 1) {
if (depth % 5 !== 0) {
let isBoundary = false;
for (let boundary of docBoundaries) {
if (Math.abs(boundary - depth) < 0.01) {
isBoundary = true;
break;
}
}
if (!isBoundary) {
const yPos = depth * scale + topReserve;
const line = document.createElement('div');
line.style.cssText = `position: absolute; top: ${yPos}px; left: 8px; right: 0; height: 1px; background: #e2e8f0; z-index: 10;`;
depthBody.appendChild(line);
}
}
}
// Забой
const bottomLine = document.createElement('div');
bottomLine.style.cssText = `position: absolute; top: ${finalDepthY}px; left: 0; right: 0; height: 2px; background: #e74c3c; z-index: 25;`;
depthBody.appendChild(bottomLine);
const bottomLabel = document.createElement('span');
bottomLabel.style.cssText = `position: absolute; right: 6px; top: ${finalDepthY}px; font-weight: 700; font-size: 0.7rem; color: #e74c3c; background: #ffffff; padding: 0 3px; transform: translateY(-50%); z-index: 150; white-space: nowrap; border: 1px solid #e74c3c; border-radius: 2px;`;
bottomLabel.textContent = totalDepth % 1 === 0 ? totalDepth.toString() : totalDepth.toFixed(1);
depthBody.appendChild(bottomLabel);
[coreBody, drillBody, assaysBody].forEach(bodyEl => {
const line = document.createElement('div');
line.style.cssText = `position: absolute; top: ${finalDepthY}px; left: 0; right: 0; height: 2px; background: #e74c3c; z-index: 25;`;
bodyEl.appendChild(line.cloneNode(true));
});
// === ОТРИСОВКА ГЕОЛОГИИ ===
const geologyBlocks = [];
mergedGeology.forEach((geo, index) => {
const topY = geo.from * scale + topReserve;
const heightY = (geo.to - geo.from) * scale;
if (heightY > 0.5 && topY <= contentHeight) {
const block = document.createElement('div');
const bgColor = getStratigraphyBackground({
stratigraphy: geo.stratigraphy,
originalStratigraphy: geo.originalStratigraphy
});
const isDark = isColorDark(bgColor);
block.style.cssText = `
position: absolute;
top: ${topY}px;
left: 0;
width: 100%;
height: ${Math.min(heightY, contentHeight - topY)}px;
background: ${bgColor};
border: 1px solid rgba(0,0,0,0.3);
cursor: pointer;
transition: all 0.15s ease;
display: flex;
align-items: center;
justify-content: center;
z-index: 20;
`;
const ageSpan = document.createElement('span');
let rawStratigraphy = geo.originalStratigraphy || geo.stratigraphy || '';
if (rawStratigraphy.includes('')) {
rawStratigraphy = decodeHtmlEntities(rawStratigraphy);
}
const finalStratigraphy = convertStratigraphyText(rawStratigraphy);
ageSpan.style.cssText = `
font-family: 'GeoindexA', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
font-weight: 700;
font-size: 0.75rem;
color: ${isDark ? '#ffffff' : '#0f172a'};
background: ${bgColor};
padding: 2px 6px;
border-radius: 2px;
text-align: center;
z-index: 21;
letter-spacing: 0.5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: ${columnWidth - 8}px;
`;
ageSpan.textContent = finalStratigraphy || '—';
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.4;
pointer-events: none;
z-index: 19;
`;
block.appendChild(patternOverlay);
}
block.dataset.layerId = index;
block.addEventListener('click', (e) => {
e.stopPropagation();
highlightGeologyBlock(index, geologyBlocks);
if (window.geologyCards && window.geologyCards[index]) {
window.geologyCards[index].scrollIntoView({ behavior: 'smooth', block: 'center' });
window.geologyCards[index].click();
}
});
coreBody.appendChild(block);
geologyBlocks.push(block);
}
});
// === ОТРИСОВКА КАТЕГОРИЙ ПОРОД (НЕЗАВИСИМАЯ КОЛОНКА) ===
rockCategoriesList.forEach((rockCat) => {
const topY = rockCat.from * scale + topReserve;
const heightY = (rockCat.to - rockCat.from) * scale;
if (heightY > 2 && topY <= contentHeight) {
const drillCell = document.createElement('div');
drillCell.style.cssText = `
position: absolute;
top: ${topY}px;
left: 0;
width: 100%;
height: ${Math.min(heightY, contentHeight - topY)}px;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
z-index: 20;
border-bottom: 1px solid #e2e8f0;
box-sizing: border-box;
`;
const categorySpan = document.createElement('div');
const fontSize = Math.min(14, Math.max(10, heightY / 4));
categorySpan.style.cssText = `
font-size: ${fontSize}px;
font-weight: 700;
color: #2c3e50;
text-align: center;
`;
categorySpan.textContent = rockCat.category;
drillCell.appendChild(categorySpan);
drillBody.appendChild(drillCell);
}
});
// ЗАПОЛНЯЕМ ПУСТЫЕ МЕСТА В КОЛОНКЕ КАТЕГОРИЙ
if (rockCategoriesList.length > 0) {
const sorted = [...rockCategoriesList].sort((a, b) => a.from - b.from);
let lastTo = 0;
// От 0 до первой категории
if (sorted[0].from > 0.01) {
const topY = 0 * scale + topReserve;
const heightY = sorted[0].from * scale;
if (heightY > 2) {
const emptyCell = document.createElement('div');
emptyCell.style.cssText = `
position: absolute;
top: ${topY}px;
left: 0;
width: 100%;
height: ${heightY}px;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
z-index: 15;
border-bottom: 1px solid #e2e8f0;
`;
emptyCell.innerHTML = '—';
drillBody.appendChild(emptyCell);
}
}
// Между категориями
for (const cat of sorted) {
if (cat.from > lastTo + 0.01) {
const topY = lastTo * scale + topReserve;
const heightY = (cat.from - lastTo) * scale;
if (heightY > 2) {
const emptyCell = document.createElement('div');
emptyCell.style.cssText = `
position: absolute;
top: ${topY}px;
left: 0;
width: 100%;
height: ${heightY}px;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
z-index: 15;
border-bottom: 1px solid #e2e8f0;
`;
emptyCell.innerHTML = '—';
drillBody.appendChild(emptyCell);
}
}
lastTo = Math.max(lastTo, cat.to);
}
// После последней категории до забоя
if (lastTo < totalDepth - 0.01) {
const topY = lastTo * scale + topReserve;
const heightY = (totalDepth - lastTo) * scale;
if (heightY > 2) {
const emptyCell = document.createElement('div');
emptyCell.style.cssText = `
position: absolute;
top: ${topY}px;
left: 0;
width: 100%;
height: ${heightY}px;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
z-index: 15;
border-bottom: 1px solid #e2e8f0;
`;
emptyCell.innerHTML = '—';
drillBody.appendChild(emptyCell);
}
}
} else {
// Нет категорий - вся колонка прочерки
const emptyCell = document.createElement('div');
emptyCell.style.cssText = `
position: absolute;
top: ${topReserve}px;
left: 0;
width: 100%;
height: ${totalDepth * scale}px;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
z-index: 15;
`;
emptyCell.innerHTML = '—';
drillBody.appendChild(emptyCell);
}
// === ОТРИСОВКА ИНТЕРВАЛОВ БЕЗ ДОКУМЕНТИРОВАНИЯ ===
let currentDepth = 0;
const actualDocumentationDepth = data.totalDepth;
const undocumentedIntervals = [];
mergedGeology.forEach((geo) => {
if (geo.from > currentDepth + 0.01) {
undocumentedIntervals.push({
from: currentDepth,
to: geo.from,
description: 'Интервал без документирования',
isBelowActual: false
});
}
currentDepth = geo.to;
});
if (currentDepth < actualDocumentationDepth - 0.01) {
undocumentedIntervals.push({
from: currentDepth,
to: actualDocumentationDepth,
description: 'Интервал без документирования',
isBelowActual: false
});
}
if (actualDocumentationDepth < totalDepth - 0.01) {
undocumentedIntervals.push({
from: actualDocumentationDepth,
to: totalDepth,
description: 'Ниже глубины документирования',
isBelowActual: true
});
}
undocumentedIntervals.forEach((interval) => {
const topY = interval.from * scale + topReserve;
const heightY = (interval.to - interval.from) * scale;
if (heightY > 0.5) {
const isBelowActual = interval.isBelowActual === true;
const visualElement = document.createElement('div');
let backgroundStyle, borderStyle, labelText;
if (!isBelowActual) {
backgroundStyle = `repeating-linear-gradient(
45deg,
transparent,
transparent 5px,
rgba(200, 200, 200, 0.15) 5px,
rgba(200, 200, 200, 0.15) 10px
)`;
borderStyle = '2px dashed #bdc3c7';
labelText = 'Нет данных';
} else {
backgroundStyle = `repeating-linear-gradient(
-45deg,
transparent,
transparent 5px,
rgba(150, 150, 150, 0.2) 5px,
rgba(150, 150, 150, 0.2) 10px
)`;
borderStyle = '2px dotted #95a5a6';
labelText = 'Ниже глубины док.';
}
visualElement.style.cssText = `
position: absolute;
top: ${topY}px;
left: 0;
width: 100%;
height: ${heightY}px;
background: ${backgroundStyle};
border-left: ${borderStyle};
border-right: ${borderStyle};
z-index: 15;
pointer-events: none;
`;
if (heightY > 30) {
const label = document.createElement('div');
label.style.cssText = `
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: ${isBelowActual ? '#7f8c8d' : '#95a5a6'};
font-size: ${Math.min(8, heightY / 4)}px;
font-weight: 500;
white-space: nowrap;
background: rgba(255, 255, 255, 0.85);
padding: 2px 6px;
border-radius: 3px;
pointer-events: none;
z-index: 100;
font-style: italic;
border: 1px ${isBelowActual ? 'dotted' : 'dashed'} #bdc3c7;
`;
label.textContent = labelText;
visualElement.appendChild(label);
}
coreBody.appendChild(visualElement);
}
});
// === ПУНКТИРНЫЕ ЛИНИИ ПО ГРАНИЦАМ ИНТЕРВАЛОВ ===
mergedGeology.forEach((geo) => {
const topY = geo.from * scale + topReserve;
const bottomY = geo.to * scale + topReserve;
const topLine = document.createElement('div');
topLine.style.cssText = `
position: absolute;
left: 0;
right: 0;
top: ${topY}px;
height: 0px;
border-top: 0.5px dashed rgba(0, 0, 0, 0.15);
pointer-events: none;
z-index: 30;
`;
assaysBody.appendChild(topLine);
if (Math.abs(bottomY - topY) > 2) {
const bottomLine = document.createElement('div');
bottomLine.style.cssText = `
position: absolute;
left: 0;
right: 0;
top: ${bottomY}px;
height: 0px;
border-top: 0.5px dashed rgba(0, 0, 0, 0.15);
pointer-events: none;
z-index: 30;
`;
assaysBody.appendChild(bottomLine);
}
});
// === ОТРИСОВКА ПРОБ ===
if (window.assaysVisible !== false && assays.length > 0) {
drawAssaysInColumn(assaysBody, mergedGeology, scale, assaysWidth, topReserve, totalDepth);
}
function highlightGeologyBlock(index, blocks) {
blocks.forEach((block, i) => {
if (i === index) {
block.style.border = '2px solid #e74c3c';
block.style.boxShadow = '0 0 0 2px rgba(231, 76, 60, 0.25)';
block.style.zIndex = '25';
} else {
block.style.border = '1px solid rgba(0,0,0,0.3)';
block.style.boxShadow = 'none';
block.style.zIndex = '20';
}
});
if (window.geologyCards) {
document.querySelectorAll('.geology-card').forEach((card, i) => {
if (i === index) {
card.style.background = '#fff7ed';
card.style.borderLeft = '4px solid #e74c3c';
} else {
card.style.background = 'white';
card.style.borderLeft = '4px solid #e9ecef';
}
});
}
}
window.geologyBlocks = geologyBlocks;
setTimeout(() => {
if (graphicsScrollContainer.scrollHeight > graphicsScrollContainer.clientHeight) {
graphicsScrollContainer.style.overflowY = 'scroll';
} else {
graphicsScrollContainer.style.overflowY = 'auto';
}
}, 100);
}
```
**Основное исправление:**
Теперь строка `'1.6-17 - VIII; 17-85 - IX'` правильно разбивается на два интервала:
- `1.6-17м → VIII`
- `17-85м → IX`
В консоли должно появиться **11 категорий** (как в исходных данных).