<!DOCTYPE html>

<html lang="de">

<head>

    <meta charset="UTF-8">

    <title>PeakFinder SVG Tool</title>

    <style>

        body {

            font-family: sans-serif;

            margin: 20px;

            max-width: 1200px;

            margin: 0 auto;

        }

        #controls {

            display: flex;

            flex-wrap: wrap;

            gap: 10px;

            margin-bottom: 20px;

        }

        .control-group {

            display: flex;

            flex-direction: column;

            gap: 5px;

            border: 1px solid #ccc;

            padding: 10px;

            border-radius: 5px;

        }

        #svg-container {

            border: 1px solid #ccc;

            margin-top: 20px;

            overflow: auto;

            max-height: 80vh;

            transform-origin: top left;

        }

        .hidden {

            opacity: 0.3;

            pointer-events: auto;

        }

        .hidden text,

        .hidden line {

            fill: grey !important;

            stroke: grey !important;

        }

        .hovered {

            fill: red !important;

            stroke: red !important;

        }

        text:hover,

        line:hover {

            cursor: pointer;

        }

        .hidden:hover {

            opacity: 1;

            z-index: 10;

        }

        #status {

            margin-top: 10px;

            font-weight: bold;

        }

    </style>

</head>

<body>

    <h1>PeakFinder SVG Tool</h1>

    

    <div id="controls">

        <div class="control-group">

            <h3>SVG Upload</h3>

            <input type="file" id="fileInput" accept=".svg" />

            <label for="zoomLevel">Zoom Level:</label>

            <input type="range" id="zoomLevel" min="1" max="5" step="0.1" value="2" />

        </div>

        

        <div class="control-group">

            <h3>Element Visibility</h3>

            <div>

                <label>

                    <input type="checkbox" id="toggleLogo" checked> Logo

                </label>

                <label>

                    <input type="checkbox" id="toggleViewpoint" checked> Viewpoint

                </label>

                <label>

                    <input type="checkbox" id="toggleRuler" checked> Ruler

                </label>

                <label>

                    <input type="checkbox" id="toggleBackground" checked> Background

                </label>

            </div>

        </div>

        

        <div class="control-group">

            <h3>Line & Label Styling</h3>

            <label>Label Stroke Width (pt):

                <input type="number" id="labelStrokeWidth" value="1" min="0.1" step="0.1">

            </label>

            <label>Line Stroke Width (pt):

                <input type="number" id="lineStrokeWidth" value="1" min="0.1" step="0.1">

            </label>

        </div>

        

        <div class="control-group">

            <h3>Export</h3>

            <button id="exportSVG">Download SVG</button>

        </div>

    </div>


    <div id="status"></div>

    <div id="svg-container"></div>


    <script>

    (function () {

        const fileInput = document.getElementById("fileInput");

        const svgContainer = document.getElementById("svg-container");

        const statusDiv = document.getElementById("status");

        const zoomLevelInput = document.getElementById("zoomLevel");

        const exportButton = document.getElementById("exportSVG");


        // Visibility toggles

        const logoToggle = document.getElementById("toggleLogo");

        const viewpointToggle = document.getElementById("toggleViewpoint");

        const rulerToggle = document.getElementById("toggleRuler");

        const backgroundToggle = document.getElementById("toggleBackground");


        // Stroke width inputs

        const labelStrokeWidthInput = document.getElementById("labelStrokeWidth");

        const lineStrokeWidthInput = document.getElementById("lineStrokeWidth");


        let prominentTextsGroup, prominentLinesGroup, allHiddenTextsGroup, allHiddenLinesGroup, currentSvg;


        fileInput.addEventListener("change", handleFileUpload);

        zoomLevelInput.addEventListener("input", handleZoom);

        exportButton.addEventListener("click", exportSVG);


        // Visibility toggles

        logoToggle.addEventListener("change", updateElementVisibility);

        viewpointToggle.addEventListener("change", updateElementVisibility);

        rulerToggle.addEventListener("change", updateElementVisibility);

        backgroundToggle.addEventListener("change", updateElementVisibility);


        // Stroke width updates

        labelStrokeWidthInput.addEventListener("input", updateStrokeWidth);

        lineStrokeWidthInput.addEventListener("input", updateStrokeWidth);


        function handleZoom() {

            const zoomLevel = zoomLevelInput.value;

            svgContainer.style.transform = `scale(${zoomLevel})`;

        }


        async function handleFileUpload() {

            if (!fileInput.files || !fileInput.files.length) {

                updateStatus("Keine Datei ausgewählt.", "error");

                return;

            }


            const file = fileInput.files[0];

            if (!file.name.toLowerCase().endsWith(".svg")) {

                updateStatus("Bitte eine SVG-Datei auswählen.", "error");

                return;

            }


            const text = await file.text().catch((err) => {

                updateStatus("Fehler beim Lesen der Datei: " + err, "error");

            });


            if (!text) return;


            const parser = new DOMParser();

            const doc = parser.parseFromString(text, "image/svg+xml");

            currentSvg = doc.documentElement;


            if (currentSvg.nodeName.toLowerCase() !== "svg") {

                updateStatus("Die ausgewählte Datei ist kein gültiges SVG.", "error");

                return;

            }


            svgContainer.innerHTML = "";

            svgContainer.appendChild(currentSvg);


            initStructure(currentSvg);

            if (!setupEventHandlers()) {

                updateStatus("Konnte die benötigte Struktur nicht finden.", "error");

            } else {

                updateStatus("SVG erfolgreich geladen.", "success");

                updateElementVisibility();

                updateStrokeWidth();

            }

        }


        function initStructure(svgRoot) {

            const labelsGroup = svgRoot.querySelector('g#labels, g > g[label="labels"], g[label=labels]');

            const allHidden = labelsGroup?.querySelector("g#all_hidden, g[id=all_hidden]");

            const prominent = labelsGroup?.querySelector("g#prominent, g[id=prominent]");


            allHiddenTextsGroup = allHidden?.querySelector("g#texts, g[id=texts]");

            allHiddenLinesGroup = allHidden?.querySelector("g#lines, g[id=lines]");

            prominentTextsGroup = prominent?.querySelector("g#texts, g[id=texts]");

            prominentLinesGroup = prominent?.querySelector("g#lines, g[id=lines]");


            const allHiddenTexts = Array.from(allHidden?.querySelectorAll("text") || []);

            const allHiddenLines = Array.from(allHidden?.querySelectorAll("line, path") || []);

            const prominentTexts = Array.from(prominentTextsGroup?.querySelectorAll("text") || []);

            const prominentLines = Array.from(prominentLinesGroup?.querySelectorAll("line, path") || []);


            function isTextInProminent(text) {

                return prominentTexts.some((promText) => promText.textContent.trim() === text.textContent.trim());

            }


            function isLineInProminent(line) {

                return prominentLines.some((promLine) => promLine.isEqualNode(line));

            }


            console.log("Initializing structure...");

            console.log(`Found ${allHiddenTexts.length} hidden texts.`);

            console.log(`Found ${allHiddenLines.length} hidden lines.`);

            console.log(`Found ${prominentTexts.length} prominent texts.`);

            console.log(`Found ${prominentLines.length} prominent lines.`);


            allHiddenTexts.forEach((text) => {

                if (!isTextInProminent(text)) {

                    console.log(`Moving hidden text: ${text.textContent.trim()} to prominent.`);

                    prominentTextsGroup.appendChild(text);

                    text.classList.add("hidden");

                } else {

                    console.log(`Duplicate text detected and removed: ${text.textContent.trim()}`);

                    allHiddenTextsGroup.removeChild(text);

                }

            });


            allHiddenLines.forEach((line, index) => {

                if (!isLineInProminent(line)) {

                    console.log(`Moving hidden line at index: ${index} to prominent.`);

                    prominentLinesGroup.appendChild(line);

                    line.classList.add("hidden");

                } else {

                    console.log(`Duplicate line detected and removed at index: ${index}`);

                    allHiddenLinesGroup.removeChild(line);

                }

            });


            prominentTexts.forEach((text) => {

                console.log(`Ensuring visibility for prominent text: ${text.textContent.trim()}`);

                text.classList.remove("hidden");

            });


            prominentLines.forEach((line, index) => {

                console.log(`Ensuring visibility for prominent line at index: ${index}`);

                line.classList.remove("hidden");

            });

        }


        function setupEventHandlers() {

            if (!prominentTextsGroup || !prominentLinesGroup) return false;


            const prominentTexts = Array.from(prominentTextsGroup.children);

            const prominentLines = Array.from(prominentLinesGroup.children);


            prominentTexts.forEach((text, index) => {

                const correspondingLine = prominentLines[index];

                text.addEventListener("mouseenter", () => handleHoverEnter(text, correspondingLine));

                text.addEventListener("mouseleave", () => handleHoverLeave(text, correspondingLine));

                text.addEventListener("click", (event) => handleClick(event, text, correspondingLine));

            });


            prominentLines.forEach((line, index) => {

                const correspondingText = prominentTexts[index];

                line.addEventListener("mouseenter", () => handleHoverEnter(correspondingText, line));

                line.addEventListener("mouseleave", () => handleHoverLeave(correspondingText, line));

                line.addEventListener("click", (event) => handleClick(event, correspondingText, line));

            });


            return true;

        }


        function handleHoverEnter(textEl, lineEl) {

            textEl.classList.add("hovered");

            lineEl.classList.add("hovered");

        }


        function handleHoverLeave(textEl, lineEl) {

            textEl.classList.remove("hovered");

            lineEl.classList.remove("hovered");

        }


        function handleClick(event, textEl, lineEl) {

            if (event.shiftKey) {

                console.log(`Removing text: ${textEl.textContent.trim()} and its line.`);

                moveToHidden(textEl, lineEl);

            } else {

                console.log(`Toggling visibility for text: ${textEl.textContent.trim()} and its line.`);

                toggleVisibility(textEl, lineEl);

            }

        }


        function toggleVisibility(textEl, lineEl) {

            if (textEl.classList.contains("hidden")) {

                console.log(`Making visible: ${textEl.textContent.trim()}`);

                textEl.classList.remove("hidden");

                lineEl.classList.remove("hidden");

            } else {

                console.log(`Hiding: ${textEl.textContent.trim()}`);

                textEl.classList.add("hidden");

                lineEl.classList.add("hidden");

            }

        }


        function moveToHidden(textEl, lineEl) {

            console.log(`Moving text: ${textEl.textContent.trim()} and its line to all_hidden.`);

            allHiddenTextsGroup.appendChild(textEl);

            allHiddenLinesGroup.appendChild(lineEl);


            textEl.classList.add("hidden");

            lineEl.classList.add("hidden");

        }


        function updateElementVisibility() {

            if (!currentSvg) return;


            const logoElements = currentSvg.querySelectorAll('[id*="logo"]');

            const viewpointElements = currentSvg.querySelectorAll('[id*="viewpoint"]');

            const rulerElements = currentSvg.querySelectorAll('[id*="ruler"]');

            const backgroundElements = currentSvg.querySelectorAll('[id*="background"]');


            logoElements.forEach(el => el.style.display = logoToggle.checked ? '' : 'none');

            viewpointElements.forEach(el => el.style.display = viewpointToggle.checked ? '' : 'none');

            rulerElements.forEach(el => el.style.display = rulerToggle.checked ? '' : 'none');

            backgroundElements.forEach(el => el.style.display = backgroundToggle.checked ? '' : 'none');

        }


        function updateStrokeWidth() {

            if (!currentSvg) return;


            const labelStrokeWidth = labelStrokeWidthInput.value + 'pt';

            const lineStrokeWidth = lineStrokeWidthInput.value + 'pt';


            const labels = currentSvg.querySelectorAll('text');

            labels.forEach(label => {

                label.style.strokeWidth = labelStrokeWidth;

            });


            const lines = currentSvg.querySelectorAll('line, path');

            lines.forEach(line => {

                line.style.strokeWidth = lineStrokeWidth;

            });

        }


        function exportSVG() {

            if (!currentSvg) {

                updateStatus("Bitte laden Sie zuerst ein SVG.", "error");

                return;

            }


            // Clone the current SVG to avoid modifying the original

            const svgClone = currentSvg.cloneNode(true);


            // Remove all elements with the 'hidden' class

            svgClone.querySelectorAll('.hidden').forEach(el => el.remove());


            // Remove all elements that are hidden via 'display: none'

            svgClone.querySelectorAll('*').forEach(el => {

                const style = el.getAttribute('style');

                if (style && style.includes('display: none')) {

                    el.remove();

                }

            });


            // Serialize the cleaned SVG

            const serializer = new XMLSerializer();

            let svgString = serializer.serializeToString(svgClone);


            // Add XML namespaces if missing

            if (!svgString.includes('xmlns="http://www.w3.org/2000/svg"')) {

                svgString = svgString.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"');

            }


            // Create a Blob from the SVG string

            const blob = new Blob([svgString], {type: 'image/svg+xml'});

            const url = URL.createObjectURL(blob);


            // Create a temporary link to trigger the download

            const a = document.createElement('a');

            a.href = url;

            a.download = 'peakfinder_export.svg';

            document.body.appendChild(a);

            a.click();

            document.body.removeChild(a);


            // Revoke the object URL to free up memory

            URL.revokeObjectURL(url);


            updateStatus("SVG erfolgreich exportiert.", "success");

        }


        function updateStatus(message, type) {

            statusDiv.textContent = message;

            statusDiv.style.color = type === "error" ? "red" : "green";

        }

    })();

    </script>

</body>

</html>