<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файле</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Название шаблона корреляции:</label> <input type="text" id="templateName" value="Корреляционный шаблон"> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div>
<script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const templateNameInput = document.getElementById('templateName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для правильного форматирования SVG контента function formatSvgContent(svgContent) { // В рабочем примере SVG имеет специфичную структуру с дополнительными атрибутами // Заменяем корневой тег SVG на тот, который используется в рабочем примере let formatted = svgContent.replace( /<svg[^>]*>/, `<svg id="svg1" height="142px" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" viewBox="0 0 282 142" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" width="282px" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1">` ); // Добавляем метаданные, которые есть в рабочем примере formatted = formatted.replace( /<defs id="defs1"\/>/, `<metadata> <rdf:RDF> <cc:Work> <dc:title>ИСИХОГИ_Литология</dc:title> </cc:Work> </rdf:RDF> </metadata> <defs id="defs1"/>` ); // В рабочем примере используются одинарные кавычки для XML декларации // и двойные для атрибутов SVG formatted = formatted.replace(/<?xml version="1.0" encoding="UTF-8"?>/, `<?xml version='1.0' encoding='UTF-8'?>`); // В рабочем примере теги line имеют другой формат атрибутов formatted = formatted.replace( /<line ([^>]*)\/>/g, '<line $1/>' ); // Экранируем только амперсанды formatted = formatted.replace(/&(?!amp;|lt;|gt;|quot;|#)/g, '&'); return formatted; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const templateName = templateNameInput.value || 'Корреляционный шаблон'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное форматирование SVG для XML svgContent = formatSvgContent(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в рабочем примере return { "color": "#ffffffff", "data": `<StyledFill name="" group="" brushColor="#000000" objectName="" id="${id}" penColor="#000000">\n <SvgFill penWidth="0.4" objectName="" patternWidth="20" lineWidth="0.4" svgFilePath="${fullSvgFilePath}" svgContent="${svgContent}"/>\n</StyledFill>\n`, "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [ { "Tracks": [ { "allHeight": false, "hTxtSet": { "vis": true }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947027, "type": 0 }, { "Logs": [ { "logDataVers": 1, "logId": 1763096947080, "logParams": [ { "contId": 1763096947014, "contName": "РИГИС", "id": 1763096947013, "nm": "литология" } ], "logType": 3, "trackId": 1763096947055 } ], "allHeight": false, "hTxtSet": { "vis": false }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947055, "width": 50.69166666666666 } ], "Version": { "build": 3, "fillData": 0, "horizonView": 0, "logData": 1, "logRange": 0, "plastBuild": 0, "plastData": 0, "stratBuild": 0, "stratData": 0, "stratWidth": 0, "timeDepth": 0, "trackWidth": 1, "view": 7 }, "header": { "textBlockList": { "textBlocks": [ { "blockId": 1763096947023, "textItems": [ { "blockId": 1763096947023, "content": "[WellName]", "font": { "b": true }, "itemId": 1763096947024, "paramsHash": [ { "id": -1, "key": "[WellName]" } ] } ] } ] } }, "id": Date.now() + 1000, "name": templateName, "plastList": { "columnId": 1763096947025, "isPlast": true, "type": 0 } } ], "corrTemplatesVersion": 0 }; // Отображение JSON jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = `<div class="message ${type}">${message}</div>`; // Автоматическое скрытие сообщения через 5 секунд setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = `1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит`; }; </script> </body> </html>
|
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файле</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Название шаблона корреляции:</label> <input type="text" id="templateName" value="Корреляционный шаблон"> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div>
<script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const templateNameInput = document.getElementById('templateName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для правильного форматирования SVG контента function formatSvgContent(svgContent) { // Убираем лишние пробелы и переносы строк, но сохраняем структуру let formatted = svgContent .replace(/\s+/g, ' ') .trim(); // В рабочем примере XML декларация использует одинарные кавычки formatted = formatted.replace(/<\?xml version="1.0" encoding="UTF-8"\?>/g, "<?xml version='1.0' encoding='UTF-8'?>"); // Экранируем только амперсанды formatted = formatted.replace(/&(?!amp;|lt;|gt;|quot;|#)/g, '&'); return formatted; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const templateName = templateNameInput.value || 'Корреляционный шаблон'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное форматирование SVG для XML svgContent = formatSvgContent(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в рабочем примере return { "color": "#ffffffff", "data": `<StyledFill name="" group="" brushColor="#000000" objectName="" id="${id}" penColor="#000000">\n <SvgFill penWidth="0.4" objectName="" patternWidth="20" lineWidth="0.4" svgFilePath="${fullSvgFilePath}" svgContent="${svgContent}"/>\n</StyledFill>\n`, "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [ { "Tracks": [ { "allHeight": false, "hTxtSet": { "vis": true }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947027, "type": 0 }, { "Logs": [ { "logDataVers": 1, "logId": 1763096947080, "logParams": [ { "contId": 1763096947014, "contName": "РИГИС", "id": 1763096947013, "nm": "литология" } ], "logType": 3, "trackId": 1763096947055 } ], "allHeight": false, "hTxtSet": { "vis": false }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947055, "width": 50.69166666666666 } ], "Version": { "build": 3, "fillData": 0, "horizonView": 0, "logData": 1, "logRange": 0, "plastBuild": 0, "plastData": 0, "stratBuild": 0, "stratData": 0, "stratWidth": 0, "timeDepth": 0, "trackWidth": 1, "view": 7 }, "header": { "textBlockList": { "textBlocks": [ { "blockId": 1763096947023, "textItems": [ { "blockId": 1763096947023, "content": "[WellName]", "font": { "b": true }, "itemId": 1763096947024, "paramsHash": [ { "id": -1, "key": "[WellName]" } ] } ] } ] } }, "id": Date.now() + 1000, "name": templateName, "plastList": { "columnId": 1763096947025, "isPlast": true, "type": 0 } } ], "corrTemplatesVersion": 0 }; // Отображение JSON jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = `<div class="message ${type}">${message}</div>`; // Автоматическое скрытие сообщения через 5 секунд setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = `1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит`; }; </script> </body> </html>Добавлено (2025-11-14, 16:51) --------------------------------------------- <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файле</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Название шаблона корреляции:</label> <input type="text" id="templateName" value="Корреляционный шаблон"> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div>
<script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const templateNameInput = document.getElementById('templateName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для правильного форматирования SVG контента function formatSvgContent(svgContent) { // Убираем лишние пробелы и переносы строк, но сохраняем структуру let formatted = svgContent .replace(/\s+/g, ' ') .trim(); // В рабочем примере XML декларация использует одинарные кавычки formatted = formatted.replace(/<\?xml version="1.0" encoding="UTF-8"\?>/g, "<?xml version='1.0' encoding='UTF-8'?>"); // Экранируем только амперсанды formatted = formatted.replace(/&(?!amp;|lt;|gt;|quot;|#)/g, '&'); return formatted; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const templateName = templateNameInput.value || 'Корреляционный шаблон'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное форматирование SVG для XML svgContent = formatSvgContent(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в рабочем примере return { "color": "#ffffffff", "data": `<StyledFill name="" group="" brushColor="#000000" objectName="" id="${id}" penColor="#000000">\n <SvgFill penWidth="0.4" objectName="" patternWidth="20" lineWidth="0.4" svgFilePath="${fullSvgFilePath}" svgContent="${svgContent}"/>\n</StyledFill>\n`, "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [ { "Tracks": [ { "allHeight": false, "hTxtSet": { "vis": true }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947027, "type": 0 }, { "Logs": [ { "logDataVers": 1, "logId": 1763096947080, "logParams": [ { "contId": 1763096947014, "contName": "РИГИС", "id": 1763096947013, "nm": "литология" } ], "logType": 3, "trackId": 1763096947055 } ], "allHeight": false, "hTxtSet": { "vis": false }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947055, "width": 50.69166666666666 } ], "Version": { "build": 3, "fillData": 0, "horizonView": 0, "logData": 1, "logRange": 0, "plastBuild": 0, "plastData": 0, "stratBuild": 0, "stratData": 0, "stratWidth": 0, "timeDepth": 0, "trackWidth": 1, "view": 7 }, "header": { "textBlockList": { "textBlocks": [ { "blockId": 1763096947023, "textItems": [ { "blockId": 1763096947023, "content": "[WellName]", "font": { "b": true }, "itemId": 1763096947024, "paramsHash": [ { "id": -1, "key": "[WellName]" } ] } ] } ] } }, "id": Date.now() + 1000, "name": templateName, "plastList": { "columnId": 1763096947025, "isPlast": true, "type": 0 } } ], "corrTemplatesVersion": 0 }; // Отображение JSON jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = `<div class="message ${type}">${message}</div>`; // Автоматическое скрытие сообщения через 5 секунд setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = `1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит`; }; </script> </body> </html> Добавлено (2025-11-14, 16:59) --------------------------------------------- <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файе</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Название шаблона корреляции:</label> <input type="text" id="templateName" value="Корреляционный шаблон"> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div>
<script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const templateNameInput = document.getElementById('templateName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для правильного форматирования SVG контента function formatSvgContent(svgContent) { // Убираем лишние пробелы и переносы строк let formatted = svgContent.replace(/\s+/g, ' ').trim(); // В рабочем примере XML декларация использует одинарные кавычки formatted = formatted.replace(/<\?xml version="1.0" encoding="UTF-8"\?>/g, "<?xml version='1.0' encoding='UTF-8'?>"); // Экранируем все специальные символы для XML как в рабочем примере formatted = formatted .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); return formatted; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const templateName = templateNameInput.value || 'Корреляционный шаблон'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное форматирование SVG для XML svgContent = formatSvgContent(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в рабочем примере return { "color": "#ffffffff", "data": `<StyledFill name="" group="" brushColor="#000000" objectName="" id="${id}" penColor="#000000">\n <SvgFill penWidth="0.4" objectName="" patternWidth="20" lineWidth="0.4" svgFilePath="${fullSvgFilePath}" svgContent="${svgContent}"/>\n</StyledFill>\n`, "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [ { "Tracks": [ { "allHeight": false, "hTxtSet": { "vis": true }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947027, "type": 0 }, { "Logs": [ { "logDataVers": 1, "logId": 1763096947080, "logParams": [ { "contId": 1763096947014, "contName": "РИГИС", "id": 1763096947013, "nm": "литология" } ], "logType": 3, "trackId": 1763096947055 } ], "allHeight": false, "hTxtSet": { "vis": false }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947055, "width": 50.69166666666666 } ], "Version": { "build": 3, "fillData": 0, "horizonView": 0, "logData": 1, "logRange": 0, "plastBuild": 0, "plastData": 0, "stratBuild": 0, "stratData": 0, "stratWidth": 0, "timeDepth": 0, "trackWidth": 1, "view": 7 }, "header": { "textBlockList": { "textBlocks": [ { "blockId": 1763096947023, "textItems": [ { "blockId": 1763096947023, "content": "[WellName]", "font": { "b": true }, "itemId": 1763096947024, "paramsHash": [ { "id": -1, "key": "[WellName]" } ] } ] } ] } }, "id": Date.now() + 1000, "name": templateName, "plastList": { "columnId": 1763096947025, "isPlast": true, "type": 0 } } ], "corrTemplatesVersion": 0 }; // Отображение JSON jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = `<div class="message ${type}">${message}</div>`; // Автоматическое скрытие сообщения через 5 секунд setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = `1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит`; }; </script> </body> </html> Добавлено (2025-11-14, 17:07) --------------------------------------------- <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файле</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Название шаблона корреляции:</label> <input type="text" id="templateName" value="Корреляционный шаблон"> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div>
<script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const templateNameInput = document.getElementById('templateName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для правильного экранирования SVG контента function formatSvgContent(svgContent) { // Убираем лишние пробелы и переносы строк let formatted = svgContent.replace(/\s+/g, ' ').trim(); // Заменяем XML декларацию на версию с одинарными кавычками formatted = formatted.replace(/<\?xml version="1.0" encoding="UTF-8"\?>/g, "<?xml version='1.0' encoding='UTF-8'?>"); // Правильно экранируем специальные символы для XML formatted = formatted .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"'); return formatted; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const templateName = templateNameInput.value || 'Корреляционный шаблон'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное форматирование SVG для XML svgContent = formatSvgContent(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в рабочем примере return { "color": "#ffffffff", "data": "<StyledFill name=\"\" group=\"\" brushColor=\"#000000\" objectName=\"\" id=\"" + id + "\" penColor=\"#000000\">\n <SvgFill penWidth=\"0.4\" objectName=\"\" patternWidth=\"20\" lineWidth=\"0.4\" svgFilePath=\"" + fullSvgFilePath + "\" svgContent=\"" + svgContent + "\"/>\n</StyledFill>\n", "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [ { "Tracks": [ { "allHeight": false, "hTxtSet": { "vis": true }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947027, "type": 0 }, { "Logs": [ { "logDataVers": 1, "logId": 1763096947080, "logParams": [ { "contId": 1763096947014, "contName": "РИГИС", "id": 1763096947013, "nm": "литология" } ], "logType": 3, "trackId": 1763096947055 } ], "allHeight": false, "hTxtSet": { "vis": false }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947055, "width": 50.69166666666666 } ], "Version": { "build": 3, "fillData": 0, "horizonView": 0, "logData": 1, "logRange": 0, "plastBuild": 0, "plastData": 0, "stratBuild": 0, "stratData": 0, "stratWidth": 0, "timeDepth": 0, "trackWidth": 1, "view": 7 }, "header": { "textBlockList": { "textBlocks": [ { "blockId": 1763096947023, "textItems": [ { "blockId": 1763096947023, "content": "[WellName]", "font": { "b": true }, "itemId": 1763096947024, "paramsHash": [ { "id": -1, "key": "[WellName]" } ] } ] } ] } }, "id": Date.now() + 1000, "name": templateName, "plastList": { "columnId": 1763096947025, "isPlast": true, "type": 0 } } ], "corrTemplatesVersion": 0 }; // Отображение JSON jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = '<div class="message ' + type + '">' + message + '</div>'; // Автоматическое скрытие сообщения через 5 секунд setTimeout(function() { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = "1300 Суглинок\n1700 Илы\n1800 Торф\n1400 Супесь\n2300 Аргиллит\n2400 Алевролит"; }; </script> </body> </html>
|