Smooth animation for newly added data points with flot - javascript

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.

Related

Highcharts stacked bar chart - how to get the stacks values

I have created an highcharts stacked bar chart, but when the data is skewed, the bars are not visible or the numbers overlap, as shown in below image.
I have seen many posts, but there is no out of the box solution for this, so i am making my custom solution.
I am setting a default height of 150 if the y value is less than 150.
This solution works, but the total of the bars now is shown to be 300 instead of the actual original value. How can i change the total stacklabel value on my own? I am unable to find a way to do that.
Here is the code to change the height to default values. I am storing the actual value in realValue variable in the point object.
chartOptions = {
type: CHARTING.CHART_OPTIONS.TYPE.COLUMN,
// On chart load, apply custom logic
events : {
load: function () {
var chart = this,
minColHeightVal = 150;
chart.series.forEach(function (s) {
s.points.forEach(function (p) {
if (p.y < minColHeightVal) {
p.update({
y: minColHeightVal,
realValue: p.y
}, false);
}
});
});
// How to iterate over the bars here and sum the actual value? i.e. point.realValue and set the stacklabel?
chart.redraw();
}
}
}
Did you try to use minPointLength option? It may be a simpler solution in your case: https://api.highcharts.com/highcharts/series.column.minPointLength
However, using your code to get the wanted result, use stackLabels.formatter function:
formatter: function() {
var series = this.axis.series,
x = this.x,
sum = 0;
series.forEach(function(s) {
if (s.points && s.points[x]) {
sum += s.points[x].realValue ? s.points[x].realValue : s.points[x].y
}
});
return sum;
}
Live demo: https://jsfiddle.net/BlackLabel/uocdykbL/
API Reference: https://api.highcharts.com/highcharts/yAxis.stackLabels.formatter

The flot graph won't update after re-draw

I created an array that contains all of the flot objects on the screen. Using the selection plugin, I am implementing a zoom feature.
Unfortunately, the code below does not work as expected. I can confirm with console.log that the options change. The clearSelection() also works but the graph never redraws.
Also, I don't think it matters but I'm using a time-based x-axis.
$(".flot").bind("plotselected", function (event, ranges) {
var plot = flots['#'+event.target.id];
plot.getOptions().xaxis.min = ranges.xaxis.from;
plot.getOptions().xaxis.max = ranges.xaxis.to;
plot.setupGrid();
plot.clearSelection();
plot.draw();
});
I figured it out. For some reason I had to change the axes min and max using the xaxes[0].min and yaxes[0].min.
$(".flot").bind("plotselected", function (event, ranges) {
var plot = flots['#'+event.target.id];
plot.getOptions().xaxes[0].min = ranges.xaxis.from;
plot.getOptions().xaxes[0].max = ranges.xaxis.to;
plot.setupGrid();
plot.clearSelection();
plot.draw();
});

dc.js: extending line and area to end of chart

I'm trying to draw an area chart using dc.js, and the end date (i.e. far right) of the chart is based on the current date, not the last date in the dataset. In cases where there's a date gap between data points, I want the area to extend from one point to the next, not draw at 0.
Given this data:
var data = [
{domain: "foo.com", project: "pdp", repo: "myrepo", commit_date: "6/1/2014", lines_added: 100, lines_deleted: 50},
{domain: "foo.com", project: "pdp", repo: "myrepo", commit_date: "7/1/2014", lines_added: 100, lines_deleted: 50}
];
var ndx = crossfilter(data);
The chart's line/area currently ends at the "7/1/2014" data point, but I want it to stretch the entire length of the chart.
The relevant code for drawing the chart is:
var dateDim = ndx.dimension(function(d) {return d.commit_date;});
var minDate = dateDim.bottom(1)[0].commit_date;
var maxDate = new Date();
var domainGroup = dateDim.group().reduceSum(function(d) {return d.cumulative_lines;});
unshippedlineChart
.width(500).height(200)
.dimension(dateDim)
.group(domainGroup)
.renderArea(true)
.x(d3.time.scale().domain([minDate,maxDate]))
.brushOn(false)
.interpolate('step-after')
.yAxisLabel("Unshipped Value");
Full example is at http://jsfiddle.net/xayhkcvn/1/
You didn't actually ask a question :-), but I think you may be looking for ways to prefilter your data so that it gets extended to today, and to remove any zeros.
This stuff isn't built into dc.js, but there is some example code in the FAQ which may help. Specifically, there is a function remove_empty_bins which adapts a group to remove any zeros.
You could similarly define a function to add a final point (untested):
function duplicate_final_bin(source_group, key) {
return {
all:function () {
var ret = Array.prototype.slice.call(source_group.all()); // copy array
if(!ret.length) return ret;
ret.push({key: key, value: ret[ret.length-1].value});
return ret;
}
};
}
You can compose this with remove_empty_bins:
var super_group = duplicate_final_bin(remove_empty_bins(domainGroup), maxDate);
The idea is to create a wrapper object which dynamically adds or remove stuff from the (always changing) source_group.all() on demand. dc.js will call group.all() whenever it is redrawing, and these wrappers intercept that call and adapt the data the crossfilter group returns.

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.

Create a custom lines in EXTJS Line Chart

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

Categories