Close Editor Run Reset Auto Update CJS const lcjs = require('@lightningchart/lcjs')
const { createProgressiveTraceGenerator } = require('@lightningchart/xydata')
const { lightningChart, synchronizeAxisIntervals, Themes, emptyLine, AxisPosition, SolidFill } = lcjs
const channelCount = 8
const channelHeight = 240
const exampleContainer = document.getElementById('chart') || document.body
exampleContainer.style.display = 'grid'
const scrollContainer = document.createElement('div')
scrollContainer.style.cssText = `
grid-area: 1 / 1;
overflow-y: auto;
`
exampleContainer.append(scrollContainer)
const chartContainer = document.createElement('div')
chartContainer.style.height = `${channelCount * channelHeight}px`
scrollContainer.append(chartContainer)
const stickyContainer = document.createElement('div')
stickyContainer.style.cssText = `
grid-area: 1 / 1;
align-self: end;
overflow: hidden;
`
exampleContainer.append(stickyContainer)
const lc = lightningChart()
const chart = lc
.ChartXY({
container: chartContainer,
legend: { visible: false },
// theme: Themes.darkGold,
})
.setTitle('')
const themeBackgroundFill = chart.getTheme().chartXYSeriesBackgroundFillStyle
const themeBackgroundColor =
typeof themeBackgroundFill.getColor === 'function'
? themeBackgroundFill.getColor()
: themeBackgroundFill.getColorStops()[themeBackgroundFill.getColorStops().length - 1].color
const backgroundFill = new SolidFill({ color: themeBackgroundColor.setA(255) })
chart.setBackgroundFillStyle(backgroundFill).setSeriesBackgroundFillStyle(backgroundFill)
chart.axisY.dispose()
for (let i = 0; i < channelCount; i += 1) {
const axisY = chart.addAxisY({
iStack: -chart.getAxes(AxisPosition.Left).length,
})
const series = chart.addLineSeries({
axisY,
schema: {
x: { pattern: 'progressive' },
y: { pattern: null },
},
})
createProgressiveTraceGenerator()
.setNumberOfPoints(1000)
.generate()
.toPromise()
.then((data) => {
series.appendJSON(data, {
start: performance.timeOrigin,
step: 60 * 1000,
})
})
}
// A second chart containing only an X-axis acts as the sticky overlay
const stickyChart = lc
.ChartXY({
container: stickyContainer,
legend: { visible: false },
// theme: Themes.darkGold,
})
.setTitle('')
.setBackgroundFillStyle(backgroundFill)
.setSeriesBackgroundFillStyle(backgroundFill)
.setSeriesBackgroundStrokeStyle(emptyLine)
stickyChart.axisY.dispose()
synchronizeAxisIntervals(chart.axisX, stickyChart.axisX)
// Match the sticky overlay with the real X-axis layout
chart.addEventListener('layoutchange', (event) => {
const axisLayout = event.axes.get(chart.axisX)
if (!axisLayout) return
const height = Math.ceil(event.chartHeight - axisLayout.top)
if (stickyContainer.clientHeight !== height) {
stickyContainer.style.height = `${height}px`
}
if (stickyContainer.clientWidth !== event.chartWidth) {
stickyContainer.style.width = `${event.chartWidth}px`
}
stickyChart.setPadding({
left: event.margins.left,
right: event.margins.right,
})
stickyChart.engine.layout()
})
// Show the overlay until the real X-axis enters the viewport
const updateStickyAxis = () => {
const distanceFromBottom = scrollContainer.scrollHeight - scrollContainer.scrollTop - scrollContainer.clientHeight
stickyContainer.style.visibility = distanceFromBottom > 1 ? 'visible' : 'hidden'
}
scrollContainer.addEventListener('scroll', updateStickyAxis)
updateStickyAxis()
JavaScript Chart with Sticky X-Axis - Editor This example shows how to keep a shared X-axis visible while scrolling vertically through a multi-channel chart in scrollable container.
A second ChartXY, containing only an X-axis, is placed over the bottom of the scrolling container. Its interval is synchronized with the main chart, while the layoutchange event keeps its size and padding aligned with the real X-axis. The overlay is hidden when the real axis enters the viewport.