|  | function calculatePadding(datasets, yValueColumnIndices, belowPaddingPercentage = 0.1, abovePaddingPercentage = 0.1) { | 
        
          |  | // Flatten all y-values across specified column indices into a single array, parsing them as floats | 
        
          |  | const datasetValues = datasets.flatMap(dataset => | 
        
          |  | yValueColumnIndices.map(index => parseFloat(Object.values(dataset)[index])).filter(value => !isNaN(value)) | 
        
          |  | ); | 
        
          |  |  | 
        
          |  | const minValue = Math.min(...datasetValues); | 
        
          |  | const maxValue = Math.max(...datasetValues); | 
        
          |  |  | 
        
          |  | // Calc range | 
        
          |  | const range = maxValue - minValue; | 
        
          |  |  | 
        
          |  | // Cal padding | 
        
          |  | const belowPadding = range * belowPaddingPercentage; | 
        
          |  | const abovePadding = range * abovePaddingPercentage; | 
        
          |  |  | 
        
          |  | return { | 
        
          |  | minPadding: minValue - belowPadding, | 
        
          |  | maxPadding: maxValue + abovePadding | 
        
          |  | }; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | module.exports = (data, headers, elem) => { | 
        
          |  | const ctx = api.$container.find(elem)[0].getContext("2d"); | 
        
          |  | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); | 
        
          |  |  | 
        
          |  | const totalColumns = Object.values(data[0]).length; | 
        
          |  | const yValueColumnIndices = Array.from({ length: totalColumns - 1 }, (_, i) => i + 1); | 
        
          |  |  | 
        
          |  | const padding = calculatePadding(data, yValueColumnIndices); | 
        
          |  |  | 
        
          |  | const datasets = headers.slice(1).map((header, index) => ({ | 
        
          |  | label: header, | 
        
          |  | data: data.map(item => ({ | 
        
          |  | t: item[headers[0]], // First header is the x-value | 
        
          |  | y: parseFloat(item[header]) // Convert y-values to float | 
        
          |  | })), | 
        
          |  | fill: false, | 
        
          |  | borderColor: `hsl(${360 * index / headers.length}, 70%, 50%)`, // Example color generation | 
        
          |  | lineTension: 0.01 | 
        
          |  | })); | 
        
          |  |  | 
        
          |  | const myLineChart = new Chart(ctx, { | 
        
          |  | type: 'line', | 
        
          |  | data: { datasets }, | 
        
          |  | options: { | 
        
          |  | plugins: { | 
        
          |  | datalabels: { | 
        
          |  | display: false | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | scales: { | 
        
          |  | yAxes: [{ | 
        
          |  | ticks: { | 
        
          |  | suggestedMin: padding.minPadding, | 
        
          |  | suggestedMax: padding.maxPadding, | 
        
          |  | autoSkip: true, | 
        
          |  | autoSkipPadding: 20 | 
        
          |  | } | 
        
          |  | }], | 
        
          |  | xAxes: [{ | 
        
          |  | type: 'time', | 
        
          |  | time: { | 
        
          |  | tooltipFormat: 'YYYY-MM-DD HH:mm:ss', | 
        
          |  | displayFormats: { | 
        
          |  | minute: 'YYYY-MM-DD HH:mm', | 
        
          |  | hour: 'YYYY-MM-DD HH:mm', | 
        
          |  | day: 'YYYY-MM-DD' | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | scaleLabel: { | 
        
          |  | display: true, | 
        
          |  | labelString: headers[0] // First header for x-axis label | 
        
          |  | }, | 
        
          |  | ticks: { | 
        
          |  | maxRotation: 90, | 
        
          |  | minRotation: 90, | 
        
          |  | autoSkip: true, | 
        
          |  | autoSkipPadding: 20 | 
        
          |  | } | 
        
          |  | }] | 
        
          |  | }, | 
        
          |  | legend: { | 
        
          |  | display: true | 
        
          |  | }, | 
        
          |  | animation: { | 
        
          |  | duration: 0 // Disable animations | 
        
          |  | } | 
        
          |  | } | 
        
          |  | }); | 
        
          |  | }; |