<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>nvline</title>
    <style>
        body {
            background-color: #121212;
            color: #ffffff;
            font-family: Arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
            padding: 20px;
            box-sizing: border-box;
        }

        h1 {
            margin-bottom: 10px;
            font-size: 24px;
        }

        #chart-container {
            width: 90%;
            height: 80%;
        }

        #chart {
            width: 100%;
            height: 100%;
        }

        .axis-label {
            fill: #ffffff;
        }

        .tooltip {
            position: absolute;
            background: rgba(0, 0, 0, 0.7);
            color: #fff;
            padding: 5px;
            border-radius: 3px;
            pointer-events: none;
            font-size: 12px;
        }

        .grid line {
            stroke: #444;
        }

        .grid path {
            stroke: none;
        }


        input[type="file"] {
            display: none;
        }

        .custom-file-upload {
            border: 1px solid #ccc;
            display: inline-block;
            padding: 6px 12px;
            cursor: pointer;
        }
    </style>
</head>

<body>
    <h1>Import nvline JSONL File and Display Memory Usage</h1>


    <label for="fileInput" class="custom-file-upload">
        Add nvline JSONL File
    </label>
    <input type="file" id="fileInput" accept=".jsonl">

    <div id="chart-container">
        <svg id="chart"></svg>
    </div>
    <div id="tooltip" class="tooltip" style="display: none;"></div>

    <script>
        document.getElementById('fileInput').addEventListener('change', handleFile, false);

        function handleFile(event) {
            const file = event.target.files[0];
            const reader = new FileReader();
            reader.onload = function (event) {
                const lines = event.target.result.split('\n').filter(line => line.trim() !== '');
                const data = lines.map(line => JSON.parse(line));
                drawChart(data);
            };
            reader.readAsText(file);
        }

        function drawChart(data) {
            const svg = document.getElementById('chart');
            svg.innerHTML = '';
            const width = svg.clientWidth;
            const height = svg.clientHeight;
            const padding = 30;
            const xScale = width / (data.length - 1);
            const yMax = Math.max(...data.map(d => d.memory_total));
            const yScale = (height - padding * 2) / yMax;

            const line = (points) => points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p[0]},${p[1]}`).join(' ');

            const memoryUsedPoints = data.map((d, i) => [i * xScale, height - padding - d.memory_used * yScale]);
            const memoryFreePoints = data.map((d, i) => [i * xScale, height - padding - d.memory_free * yScale]);
            const memoryTotalPoints = data.map((d, i) => [i * xScale, height - padding - d.memory_total * yScale]);

            const gridX = document.createElementNS('http://www.w3.org/2000/svg', 'g');
            const gridY = document.createElementNS('http://www.w3.org/2000/svg', 'g');

            for (let i = 0; i < data.length; i++) {
                const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
                line.setAttribute('x1', i * xScale);
                line.setAttribute('y1', height - padding);
                line.setAttribute('x2', i * xScale);
                line.setAttribute('y2', padding);
                line.setAttribute('class', 'grid');
                line.setAttribute('stroke', '#444');
                gridX.appendChild(line);
            }

            for (let i = 0; i <= yMax; i += yMax / 10) {
                const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
                line.setAttribute('x1', 0);
                line.setAttribute('y1', height - padding - i * yScale);
                line.setAttribute('x2', width);
                line.setAttribute('y2', height - padding - i * yScale);
                line.setAttribute('class', 'grid');
                line.setAttribute('stroke', '#444');
                gridY.appendChild(line);
            }

            svg.appendChild(gridX);
            svg.appendChild(gridY);

            const pathUsed = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            pathUsed.setAttribute('d', line(memoryUsedPoints));
            pathUsed.setAttribute('stroke', 'red');
            pathUsed.setAttribute('fill', 'none');
            svg.appendChild(pathUsed);

            const pathFree = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            pathFree.setAttribute('d', line(memoryFreePoints));
            pathFree.setAttribute('stroke', 'green');
            pathFree.setAttribute('fill', 'none');
            svg.appendChild(pathFree);

            const pathTotal = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            pathTotal.setAttribute('d', line(memoryTotalPoints));
            pathTotal.setAttribute('stroke', 'blue');
            pathTotal.setAttribute('fill', 'none');
            svg.appendChild(pathTotal);

            memoryUsedPoints.forEach((point, i) => {
                const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                circle.setAttribute('cx', point[0]);
                circle.setAttribute('cy', point[1]);
                circle.setAttribute('r', 3);
                circle.setAttribute('fill', 'red');
                circle.setAttribute('class', 'dot dot-used');
                circle.setAttribute('data-index', i);
                svg.appendChild(circle);
            });

            memoryFreePoints.forEach((point, i) => {
                const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                circle.setAttribute('cx', point[0]);
                circle.setAttribute('cy', point[1]);
                circle.setAttribute('r', 3);
                circle.setAttribute('fill', 'green');
                circle.setAttribute('class', 'dot dot-free');
                circle.setAttribute('data-index', i);
                svg.appendChild(circle);
            });

            memoryTotalPoints.forEach((point, i) => {
                const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                circle.setAttribute('cx', point[0]);
                circle.setAttribute('cy', point[1]);
                circle.setAttribute('r', 3);
                circle.setAttribute('fill', 'blue');
                circle.setAttribute('class', 'dot dot-total');
                circle.setAttribute('data-index', i);
                svg.appendChild(circle);
            });

            const xAxisLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
            xAxisLabel.setAttribute('x', width / 2);
            xAxisLabel.setAttribute('y', height - 10);
            xAxisLabel.setAttribute('class', 'axis-label');
            xAxisLabel.setAttribute('text-anchor', 'middle');
            xAxisLabel.textContent = 'Data Points';
            svg.appendChild(xAxisLabel);

            const yAxisLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text');
            yAxisLabel.setAttribute('x', -height / 2);
            yAxisLabel.setAttribute('y', 20);
            yAxisLabel.setAttribute('class', 'axis-label');
            yAxisLabel.setAttribute('text-anchor', 'middle');
            yAxisLabel.setAttribute('transform', 'rotate(-90)');
            yAxisLabel.textContent = 'Memory Usage';
            svg.appendChild(yAxisLabel);

            const tooltip = document.getElementById('tooltip');
            svg.addEventListener('mousemove', (event) => {
                const rect = svg.getBoundingClientRect();
                const x = event.clientX - rect.left;
                const index = Math.round(x / xScale);

                document.querySelectorAll('.dot').forEach(dot => dot.style.display = 'none');

                if (index >= 0 && index < data.length) {
                    const memoryUsed = data[index].memory_used;
                    const memoryFree = data[index].memory_free;
                    const memoryTotal = data[index].memory_total;
                    const timestamp = new Date(1000 * data[index].timestamp).toISOString();

                    tooltip.style.display = 'block';
                    tooltip.style.left = event.pageX + 10 + 'px';
                    tooltip.style.top = event.pageY - 10 + 'px';
                    tooltip.innerHTML = `Total: ${memoryTotal} Used: ${memoryUsed}<br>Free: ${memoryFree}<br> Timestamp: ${timestamp}`;

                    document.querySelector(`.dot-used[data-index='${index}']`).style.display = 'block';
                    document.querySelector(`.dot-free[data-index='${index}']`).style.display = 'block';
                    document.querySelector(`.dot-total[data-index='${index}']`).style.display = 'block';
                } else {
                    tooltip.style.display = 'none';
                }
            });

            svg.addEventListener('mouseout', () => {
                tooltip.style.display = 'none';
                document.querySelectorAll('.dot').forEach(dot => dot.style.display = 'none');
            });
        }
    </script>
</body>

</html>