I'm looking for appropriate way to refresh bar chart which is constantly getting data from API.
$http({
method: 'GET',
url: '/data' //getting data from API
}).then(function ( json ) {
//chart
}
There is a similar situation on the plunker, but I'm affraid of memory leak with this method and chart is always blinking.
Do anyone has a suggestion what to use instead of interval? Or use it in some other way?
Thanks.
That Plunker is great, but the problem is that it calls c3.generate continuously, which is why it's leaking memory and flashing (You're essentially creating a new C3 chart instance every time you run generate; all it does is called new Chart(config);)
What you need to do is instantiate C3 in the controller and then call c3.load() in your $http call.
Updated Plunker
Key bit:
$interval(function() {
$http.get('chartData.json')
.then(function(json) {
$scope.countries = formatData(json.data); // format received data
$scope.chart.load({json: $scope.countries, keys: { value: ['Croatia', 'Belgium', 'Argentina'] }});
});
}, 1000);
The $interval+$http combo should work okay, provided that the JSON file you're loading is just on a CDN somewhere (if it's being generated on a per-request basis by a REST API, you'll either get throttled or rinse your server). You may want to take a look at $http's caching docs.
Related
I have an array that is being filled on page load by D3. I want to access that same array at another time but I still need to confirm that it has been loaded.
I don't know the propper way to do this so I just guessed a few time and I kept getting "not a function" errors
First Code (populate my svg, snapshot of current values)
d3.tsv("file.txt").then( function(data) { Loaded_Data[1]=data; document.getElementById("valve1").innerHTML = data[data.length-1]['OnOff']; //etc
});
much later, but still in a relevant timescale of async, I want to do some d3 graphing with this data, but I want to make sure that there is data in my array.
Later Code (populate graphs, weeks of data)
Loaded_Data[1].addEventListener('load', () => {console.log("success"); //d3.graphing; });
I basically want a:
while (array[1] is undefined){ Listen; }
when done => graph;
Or would it just be easier to load the entire set of documents again in another d3.tsv().then()? it seems like a waste of resources to reload the entire data. What makes this difficult is the number of sources I have to load in, and consolidating my data into one array will be (hopefully) more convenient.
just graph in the then call after you read the data:
d3.tsv("file.txt")
.then(data => graph(data)); //data is available to be used at this point
also, if I'm reading this correctly, you are listening for the array to be populated with the load event, but that is only fired when the whole page is loaded and isn't relevant to the populating of a data structure. If you need the data stored somewhere in addition to graphing, you could modify the above to:
d3.tsv("file.txt")
.then(data => {
graph(data);
myArray = data;
});
So I haven't been able to find an example. I'm loading this huge dataset from an external file with D3, and I'm making some graph with some part of the data. When a slider is moved, I wish make the same graph with some other part of the data.
I used d3.json() for loading the data. The trouble that I'm facing is: since the d3.json() is asynchronous, it loads the dataset for once, and then I can't access it from other functions. I can't have another update function that makes a new graph since I simply can't access the data anymore.
Other people's suggestions have been "only using the data in the d3.json() function: How to store a JSON object loaded from a file?
d3.json("temp.json", function(data){
//use data here
})
// do not use data anymore
I tried to use a variable to store the data (the second answer from the same question link above):
var DATASET; // global
d3.json("file.json", function(data) {
DATASET = data;
//any other functions that depend on data
});
d3.selectAll().data(DATASET).......
And I couldn't get it to work at all, since (I assume this is the reason) the data hasn't been loaded to DATASET when the last line of d3.data calls DATASET
Is there any way I could update external data in d3? Should I just load the data again in my update function? Will it affect performance since the dataset is huge?
Thank you so much for answering!
If you want to read all the data once, you should store it in your global DATASET variable, just as you show in your code fragment. But instead of placing the update logic in your main script flow, put it inside an update(...) function, and call that from the d3.json callback, too... something like this (untested):
var DATASET; // global
d3.json("file.json", function(data) {
// data is loaded, save the full set
DATASET = data;
// filter the initial subset
var subdata = data.filter(...);
// now update the graph
updateGraph(subdata);
});
function updateGraph(data) {
// when invoked without any data, use the full dataset
var newdata = (data == null ? DATASET : data);
// data rendering logic starts here...
d3.selectAll().data(newdata);
...
}
This saves the full dataset in a global variable, draws the inital graph with a filtered subset of the data, and also allows you to change which data is shown by using a different filter before calling the function again.
I have a not too big grid (30x20) with numbers in cells. I have to display all, calculate them in different ways (by columns, rows, some cells, etc.) and write values to some cells. This data is also written and read from db table fields. Everything is working, excluding simple (theoretically) mask tools.
In time of e.g. writing data to the field in the table I try to start mask and close it on finish. I used such a “masks” very often but only in this situation I have a problem and can’t solve it.
I prepare this mask the following way:
msk = new Ext.LoadMask(Ext.getBody(), { msg: "data loading ..." });
msk.show();
[writing data loops]
msk.hide();
msk.destroy();
I also tried to use grid obiect in place of Ext.getBody(), but without result.
I found also that the program behaves in a special way – loops which I use to write data to the table field are "omitted" by this mask, and it looks like loops are working in the background (asynchronously).
Would you be so kind as to suggest something?
No, no, no, sorry guys but my description isn’t very precise. It isn’t problem of loading or writing data to the database. Let’s say stores are in the memory but my problem is to calculate something and write into the grid. Just to see this values on the screen. Let me use my example once again:
msk = new Ext.LoadMask(Ext.getBody(), { msg: "data loading ..." });
msk.show();
Ext.each(dataX.getRange(), function (X) {
Ext.each(dataY.getRange(), function (Y) {
…
X.set('aaa', 10);
…
}
msk.hide();
msk.destroy();
And in such a situation this mask isn’t visible or is too fast to see it.
In the mean time I find (I think) a good description of my problem but still can’t find a solution for me. When I use e.g. alert() function I see this mask, when I use delay anyway, mask is too fast. Explanation is the following:
The reason for that is quite simple - JS is single threaded. If you modify DOM (for example by turning mask on) the actual change is made immediately after current execution path is finished. Because you turn mask on in beginning of some time-consuming task, browser waits with DOM changes until it finishes. Because you turn mask off at the end of method, it might not show at all. Solution is simple - invoke store rebuild after some delay.*
I have no idea how is your code looks in general but this is some tip that you could actually use.
First of all loading operations are asynchronously so you need to make that mask show and then somehow destroy when data are loaded.
First of all check if in your store configuration you have autoLoad: false
If yes then we can make next step:
Since Extjs is strongly about MVC design pattern you should have your controller somewhere in your project.
I suppose you are loading your data on afterrender or on button click event so we can make this:
In function for example loadImportantData
loadImportantData: function(){
var controller = this;
var store = controller.getStore('YourStore'); //or Ext.getStore('YourStore'); depends on your configuration in controller
var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
myMask.show();
store.load({
callback: function (records, operation, success) {
//this callback is fired when your store load all data.
//then hide mask.
myMask.hide();
}
});
}
When data is loaded your mask will disappear.
If you have a reference to the grid, you can simply call grid.setLoading(true) to display a loading mask over the grid at any time.
I am exploring using DGrid for my web application. I am trying to have a table similar to this.
The code for the example above is here.
The table uses a memory store as the source of its data - the summary field there is what shows up when we click and expand each row.
I want the details(i.e the text shown when we click a row) to be fetched from the server on clicking on the row instead of being statically loaded along with rest of the page.
How do I modify the above code to be able to do that?
(My requirement is that of an HTML table, each row expandable on clicking, where the data on each expansion is fetched from the server, using AJAX for instance. I am just exploring dgrid as an option, as I get sortable columns for free with dgrid. If there is a better option, please let me know)
EDIT: Basically I am looking for ideas for doing that and not expecting anyone to actually give me the code. Being rather unfamiliar with Dojo, I am not sure what would be the right approach
If your ajax call returns html, you could place a dijit/layout/ContentPane in your renderer, and set the url of the contents you want to fetch in the ContentPane's href property. Assuming that your initial data (the equivalent of the example's memory store) would have a property called "yourServiceCallHref" containing the url you want to lazy load, your could try this :
require(["dijit/layout/ContentPane", ...], function(ContentPane){
renderers = {
...,
table: function(obj, options){
var div = put("div.collapsed", Grid.prototype.renderRow.apply(this, arguments)),
cp = new ContentPane({
href : obj.yourServiceCallHref
}),
expando = put(div, "div.expando", cp.domNode);
cp.startup();
return div;
}
});
If your service returns json, you could probably do something with dojo/request in a similar fashion. Just add your dom creation steps in your request callback and put them inside the div called "expando"...
Another option would be to replace the Memory store by a JsonRest store, and have the server output the same json format than the one you see on the Memory store. That means all the data would be fetched in a single call though...
I currently have a Highcharts scatterplot on my page that has the following structure:
$(function() {
$('#container').highcharts({
/*chart options, etc... this does not change*/
series: [/*there is some default data here*/]
});
});
This chart looks and works great. In addition, I have several checkboxes and a button on the page. When the button is pressed, I have some jQuery that looks at which checkboxes are checked, and sends this information to a PHP file that returns a NEW data series based on the selected checkboxes. That code looks like this:
var Obj = {};
$('button').click(function(e) {
var tableIDs = $("#boxes input:checkbox:checked").map(function() {
return $(this).val();
}).get();
var idClicked = e.target.id;
Obj.tables = tableIDs;
$.ajax({
url: 'update.php',
type: 'post',
data: {
"points": JSON.stringify(Obj)
},
success: function(data) {
console.log(data); /*for testing*/
}
});
});
This code is at the very end of the script, and outside of my highcharts function. I have thoroughly tested the AJAX back-and-forth and everything is working just fine. The way the PHP is set up, the AJAX return is of the following format:
{name: 'series1', data: [[...,...],[...,...],...]},
{name: 'series2', data: [[...,...],[...,...],...]}
Not an array, just a very long string with lots of numbers in it (I put the above on two lines for clarity). In other words, it is formatted exactly as it needs to be within the 'series:' option of my Highchart. The number of series that my PHP returns changes depending on which/how many checkboxes are checked.
So, here's my question: What is the best way to replace my default data that is already displayed on my highchart with the new data returned by AJAX? Alternatively, the default data is optional, and can be removed if it makes this any easier.
There are quite a few similar questions out there but I seem to be having troule adopting other people's solutions to my issue. I have looked a few direct update solutions, such as those proposed by rockStar and LeJared, but I have not had any luck getting them to update the old data to the new data or inserting any data for that matter.
I particularly like the solution that was proposed by DemoUser, basically passing data as a variable to a wrapped highcharts function. Here what that typically looks like:
function my_chart(data) {
$('#container').highcharts({
/*chart options, etc... this does not change*/
series: [ /*there is some default data here*/ ]
});
}
However, when I do this, it completely breaks my chart and I have been unable to get this working and passing properly.
Any suggestions/comments would be greatly appreciated.
Im doing it this way
var chart = $('#container').highcharts();
if (chart) {
chart.series[0].setData([]);
}
That should clear the data from the chart.
I just noticed in my code that im recreating the chart from scratch for the new data but i dont think that's necessary.
Once you get the new data try setting it again using
chart.series[0].setData([data]);