I'm working on an implementation of a live-updating line graph using gRaphael which is a graphic extension of the Raphael SVG library.
I can't seem to find any examples of somebody doing this as a near-realtime updating project, which is fine. I'm assuming there's a way to call refresh on the graph with a new data set (without the need to re-initialize a whole new Raphael object each time!), but therein lies the problem:
There doesn't seem to be accurate documentation anywhere. I discovered this StackOverflow question: Graphael line chart which in turn led to this documentation project: https://github.com/kennyshen/g.raphael/tree/master/docs , but the results were cold. Using the examples provided, I ran into some errors:
the syntax r.g.linechart() used in the examples was no longer valid (where r is the Raphael object and I assume g is a gRaphael property within). Somewhere along the way somebody must have switched to properly extending the Raphael object so that r.linechart() worked.
The parameters passed into linechart() were incorrect, resulting in an undefined error again. If I passed in only the #x, #y, width, height, arrayX, arrayY parameters and dropped the chart labels, etc., I could render a plain line. But of course I need to be able to label my axes and provide a legend, etc.
Needless to say, a library without an API document isn't going to do anybody much good, but there are stalwarts out there who are willing to learn based strictly on reading the code itself. I'm not one of those. I would probably do OK with a well-commented example, preferably using live updates.
So I guess the questions are:
Does anybody know better documentation than the one I linked to?
Can someone point me to examples, documentation failing?
Can someone provide a proper itemization of the parameters that linechart() will accept?
Thanks!
For the record, here's how far I am so far:
var r = Raphael('line-chart');
// did NOT work -->
var linechart = r.g.linechart(
10,10,300,220,[1,2,3,4,5],[10,20,15,35,30],
{"colors":["#444"], "symbol":"s", axis:"0 0 1 1"}
);
// worked in a limited way, rendering a plain line with no visible labels/graph -->
var linechart = r.linechart(
10,10,300,220,[1,2,3,4,5],[10,20,15,35,30]
);
I am still trying to learn Raphael myself, but here are the primary resources I have been using: http://g.raphaeljs.com/reference.html and the same sans the "g."
here is a fiddle that pretty much pulls off an updating linechart with knockout/gRaphael, prob not the best solution, but its an idea: http://jsfiddle.net/kcar/mHG2q/
Just a note, I didn't start learning it until I combined reading with trial/error (with a lot of error), so play with the fiddle and see how things change.
but the basic code for it is like:
//constructor
var lines = r.linechart(10, 10, width, height, xVals, yVals, { nostroke: false, axis: "0 0 1 1", symbol: "circle", smooth: true })
.hoverColumn(function () { //this function sets the hover tag effect
this.tags = r.set();
for (var i = 0, ii = this.y.length; i < ii; i++) {
this.tags.push(r.tag(this.x, this.y[i], this.values[i], 160, 10).insertBefore(this).attr([{ fill: "#fff" }, { fill: this.symbols[i].attr("fill") }]));
}
}, function () {
this.tags && this.tags.remove();
});
lines.symbols.attr({ r: 3 }); //this adjusts size of the point symbols
There is a fork in GitHub that is working on the documentation and examples.
You will need to download the code and view it from you computer. It is a work in progress but it's more than you can find in the official g.Raphael page.
I also found this small post with some examples.
Related
I am regularly updating several Dygraphs graphs. After some period of time, normally a few minutes, some or all of them get corrupted as shown in the figure below. I haven't been able to tie this a particular event or browser. This happens even with a simple graph where I am just reloading the data stored in a CSV file. I call updateOptions({ file: URL }) on the graph object, where URL points to the CSV file, followed by calling resetZoom() on the graph object to update the axes. Googling hasn't revealed anyone suffering similar behaviour, so I'm lost as to what is causing this.
Update 1: It is linked to minimizing and maximizing the browser.
Update 2: The problem doesn't occur in Firefox. It does happen in Google Chrome and Internet Explorer, although IE has the additional problem of freezing after a while (a problem for another day).
Update 3: Minimum working examples added at http://jsfiddle.net/williamshipman/tvxekq56/ and http://jsfiddle.net/williamshipman/af66qstt/. Repeatedly minimize and maximize the browser window, after a while the distortion occurs. The first example uses AngularJS (like my own work), while the second demonstrates the same bug in pure JavaScript. You may have to minimize and maximize more than a dozen times to see the bug, it seems pretty random.
For me similar problem appears when I show and hide Y2 axis.
This one line helped me: ctx.clearRect(0, 0, this.width, this.height);
File: dygraph-canvas.js
var DygraphCanvasRenderer = function(dygraph, element, elementContext, layout) {
...
ctx = this.dygraph_.hidden_ctx_;
ctx.clearRect(0, 0, this.width, this.height); // <== clear whole canvas before cliping
ctx.beginPath();
ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h);
ctx.clip();
};
The root of the problem
Canvas context is not fully restored after all draw is done.
Solution 1. (workaround)
Injecting canvas_ctx_.restore() after draw is done and context.save() before. save() is needed because library is restoring the context before every draw(except the initial one).
let g = new Dygraph('graph', {
underlayCallback: (context) => {
context.save();
},
drawCallback: (dygraph) => {
dygraph.canvas_ctx_.restore();
},
});
Solution 2. (library fix)
Here is my commit you can apply to the lib's src/dygraph.js
https://github.com/pawelzwronek/dygraphs/commit/c66ca37b82f14e096652a338cae8abf568b9c764
I am trying to implement some sort of animation while a large graph gets rendered using Flot chart. I have tried numerous solutions all of which have failed. Does anyone know if this is at all possible so the user can see that the graph is being rendered.
I have attempted to use an overlay with a loading gif but the gif does not animate until the graph has stopped rendering.
The code is being asked a lot of but I want to make sure the user can see the progress.
Thanks in advance
Flot renders the whole plot in one pass on the UI thread. There's no way to show progress without modifying the library itself. A perfect solution would take a lot of work, but, depending on your data, a decent approximation might not require much effort.
For example, let's say your plot contains many series, and each one by itself renders pretty quickly, but together they take a long time. In that case, if you open the Flot source and look for the draw function, you'll see that there is a simple loop calling drawSeries for each series:
function draw() {
CODE BLOCK A
for (var i = 0; i < series.length; ++i) {
executeHooks(hooks.drawSeries, [ctx, series[i]]);
drawSeries(series[i]);
}
CODE BLOCK B
}
Replace that with (roughly; haven't tested this) the following:
function draw() {
CODE BLOCK A
var i = 0,
drawNextSeries = function() {
drawSeries(series[i]);
if (++i < series.length) {
setTimeout(drawNextSeries, 0);
} else {
CODE BLOCK B
}
};
setTimeout(drawNextSeries, 0);
}
The idea is to draw each series in a separate call via setTimeout. The zero-millisecond delay queues up the call to run after any pending work, like other JS code, animations, etc. So after each series draws, there's a chance for the UI to update before the next one draws.
Again, this only works if you have many series that each draw fairly quickly. If you have just one big series, you'll still end up doing something similar, but within drawSeries.
I have inherited a project that is using Highcharts.
The previous dev used the .addSeries method to add all of the series to each chart that was being rendered. From what I've read of Highcharts, it seems like .addSeries is really for adding data dynamically.
The data that is being used to populate the charts are coming from an AJAX request. The old dev's approach was to get the data, render the chart, and then add a series using .addSeries. I was thinking that it might be better to update options.series and then pass the whole thing along to new Highcharts.Chart() for rendering, taking the .addSeries out of the equation.
However, since I'm new with Highcharts, I was hoping to get some feedback on what the better method would be.
You're on a good path, though your question suggests you may simply be looking for preference over a strict right/wrong answer.
From what I've seen, unless you have interactions on the page that would trigger a need to update your chart after it's been drawn, the benefit to using addSerie would be to add some visual flare. Using addSerie, your charts will visually draw themselves in front of the visitor - vs them already being drawn. (I believe HighCharts demo site has some good examples of this.)
I also recently inherited a HighCharts project and am generating a new Highcharts.Chart() using dynamic data by parsing the AJAXed data on the fly. The good news is that all of the charts still have nice visual flare (flare is important) since they don't draw until the AJAXed data is fully loaded. This snippet illustrates how I've been loading dynamic charts, parsing the JSON data on the fly:
$(function () {
var visitsChart;
$(document).ready( function() {
$.getJSON('/json-data-url', function(json){
var visitsChart = new Highcharts.Chart({
chart: {
renderTo: 'visitsContainer',
type: 'spline',
},
title: {
text: 'Test Widget'
},
series: [{
name: 'Speed',
data: [parseInt(json.visits)],
}],
...
});
});
});
});
I won't lie ... I had a few minutes of hair pulling when I got started but now I wish I had more time to work with Highcharts as it's quite fun once you get on a roll. Hope this helps.
I am running into a problem with gRaphael javascript line chart library.
I am building a line chart from a CSV file that has five columns (# of minutes, time, waiting time, in treatment, closed, in location).
Previously I have been able to draw the full chart without animation. It correctly had all four lines etc.
Now my code fails on the animation function. Here is the error:
Uncaught TypeError: Object # has no method 'animate'
I assume that jQuery is somehow messing with animate function, and trying to take the reins of it.
function animateChart(newX, newW, newInT, newC, newInL){
var chart2 = paper.linechart(
20, 20, // padding
newX.length, 400, // dimensions
newX, [newW, newInT, newC, newInL] // values
);
for (i = 0; i < chart.lines.length; i++){
elem = chart.lines[i][0];
elem.animate({ path: chart2.lines[i][0].getAttribute("d") }, 200);
}
chart2.remove();
}
Full code:
http://pastebin.com/YmvkrmQ3
I have the following libraries loaded, in order:
raphael-min.js
g.raphael-min.js
g.line.min.js
jquery.js
Thanks in advance for any help.
UPDATE:
The problem is in the animate method. Even though I am calling the method on a path element, I get the error. I still don't know why Raphael doesn't recognize the path element as path element.
I tried disabling jQuery (and replacing it's ajax function with vanilla javascript), but it didn't help.
You probably have an SVG path element and not a Raphael path element. It's probably the [0] at the end of elem = chart.lines[i][0];.
I have asked this question before and it seemed that the code I was using was pretty confusing. So this is a virtually dumed down version of the same code.
I draw a square on the canvas using the add function. Like wise I should be able to remove the item from the canvas using the remove function! Alas it doesn't seem to happen so.
Here is the code
$(window).addEvent('load',function(){
CANVAS.init({ canvasElement : 'canvas' });
CANVAS.layers.add( new Layer({
id : 'myLayer'
}));
var colors = [
'rgba(255,0,0,1)',
];
var pos = [
{ x: 150, y : 100 },
]
var foo = new CanvasItem({
id : 'item',
x : pos[0].x,
y : pos[0].y,
fillStyle : colors[0],
events : {
onDraw : function(ctx)
{
ctx.fillStyle = this.fillStyle;
ctx.fillRect(this.x,this.y,200,200);
}
}
});
CANVAS.layers.get('myLayer').add(foo);
CANVAS.draw();
CANVAS.layers.get('myLayer').remove(foo);
CANVAS.draw();
});
It can also be seen here is jsfiddle
The library I am using to implement this is via mootools canvas library. Here is the link of the functions.
Hopefully this will help people get my query. Feel free to ask questions if you are still pondering about what exactly is my problem! Thanks
EDIT : There is a bug in the library. Please find the link to the corrected code below in the comments of the answer. Thanks.
Looking at the docs of the remove function it seems that you should be passing the itemId not the the actual item object when calling it.
the error in the library was in the remove function. I have the following script which removes the bug. Hope it helps people. :)
http://gist.github.com/589185