When you use lightningchart to set the scale to be displayed, the default size is 5 or 10 increments.
Is it possible to change this to an arbitrary increments (2 increments, 3 increments, etc.)?
Please let me know.
The Axis automatically calculates the increment size depending on the level of zooming for the Axis and space available for each tick label. We're looking towards improving our Axis behavior with the next Major release this Summer.
In the meanwhile, it is possible to create this behavior manually by using customTicks.
/*
* LightningChartJS example that showcases a simple XY line series.
*/
// Import LightningChartJS
const lcjs = require('#arction/lcjs')
// Extract required parts from LightningChartJS.
const {
lightningChart,
ColorRGBA,
UIElementBuilders,
emptyFill,
emptyLine,
emptyTick,
SolidLine,
SolidFill
} = lcjs
// Create a XY Chart.
const chart = lightningChart().ChartXY()
.setTitle('XY Chart with custom tick interval')
// Get the default X Axis and cache it
const defXAxis = chart.getDefaultAxisX()
// Set the default Axis style as emptyTick, hiding the default Ticks created
// by the AxisTickStrategy
defXAxis.setTickStyle(emptyTick)
// Iterate an arbitrary amount of ticks, creating a new customTick with interval of 2
for ( let i = 10; i <= 90; i += 2 ) {
// Add a new custom tick to the X Axis
defXAxis.addCustomTick(
// Modify the textBox to hide its background and border
UIElementBuilders.PointableTextBox.addStyler(
(styler) => {
styler.setBackground(
(bg)=>
bg
.setFillStyle(emptyFill)
.setStrokeStyle(emptyLine)
) }
))
// Set the tick position
.setValue( i )
// Make the Grid stroke less visible
.setGridStrokeStyle(
new SolidLine( {
thickness: 1,
fillStyle: new SolidFill( { color: ColorRGBA(200, 200, 200, 50)})
})
)
}
Related
I have a react js application in which, I have used a point series to plot data in chart.
I got the chart to display. But, I want real time data to be binded to chart.
Eg: If a chart contains 10 points on loading, it is marked to chart. Then in 5 sec interval, I will be getting datas from socket which I have to add to the existing chart. So now, there has to be 15 points in charts and the chart has to move from left to right as the data comes in.
Here is my code that is used to bind data at the starting
import {
lightningChart,
AxisTickStrategies,
LegendBoxBuilders,
Themes,
PointShape,
translatePoint,
AxisScrollStrategies
} from "#arction/lcjs";
const dateOrigin = new Date(startingDate);
const chart = lightningChart()
.ChartXY({
container: id,
theme: Themes.lightNew,
columnIndex: 0,
columnSpan: 1,
rowIndex: 0,
rowSpan: 1
})
.setTitle(id.split(" ")[1]);
const originDate = new Date(moment().subtract(1, 'days'))
const xAxis = chart.getDefaultAxisX().setTickStrategy(
// Use DateTime TickStrategy for this Axis
AxisTickStrategies.DateTime,
// Modify the DateOrigin of the TickStrategy
// (tickStrategy) => tickStrategy.setDateOrigin(dateOrigin)
(tickStrategy) => tickStrategy.setDateOrigin(originDate)
);
const yAxis = chart
.getDefaultAxisY()
.fit(true)
.setScrollStrategy(undefined)
.setInterval(-20, 20)
.setTitle("");
const series = chart
.addPointSeries({
xAxis: xAxis,
yAxis: yAxis,
pointShape: PointShape.Circle
})
.setName("Actual");
const dataFrequency = ((((600 - 600 * 250) - (60 * 60 * 100)) - (1000 * 2)) - 900)
//0-24 hrs
chart.getDefaultAxisX().setInterval(92 * dataFrequency, 60);
series.add(
sensorData.map((point) => ({
//x: new Date(point.x).getTime() - startingDate.getTime(),
x: new Date(point.x).getTime() - new Date(startingDate).getTime(),
y: point.y, // * 1000,
}))
);
Please let me know how the incomming data from socket has to be added to the existing points in charts.
Thanks in Advance.
You can append more data points to a PointSeries with another call to add method, same way as you use it for the initial data.
So keep a reference to the PointSeries object and when you receive the new data from websocket just use the add method in exactly same way as you did before to append the data on top of the previous data points.
For "moving the chart from left to right as data points come in", you should configure the X axis scroll strategy to be progressive. Please refer to this ECG chart example for code reference (line 44, chart.getDefaultAxisX()...).
For means of Stack Overflow historical completeness I'll also add the highlighted code line here:
// Configure X Axis as progressive scrolling with value interval of 1000
chart.getDefaultAxisX().setInterval(0, 1000).setScrollStrategy(AxisScrollStrategies.progressive)
I am using ProgressBar.js to create a circle with a percentage in the center. The circle creates properly but when I run it again, I want it to update the text (the percentage) with the new passed in value.
How can I do this? Currently, the code does not update the inner text.
Use circle.animate(value) or circle.set(value):
let circle = null
/**
* #param percentage - decimal from 0 to 1 (0.7 => 70%)
*/
function refreshCircle(percentage) {
if (!circle) {
circle = /* initialize */
}
circle.animate(percentage)
// or without animation:
circle.set(percentage)
}
demo
I am wondering if it is possible to set the value of a series to always be the top of the current chart, more or less like using plotBands or plotLines.
For example, I would love to have a series like: [1,1], [1,yAxis.top] ...
Is that possible?
Yo do not know what is an axis max until you set it or let the Highcharts calculate it. I assume that you do not want to set axis.max, so you need to wait until the Highcharts sets axis max and then add a max point dynamically. You can use a load event to achieve that.
chart: {
events: {
load: function () {
const axis = this.yAxis[0]
const max = axis.max
const series = this.series[0]
axis.update({ max })
series.addPoint(axis.max, true, false, false)
}
}
},
example http://jsfiddle.net/qb2tn7jh/
I want to use a chartjs linechart to visualize my data points. Chartjs seems to animate the graph by default, but it does not animate the values on the x-axis. The x-axis only move in discrete steps.
Is there any way to enable animation on the axis also?
Thanks!
As far as I am aware, ChartJS does not support x-axis animation out-of-the-box. So you'll have to hack it. There are several ways to possibly do this, but the following methods seems to work.
If You Want to Animate the Data On the X-Axis
When a chart is updated, the following steps occur: 1) The axes are drawn, and then 2) a draw() function is called to draw the data. There are different draw() functions for different chart types, and the function for line charts is Chart.controllers.line.prototype.draw. The draw() functions take one argument, which I will call animationFraction, that indicates how complete the animation is as a fraction. For instance, if an animation is 5% complete, animationFraction will be 0.05, and if an animation is 100% complete (i.e. if the chart is in its final form), animationFraction=1. The draw() function is called at each step of the animation to update the data display.
One hack to animate the x-axis then is to monkey-patch the line chart draw() function to translate the canvas in the horizontal dimension at every draw step:
var hShift = (1-animationFraction)*ctx.canvas.width;
hShift is the horizontal shift in pixels of the chart. As defined above, the data will sweep in from the right; if you want it to sweep in from the left, you can make the above negative. You then save the canvas context state, transform the canvas using hShift, draw the chart data, and then restore the canvas to its original state so that on the next animation frame the axes will be drawn in the correct spot:
ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift, 0);
ctx.oldDraw.call(this, animationFraction);
ctx.restore();
In the above, this refers to the chart object, and oldDraw refers to the original line chart drawing function that was saved previously:
var oldDraw = Chart.controllers.line.prototype.draw;
You can additionally setup your new draw() function to read new animation options that allow you to set whether the x-axis and y-axis are animated:
var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
var animationConfig = this.chart.options.animation;
if (animationConfig.xAxis === true) {
var ctx = this.chart.chart.ctx;
var hShift = (1-animationFraction)*ctx.canvas.width;
ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift,0);
if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
ctx.restore();
} else if (animationConfig.yAxis === true) {
oldDraw.call(this, animationFraction);
} else {
oldDraw.call(this, 1);
}
}
You can then create a line chart with both axes animated with:
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 5000,
xAxis: true,
yAxis: true,
}
}
});
See https://jsfiddle.net/16L8sk2p/ for a demo.
If You Want to Animate the X-Axis Limits
If you want to animate the x-axis limits--i.e. move the data, axis ticks, and tick labels, then you can use the following strategy. It's a bit quirky, so it might take some effort to work out the kinks for any given use-case, but I believe it should work generally. First, you'll need to convert the line plot to a scatter plot. Line charts have categorical x-axes that move in steps, so you can't set the axis limits to be between ticks, which is what you'll need to do to get the animation. So you'll need to use a line scatter plot instead, since scatter plots can have arbitrary axis limits. You can do this by numbering each data point, and assigning that number to the x-value for that data point. For instance, to generate a random dataset, you could do:
var DATA_POINT_NUM = 58;
var data = {
labels: [],
datasets: [
{
data: [],
},
]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
data.datasets[0].data.push({ x: i,
y: Math.random()*10
});
data.labels.push(String.fromCharCode(65+i));
}
You'll then need to write a function to convert between the assigned x-values of your data points, and the data point labels (i.e. the categories that will be on the charts x-axis):
function getXAxisLabel(value) {
try {
var xMin = lineChart.options.scales.xAxes[0].ticks.min;
} catch(e) {
var xMin = undefined;
}
if (xMin === value) {
return '';
} else {
return data.labels[value];
}
}
where lineChart is our Chart object, which will be defined below. Note that ChartJS draws the chart slightly differently if there's a label at x-axis's minimum value, so you'll need to write this function to return an empty string if the value==the minimum value of the x-axis. You can then define the Chart object:
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: false,
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
ticks: {
min: 0,
max: 10,
callback: getXAxisLabel, // function(value) { return data.labels[value]; },
autoSkip: false,
maxRotation: 0,
},
}]
}
}
});
ticks.callback is set to our getXAxisLabel function above. When ChartJS draws the x-axis, it will pass the x-values of the data points to the callback function and then use the resulting string as the value on the x-axis. In this way, we can draw a scatter chart like a line chart. I've also set autoSkip=false and maxRotation=0 to make sure the axis labels get drawn in a consistent way.
You can then animate the chart by adjusting the x-axis ticks.min and ticks.max values and calling the chart's .update() method. To illustrate this, the code below scans along the charts x-axis, showing ten data points at a time.
var xMin = 0; // Starting minimum value for the x-axis
var xLength = 10; // Length of the x-axis
var animationDuration = 5000; // Duration of animation in ms
// Calculate animation properties
var framesPerSec = 100;
var frameTime = 1000/framesPerSec;
var xStep = (DATA_POINT_NUM-xMin+xLength)/(animationDuration/1000*framesPerSec);
function nextFrame() {
var xMax = xMin+xLength;
if (xMax < DATA_POINT_NUM-1) {
if (xMax+xStep > DATA_POINT_NUM-1) {
xMax = DATA_POINT_NUM-1;
xMin = xMax-xLength;
}
lineChart.options.scales.xAxes[0].ticks.min = xMin;
lineChart.options.scales.xAxes[0].ticks.max = xMax;
lineChart.update();
setTimeout(nextFrame, frameTime);
xMin += 0.1;
}
}
nextFrame();
Putting it all together: https://jsfiddle.net/qLhojncy/
I am no expert in javascript but I found an example for Chartjs that, when inserted a new data point, updates the x-axis via animation as it seems, maybe it helps you: example.
Example source: sitepoint.com
I need to add a vertical line and a text on my Line chart near to a specified point on chart (specified by data, not coordinates). I tried to use CompositeSprites, but it doesn't show on screen completely. I'm new to ExtJS drawing.
You should put the logic that adds the vertical line inside of the chart's refresh event listener, that way, if the data changes the line position will be updated to reflect the new data.
Here's an example of how you could do it, assuming you can get a reference to the chart container (e.g. "myPanel"):
var myChart = myPanel.down('chart'),
myChart.on('refresh', function(myChart) {
// First, get a reference to the record that you want to position your
// vertical line at. I used a "findRecord" call below but you can use
// any of the datastore query methods to locate the record based on
// some logic: findBy (returns index #), getAt, getById, query, queryBy
var myRecord = myChart.store.findRecord(/*[someField]*/, /*[someValue]*/),
// a reference to the series (line) on the chart that shows the record
mySeries = myChart.series.first(),
// get the chart point that represents the data
myPoint = Ext.each(mySeries.items, function(point) {
return myRecord.id === point.storeItem.id;
}),
// the horizontal position of the point
xCoord = point.point[0],
// check for any previously drawn vertical line
myLine = myChart.surface.items.findBy(function(item) {
item.id === 'vert'
});
// if there is no previously drawn line add it to the "surface"
if (!myLine) {
myChart.surface.add({
id: 'vert', // an id so that we can find it again later
type: 'rect',
width: 4,
height: myChart.surface.height, // the same height as the chart
fill: 'black',
opacity: 0.5, // some transparency might be good
x: xCoord,
y: 0 // start the line at the top of the chart
});
// if we already had a line just reposition it's x coordinate
} else {
myLine.setAttributes({
translate: {
x: xCoord,
y: 0
}
// I think the chart gets drawn right after the refresh event so
// this can be false, I haven't tested it though
}, false);
}
});
If you are using the MVC pattern your event handler would look a little different (you wouldn't use myChart.on()).