I am creating 5 separate charts and try to update them every few seconds with new series data.
If I define just one function that creates new chart and add series data in constructor, it works, but the downside is that every page refresh with setInterval() destroys charts and rebuilds them, which looks terrible.
So I created two functions, CreateChart() called once, and UpdateChart() called on every setInterval() refresh. Now charts are empty and I get error on UpdateChart():
TypeError: FlightCharts[Index].series[0] is undefined
Link to javascript code
Link to example json series data
Any tips (I'm new to javascript)
thanks
The problem is that you defined empty series:
series: []
Next you are trying to set data for a first series:
FlightCharts[Index].series[0]
Instead you should create that one series at least:
series: [{
name: "MyName",
data: []
}]
Related
I have trouble getting the hideNoData() and showNoData() to work with the official highcharts-angular component (https://github.com/highcharts/highcharts-angular).
Here is a basic example in stackblitz: https://stackblitz.com/edit/angular-highcharts-zvkcys?file=app%2Fapp.component.ts
This is a simplified version. In my real project I'm fetching data async, and while loading I show my custom (not the one highcharts provides) loading indicator. So initially I want to turn off the no Data Message but once the result comes back, depending on the result I might need to show the no Data Message.
I already tried using the [(update)]="updateFlag" on the chart component to trigger a change after calling hideNoData() but with no effect. Same goes for update(), reflow() or redraw().
I even manually called detectChanges to force a digest cycle but also with no effect.
With Highcharts, I find it's important for my components to know the charts reference, you can use the supplied Output callback, in highcharts-chart to do this. In your component you can do:
public callback = this.chartCallback.bind(this);
Where chartCallback is:
public chartCallback(chart: Highcharts.Chart)
{
this.chart = chart;
}
HTML will look like:
<highcharts-chart [Highcharts]="Highcharts" [options]="options
[callbackFunction]="callback">
</highcharts-chart>
This allows us to grab the actual reference of the Highchart object, and use it like:
public hideNoData(): void
{
this.chart.hideNoData();
}
But ofcourse, once you have the reference to the chart, you can use it freely within the component.
See here for a full working example.
Additionally, if you never want the no data message to show. Then this might be your best route:
this.options = {
title : { text : 'simple chart' },
series: [{
data: [],
}],
noData: null
};
ok I found the solution. Apparently Highcharts cannot handle it in the same digest cycle. if i call
setTimeout(() => {
chart.hideNoData();
});
It works and is correctly hidden. However now it briefly flashes in the beginning, the solution to that is disabling the automatic message completely. In the chart options add following:
chart: {
events: {
load(): void {
this.hasData = (): boolean => {
return true;
};
},
},
},
I'm generating a JSON with a random set of X's and O's and trying to plot them into a simple grid using a custom element in polymer. When I first open the page everything runs fine and i see a different grid each time. I've also added a button on an index.html page that regenerates the JSON with a new set of X's and O's, but the polymer element wont flag an event change or update its child elements with the new data.
It only seems to be an issue with my JSON object, because if i change it to a string, i get a change notification each time...
i have written a simple "forceDB.js" script that generates the JSON and passes it to the polymer element with .setAttribute('layout', data) how do I notifiy the change to polymer and have all the children elemtents of my polymer script update?
The JSON object looks like this
let data = {
"a1":"",
"a2":"",
"a3":"",
"b1":"",
"b2":"",
"b3":"",
"c1":"",
"c2":"",
"c3":""
};
my polymer script side of the element looks like this...
enter code here
<script>
Polymer({
is:'grid-layout',
properties:{
layout: {
type: Object,
reflectToAttribute : true
},
observers: 'layoutChanged(layout.*)'
},
setLayout: function(newdb){
console.log('new - ' + JSON.stringify(newdb));
this.set('layout', newdb);
},
layoutChanged: function(changedthing){
alert("Layout Changed!");
},
});
</script>
I think that I may be missing a key point in polymer or maybe I'm doing something wrong. But I have a simple X's and O's game that I'm developing to try come to grips with polymers data binding principals and seem to be falling short where.
Could it be that the layout property needs:
notify: true
And it might be helpful to see how you are data binding the layout property to the child elements in the HTML.
I have following kendo example with a custom edit template:
In the example there is a custom edit template, so when you double click on the calendar to make a new event this will show with the custom fields.
There is a custom field for "Contacts" which has an array as data source.
This data source is an array I get from the server (takes 1-2 seconds to get).
The fact that the edit template is prepared with tags makes it not possible to simply create in my success (or done) handler of the ajax call that gets the data.
The only way I see is to have the data ready at page load so that the template picks it up.
I want however to either create the template whenever my data load is done or add my data to it after it is loaded.
To simulate the time the server takes for the data to load I use setTimeout of 1 sec, that way the edit template does not pick up the data.
To recreate:
double click on the calendar to create an event
notice that the contact field is empty (because data is not ready at page load)
Any help appreciated
This has nothing to do with the async delay. Your kontaktdata array is local to the anonymous function you pass to setTimeout, so it simply doesn't exist in the context the template is evaluated in.
Your data has to either be defined on the data model itself or in the global context.
The other problem is that the data structure itself has to exist - either a kendo.data.DataSource or an array, and you need to update it with new data if you want an existing view to be aware of that new data. If you simply replace it, the edit template has no way of picking that up immediately (if you open a new edit dialog, it will also work, of course).
So if you do this, for example, it will work:
var kontaktdata = [];
setTimeout(function(){
kontaktdata.push.apply(kontaktdata, [
{ text: "Demo B Client", value: 1 },
{ text: "Martin", value: 2 },
{ text: "Herbert", value: 3 }]);
}, 4000);
Is possible to pass custom data when rendering a Highcharts graph (funnel, in this case), so that when I bind a click event, I can use this custom data point?
Currently, all that I can get is the "name" event.point.name, which I provide for the Label, but I also want to pass a song_id too.
http://jsfiddle.net/y4a2end3/1/
Is there a place in the graph code that I can add another data point, like "song_id"?
series: [{
name: 'Song Plays',
data: [
['song_name1',123, 'song_id_1'], /* song_id_1 would be the custom data */
['song_name2',234, 'song_id_2']
]
}]
If you want to attach additional data to points in a series you can initialize the points that need additional data as objects instead of arrays/ints. For example, with your code you could do:
series: [{
name: 'Song Plays',
data: [
{x:'song_name1', y:123, songid:'song_id_1'},
{x:'song_name2', y:234, songid:'song_id_2'}
]
}]
You can then get it from the point on click as event.point.songid. See this JSFiddle demo using point click and tooltip.
Note that in many cases x in the object will not be required. It is often automatic and sequential.
You can try
alert(event.point.series.userOptions.data[event.point.x][2])
Updated fiddle: http://jsfiddle.net/y4a2end3/2/
Or this:
alert(event.point.series.userOptions.data[event.point.series.data.indexOf(event.point)][2]);
I use D3.js to visualize a couple of datasets in an interactive and dynamic way. Users can explore all graphs and retrieve individual views on the data by loading combining additional data and views. I want users to be able to share their treasure found in the data via mail, facebook etc. but in a way the new user, visiting the shared "snapshot" could move on exploring the data. So I need to
persist the current state of my dynamic webpage
be able to load and display this state fast.
bind all events that have been bound in the moment the user snapshot
As a as simple as possible example (there are going to be various graphs and lots of events), imagine having a simple d3 linegraph and
graph.selectAll("path").on('mouseover', function(d){
$.get("ajaxFunction",{"d" : d} ,function(jsonData) {
//INIT NEW SVG
});
});
This new dynamically loaded page contains i.e. several svgs. But if I simply save the shape and position of every svg, it could be hard to keep track of all current event-bindings.
And if I save every action the former user did, how could I reload the snapshot efficiently?
The simplest thing i can imagine would be looping over all the nodes storing their identity and their state as a hash then sending this hash as json using ajax back to the server and putting the hash in a databas along with a key that is returned to the user as an url.
when visiting the url you then load the d3js object and run through the hash setting the state of each node to what it was.
getting the state of the nodes would require some more knowledge in d3js.
What kind of data are you displaying? You should perhaps beable to add an event register to your js and record all the events executed. trough the event callers.
for instance say I have the following data
{"Things":{
"Balls":{
"Footballs":"",
"Basketballs":""
},
"Persons":{
"Painter":{
"Pablo":"","Robert":""
},
"Programmers":{
"Robert":""}}}
You should and want to show/hide nodes of this tree on mouse click.
You should be able to do somthing like this
var eventlog = [];
$(".nodes").onClick(function(this){
if (isClosed(this)){
function_to_open_node();
eventlog.append({"action" : "open", "id" : this.id})
}else{
function_to_close_node();
eventlog.append({"action" : "close", "id" : this.id})
}
})
This way you should end up with somthing like this
[{"action" : "close", "id" : "id"},{"action" : "close", "id" : "someotherid"},{"action" : "close", "id" : "someid"}]
Thus you have a storable state! that can be executed.