LightningJs - Find if chart is ready - javascript

I have x and y data fetched via ajax , after I fetch I add series like below
series.add({ x: xVal, y: yVal})
But problem is out of 5 times , 3 times chart not loading. I think it is because I try to add series before chart is ready. Is there any callback to know if chart is ready and then I can add the x and y to series ?

At least as of now, LCJS renders synchronously with animation frames so you can find out when the Chart has rendered its first frame (and is pretty much "ready") with requestAnimationFrame:
const chart = lightningChart().ChartXY()
// ... Chart application code ...
// Get informed when Chart has rendered.
requestAnimationFrame( () => console.log('ready') )
But you really shouldn't need to wait for the Chart before adding data to it.

Currently there is no callback to know when the chart is ready.
The behavior you described shouldn't be possible, as long as you're always creating the chart first, before the series - and creating the series before adding a point to it.
Please make sure the order of creation is Chart -> Series -> Series.add

Related

Moving navigator in Highcharts

I would like to fetch data for example from this website: https://www.highcharts.com/stock/demo/lazy-loading
To get the data with high resolution, I have to set the min max to small value and then I have to go over the complete diagram.
It is possible to get data from the website with "Highcharts.charts[0].series[0]"
But I didn't find a possibility to programable changing the navigators, to get other data ranges.
Is it possible to move the navigator to a specific position?
You can use Axis.setExtremes function for this.
Live demo: http://jsfiddle.net/kkulig/am3cgo5w/
API reference: https://api.highcharts.com/class-reference/Highcharts.Axis#setExtremes
Thank you for your answear. Here is my code if somebody needs:
I saw, that the redraw event will be called 5 times till the diagram is finishd redrawn
counter = 1
// Get chart
chart = $('#highcharts-graph').highcharts()
// add event
Highcharts.addEvent(chart, 'redraw', function (e) {
console.log(counter);
counter = counter+1;
if(counter>5){
console.log('finish loaded')
function2()
}
})
var newSelectedMin = 0
var newSelectedMax = 10
chart.xAxis[0].setExtremes(newSelectedMin, newSelectedMax);

Template level reactivity in Meteor

I'm working on a problem where I want to display data in a dashboard both as a chart (via perak:c3) and in a table (via aslagle:reactive-table). My issue is that the data is pulled from a collection in MongoDB, and it's format is instantly amenable to plotting via c3, but needs to be transformed into a local collection to be used by the reactive-table package, as suggested in this answer to a previous question.
When I change the dataset to be displayed I want the chart to be updated, and the table also. This requires changing the values in the local collection, however, which slows things down and so rather than the chart being smoothly redrawn, there is a freeze on the page, and then the new data is displayed.
I have created a sample project on GitHub here so the problem can be replicated easily. If you run the app and select a dataset in your browser you will see exactly what I mean
To see the reactive behaviour I want to preserve in the chart go to client/templates/dashboard/dashboard.html and simply comment out the table template {{> dashboardTable}}
and now change the dataset to see how the chart is smoothly redrawn. Essentially I am trying to ensure both templates dashboardChart and dashboardTable render independently of one another.
UPDATE
Following Michael Floyd's suggestion of using a timeout helped a bit
Meteor.setTimeout(function(){createLocalCollection(data)},200);
but although the chart gets smoothly drawn, when the table finishes being filled, the chart is drawn again. It looks like it jumps to some intermediate state that I can't understand. Here is a video showing what I mean.
I'm adding this as a separate answer because it's a completely different approach.
Use the onRendered callback in d3 to invoke the local collection update.
Where you have:
chart = c3.generate({
bindto: '#dataset-chart',
in dashboard_chart.js, add:
chart = c3.generate({
onrendered: createLocalCollection(),
bindto: '#dataset-chart',
Of course you need to remove createLocalCollection(data) from your event handler.
To avoid having to pass the data context through the onrendered handler in d3 also update your createLocalCollection function to use the reactive variable datasetID that you defined earlier to establish the current dataset:
var createLocalCollection = function() {
var values = My_First_Collection.find({datasetID: datasetID.get()}).fetch();
var tempDoc = {};
local.remove({});
tempDoc = {};
for (var i in values[0].value) {
tempDoc.value = values[0].value[i];
tempDoc.date = values[0].date[i];
local.insert(tempDoc);
}
};
Using this method you let D3 tell you when the chart rendering is done and then your table can start getting populated. The result is an instantaneous chart update followed by the table updating. No mucking with timeouts either.
Remember that js is single threaded. You have two things to and they are going to happen sequentially. What you can do is defer the code that is updating the local collection using Meteor.setTimeout(). This will allow the chart to update first and then your table can update second. I've seen this before where you run a function that updates the DOM (in your case d3 is updating the svg canvas) but the actual screen update gets stuck behind long running js.
I tried this specifically and chart performance was fine.
Meteor.setTimeout(function(){createLocalCollection(data)},500);
Cutting the interval down to 100 allowed the chart to update but then the menu didn't fade out completely until the local collection finished updating.
One thing that I've used with tables and local collections is to only update the local collection document when the corresponding non-local document is being rendered on screen (assuming there's a 1:1 relationship between the original data and the transformed version). This allows the reactive table to load lazily.

Highcharts: Cannot read property 'chart' of undefined

So I have this chart built out and it works except it keeps throwing the error Cannot read property 'chart' of undefined. I am reloading the chart on window resize so that the html labels reload in correct positions.
It's a double donut chart and shows/hides content based on the selected slice.
Any help would be greatly appreciated.
First of all, you define var chart variable in createChart function, so it always will be undefined - use only one definition (the one on top), later just assign chart to that variable. Anyway, I see two solutions:
use setTimeout() in resize event, to render chart with a delay. Not a reliable solution, because user can play around with width of the browser and something may be broken again
wrap initReflow method to check if chart exists, like this:
(function(H, HA) {
H.wrap(H.Chart.prototype.initReflow = function () {
var chart = this,
reflow = function (e) {
if(chart && chart.options) {
chart.reflow(e);
}
};
HA.addEvent(window, 'resize', reflow);
HA.addEvent(chart, 'destroy', function () {
HA.removeEvent(window, 'resize', reflow);
});
});
})(Highcharts, HighchartsAdapter)
Working demo: https://jsfiddle.net/dpsn9gx8/7/
Edit:
Since Highcharts 4.1.10 Highcharts adapter is built-in, so remove it and use Highcharts: https://jsfiddle.net/dpsn9gx8/11/

Flot chart loading animation while rendering

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.

loading chart from data fetched using ajax call

I am using jqPlot javascript library ( http://www.jqplot.com/ ) for graphs and charts in one of my application.
In my application, there are 5-6 pages where this library is used. But I would like to discuss one particular case here.
On 1 of page, I am loading 3 charts. Data for these 3 charts is populated from database tables.
There is different set of queries for each chart. So, populated data for each chart is different too.
Once I have populated data, I have to process it, before providing its input to chart.
What is the problem then:
Problem that I am facing is it takes lots of time for page to render on browser (which is quiet obvious, as first it will form query, then fire that query against database tables, get the data, process on data and give to chart)
One of my friend suggested to implement following thing using ajax. I really liked his solution.
This is what I intend to do:
I would create a page, which will load all the required js/css files for jqPlot library.
There will be 3 sections on that page, where I would put some GIF images indicating that some process is going on (say ajax-loader.gif)
Once page is loaded, it will fire 3 ajax call, one at a time, to fetch each chart.
My Question Is how can I load chart from data received from ajax-call?
jqplot puts data and creates chart in following way (look at example below)
<script class="code" type="text/javascript">
$(document).ready(function(){
var plot2 = $.jqplot ('chart2', [[3,7,9,1,4,6,8,2,5]], {
// Give the plot a title.
title: 'Plot With Options',
// You can specify options for all axes on the plot at once with
// the axesDefaults object. Here, we're using a canvas renderer
// to draw the axis label which allows rotated text.
axesDefaults: {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
},
// An axes object holds options for all axes.
// Allowable axes are xaxis, x2axis, yaxis, y2axis, y3axis, ...
// Up to 9 y axes are supported.
axes: {
// options for each axis are specified in seperate option objects.
xaxis: {
label: "X Axis",
// Turn off "padding". This will allow data point to lie on the
// edges of the grid. Default padding is 1.2 and will keep all
// points inside the bounds of the grid.
pad: 0
},
yaxis: {
label: "Y Axis"
}
}
});
});
</script>
Since you're using jQuery, you'd use the jQuery Ajax method to fetch the chart data after the page has loaded.
In your success function, your JS code (on the browser) receives the data from your server. Once you have the data, make the call to $.jqplot -- passing in the data you've just received.
To initially show the busy gif, just use the img element as the static content of the chart2 div which will later be the graph's container.
Some tips:
Some browsers don't do well at handling an animated gif while running a js program. So you may want to try a text message ("Loading chart...") in addition to the rotating gif. -- Or update the text messages. Eg start with "Fetching chart data from server" then update to "Processing chart data" once your success function has been called.
Rather than starting all 3 Ajax calls at once, experiment with having the success function for the first chart initiating the second Ajax call. (In addition to it charting the data.)
If you have problems with your Ajax calls, Google for examples and ask a separate question on SO if you still have problems.

Categories