// A wandering line (numeric x, ~45 points) so there is room to zoom, pan,
// annotate and measure. Randomize regenerates it into a fresh checkpoint.
function randomSeries() {
  var d = []
  var v = 45 + Math.random() * 25
  for (var i = 0; i < 45; i++) {
    v += (Math.random() - 0.5) * 22
    if (v < 8) v = 8
    if (v > 100) v = 100
    d.push([i + 1, Math.round(v)])
  }
  return d
}

var options = {
  series: [{ name: 'Value', data: randomSeries() }],
  chart: {
    height: 400,
    type: 'line',
    id: 'rewind-demo',
    fontFamily: 'Helvetica, Arial, sans-serif',
    animations: { enabled: true },
    // Toolbar on so zoom / pan / reset (and the measure tool) are one click away.
    toolbar: { show: true, autoSelected: 'zoom' },
    zoom: { enabled: true, type: 'x' },
    history: { enabled: true, maxDepth: 50, coalesceMs: 250, keyboard: true },
    // Right-click actions: drop a note, a dashed marker line, or seed the ruler.
    contextMenu: {
      enabled: true,
      line: { text: 'Marker', strokeDashArray: 5, color: '#0EA5E9' },
      items: ['annotate', 'xline', 'yline', 'measure'],
    },
    // Measure ruler + editable / draggable annotations. Both commit checkpoints,
    // so Undo / Redo steps through them alongside data and zoom changes.
    measure: { enabled: true },
    ink: { enabled: true, snap: true },
  },
  colors: ['#0EA5E9'],
  stroke: { width: 2.5, curve: 'smooth' },
  markers: { size: 0, hover: { size: 5 } },
  dataLabels: { enabled: false },
  title: {
    text: 'Undo / redo over data, zoom, annotations, and measurements',
    align: 'left',
  },
  xaxis: { type: 'numeric', title: { text: 'Session' }, tickAmount: 10 },
  yaxis: { decimalsInFloat: 0 },
  grid: { borderColor: '#eceff5' },
}

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

var undoBtn = document.getElementById('undo')
var redoBtn = document.getElementById('redo')
var readout = document.getElementById('readout')

function syncButtons(state) {
  if (!state) state = chart.history.state()
  undoBtn.disabled = !state.canUndo
  redoBtn.disabled = !state.canRedo
  readout.innerHTML =
    'history: <b>' +
    (state.index + 1) +
    ' / ' +
    state.length +
    '</b> checkpoints'
}

chart.addEventListener('historyChange', function (c, state) {
  syncButtons(state && state.length != null ? state : undefined)
})

undoBtn.addEventListener('click', function () {
  chart.history.undo()
})
redoBtn.addEventListener('click', function () {
  chart.history.redo()
})
document.getElementById('randomize').addEventListener('click', function () {
  chart.updateSeries([{ name: 'Value', data: randomSeries() }])
})
document.getElementById('reset').addEventListener('click', function () {
  chart.history.clear()
})

// initial state once the baseline checkpoint lands
setTimeout(syncButtons, 300)
Undo / Redo (Rewind) - JavaScript Narrative & State | ApexCharts.js | ApexCharts.js