English 中文(简体)
如何用超文本、联合材料和图表处理CSV大案。 j)
原标题:How to handle a big CSV file with HTML, JS and Chart.js

我必须上载90份中小口径终端文档,然后用图表分析。 j 图表。 CSV文档测量了每分钟记录的价值。 当时,90个甲基溴的数值接近一年。 我已经为网站设定了高价值的反应时间。 但是,我的法典正在减少流失。 因此,我已做,只显示一定数量的数据价值,然后每隔一段时间通过图表点击。 即便如此,也仍然非常缓慢,而不是.。 对评价而言,至少每月一次的概述会不准确。 但我不知道我能做什么调整。 你们是否有任何想法?

传真

<!DOCTYPE html>
<html lang="de">
   <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>CSV Diagramm mit Chart.js</title>
      <link rel="stylesheet" href="styles.css">
   </head>
   <body>
      <div id="drop-area" class="drop-area" style="width: 100%;" ondrop="handleDrop(event)" ondragover="handleDragOver(event)">
         <p>Datei hier ablegen</p>
         <input type="file" id="csvFileInput" accept=".csv" style="display:none;" onchange="handleUpload()">
      </div>
      <div class="chart-container" style="width: 100%;">
         <canvas id="myChart"></canvas>
      </div>
      <button onclick="showPreviousData()">Vorheriger Tag</button>
      <button onclick="showNextData()">Nächster Tag</button>
      <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js" integrity="sha512-UXumZrZNiOwnTcZSHLOfcTs0aos2MzBWHXOHOuB0J/R44QB0dwY5JgfbvljXcklVf65Gc4El6RjZ+lnwd2az2g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/2.0.1/chartjs-plugin-zoom.min.js" integrity="sha512-wUYbRPLV5zs6IqvWd88HIqZU/b8TBx+I8LEioQ/UC0t5EMCLApqhIAnUg7EsAzdbhhdgW07TqYDdH3QEXRcPOQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
      <script src="script.js"></script>
   </body>
</html>

JS

let startIndex = 0;
const displayCount = 1440;
let labels = [];
let datasets = [];
let originalDatasetVisibility = [];

function handleUpload() {
    const fileInput = document.getElementById( csvFileInput );
    const file = fileInput.files[0];
    handleFile(file);
}

function processData(csvData) {
    const rows = csvData.split( 
 );
    labels = [];
    datasets = [];
    originalDatasetVisibility = [];

    const colors = [ rgba(255, 0, 0, 1) ,  rgba(0, 255, 0, 1) ,  rgba(255, 255, 0, 1) ,  rgba(0, 0, 255, 1) ];

    const columns = rows[0].split( ; );

    for (let i = 1; i < columns.length; i++) {
        const data = [];
        const currentLabel = columns[i];
        const color = colors[i - 1];

        for (let j = 1; j < rows.length; j++) {
            const cols = rows[j].split( ; );
            if (i === 1) {
                labels.push(cols[0]);
            }
            data.push(parseFloat(cols[i]));
        }

        const dataset = {
            label: currentLabel,
            data: data,
            backgroundColor: color,
            borderColor: color,
            fill: false,
            borderWidth: 1,
            pointRadius: 1,
        };

        datasets.push(dataset);
        originalDatasetVisibility.push(true);
    }

    createChart(labels.slice(startIndex, startIndex + displayCount), datasets, function() {
        console.log( Diagramm wurde erstellt );
    });
}

function createChart(labels, datasets, callback) {
    const chartContainer = document.querySelector( .chart-container );
    const canvasElement = document.getElementById( myChart );

    if (canvasElement) {
        chartContainer.removeChild(canvasElement);
    }

    chartContainer.inner传真 =  <canvas id="myChart"></canvas> ;

    const ctx = document.getElementById( myChart ).getContext( 2d );
    window.myChart = new Chart(ctx, {
        type:  line ,
        data: {
            labels: labels,
            datasets: datasets.map((dataset, index) => ({
                ...dataset,
                data: dataset.data.slice(startIndex, startIndex + displayCount),
                hidden: !originalDatasetVisibility[index],
            })),
        },
        options: {
            scales: {
                x: {
                    stacked: true,
                    min: labels[startIndex],
                    max: labels[startIndex + displayCount - 1],
                },
                y: {},
            },
            plugins: {
                zoom: {
                    pan: {
                        enabled: true,
                        mode:  x 
                    },
                    zoom: {
                        wheel: {
                            enabled: true,
                        },
                        pinch: {
                            enabled: true
                        },
                        mode:  x ,
                    }
                }
            }
        }
    });

    if (callback && typeof callback ===  function ) {
        callback();
    }

    window.myChart.resetZoom();
    window.myChart.ctx.canvas.addEventListener( wheel , handleZoom);
}

function handleZoom(event) {
    const chart = window.myChart;
    const chartArea = chart.chartArea;
    const originalDatasets = chart.data.datasets;

    const zoomEnabled = chart.options.plugins.zoom.zoom.wheel.enabled;
    const deltaY = event.deltaY;

    if (zoomEnabled && deltaY !== 0) {
        const deltaMode = event.deltaMode;
        const scaleDelta = deltaY > 0 ? 0.9 : 1.1;

        let newMinIndex = chart.getDatasetMeta(0).data.findIndex(
            (d) => d.x >= chartArea.left
        );
        let newMaxIndex = chart.getDatasetMeta(0).data.findIndex(
            (d) => d.x >= chartArea.right
        );

        if (deltaMode === 0) {
            newMinIndex = Math.max(0, newMinIndex - Math.abs(deltaY));
            newMaxIndex = Math.min(
                originalDatasets[0].data.length - 1,
                newMaxIndex + Math.abs(deltaY)
            );
        } else if (deltaMode === 1) {
            newMinIndex = Math.max(0, newMinIndex - Math.abs(deltaY) * 10);
            newMaxIndex = Math.min(
                originalDatasets[0].data.length - 1,
                newMaxIndex + Math.abs(deltaY) * 10
            );
        }

        const newMinLabel = originalDatasets[0].data[newMinIndex].label;
        const newMaxLabel = originalDatasets[0].data[newMaxIndex].label;

        chart.options.scales.x.min = newMinLabel;
        chart.options.scales.x.max = newMaxLabel;

        chart.update();
    }
}

function handleFile(file) {
    if (file) {
        const reader = new FileReader();

        reader.onload = function (e) {
            const csvData = e.target.result;
            processData(csvData);
        };

        reader.readAsText(file);
    } else {
        alert( Bitte eine CSV-Datei auswählen. );
    }
}

function handleDrop(event) {
    event.preventDefault();
    const file = event.dataTransfer.files[0];
    handleFile(file);
}

function handleDragOver(event) {
    event.preventDefault();
}

function showPreviousData() {
    if (startIndex - displayCount >= 0) {
        startIndex -= displayCount;
        updateChart();
    }
}

function showNextData() {
    if (startIndex + displayCount < labels.length) {
        startIndex += displayCount;
        updateChart();
    }
}

function updateChart() {
    const endIndex = Math.min(startIndex + displayCount, labels.length);
    const updatedLabels = labels.slice(startIndex, endIndex);
    const updatedDatasets = datasets.map((dataset, index) => ({
        ...dataset,
        data: dataset.data.slice(startIndex, endIndex),
        hidden: !originalDatasetVisibility[index],
    }));

    window.myChart.data.labels = updatedLabels;
    window.myChart.data.datasets = updatedDatasets;
    window.myChart.options.scales.x.min = updatedLabels[0];
    window.myChart.options.scales.x.max = updatedLabels[updatedLabels.length - 1];

    window.myChart.update();
}

function removeZoomEventListener() {
    window.myChart.ctx.canvas.removeEventListener( wheel , handleZoom);
}

问题回答

但这取决于您的使用情况、数据如何直观、代表的准确度以及需要如何加快。

基本上有两个攻击点: 缩小”数据 保持客户方工作量低

这里所说的是改进业绩的一些捷径:

<><>><>>>>>>

  1. www.chartjs.org/docs/latest/general/ Performance.html

    • on my local high data example (~100MB): "Disable Animations", "Disable Point Drawing", "Enable spanGaps" and "Specify min and max for scales" drastically improved the performance, just to name a few. (but you will have to tweak the options, for optimal speed and visual appeal)

    Image 1: Minor tweaks ~ 70 Sec (5255999 data rows) No Scales ~ 70 Seconds

    Image 2: Minor tweaks + fixed Scaling ~ 3 Sec (5255999 data rows) Some scale adjustments ~ 4 Sec

  2. 编制数据供轻使用

    • send parsed and sorted json data instead of csv, that you manually parse on the client side. (the file might be bigger, but chartjs won t need to reparse and normalize the data on the clientside)
    • aggregate / pre-calcuate / clean data before you send it to the user.
  3. 您可以装上少量数据,并作为总重装数据,并更新图表数据,checkout这一最新图表

On the Data/Web side

  1. First of all analyze your data
    • do you have to send all the columns, for one single chart? If not remove unneeded columns and rows.
    • As seen in the images above, chartjs "hides" some values to fit the chart on the canvas, if you know this, just send "visible" values.
  2. If not 100% accuracy is needed, remove some rows and let chartjs fillin the gaps.
  3. Just send data for the max resolution needed, split the data into multiple files. Especially if you only need a subset for a specific data-resolution and/or if the data is used in different charts.
  4. load the data async, and when it is loaded display is.

Bonus Tipp: if you don t have to use chartjs check out this SO question/answer here, it recommends using Highcharts for bigdata instead of chartjs.

在撰写我最后一份答复之后,我试图优化你的(隆重)代码。

  1. the upload is only on the clientside
  2. And probably the main issue (without knowing your data) is the parsing of the csv data. (with my test dataset it takes > 8 sec, just to parse the csv-file, the chart rendering is "fast")

<><>>>> 令人痛心的是,我最后的回答对你的具体案例并不有用,因此,这里是一个更有针对性的解决办法。

www.un.org/Depts/DGACM/index_spanish.htm 因此,解决办法可以是。

  1. If you can define the file upload format, try to make it a json file that can be used right away, with JSON.parse or so.
  2. If it has to be csv file, maybe you can change the structure, simply transpose the data, so that you don t have to iterate so many times over it. (one line/row is one dataset, so to speak)
  3. If all that is not possible, and you need to use that file-type and structure, you could rewrite your for -loops to something like this:
function processData(csvData) {
    const colors = [  rgba(255, 0, 0, 1) ,  rgba(0, 255, 0, 1) ,
         rgba(255, 255, 0, 1) ,  rgba(0, 0, 255, 1)  ];
    const rows = csvData.split( 
 );
    const columns = rows[0].split( ; );
    labels = [];
    originalDatasetVisibility =  1 .repeat(columns.length - 1).split(  );
    datasets =  1 .repeat(columns.length - 1).split(  ).map( (x, idx) => ({
            data: [],
            backgroundColor: colors[idx],
            borderColor: colors[idx],
            fill: false,
            borderWidth: 1,
            pointRadius: 0,  // minor performance tweak
            spanGaps: true,  // minor performance tweak
        })
    );
    for (let rowIdx = 1; rowIdx < rows.length; rowIdx++){
        let cols = rows[rowIdx].split( ; );
        for(let colIdx = 1; colIdx < cols.length; colIdx++){
            if (colIdx === 1) {
                labels.push(cols[0]);
            }
            datasets[colIdx - 1].label = columns[colIdx];
            datasets[colIdx - 1].data.push(cols[colIdx]);
        }
    }
    createChart(labels.slice(startIndex, startIndex + displayCount), datasets,
        () => console.log( Diagramm wurde erstellt )
    );
}

由于在最初的法典中,split功能称为cols x rows<>_em>(就我的情况而言,1279995次),而且“成本”操作量相当高,因此仅仅改动了休息室的顺序可改善 >:time-to-render<>;8 sec to < 3 sec (用于我的数据测试)

如果你想投入更多的时间,或许还要做最优化的工作,但这对我来说是一个突出的问题。

Here the result chart of my dataset:
Screenshot test dataset





相关问题
CSS working only in Firefox

I am trying to create a search text-field like on the Apple website. The HTML looks like this: <div class="frm-search"> <div> <input class="btn" type="image" src="http://www....

image changed but appears the same in browser

I m writing a php script to crop an image. The script overwrites the old image with the new one, but when I reload the page (which is supposed to pickup the new image) I still see the old one. ...

Firefox background image horizontal centering oddity

I am building some basic HTML code for a CMS. One of the page-related options in the CMS is "background image" and "stretch page width / height to background image width / height." so that with large ...

Separator line in ASP.NET

I d like to add a simple separator line in an aspx web form. Does anyone know how? It sounds easy enough, but still I can t manage to find how to do it.. 10x!