Create a custom lines in EXTJS Line Chart - javascript

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()).

Related

How to change the scale to an arbitrary number using lightningchart

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

Cytoscape.js Preset Layout Documentation

I have a cytoscape.js graph that renders. I'm interested in leveraging the preset layout to place the nodes. The cytoscape.js documentation shows the following for the preset layout:
var options = {
name: 'preset',
positions: undefined, // map of (node id) => (position obj); or function(node){ return somPos; }
zoom: undefined, // the zoom level to set (prob want fit = false if set)
pan: undefined, // the pan level to set (prob want fit = false if set)
fit: true, // whether to fit to viewport
padding: 30, // padding on fit
animate: false, // whether to transition the node positions
animationDuration: 500, // duration of animation in ms if enabled
animationEasing: undefined, // easing of animation if enabled
ready: undefined, // callback on layoutready
stop: undefined // callback on layoutstop
};
Can some one help me understand or give an example of what the documentation means when it says the following
// map of (node id) => (position obj); or function(node){ return somPos; }
I store all the nodes in a MySQL database table with the following columns
id, origin, destination, x position, y position
Does the cytoscape.js positions take a dictionary that looks like this:
{'id': 1, {'x':10, 'y':45}}, {'id': 2, {'x':21, 'y':32}} etc?
This means when the positions is set as undefined you need to create a function to get the positions of each node.
For example:
cy.nodes().forEach(function(n){
var x = n.data("x");
var y = n.data("y");
});
This should return your node position.
EDIT
You can set the node position when you are creating it. For example:
var elements;
elements: [{"data":{"id":"yourID","name":"name"},"position"{"x":"0.0","y":"0.0"}}];
For more, see this Demo on Cytoscape js site. Here they set the position manually.

Chartjs animate x-axis

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

Highcharts: update chart when data actualized

I am using Highcharts and I would like this chart to update each second. This is what I have now: JSFiddle
I have timer window.setInterval(updateChart, 1000); and it works properly actualizing data each second.
But I have no idea how to actualize the view. It is important that I don't want to draw chart again and again each second. I only want to shift points and add new ones. Do anyone know how to do that?
Look at the the series.addPoint method.
Your updateChart function becomes:
function updateChart()
{
for (var source = 1; source <=3; source++)
{
var point = [
23,
Math.floor((Math.random() * 10*source) + 5+source*2),
source
];
Highcharts.charts[0].series[0].addPoint(point, false, true); // add the point, don't redraw and shift off a point
}
Highcharts.charts[0].redraw(); // 3 points added, now redraw
}
Update fiddle.

Smooth animation for newly added data points with flot

I need to animate a real time graph with flot so that each new data point will transition smooth into the data set etc.
I've made a plunker with the basic flow:
http://plnkr.co/edit/oPahmS?p=preview
But I would like to make it more like highcharts
http://www.highcharts.com/demo/dynamic-update
Does anyone know a plugin or a way to do this with flot?
I don't believe either of the flot animation plugins provide this ability. Instead, it can be done with a little bit of jquery animate magic.
addPointAnimate = function(){
var series = somePlot.getData()[0]; // first series
var lastX = series.data[series.data.length-1][0]; // last x value
var opts = somePlot.getOptions();
opts.xaxes[0].max += 1; // adjust xaxis to make room for new point
somePlot.setupGrid();
$('#placeholder').animate( { 1:1 }, {
duration: 1000,
step: function ( now, fx ) {
series.data.push([lastX+fx.pos, Math.sin(lastX+fx.pos)]); // for each step of animation, push on an intermediate value
somePlot.setData( [series] );
somePlot.draw(); // redraw with intermediate value
}
});
return true;
}
Here's a working fiddle.

Categories