var TOTAL_POINTS = 500000

function generateData(count) {
  var data = new Array(count)
  var startTime = new Date('2010-01-01T00:00:00Z').getTime()
  var step = 60 * 1000 // 1 minute
  var y = 100
  for (var i = 0; i < count; i++) {
    // Random walk with periodic components — gives visible structure at
    // multiple zoom levels (slow trend + faster cycle + noise).
    y +=
      (Math.random() - 0.5) * 2 +
      Math.sin(i / 5000) * 0.05 +
      Math.cos(i / 1200) * 0.02
    data[i] = [startTime + i * step, +y.toFixed(3)]
  }
  return data
}

var seriesData = generateData(TOTAL_POINTS)
var lastRenderMs = 0
var lastZoomLabel = 'full range'

function fmt(ts) {
  var d = new Date(ts)
  return (
    d.getFullYear() +
    '-' +
    String(d.getMonth() + 1).padStart(2, '0') +
    '-' +
    String(d.getDate()).padStart(2, '0')
  )
}

// Accepts the live chart instance as an argument so the React and Vue builds
// (which have no global `chart` var) can share this stateless helper.
function updateStats(chart) {
  var statsEl = document.getElementById('stats')
  if (!statsEl || !chart || !chart.w) return
  var drawn = (chart.w.globals.series[0] || []).length
  statsEl.innerHTML =
    'Raw points: <b>' +
    TOTAL_POINTS.toLocaleString() +
    '</b> &nbsp;·&nbsp; Currently drawn: <b>' +
    drawn.toLocaleString() +
    '</b> &nbsp;·&nbsp; Window: <b>' +
    lastZoomLabel +
    '</b> &nbsp;·&nbsp; Render: <b>' +
    lastRenderMs +
    ' ms</b>'
}

var options = {
  series: [{ name: 'Sensor reading', data: seriesData }],
  chart: {
    height: 460,
    type: 'line',
    animations: { enabled: false },
    zoom: { enabled: true, type: 'x', autoScaleYaxis: true },
    toolbar: { autoSelected: 'zoom' },
    dataReducer: {
      enabled: true,
      algorithm: 'lttb',
      targetPoints: 500,
      threshold: 1000,
    },
    events: {
      zoomed: function (chartCtx, args) {
        var xaxis = args && args.xaxis
        lastZoomLabel =
          xaxis && xaxis.min && xaxis.max
            ? fmt(xaxis.min) + ' → ' + fmt(xaxis.max)
            : 'full range'
        requestAnimationFrame(function () {
          updateStats(chartCtx)
        })
      },
      beforeResetZoom: function () {
        lastZoomLabel = 'full range'
      },
    },
  },
  stroke: { curve: 'straight', width: 1 },
  dataLabels: { enabled: false },
  markers: { size: 0 },
  title: {
    text: 'Line chart — 500,000 raw datapoints',
    align: 'left',
  },
  subtitle: {
    text: 'LTTB downsampling enabled — zoom in to re-sample the raw series at higher resolution within the visible window',
    align: 'left',
  },
  xaxis: {
    type: 'datetime',
    labels: { datetimeUTC: false },
  },
  yaxis: {
    labels: {
      formatter: function (val) {
        return val.toFixed(2)
      },
    },
  },
  tooltip: { x: { format: 'yyyy-MM-dd HH:mm' } },
}

var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()

// Initial render is started by the template above; wait one frame and update
// stats once the chart instance has finished its first paint.
requestAnimationFrame(function poll() {
  if (chart.w && chart.w.globals && chart.w.globals.series) {
    updateStats(chart)
  } else {
    requestAnimationFrame(poll)
  }
})

function rebuild() {
  var enabled = document.getElementById('toggleReducer').checked
  var targetPoints = parseInt(document.getElementById('targetPoints').value, 10)

  options.chart.dataReducer.enabled = enabled
  options.chart.dataReducer.targetPoints = targetPoints
  options.subtitle.text = enabled
    ? 'LTTB downsampling enabled — drawing ~' +
      targetPoints.toLocaleString() +
      ' points'
    : 'Downsampling disabled — drawing every raw point'

  var t2 = performance.now()
  chart.destroy()
  chart = new ApexCharts(document.querySelector('#chart'), options)
  chart.render().then(function () {
    lastRenderMs = Math.round(performance.now() - t2)
    updateStats(chart)
  })
}

document.getElementById('rerender').addEventListener('click', rebuild)
document.getElementById('toggleReducer').addEventListener('change', rebuild)
document.getElementById('resetZoom').addEventListener('click', function () {
  if (chart) chart.resetSeries(true, true)
})
Large Dataset Downsampling - JavaScript Line Charts | ApexCharts.js | ApexCharts.js