Понял проблему! Из консоли видно, что изначально было **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 категорий** (как в исходных данных).