I use javascript to display a series of charts (graphs) one under the other. The Javascript script requests data from a PHP script then draws the charts and displays it. It doesn't take much time to fetch data for one chart and diplay it but with many charts the time accumulates which is boring. I would like to display the first chart when it is ready and then the second chart etc. so user sees how those get dynamically appended on the page making the page longer and longer.
Basically here is what I have:
<script>
var i=0;
$.getJSON('stats.php', function (data) {
for (chartData in data) {
i++;
var chart = new AmStockChart();
dataSet.dataProvider = chartData;
// etc. etc.
$('#stats').append('div id="chartdiv' + i + '"></div>');
chart.write("chartdiv" + i);
}
});
</script>
<div id="stats"></div>
That produces about 10 graphs one under the other but the problem is that shows empty screen for about 3-5 seconds and then displays all the graphs at once. If I limit it to diplay only one graph it shows up much faster. It would be nice to show those graphs gradually one by one when each graph is ready.
UPD: Here is the jsfiddle I put test data and cycled through one graph 20 times.
Some thing along the lines of this should help.....
var i = 0;
$.getJSON('stats.php', function (data) {
for (chartData in data) {
i++;
setTimeout(function(index,d1){
return function() {
var chart = new AmStockChart();
dataSet.dataProvider = data[d1];
// etc. etc.
$('#stats').append('div id="chartdiv' + index + '"></div>');
chart.write("chartdiv" + index);
}
}(i,chartData), 3000*i);
}
});
Here is the demo
Related
I'm using the Div print method to download or print the data of a long table. i face the problem that only a few columns are shown on one page and the remaining is looking cutting on the first page...means the data is not setting in multiple pages,as shown in the below pictures...
The code that i'm using is below
$scope.pdf = function () {
var getpanel = document.getElementById("table-scroll");
var MainWindow = window.open('', '', '');
var style = document.getElementById('printcss').value;
MainWindow.document.write('<html><head><title></title>');
MainWindow.document.write("<link rel=\"stylesheet\" href=\"styles/Print.css\" type=\"text/css\"/>");
MainWindow.document.write('</head><body onload="window.print();window.close()">');
MainWindow.document.write(getpanel.innerHTML + '<style>' + style + '</style>');
MainWindow.document.write('</body></html>');
MainWindow.document.close();
setTimeout(function () {
MainWindow.print();
}, 500)
return false;
}
The scroller in the above picture shows too many data...
while the the data is printed like this... as shown in the below picture
I have a project that stores a series of moves in PHP.
For example, I have a 100x100 grid with two boxes in it. The PHP code creates the coordinates that the boxes move to and each box can do multiple moves per turn.
I would like to animate the moves so users could see the boxes move in real time. To do this, I created a JS array of the coordinates using PHP, then created a jQuery script to iterate through the array and move the objects one at a time, using a setTimeout to control the speed of the changes.
However, this seems to just process all the moves and then only output the final locations. Firefox works a bit better than Chrome, but the setTimeout just seems to delay the final result being shown, rather than delaying each step.
Is there a way to show each move in real time?
Here is my JS:
var locations = {};
locations[0] = { "box":"box1" , "left":"52" , "top":"94" };
locations[1] = { "box": "box2" , "left":"0" , "top":"18" };
locations[2] = { "box": "box1" , "left":"29" , "top":"34" };
...
$(document).ready(function(){
$.each(locations,function(step,details){
setTimeout(processMove,1000,step,details);
});
});
function processMove(step,details){
var box = $('#' + details['box']);
box.css("left",details['left'] + 'px');
box.css("top",details['top'] + 'px');
}
Thanks in advance :)
This would work with your setup but I would recommend using array locations rather than object.
var locations = {};
locations[0] = { "box":"box1" , "left":"52" , "top":"94" };
locations[1] = { "box": "box2" , "left":"0" , "top":"18" };
locations[2] = { "box": "box1" , "left":"29" , "top":"34" };var cnt = 0;
var handle = setInterval( function() {
//processMove(locations[cnt]);
console.log(locations[cnt++]);
if (cnt > Object.keys(locations).length - 1) {
clearInterval(handle);
}
}, 1000);
You can. There is a whole API for this in jQuery:
http://api.jquery.com/animate/
There are two dygraphs on my page. On regular intervals new time series data is read from source and written to local variables, then the graphs are updated using the following commands:
vm.graph1.updateOptions(
{ 'file': customData1, 'labels': vm.labels1 });
vm.graph2.updateOptions(
{ 'file': customData2, 'labels': vm.labels2 });
This works perfectly fine, the graphs show the live trend as expected.
However, when I try to synchronize the two graphs by including the syncrhonizer.js and using the following command:
vm.graphSync = Dygraph.synchronize(vm.graph1, vm.graph2);
Then the "live updates" stop working. In other words, the graph doesn't display any of the new incoming values (it just displays the same static time span). The syncronization works fine, both for selection and zoom.
The data is still getting updated, but now I have to double click on the graph (or manually pan) in order to see the most recent data.
Anyone have any ideas or working solutions for syncrhronizing live trends using Dygraphs?
You'll need to explicitly set the dateWindow after updating the data:
vm.graph1.updateOptions(
{ 'file': customData1, 'labels': vm.labels1 });
vm.graph2.updateOptions(
{ 'file': customData2, 'labels': vm.labels2 });
vm.graph1.updateOptions({
dateWindow: vm.graph1.xAxisExtremes()
});
// ^^^ this will synchronize the other charts, too
The fact that you have to do this could be considered a bug with synchronizer. Feel free to file an issue against dygraphs, preferably with a link to a repro via dygraphs.com/fiddle.
This is a working solution, however, I had to change the "synchronizer.js" from dygraphs, so comments and other suggestions are still welcome.
In attachZoomHandlers function in synchronizer.js, I made this change:
for (var j = 0; j < gs.length; j++) {
if (gs[j] == me) continue;
//added if/else block, the original code was the stuff inside else block
if (me.ignoreXrangeSync && me.ignoreXrangeSync === true) {
//if ignoreXrangeSync flag is set, only update y-range
gs[j].updateOptions( {
valueRange: yrange
});
}
else {
//if ignoreXrangeSync flag is NOT set, run original code (so manual zoom works)
gs[j].updateOptions( {
dateWindow: range,
valueRange: yrange
});
}
}
And in my original code, I made this change.
vm.graph1.ignoreXrangeSync = vm.graph2.ignoreXrangeSync = true;
vm.graph1.updateOptions(
{ 'file': customData1, 'labels': vm.labels1 });
vm.graph2.updateOptions(
{ 'file': customData2, 'labels': vm.labels2 });
vm.graph1.ignoreXrangeSync = vm.graph2.ignoreXrangeSync = false;
Also, I needed to add these zoom callbacks (one for each graph) for my graph for live trending to start when double clicking after having manually zoomed in the graph(s).
var graph1ZoomCallback = function () { //callback for graph1
if(!vm.graph1.isZoomed()) { //if graph1 has been double clicked
vm.graph2.ignoreXrangeSync = true; //note, graph2
vm.graph2.resetZoom();
vm.graph2.ignoreXrangeSync = false;
}
}
I am using an MVC Razor foreach to render charts, sometimes over 150.
This is how I generate the script:
#{chartCount = 0;}
#foreach (var item in Model.ChartRows.Where(m => !m.SummaryRow))
{
$('#container_#(chartCount)').highcharts({
//code removed for brevity
});
chartCount++;
}
And then in my HTML I use this to render the containers:
#for (int i = 0; i < chartCount; i++)
{
<div id="container_#(i)"></div><br />
}
However, when there are 100's of items in ChartRows, the page can take a long time to load before suddenly all of the charts appear.
I have taken a look on the HighCharts website and have found a chart type called "Sparkline" and the jsFiddle example shows a way that the rendering can be delayed using a setTimout with it then rendering them in "chunks".
For me to make this work the way that I would need, I would have to remove all of the data from the script (or at least anything being populated from item.) and instead add 7+ data attributes onto each of the HTML containers and use jQuery to get those data attributes to populate the chart data. I'm not really excited about this approach as it could make troubleshooting a bit of a nightmare.
Does anyone know if it is possible to add each of the charts being rendered into some kind of queue so that they get rendered 1 at a time instead of the browser doing them all at the same time?
This is how I did it:
<script>
var chartFunctions = [];
#foreach (var item in Model.ChartRows.Where(m => !m.SummaryRow))
{
var chart_#(item.ID) = function () {
$('#container_#(item.ID)').highcharts({
//code removed for brevity
});
}
//add this function into the array
chartFunctions.push(chart_#(item.ID));
}
function renderCharts() {
var time = +new Date(),
len = chartFunctions.length;
for (i = 0; i < len; i += 1) {
//call each function in the function array
chartFunctions[i]();
// If the process takes too much time
if (new Date() - time > 500) {
chartFunctions.splice(0, i + 1);
setTimeout(renderCharts, 0);
break;
}
}
}
renderCharts();
</script>
And I also needed to use a foreach to match up the chartID and the containerID:
#foreach (var item in Model.ChartRows.Where(m => !m.SummaryRow))
{
<div id="container_#(item.ID)"></div><br />
}
Is it possible to create a "Print all" button for Highcharts, where more that one chart is printed?
I know that exporting multiple charts is possible, as demonstrated in the jFiddle: http://jsfiddle.net/highcharts/gd7bB/1/ but I'm not sure Highcharts allows a similar method with printing.
The exportChart method accepts parameters so you can send it more than one chart. However, the print method does not accept any parameters. So, to print you have to specify each chart separately like chart1.print(); and chart2.print(); which prints them each separately.
There are two workarounds:
Printing the whole page without using Highcharts printing. Here is an example.
You could export both of the charts to a pdf file and then print form there. Here is an example on how to export multiple charts to one pdf.
Here is an alternative solution that does the printing directly. It's based on the chart.print() function, but it works on multiple charts.
See the demo here: http://jsfiddle.net/jim31415/q5Rzu/150/
//--------------------------------------------------------------------
$("#print").click(function () {
printCharts([chart1, chart2, chart3]);
});
//--------------------------------------------------------------------
function printCharts(charts) {
var origDisplay = [],
origParent = [],
body = document.body,
childNodes = body.childNodes;
// hide all body content
Highcharts.each(childNodes, function (node, i) {
if (node.nodeType === 1) {
origDisplay[i] = node.style.display;
node.style.display = "none";
}
});
// put the charts back in
$.each(charts, function (i, chart) {
origParent[i] = chart.container.parentNode;
body.appendChild(chart.container);
});
// print
window.print();
// allow the browser to prepare before reverting
setTimeout(function () {
// put the charts back in
$.each(charts, function (i, chart) {
origParent[i].appendChild(chart.container);
});
// restore all body content
Highcharts.each(childNodes, function (node, i) {
if (node.nodeType === 1) {
node.style.display = origDisplay[i];
}
});
}, 500);
}
});