Close Editor Run Reset Auto Update CJS /*
* LightningChartJS example for rendering a 'Mesh Circle'.
*/
// Import LightningChartJS
const lcjs = require('@lightningchart/lcjs')
// Import xydata
const xydata = require('@lightningchart/xydata')
// Extract required parts from LightningChartJS.
const {
lightningChart,
OnScreenMenuButtonType,
OnScreenMenuButtonShape,
ColorRGBA,
SolidFill,
PointShape,
SolidLine,
Themes,
emptyFill,
emptyLine,
} = lcjs
const { createProgressiveTraceGenerator, createProgressiveRandomGenerator } = xydata
// NOTE: Using `Dashboard` is no longer recommended for new applications. Find latest recommendations here: https://lightningchart.com/js-charts/docs/more-guides/grouping-charts/
const dashboard = lightningChart().Dashboard({
numberOfColumns: 1,
numberOfRows: 3,
// theme: Themes.darkGold
})
// Add XY Chart to top Cell in Dashboard.
const chart = dashboard
.createChartXY({
columnIndex: 0,
columnSpan: 1,
rowIndex: 0,
rowSpan: 2,
legend: { visible: false },
})
.setCursorMode('show-all-interpolated')
const axisX = chart.getDefaultAxisX().setInterval({
start: 0,
end: 100,
})
// Add Zoom Band Chart to bottom Cell in Dashboard.
const zoomBandChart = dashboard.createZoomBandChart({
columnIndex: 0,
rowIndex: 2,
})
// Add LineSeries to the XY Chart.
const line = chart.addLineSeries()
// Styles for 2nd LineSeries
const customStrokeStyle = new SolidLine({
fillStyle: new SolidFill({ color: ColorRGBA(200, 50, 50) }),
thickness: 2,
})
// Add 2nd LineSeries to the XY Chart.
const line2 = chart.addLineSeries({}).setStrokeStyle(customStrokeStyle)
// Add PointSeries to the XY Chart.
const point = chart
.addPointSeries({})
.setPointFillStyle(new SolidFill({ color: ColorRGBA(180, 180, 180) }))
.setPointSize(10)
zoomBandChart.add(line)
zoomBandChart.add(line2)
zoomBandChart.add(point)
// Array that keeps data of 1st line series
const arr1 = []
// Flag that dispose or restore PointSeries
let checked = false
// Data of point coordinates
let prevPoint
// Fill the Line Series with arbitrary data.
createProgressiveTraceGenerator()
.setNumberOfPoints(250)
.generate()
.toPromise()
.then((data) => {
arr1.push(...data)
line.appendJSON(data)
})
// Stream some random data.
createProgressiveRandomGenerator()
.setNumberOfPoints(250)
.generate()
.setStreamBatchSize(1)
.setStreamInterval(50)
.setStreamRepeat(false)
.toStream()
.forEach((point) => {
const y = point.y * (Math.random() * 20) - 10
line2.appendSample({ x: point.x, y })
// check intersection of line series
getIntersection({ x: point.x, y })
if (point.x > 50 && point.x < 200) {
const oldInterval = axisX.getInterval()
axisX.setInterval({
start: oldInterval.start + 1,
end: oldInterval.end + 1,
})
}
})
// Add On-Screen menu
chart.addOnScreenMenu(
[
[
// Default buttons
OnScreenMenuButtonType.ZoomInX,
OnScreenMenuButtonType.ZoomOutX,
OnScreenMenuButtonType.ZoomInY,
OnScreenMenuButtonType.ZoomOutY,
OnScreenMenuButtonType.ZoomToFit,
OnScreenMenuButtonType.ToggleAnimations,
// Custom button
{
icon: new URL(document.head.baseURI).origin + new URL(document.head.baseURI).pathname + 'examples/assets/0706/icon.png',
dimensions: { rows: 1, columns: 1 },
opacity: '0.8',
color: 'blue',
shape: OnScreenMenuButtonShape.RoundedRectangle,
action: show,
},
],
],
OnScreenMenuButtonShape.RoundedRectangle,
)
// Function for actions of Custom On Screen Menu Button
function show() {
if (!checked) {
point.setVisible(false)
} else {
point.setVisible(true)
}
checked == false ? (checked = true) : (checked = false)
}
function getIntersection(currPoint) {
// Index of last generated point
const index = currPoint.x
if (currPoint.x > 0) {
// Check if lines were intersected
if (
(currPoint.y > arr1[index].y && prevPoint.y < arr1[index - 1].y) ||
(currPoint.y < arr1[index].y && prevPoint.y > arr1[index - 1].y)
) {
// Find point of intersection
const interSectionPoint = calculateIntersection(currPoint, prevPoint, arr1[index], arr1[index - 1])
point.appendSample(interSectionPoint)
}
// Reassign curr point as prev. point
prevPoint = currPoint
} else {
// Assign curr point as prev. point
prevPoint = currPoint
}
}
// The explanation of formula can be found in the description below
function calculateIntersection(currPoint1, prevPoint1, currPoint2, prevPoint2) {
// Expressions of numerator
const exp1 = currPoint1.x * prevPoint1.y - currPoint1.y * prevPoint1.x
const exp2 = currPoint2.x * prevPoint2.y - currPoint2.y * prevPoint2.x
const exp3 = currPoint2.x - prevPoint2.x
const exp4 = currPoint1.x - prevPoint1.x
const exp5 = currPoint2.y - prevPoint2.y
const exp6 = currPoint1.y - prevPoint1.y
// Denominator
const d1 = (currPoint1.x - prevPoint1.x) * (currPoint2.y - prevPoint2.y)
const d2 = (currPoint1.y - prevPoint1.y) * (currPoint2.x - prevPoint2.x)
const d = d1 - d2
if (d === 0) {
throw new Error('Number of intersection points is zero or infinity.')
}
const px = (exp1 * exp3 - exp4 * exp2) / d
const py = (exp1 * exp5 - exp6 * exp2) / d
const p = { x: px, y: py }
// Return point
return p
}
JavaScript On Screen Menu - Editor Example showcasing the use of On Screen Menu.
On-Screen Menu (OSM) is part of UI that can be used to simplify interaction with charts. In this case the default buttons are used along with a custom button that shows/hides the intersection points of lines.
The On-Screen menu can be added this way:
const chart = lightningChart ( ) . ChartXY ( )
chart. addOnScreenMenu (
[
[
OnScreenMenuButtonType. ZoomInX,
OnScreenMenuButtonType. ZoomOutX,
OnScreenMenuButtonType. ZoomInY,
OnScreenMenuButtonType. ZoomOutY,
OnScreenMenuButtonType. ZoomToFit,
OnScreenMenuButtonType. ToggleAnimations,
] ,
] ,
OnScreenMenuButtonShape. RoundedRectangle,
) To add a custom button parameters must be defined.
const chart = lightningChart ( ) . ChartXY ( )
chart. addOnScreenMenu ( [
[
{
icon: new URL ( document. head. baseURI) . origin + new URL ( document. head. baseURI) . pathname + 'examples/assets/9999/icon.png' ,
dimensions: { rows: 1 , columns: 1 } ,
label: '' ,
opacity: '0.8' ,
color: 'blue' ,
shape: OnScreenMenuButtonShape. RoundedRectangle,
action: show,
} ,
] ,
] ) 'addOnScreenMenu' takes an array of arrays as a parameter. Each sub array adds a new line on the OSM menu.
const chart = lightningChart ( ) . ChartXY ( )
chart. addOnScreenMenu ( [
[
OnScreenMenuButtonType. ZoomInX,
OnScreenMenuButtonType. ZoomOutX,
OnScreenMenuButtonType. ZoomInY,
OnScreenMenuButtonType. ZoomOutY,
OnScreenMenuButtonType. ZoomIn,
OnScreenMenuButtonType. ZoomOut,
] ,
[ OnScreenMenuButtonType. ZoomToFit, OnScreenMenuButtonType. ToggleAnimations] ,
[
{
icon: new URL ( document. head. baseURI) . origin + new URL ( document. head. baseURI) . pathname + 'examples/assets/9999/icon.png' ,
dimensions: { rows: 1 , columns: 1 } ,
opacity: '0.8' ,
color: 'blue' ,
shape: OnScreenMenuButtonShape. RoundedRectangle,
action: show,
} ,
] ,
] ) Formula of lines intersection
function calculateIntersection ( currPoint1, prevPoint1, currPoint2, prevPoint2 ) {
const exp1 = currPoint1. x * prevPoint1. y - currPoint1. y * prevPoint1. x
const exp2 = currPoint2. x * prevPoint2. y - currPoint2. y * prevPoint2. x
const exp3 = currPoint2. x - prevPoint2. x
const exp4 = currPoint1. x - prevPoint1. x
const exp5 = currPoint2. y - prevPoint2. y
const exp6 = currPoint1. y - prevPoint1. y
const d1 = ( currPoint1. x - prevPoint1. x) * ( currPoint2. y - prevPoint2. y)
const d2 = ( currPoint1. y - prevPoint1. y) * ( currPoint2. x - prevPoint2. x)
const d = d1 - d2
if ( d === 0 ) {
throw new Error ( 'Number of intersection points is zero or infinity.' )
}
const px = ( exp1 * exp3 - exp4 * exp2) / d
const py = ( exp1 * exp5 - exp6 * exp2) / d
const p = { x: px, y: py }
return p
}