Select points in line series - lightningchart

I'd like to use a modifier key with the left mouse button that will select the data inside the rectangle, rather than the zoom to that data. Is this possible? I cannot find a suitable API for it. Bonus points if there's a way to select data that falls inside a polygon (like a lasso tool).

Here's one example of completely custom ChartXY interactions.
Key points:
Default rectangle fit & zoom interactions are disabled.
Line series data is cached to a variable which can be used for custom statistics.
RectangleSeries is used for visualizing drag area on chart.
UI elements are used for displaying statistics of selected area.
ChartXY.onSeriesBackgroundMouseDrag event is used for hooking custom actions to user interactions.
Below you'll find a code snippet where dragging with left mouse button creates a rectangular area which shows highlighted X area and solved Y data range within.
Releasing the mouse button results in the full selected data points array being solved (length is logged to console).
const {
Point,
ColorRGBA,
SolidFill,
RadialGradientFill,
SolidLine,
translatePoint,
lightningChart,
UIOrigins,
UIElementBuilders,
UILayoutBuilders,
emptyFill
} = lcjs;
const { createProgressiveTraceGenerator } = xydata;
const chart = lightningChart()
.ChartXY()
// Disable default chart interactions with left mouse button.
.setMouseInteractionRectangleFit(false)
.setMouseInteractionRectangleZoom(false)
.setTitleFillStyle(emptyFill)
const axisX = chart.getDefaultAxisX()
const axisY = chart.getDefaultAxisY()
const lineSeries = chart.addLineSeries({
dataPattern: {
pattern: 'ProgressiveX',
},
})
// Generate test data set.
let dataSet
createProgressiveTraceGenerator()
.setNumberOfPoints(10 * 1000)
.generate()
.toPromise()
.then((data) => {
// Cache data set for analytics logic + add static data to series.
dataSet = data
lineSeries.add(data)
})
// Rectangle Series is used to display data selection area.
const rectangleSeries = chart.addRectangleSeries()
const rectangle = rectangleSeries
.add({ x1: 0, y1: 0, x2: 0, y2: 0 })
.setFillStyle(
new RadialGradientFill({
stops: [
{ offset: 0, color: ColorRGBA(255, 255, 255, 30) },
{ offset: 1, color: ColorRGBA(255, 255, 255, 60) },
],
}),
)
.setStrokeStyle(
new SolidLine({
thickness: 2,
fillStyle: new SolidFill({ color: ColorRGBA(255, 255, 255, 255) }),
}),
)
.dispose()
// UI elements are used to display information about the selected data points.
const uiInformationLayout = chart.addUIElement(UILayoutBuilders.Column, { x: axisX, y: axisY }).dispose()
const uiLabel0 = uiInformationLayout.addElement(UIElementBuilders.TextBox)
const uiLabel1 = uiInformationLayout.addElement(UIElementBuilders.TextBox)
// Add events for custom interactions.
chart.onSeriesBackgroundMouseDrag((_, event, button, startLocation) => {
// If not left mouse button, don't do anything.
if (button !== 0) return
// Translate start location and current location to axis coordinates.
const startLocationAxis = translatePoint(
chart.engine.clientLocation2Engine(startLocation.x, startLocation.y),
chart.engine.scale,
lineSeries.scale,
)
const curLocationAxis = translatePoint(
chart.engine.clientLocation2Engine(event.clientX, event.clientY),
chart.engine.scale,
lineSeries.scale,
)
// Place Rectangle figure between start location and current location.
rectangle.restore().setDimensions({
x1: startLocationAxis.x,
y1: startLocationAxis.y,
x2: curLocationAxis.x,
y2: curLocationAxis.y,
})
// * Gather analytics from actively selected data *
const xStart = Math.min(startLocationAxis.x, curLocationAxis.x)
const xEnd = Math.max(startLocationAxis.x, curLocationAxis.x)
// Selected Y range has to be solved from data set.
// NOTE: For top solve performance, results should be cached and only changes from previous selection area should be checked.
const { yMin, yMax } = solveDataRangeY(xStart, xEnd)
// Set UI labels text.
uiLabel0.setText(`X: [${xStart.toFixed(0)}, ${xEnd.toFixed(0)}]`)
uiLabel1.setText(`Y: [${yMin.toFixed(1)}, ${yMax.toFixed(1)}]`)
// Place UI layout above Rectangle.
uiInformationLayout
.restore()
.setOrigin(UIOrigins.LeftBottom)
.setPosition({ x: xStart, y: Math.max(startLocationAxis.y, curLocationAxis.y) })
})
chart.onSeriesBackgroundMouseDragStop((_, event, button, startLocation) => {
// If not left mouse button, don't do anything.
if (button !== 0) return
// Translate start location and current location to axis coordinates.
const startLocationAxis = translatePoint(
chart.engine.clientLocation2Engine(startLocation.x, startLocation.y),
chart.engine.scale,
lineSeries.scale,
)
const curLocationAxis = translatePoint(
chart.engine.clientLocation2Engine(event.clientX, event.clientY),
chart.engine.scale,
lineSeries.scale,
)
// Print selected data points to console.
const xStart = Math.max(0, Math.floor(Math.min(startLocationAxis.x, curLocationAxis.x)))
const xEnd = Math.min(dataSet.length - 1, Math.ceil(Math.max(startLocationAxis.x, curLocationAxis.x)))
const selectedDataPoints = dataSet.slice(xStart, xEnd)
console.log(`Selected ${selectedDataPoints.length} data points.`)
// Hide visuals.
rectangle.dispose()
uiInformationLayout.dispose()
})
// Logic for solving Y data range between supplied X range from active data set.
const solveDataRangeY = (xStart, xEnd) => {
// Reduce Y data min and max values within specified X range from data set.
// Note, this can be very heavy for large data sets - repeative calls should be avoided as much as possible for best performance.
let yMin = Number.MAX_SAFE_INTEGER
let yMax = -Number.MAX_SAFE_INTEGER
xStart = Math.max(0, Math.floor(xStart))
xEnd = Math.min(dataSet.length - 1, Math.ceil(xEnd))
for (let iX = xStart; iX < xEnd; iX += 1) {
const y = dataSet[iX].y
yMin = y < yMin ? y : yMin
yMax = y > yMax ? y : yMax
}
return { yMin, yMax }
}
<script src="https://unpkg.com/#arction/xydata#1.4.0/dist/xydata.iife.js"></script>
<script src="https://unpkg.com/#arction/lcjs#3.0.0/dist/lcjs.iife.js"></script>
There's many different directions to go with this kind of custom interactions, and while we can't cover every single one with an example, most of the logic should stay the same.

Related

How to Mark a Lightningchart Cell

How to mark a LightningChart cell like this?
RectangleSeries allows drawing rectangles inside the series area. At first glance this would sound to match your requirement.
However, if your intention is to align the rectangle to the gridlines, then this probably doesn't help much. In this case, I would like to learn more about your use case before drilling further.
const { lightningChart, SolidFill, ColorRGBA } = lcjs
const chart = lightningChart().ChartXY({ disableAnimations: true })
.setTitle('')
const series = chart.addLineSeries({
dataPattern: {
pattern: 'ProgressiveX',
regularProgressiveStep: true,
},
})
series.addArrayY([0,100,50,40,70,10,90])
chart.addLegendBox().add(chart)
//
const rectangleSeries = chart.addRectangleSeries()
const rectangleFigure = rectangleSeries.add({ x1: 1.5, x2: 2, y1: 20, y2: 40 })
.setFillStyle(new SolidFill({ color: ColorRGBA(255, 0, 0) }))
<script src="https://unpkg.com/#arction/lcjs#3.4.0/dist/lcjs.iife.js"></script>

Increase size of one of the series in R highchart

I'm trying to show a line and % changes in a single highchart plot, but the changes are very little and It can't be seen in the plot. I made a simplified code to show my problem:
a <- c(300,200, 400, 10, 40, 80)
b <- c(0.8, 2, -2, -1.5, -1.1, 2)
d<-cbind(a,b)
dt <- seq(as.Date("2018-01-01"), as.Date("2018-01-06"), by = "days")
ts <- xts(d, dt )
highchart(type="stock") %>%
hc_add_series(ts$a,
type = "line",
color="black") %>%
hc_add_series(ts$b,
type = "lollipop",
color="red")
I need to increase the size of "ts$b" in the plot, how can I do it? I also tried with two axis, but It seems doesn't solve the problem.
I see two solutions to achieve that.
The first you mentioned - using two yAxis and manipulating their height and top distance.
Example JS code:
yAxis: [{
height: '90%',
opposite: false
},
{
visible: false,
top: '83%',
height: '15%',
}
]
Demo:
https://jsfiddle.net/BlackLabel/0826r7sh/
Another way is using a modified logarithmic axis. Negative values can't be plotted on a log axis, because by nature, the axis will only show positive values. In that case you need to use a custom extension according to the following thread:
Highcharts negative logarithmic scale solution stopped working
(function(H) {
H.addEvent(H.Axis, 'afterInit', function() {
const logarithmic = this.logarithmic;
if (logarithmic && this.options.custom.allowNegativeLog) {
// Avoid errors on negative numbers on a log axis
this.positiveValuesOnly = false;
// Override the converter functions
logarithmic.log2lin = num => {
const isNegative = num < 0;
let adjustedNum = Math.abs(num);
if (adjustedNum < 10) {
adjustedNum += (10 - adjustedNum) / 10;
}
const result = Math.log(adjustedNum) / Math.LN10;
return isNegative ? -result : result;
};
logarithmic.lin2log = num => {
const isNegative = num < 0;
let result = Math.pow(10, Math.abs(num));
if (result < 10) {
result = (10 * (result - 1)) / (10 - 1);
}
return isNegative ? -result : result;
};
}
});
}(Highcharts));
.
yAxis: {
type: 'logarithmic',
custom: {
allowNegativeLog: true
}
},
Demo
https://jsfiddle.net/BlackLabel/nw6osucm/

heatmapGridSeries overlay over line chart

I came Across heatmapGridSeries in lightning chart , I just want to know if this is possible.
Please Check above image , I have lineseries with one axis.. and i want this color bands above the line series with opacity.
For example
if I add value to the heatmapGridSeries from 0 to 100 , it should automatically show orange.. from 100 to 200 it should show green and so on.
Can be done, but shouldn't be a very practical usage case for heatmaps.
Paletted/gradient series background or bands should give nicer results.
Here's a snippet that looks like your picture (without the line series), and also adds a single Band so you can see how they behave a bit differently.
Transparency can be added after R,G,B.
const {
lightningChart,
LUT,
PalettedFill,
ColorRGBA,
emptyLine,
SolidFill,
AxisScrollStrategies,
} = lcjs
const chart = lightningChart().ChartXY()
const line = chart.addLineSeries()
const heatmap = chart.addHeatmapScrollingGridSeries({
scrollDimension: 'columns',
resolution: 1,
step: {
x: 1,
y: 1,
},
})
const transparency = 100
heatmap
.setFillStyle(new PalettedFill({
lut: new LUT({
steps: [
{value: 0, color: ColorRGBA(255,127,39, transparency)},
{value: 1, color: ColorRGBA(181,230,29, transparency)},
{value: 2, color: ColorRGBA(112,146,190, transparency)},
{value: 3, color: ColorRGBA(255,242,0, transparency)},
{value: 4, color: ColorRGBA(237,28,36, transparency)}
]
})
}))
.setPixelInterpolationMode('disabled')
.setWireframeStyle(emptyLine)
chart.getDefaultAxisX().setInterval(-10, 0).setScrollStrategy(AxisScrollStrategies.progressive)
line.add({x:0,y:0})
let x = 1
setInterval(() => {
const y = Math.random()
const p = {x, y}
line.add(p)
const iColor = x % 5
heatmap.addIntensityValues([[iColor]])
x += 1
}, 1000)
<script src="http://unpkg.com/#arction/lcjs#3.1.0/dist/lcjs.iife.js"></script>

Draw lines from one X-axis to another X-axis

I want to draw line from one x-axis to another x-axis , is it possible ?
Right now I can see only constant line is there , but its drawing horizontal line in full page.
const axis = chart.getDefaultAxisX();
const line = axis.addConstantLine(false).setMouseInteractions(false);
Is there any other way to do it like with rectangle ? or do you guys have any plan to do that via constant line in future ?
I have attached example image below
If I have understood your question correctly you want to draw a line from one X axis value to another X axis value on the same axis.
This can be done by using ChartXY.addSegmentSeries(). This series type allows you to draw individual line segments from Point A to Point B. Each segment can be configured individually. See the API Documentation for configuration specifics: https://www.arction.com/lightningchart-js-api-documentation/v3.0.0/classes/segmentfigure.html
To achieve a line from X = 30 to X = 70 you need to first create a new SegmentSeries if you don't already have one.
You can specify the X (or/and Y) axis for the SegmentSeries when creating the series. chart.addSegmentSeries({xAxis: axisX1})
const axisX1 = chart.addAxisX()
// create series
const lineSegment = chart.addSegmentSeries({
xAxis: axisX1
})
// optionally disable cursor and mouse interactions
.setCursorEnabled(false)
.setMouseInteractions(false)
Then you can create a new line on the series
lineSegment.add({
startX: 30,
endX: 70,
startY: 0.2,
endY: 0.2
})
.setStrokeStyle(stroke => stroke.setFillStyle(fill => fill.setColor(ColorHEX('#0f0a'))))
This would create semi-transparent green line from {x: 30, y: 0.2} to {x: 70, y: 0.2}.
You can create as many lines as you need just by calling lineSegment.add() again with new startX/Y and endX/Y values.
Alternatively if you would like to have a rectangle on the chart instead of line you can add a new RectangleSeries. And add a new rectangle on that series.
const axisX2 = chart.addAxisX()
const rectSeries = chart.addRectangleSeries({
xAxis: axisX2
})
.setMouseInteractions(false)
.setCursorEnabled(false)
rectSeries.add({
x1: 30,
x2: 70,
y1: 0.3,
y2: 0.7,
})
.setFillStyle(f => f.setColor(ColorHEX('#f00a')))
See below for a working example with both line and rectangle.
// Extract required parts from LightningChartJS.
const {
lightningChart,
Themes,
UIElementBuilders,
UIBackgrounds,
ColorHEX,
SolidFill
} = lcjs
// Import data-generator from 'xydata'-library.
const {
createProgressiveRandomGenerator
} = xydata
const chart = lightningChart().ChartXY()
const axisX1 = chart.getDefaultAxisX()
const axisX2 = chart.addAxisX()
const axisX3 = chart.addAxisX({
opposite: true
})
const series = chart.addLineSeries()
chart.getDefaultAxisX().setInterval(0, 100, false, true)
chart.getDefaultAxisY().setInterval(0, 1, false, true)
createProgressiveRandomGenerator()
.setNumberOfPoints(100)
.generate()
.toPromise()
.then(data => {
series.add(data)
})
const rectSeries = chart.addRectangleSeries({
xAxis: axisX2
})
.setMouseInteractions(false)
.setCursorEnabled(false)
rectSeries.add({
x1: 30,
x2: 70,
y1: 0.3,
y2: 0.7,
})
.setFillStyle(f => f.setColor(ColorHEX('#f00a')))
const lineSegment = chart.addSegmentSeries({
xAxis: axisX3
})
.setCursorEnabled(false)
.setMouseInteractions(false)
lineSegment.add({
startX: 30,
endX: 70,
startY: 0.2,
endY: 0.2
})
.setStrokeStyle(stroke => stroke.setFillStyle(fill => fill.setColor(ColorHEX('#0f0a'))))
lineSegment.add({
startX: 40,
endX: 90,
startY: 0.2,
endY: 0.1
})
.setStrokeStyle(stroke => stroke.setFillStyle(fill => fill.setColor(ColorHEX('#fffa'))))
<script src="https://unpkg.com/#arction/lcjs#3.0.0/dist/lcjs.iife.js"></script>
<script src="https://unpkg.com/#arction/xydata#1.4.0/dist/xydata.iife.js"></script>
You can use the Axis Band to draw a rectangle which will work similar to the constant line.
const axis = chart.getDefaultAxisX()
const band = axis.addBand()
You can set both the constant line and band to be either on top of all the Series in the chart, or below all Series in the chart, by supplying the onTop: boolean parameter when creating one.
You can set the start and end values of the Band with the Band.setValueStart() and Band.setValueEnd() methods respectively.
For example:
band.setValueStart(100)
band.setValueEnd(200)
This would set the Band cover the range from 100 to 200.
If you have mouse interactions enabled for the band (which is on by default), users can also click and drag the band from its edges to resize it.
The full API documentation for band can be found here.

Get axis value on mouse hover

how do we get X axis value ?
If you see above image , how do we get X axis value if mouse moved over the chart or clicked on anywhere of charts , is there any callback functions ?
You can attach an event handler to chart.onChartBackgroundMouseMove event.
Then you will need to convert the event location to an engine coordinate space. This can be done with publicEngine.engineLocation2Client() method, chart.engine.clientLocation2Engine(ev.clientX, ev.clientY)
The last the is to convert the engine location to a point on a scale. This can be done with translatePoint() function. const onScale = translatePoint(engineLocation, chart.engine.scale, {x: chart.getDefaultAxisX().scale, y: chart.getDefaultAxisY().scale})
chartOHLC.onChartBackgroundMouseMove((obj, ev)=>{
const point = obj.engine.clientLocation2Engine(ev.clientX, ev.clientY)
const onScale = translatePoint(point, obj.engine.scale, {x:obj.getDefaultAxisX().scale, y:obj.getDefaultAxisY().scale})
console.log(onScale)
})
See the snippet below where I log the mouse location on a scale to console.
// Extract required parts from LightningChartJS.
const {
lightningChart,
AxisTickStrategies,
LegendBoxBuilders,
SolidFill,
SolidLine,
emptyLine,
ColorRGBA,
UIOrigins,
Themes,
translatePoint
} = lcjs
// Import data-generator from 'xydata'-library.
const {
createOHLCGenerator,
createProgressiveTraceGenerator
} = xydata
// Create dashboard to house two charts
const db = lightningChart().Dashboard({
// theme: Themes.dark
numberOfRows: 2,
numberOfColumns: 1
})
// Decide on an origin for DateTime axis.
const dateOrigin = new Date(2018, 0, 1)
// Chart that contains the OHLC candle stick series and Bollinger band
const chartOHLC = db.createChartXY({
columnIndex: 0,
rowIndex: 0,
columnSpan: 1,
rowSpan: 1
})
// Use DateTime TickStrategy with custom date origin for X Axis.
chartOHLC
.getDefaultAxisX()
.setTickStrategy(
AxisTickStrategies.DateTime,
(tickStrategy) => tickStrategy.setDateOrigin(dateOrigin)
)
// Modify Chart.
chartOHLC
.setTitle('Trading dashboard')
//Style AutoCursor.
.setAutoCursor(cursor => {
cursor.disposeTickMarkerY()
cursor.setGridStrokeYStyle(emptyLine)
})
.setPadding({
right: 40
})
chartOHLC.onChartBackgroundMouseMove((obj, ev) => {
const point = obj.engine.clientLocation2Engine(ev.clientX, ev.clientY)
const onScale = translatePoint(point, obj.engine.scale, {
x: obj.getDefaultAxisX().scale,
y: obj.getDefaultAxisY().scale
})
console.log(onScale)
})
// The top chart should have 66% of view height allocated to it. By giving the first row a height of 2, the relative
// height of the row becomes 2/3 of the whole view (default value for row height / column width is 1)
db.setRowHeight(0, 2)
// Create a LegendBox for Candle-Stick and Bollinger Band
const legendBoxOHLC = chartOHLC.addLegendBox(LegendBoxBuilders.HorizontalLegendBox)
.setPosition({
x: 100,
y: 100
})
.setOrigin(UIOrigins.RightTop)
// Define function which sets Y axis intervals nicely.
let setViewNicely
// Create OHLC Figures and Area-range.
//#region
// Get Y-axis for series (view is set manually).
const stockAxisY = chartOHLC.getDefaultAxisY()
.setScrollStrategy(undefined)
.setTitle('USD')
// Add series.
const areaRangeFill = new SolidFill().setColor(ColorRGBA(100, 149, 237, 50))
const areaRangeStroke = new SolidLine()
.setFillStyle(new SolidFill().setColor(ColorRGBA(100, 149, 237)))
.setThickness(1)
const areaRange = chartOHLC.addAreaRangeSeries({
yAxis: stockAxisY
})
.setName('Bollinger band')
.setHighFillStyle(areaRangeFill)
.setLowFillStyle(areaRangeFill)
.setHighStrokeStyle(areaRangeStroke)
.setLowStrokeStyle(areaRangeStroke)
.setMouseInteractions(false)
.setCursorEnabled(false)
const stockFigureWidth = 5.0
const borderBlack = new SolidLine().setFillStyle(new SolidFill().setColor(ColorRGBA(0, 0, 0))).setThickness(1.0)
const fillBrightRed = new SolidFill().setColor(ColorRGBA(255, 0, 0))
const fillDimRed = new SolidFill().setColor(ColorRGBA(128, 0, 0))
const fillBrightGreen = new SolidFill().setColor(ColorRGBA(0, 255, 0))
const fillDimGreen = new SolidFill().setColor(ColorRGBA(0, 128, 0))
const stock = chartOHLC.addOHLCSeries({
yAxis: stockAxisY
})
.setName('Candle-Sticks')
// Setting width of figures
.setFigureWidth(stockFigureWidth)
// Styling positive candlestick
.setPositiveStyle(candlestick => candlestick
// Candlestick body fill style
.setBodyFillStyle(fillBrightGreen)
// Candlestick body fill style
.setBodyStrokeStyle(borderBlack)
// Candlestick stroke style
.setStrokeStyle((strokeStyle) => strokeStyle.setFillStyle(fillDimGreen))
)
.setNegativeStyle(candlestick => candlestick
.setBodyFillStyle(fillBrightRed)
.setBodyStrokeStyle(borderBlack)
.setStrokeStyle((strokeStyle) => strokeStyle.setFillStyle(fillDimRed))
)
// Make function that handles adding OHLC segments to series.
const add = (ohlc) => {
// ohlc is equal to [x, open, high, low, close]
stock.add(ohlc)
// AreaRange looks better if it extends a bit further than the actual OHLC values.
const areaOffset = 0.2
areaRange.add({
position: ohlc[0],
high: ohlc[2] - areaOffset,
low: ohlc[3] + areaOffset,
})
}
// Generate some static data.
createOHLCGenerator()
.setNumberOfPoints(100)
.setDataFrequency(24 * 60 * 60 * 1000)
.generate()
.toPromise()
.then(data => {
data.forEach(add)
setViewNicely()
})
//#endregion
// Create volume.
//#region
const chartVolume = db.createChartXY({
columnIndex: 0,
rowIndex: 1,
columnSpan: 1,
rowSpan: 1
})
// Use DateTime TickStrategy with custom date origin for X Axis.
chartVolume
.getDefaultAxisX()
.setTickStrategy(
AxisTickStrategies.DateTime,
(tickStrategy) => tickStrategy.setDateOrigin(dateOrigin)
)
// Modify Chart.
chartVolume
.setTitle('Volume')
.setPadding({
right: 40
})
// Create a LegendBox as part of the chart.
const legendBoxVolume = chartVolume.addLegendBox(LegendBoxBuilders.HorizontalLegendBox)
.setPosition({
x: 100,
y: 100
})
.setOrigin(UIOrigins.RightTop)
// Create Y-axis for series (view is set manually).
const volumeAxisY = chartVolume.getDefaultAxisY()
.setTitle('USD')
// Modify TickStyle to hide gridstrokes.
.setTickStrategy(
// Base TickStrategy that should be styled.
AxisTickStrategies.Numeric,
// Modify the the tickStyles through a mutator.
(tickStrat) => tickStrat
// Modify the Major tickStyle to not render the grid strokes.
.setMajorTickStyle(
tickStyle => tickStyle.setGridStrokeStyle(emptyLine)
)
// Modify the Minor tickStyle to not render the grid strokes.
.setMinorTickStyle(
tickStyle => tickStyle.setGridStrokeStyle(emptyLine)
)
)
const volumeFillStyle = new SolidFill().setColor(ColorRGBA(0, 128, 128, 60))
const volumeStrokeStyle = new SolidLine()
.setFillStyle(volumeFillStyle.setA(255))
.setThickness(1)
const volume = chartVolume.addAreaSeries({
yAxis: volumeAxisY
})
.setName('Volume')
.setFillStyle(volumeFillStyle)
.setStrokeStyle(volumeStrokeStyle)
createProgressiveTraceGenerator()
.setNumberOfPoints(990)
.generate()
.toPromise()
.then(data => {
volume.add(data.map(point => ({
x: point.x * 2.4 * 60 * 60 * 1000,
y: Math.abs(point.y) * 10
})))
setViewNicely()
})
//#endregion
// Add series to LegendBox and style entries.
const entries1 = legendBoxOHLC.add(chartOHLC)
entries1[0]
.setButtonOnFillStyle(areaRangeStroke.getFillStyle())
.setButtonOnStrokeStyle(emptyLine)
const entries2 = legendBoxVolume.add(chartVolume)
entries2[0]
.setButtonOnFillStyle(volumeStrokeStyle.getFillStyle())
.setButtonOnStrokeStyle(emptyLine)
setViewNicely = () => {
const yBoundsStock = {
min: areaRange.getYMin(),
max: areaRange.getYMax(),
range: areaRange.getYMax() - areaRange.getYMin()
}
const yBoundsVolume = {
min: volume.getYMin(),
max: volume.getYMax(),
range: volume.getYMax() - volume.getYMin()
}
// Set Y axis intervals so that series don't overlap and volume is under stocks.
volumeAxisY.setInterval(yBoundsVolume.min, yBoundsVolume.max)
stockAxisY.setInterval(yBoundsStock.min - yBoundsStock.range * .33, yBoundsStock.max)
}
stock.setResultTableFormatter((builder, series, segment) => {
return builder
.addRow(series.getName())
.addRow(series.axisX.formatValue(segment.getPosition()))
.addRow('Open ' + segment.getOpen().toFixed(2))
.addRow('High ' + segment.getHigh().toFixed(2))
.addRow('Low ' + segment.getLow().toFixed(2))
.addRow('Close ' + segment.getClose().toFixed(2))
})
volume.setResultTableFormatter((builder, series, position, high, low) => {
return builder
.addRow(series.getName())
.addRow(series.axisX.formatValue(position))
.addRow('Value ' + Math.round(high))
.addRow('Base ' + Math.round(low))
})
<script src="https://unpkg.com/#arction/xydata#1.4.0/dist/xydata.iife.js"></script>
<script src="https://unpkg.com/#arction/lcjs#2.2.1/dist/lcjs.iife.js"></script>

Resources