// 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)