I am updating a Line chart using HTTP get through ngResource and a rest API.
My technique is to get the JSON dataset and create a new chart every time a user is clicking on a button.
It works great, but at one time, it causes the browser crash. I have tested on Chrome, Firefox on both Windows and Linux.
In my controller :
$scope.labels = $scope.dataFromREST;
$scope.series = ['Series A'];
$scope.data = [$scope.dataFromREST2];
$scope.onClick = function (points, evt) {
console.log(points, evt);
};
$scope.datasetOverride = [{ yAxisID: 'y-axis-1' }];
$scope.options = {
scales: {
yAxes: [
{
id: 'y-axis-1',
type: 'linear',
display: true,
position: 'left'
}
],
xAxes: [{
responsive: true,
ticks: {
autoSkip: true,
maxTicksLimit: 20
}
}]
}
};
In my index.html :
<canvas id="line" class="chart chart-line" chart-data="data"
chart-labels="labels" chart-series="series" chart-options="options"
chart-dataset-override="datasetOverride" chart-click="onClick">
</canvas>
Is there a way to just update or refresh the Line Chart with the $scope.dataFromREST data received and not create a new Chart object every time? (Because I think, the crash come from creating a new chart every time) I see the ".update()" function, but I can't seem to get it to work.
I have also tried the ".destroy()" and I am still getting the browser wind up to crash.
How can I get rid of that crash? Please help!
Yes, there is a way to simply update the underlying chart.js chart data without having to re-instantiate the chart each and every time. You just need to use the update(duration, lazy) function from the API.
Here is an example that I use in one of my apps (modified for your specific case). Note, chart is my chart.js object (what was returned from new Chart()...:
assembledData = {};
assembledData.data = // data from api call in an acceptable data format that chart.js understands
assembledData.colors = // new color definition for your data so it will update correctly
assembledData.labels = // new label definition for your data so it will update correctly
chart.data.datasets[0].data = assembledData.data;
chart.data.datasets[0].backgroundColor = assembledData.colors;
chart.data.labels = assembledData.labels;
chart.update();
Depending on how your chart behaves you may not have to re-define colors and labels on each update.
Related
Hi I have created a sample chart using public data, but it has more data to display in the chart, so I'm trying to add scroll-bar along x-axis so that all the data are displayed neatly. But I'm finding it difficult to add the scroll-bar to x-axis, so how to add scroll-bar to the chart. I have attached a plnkr for viewing. Please help me.Thank you :)
Controller:
var myApp = angular.module('app',["chart.js"]);
myApp.controller("chartController",function($scope,$http){
$scope.totalDocks = [];
$scope.availDocks =[];
$http.get("http://citibikenyc.com/stations/json")
.then(function(item){
var dataFetched = item;
console.log(dataFetched.data.stationBeanList[0]);
for(var i=0; i < 100 ; i++){
$scope.totalDocks.push(dataFetched.data.stationBeanList[i].totalDocks);
$scope.availDocks.push(dataFetched.data.stationBeanList[i].availableDocks);
}
})
})
Plunker File
Since angular.chart is responsive by itself, you do not have to add scroll bar manually, instead inorder to make chart to appear claerly you can make ticks along x axis to be skipped.
Add this to your options config,
$scope.options = {
scales: {
xAxes: [{
ticks: {
autoSkipPadding: 100
}
}]
},
responsive: true,
maintainAspectRatio: true
};
DEMO
I used angular-chart.js in my website to create a Pie chart, and I would like to customize the legend. By default, the legend shows the color and the label. (As shown in the picture below) I would like to add the value/data of that label, like what it shown in the tooltip of the chart.
This is my HTML code:
<canvas id="pie" class="chart chart-pie"
chart-data="chartData" chart-labels="chartLabels" chart-options="chartOptions">
</canvas>
Based on the angular-chart.js documentation, legend is now a Chart.js option so the chart-legend attribute has been removed.
That is why, in my JS code I've tried to add generateLabels, just in case this is what I need to customize the legend:
$scope.chartOptions = {
legend: {
display: true,
labels: {
generateLabels: function(chart){
console.log(chart.config);
}
}
}
};
But whenever I add this lines, it will not show the chart. I think it is an error or something. And I'm not sure, if generateLabels is the right option that I needed.
Can somebody teach me the right way to customize the legend to achieve what I wanted?
Thanks in advance!
Let me try shedding some light/answering your question:
generateLabels: does make custom labels,and replaces templates from v1 but in order to use it you have to get your chart information and reimplement legend labels adhering to the Legend Item Interface found in the docs and code. Sounds a bit cryptic, but in practice is somehow simple and goes like this:
var theHelp = Chart.helpers;
// You need this for later
// Inside Options:
legend: {
display: true,
// generateLabels changes from chart to chart, check the source,
// this one is from the doughnut :
// https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.doughnut.js#L42
labels: {
generateLabels: function(chart) {
var data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
var meta = chart.getDatasetMeta(0);
var ds = data.datasets[0];
var arc = meta.data[i];
var custom = arc && arc.custom || {};
var getValueAtIndexOrDefault = theHelp.getValueAtIndexOrDefault;
var arcOpts = chart.options.elements.arc;
var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
return {
// And finally :
text: ds.data[i] + "% of the time " + label,
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
index: i
};
});
}
return [];
}
}
}
Result:
Codepen: Chart.js Pie Chart Custom Legend Labels
There are other alternatives, if you notice on the pen/pie, the slices also have data information, that is from a plugin (check the pen)
Still another option, is to render the legend labels off canvas,for instance:
myPieChart.generateLegend();
Which gives you this Html:
"<ul class='0-legend'><li><span style='background-color:black'> </span>she returns it </li><li><span style='background-color:white'></span>she keeps it</li></ul>"
I haven't tried it, but I think you can modify it with the global method for your data Legend on the callback an it will give you a block of Html you can insert off canvas.
I am using a highchart pie-legend graph in a backbone application.If i click on a portion of pie chart,it calls back-end for only 1 time. If I click again on a portion without getting chart redrawn,even then only 1 call to back end is there. But if I cause chart to be redrawn by clicking on a legend and then I click on a portion of pie-chart, it calls two times for back end. I can see it on console of firebug debugger. And if I again make chart to be redrawn by any change, calls to the back-end increase accordingly. How can I restrict these unwanted multiple calls on clicking pie-legend chart.
The click on legent is also captured and kept. And when I click on pie chart,it accumulates the number of clicks and send multiple calls to back-end through model.
Thanks is advance.
The code is as follows:
chart: {
backgroundColor: null,
events:{
redraw: function() {
var dataObj = this.series[0].data;
$.each(dataObj, function( index ) {
var pathObj = dataObj[index].graphic.element;
pathObj['contentValue']=dataObj[index].name;
$(pathObj).popoverClosable({
container:'div#chart-donut',
html: true,
trigger:'click',
placement: 'top',
content:'<div class="popover-dummy"></div>'
});
$(pathObj).on('click', function () {
//render the corresponding popover content
var spinner = new Spinner().spin();
$('div.popover-dummy').html(spinner.el);
var contentCategory=pathObj.point.name;
var model = Backbone.model;
if(!that.brandDetailsPopoverView || that.brandDetailsPopoverView == null){
that.brandDetailsPopoverView = new BrandDetailsPopoverView({model:model,brandName:that.selectedBrandName,topicId:that.curTopicId,brandId:that.brandId,contentCategory:contentCategory,groupId: that.selectedGroupId,el:"#discover-popover-content"});
}
that.brandDetailsPopoverView.render(contentCategory);
$('div.popover-dummy').html($('#discover-popover-content').html());
});
});
}
},
margin: [10,20,10,10]
},
While displaying nvd3 chart with Ajax requests, the charts are getting wired up. So I thought the problem is occurring due to asynchronous call delays (may be the chart is displaying before the full data is loaded, etc). So I have used promises, but still I am getting the same problem. Please see the plunker http://plnkr.co/edit/AcIpmki7GNvcoT6Z38Pm?p=preview.
If you change the date range slider, the main chart won't display properly. I am not sure where the problem is? After searching some of the posts in forum, I have come across some thing like gaps in the time series, is it due to that? If that is the case, how can I fix that time series gap issue? I searched nvd3 website, but I don't find any documentation regarding to fill up the gaps in time series data. Some of the forum posts suggests to use c3.js instead nvd3, but I don't know is it really worth to shift to c3.js? Within my experience I feel nvd3 are the best and I don't feel like leaving nvd3.
If nvd3 website provides more samples with real time series data and documentation on some of the common issues like filling gaps in time series, sorting the data, etc it will be really helpful for the beginners.
As my project release dates are nearing, I am not sure what to do now ? Shifting to c3.js is the worst option for me. I have attached the error screen shot too from the same plunker.
I feel there is no problem with the sorting that I am doing with my json data:
angular.forEach($scope.data, function(
series, index) {
series.values.sort(function(a, b) {
return a.x - b.x;
});
});
Couple of issues for you to look at:
I agree with shabeer90, the data is funky. You have multiple values occurring at the same time.
Your sort is correct, but where you have it in your code doesn't work...try adding it inside the response of the ajax call (right after setting $scope.data = data).
Also, you need to make the changes that I outlined in another question (to nvd3 in the lineWithFocusChart model).
Accessing the xScale is a little more tricky...on this chart you need to go through the lines:
$scope.options = {
chart: {
type: 'lineWithFocusChart',
height: 450,
margin : {
top: 20,
right: 20,
bottom: 60,
left: 40
},
transitionDuration: 500,
lines : { // <-- add this
xScale : d3.time.scale()
},
lines2 : { // <-- add this too
xScale : d3.time.scale()
},
xAxis: {
ticks : d3.time.months, <-- add the time interval
axisLabel: 'X Axis',
tickFormat: function(d){
return d3.time.format('%d/%m/%y')(new Date(d))
}
},
x2Axis: {
tickFormat: function(d){
return d3.time.format('%d/%m/%y')(new Date(d))
}
},
yAxis: {
axisLabel: 'Y Axis',
tickFormat: function(d){
return d3.format(',.2f')(d);
},
rotateYLabel: false
},
y2Axis: {
tickFormat: function(d){
return d3.format(',.2f')(d);
}
}
}
};
I am currently working on a task which want to display bar charts/tables on the website.
The application is using: sproutcore (1.6) as front-end, Java Restful as backend.
However, I can't find some useful library for charts in sproutcore. Are there any ideas for that?
I search on the website, I feel the google chart tools is quite good, also jFreechart as backend is also a good choice.
I am not sure how to integrate that to sproutcore.
Thanks.
I'm using Flot to display charts on my Sproutcore app.
To use it, you need to create a flot directory inside the frameworks folder which will include the jquery.flot.js file (I've also include jquery.flot.pie.js file) and a core.js file with this content:
sc_require('jquery.flot.js');
sc_require('jquery.flot.pie.js');
Flot = SC.Object.create({
plot: $.plot
}) ;
Then, you need to add this new library to your buildfile :
config :yourapp,
:required => ['flot']
To display your charts in your app, you can use this custom view that I made to work with Flot:
GX.FlotView = SC.View.extend({
classNames: ['flot'],
//ex: [{ data: [[1326366000000, 1500], [1326452400000, 600]], label: 'title of the serie' }, ...]
data: [],
/*
ex: {
legend: { show: true },
series: line, points,
xaxis: { mode: "time", timeformat: "%d/%m/%y", }
grid: { backgroundColor: { colors: ["#FFF", "#fefefe"]}},
}
*/
options: [],
render: function(context, firstTime) {
var frame = this.get('frame'),
data = this.get('data'),
options = this.get('options');
// To avoid an error with flot, we check if width and height > 0
if(frame.width > 0 && frame.height > 0 && data && data.length) {
var layer = this.get('layer'),
plot = Flot.plot(layer, data, options);
}
},
viewDidResize: function() {
this.invokeLast(function() {
if (this.get('isVisibleInWindow')) this.set('layerNeedsUpdate', YES);
});
}.observes('data', 'data.[]'),
});
Then, you just have to bind the data and the option properties with your data.