google.visualization.LineChart is not loading second time - angularjs

I am working on Angular/ionic Cordova project. I am using google.visualization.LineChart to display the chart in my project. First time when we come on the page where I have draw the chart, It is working properly. But when I further navigate to next ion-view and came back to the screen where I have drawn the chart, chart does not appear. Any idea why it is happening? here is my code:
$scope.$on('$ionicView.enter', function() {
$ionicLoading.show({
template: '<ion-spinner icon="spiral"></ion-spinner>',
noBackdrop:false
});
serverRepo.salesMonthly().then(function(objS){
$scope.monthlyData=objS.data;
if(objS.data.orders == null){
$ionicLoading.hide();
alert('There is not data regarding Monthly Sale');
}else{
angular.forEach(objS.data.orders, function(value, key) {
objS.data.orders[key].CreatedOn=new Date(objS.data.orders[key].CreatedOn);
if(key == objS.data.orders.length-1){
$scope.data = objS.data;
drawChart();
console.log('drawChart Called');
}
})
$ionicLoading.hide();
}
},function(objE){
console.log("Error:-\n"+JSON.stringify(objE));
$ionicLoading.hide();
});
});
function drawChart(){
var options = {
legend: { position: 'bottom' },
curveType: 'function',
titlePosition: 'in',
axisTitlesPosition: 'in',
hAxis: {
textPosition: 'in',
minValue: 0,
textStyle:{color: "#fff"}
},
vAxis: {
minValue: 0,
maxValue: 13,
textPosition: 'in',
textStyle:{color: "#fff"},
minorGridlines:{color: "#ccc"}
},
lineWidth: 6,
fontSize:11,
chartArea:{left:0,top:0,width: '100%', height: '100%',backgroundColor: '#43396D'},
colors: ['#32BD76'],
animation:{
duration: 1500,
easing: 'out',
startup: true
}
};
google.charts.setOnLoadCallback( function () {
// Create and populate the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'labels');
data.addColumn('number', 'data');
for(i = 0; i < $scope.data.labels.length; i++)
data.addRow([$scope.data.labels[i], $scope.data.datasets.data[i]]);
// Create and draw the visualization.
$scope.myChart=new google.visualization.LineChart(document.getElementById('curve_chartmonthly'));
$scope.myChart.draw(data, options);
console.log('chart drawn.......');
});
}

think the problem has to do with google.charts.setOnLoadCallback
which is called once per page load
try moving the code inside the callback to drawChart
then call drawChart from the callback
see following example...
$scope.$on('$ionicView.enter', function() {
$ionicLoading.show({
template: '<ion-spinner icon="spiral"></ion-spinner>',
noBackdrop:false
});
serverRepo.salesMonthly().then(function(objS){
$scope.monthlyData=objS.data;
if(objS.data.orders == null){
$ionicLoading.hide();
alert('There is not data regarding Monthly Sale');
}else{
angular.forEach(objS.data.orders, function(value, key) {
objS.data.orders[key].CreatedOn=new Date(objS.data.orders[key].CreatedOn);
if(key == objS.data.orders.length-1){
$scope.data = objS.data;
drawChart();
console.log('drawChart Called');
}
})
$ionicLoading.hide();
}
},function(objE){
console.log("Error:-\n"+JSON.stringify(objE));
$ionicLoading.hide();
});
});
function drawChart(){
var options = {
legend: { position: 'bottom' },
curveType: 'function',
titlePosition: 'in',
axisTitlesPosition: 'in',
hAxis: {
textPosition: 'in',
minValue: 0,
textStyle:{color: "#fff"}
},
vAxis: {
minValue: 0,
maxValue: 13,
textPosition: 'in',
textStyle:{color: "#fff"},
minorGridlines:{color: "#ccc"}
},
lineWidth: 6,
fontSize:11,
chartArea:{left:0,top:0,width: '100%', height: '100%',backgroundColor: '#43396D'},
colors: ['#32BD76'],
animation:{
duration: 1500,
easing: 'out',
startup: true
}
};
// Create and populate the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'labels');
data.addColumn('number', 'data');
for(i = 0; i < $scope.data.labels.length; i++)
data.addRow([$scope.data.labels[i], $scope.data.datasets.data[i]]);
// Create and draw the visualization.
$scope.myChart=new google.visualization.LineChart(document.getElementById('curve_chartmonthly'));
$scope.myChart.draw(data, options);
console.log('chart drawn.......');
}
google.charts.setOnLoadCallback(drawChart);

I have the same problem. I resolve change the ID reference for a class.
Ex:
to
After, identify the element with jquery:
from document.getElementById('your_chart_id') to $('.your_chart_id')[0]

Related

AngularJS Nvd3 Chart - Call the callback on every statechange

I have a graph who can have one set of data or multiples set of data. I need to check every stateChange and triggered the callback (he make actions that I need to make at every changes).
here is my graph :
scope.options = {
chart: {
type: 'lineChart',
height: 450,
margin : {
top: 20,
right: 20,
bottom: 40,
left: 55
},
useInteractiveGuideline: false,
dispatch: {
stateChange: function(){ console.log("stateChange"); },
changeState: function(){ console.log("changeState"); },
tooltipShow: function(){ console.log("tooltipShow"); },
tooltipHide: function(){ console.log("tooltipHide"); },
},
xAxis: {
axisLabel: 'Temperature (Celcius)'
},
yAxis: {
axisLabel: 'Fluorescence',
tickFormat: function(d){
return d3.format('0f')(d);
},
axisLabelDistance: -10
},
callback: function(chart){
console.log("!!! lineChart callback !!!");
// If there is a tm point we show it
if (data.length === 1 && angular.isObject(tmPoints[data[0].key])){
console.log("SHOW TM");
data[0].values.forEach(function(element){
if (parseInt(element.x) === parseInt(tmPoints[data[0].key].tm)){
// Recuperer l'objet point et non ses valeurs
highlightPoint(chart, {'point' : element}, 10, true);
}
});
}
console.log(data.length);
if (data.length === 1) {
chart.lines.dispatch.on("elementClick", function(e) {
// Faire ça uniquement si il y a UN graph
if (clickedPoints.length >= 2){
// Remove the first point of the array
var pointToDelete = clickedPoints.shift(0,1);
// And remove his highlight
removeHighlightPoint(pointToDelete, pointToDelete.element.attributes[1].nodeValue);
}
clickedPoints.push(e);
highlightPoint(chart, e, 7, false);
});
}
},
},
title: {
enable: true,
text: 'Title for Line Chart'
},
};
I need to make actions when only one set of data is show, I have my condition for the if but the callback is called only one time at the beggining, how can I call at every stateChange ?
I also need to call the callback when my options change, currently when I change the scope.options, no one of the event (stateChange) are triggered, and the callback is not triggered too.
Anyone have an idea ?

Why isn't my spline chart showing when using combo charts?

So I'm using Highcharts-ng with Angular to create a combination chart of a spline chart and a column chart formatted as a histogram to show trends.
The way it works is that the on the load of the page, I only see the histogram, and not the spline. Changing the order does nothing.
It looks as though if I have the spline chart data hard-coded it shows, but using the program to add in the data after a service is called in does not work.
(function() {
'use strict';
angular
.module('app.widgets')
.directive('trends', trends);
trends.$inject = ['ResultsService'];
/* #ngInject */
function trends() {
var ddo = {
restrict: 'EA',
templateUrl: 'app/widgets/trends/trends.directive.html',
link: link,
scope: {
data: '=',
config: '='
},
controller: controller,
controllerAs: 'vm',
bindToController: true
};
return ddo;
function link(scope, element, attrs) {
}
function controller($scope, ResultsService) {
var vm = this;
var parent = $scope.widgetController;
var size = {
height: angular.element('li.widget-border.ng-scope.gridster-item')[1].style.height - 20 ,
width: angular.element('li.widget-border.ng-scope.gridster-item')[1].style.width - 20
};
vm.histogram = {
chart: {
zoomType: 'xy'
},
title: {
text: 'Average Monthly Weather Data for Tokyo'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
crosshair: true
},
yAxis: { // Primary yAxis
labels: {
style: {
color: Highcharts.getOptions().colors[2]
}
},
title: {
text: 'Events',
style: {
color: Highcharts.getOptions().colors[2]
}
}
},
tooltip: {
shared: true
},
legend: {
layout: 'vertical',
align: 'left',
x: 80,
verticalAlign: 'top',
y: 55,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
},
series: [{
name: 'Average',
type: 'spline',
data: [],
marker: {
enabled: true
}
}],
loading: false,
useHighStocks: false,
size: {
height: size.height,
width: size.width
}
};
vm.processChartData = processChartData;
vm.data = {
charts: {
}
};
ResultsService.getData().then(function(res) {
vm.data = {
charts: {}
};
vm.data.charts = processChartData(res);
vm.histogram.xAxis.categories = [];
vm.histogram.series.push ({
name: 'Events per month',
type: 'column',
data: [],
marker: {
enabled: true
}
});
console.log(vm.histogram.series);
angular.forEach(vm.data.charts.months, function(v,k){
vm.histogram.xAxis.categories.push(k);
vm.histogram.series[1].data.push(v);
});
vm.histogram.options = {
plotOptions: {
}
};
vm.histogram.options.plotOptions = {
column: {
borderWidth: 0.5,
groupPadding: 0,
shadow: true
},
};
console.log(vm.data.charts.months);
vm.histogram.xAxis.categories.sort();
var average = calculateAverage();
vm.histogram.series[0].data=average;
console.log(vm.histogram.series);
});
function swap(pos1, pos2){
var temp = vm.histogram.series[pos1];
vm.histogram.series[pos1] = vm.histogram.series[pos2];
vm.histogram.series[pos2] = temp;
}
function calculateAverage() {
var averageArray = [];
var total = 0;
angular.forEach(vm.data.charts.months, function(v,k){
console.log(v);
total += v;
});
console.log((total/12.0).toFixed(2));
var average = (total/12.0).toFixed(2);
angular.forEach(vm.histogram.xAxis.categories, function(v,k){
averageArray.push(average);
});
return averageArray;
}
function processChartData(data) {
var output = {};
var months = {};
var dayOfWeek = {};
var epoch = {};
angular.forEach(data, function (value, index) {
// by month
if (!months[value.eventDate.month]) {
months[value.eventDate.month] = 1;
}
months[value.eventDate.month] += 1;
// by day of week
if (!dayOfWeek[value.eventDate.dayOfWeek]) {
dayOfWeek[value.eventDate.dayOfWeek] = 1;
}
dayOfWeek[value.eventDate.dayOfWeek] += 1;
// by day
if (!epoch[value.eventDate.epoch]) {
epoch[value.eventDate.epoch] = 1;
}
epoch[value.eventDate.epoch] += 1;
});
output.months = months;
output.dayOfWeek = dayOfWeek;
return output;
}
$scope.$on('gridster-item-resized', function(item){
var element = angular.element(item.targetScope.gridsterItem.$element[0]);
vm.histogram.size = {
height: element.height()-35,
width: element.width()
};
$scope.$broadcast('highchartsng.reflow');
});
}
}
})();
The chart on the webpage looks like this with the given code!
As you can see, it shows the legend with the spline, but the spline doesn't show up. I can't figure out why.
Your calculateAverage() function returns an array of strings since .toFixed(2) returns a string. Make sure it's an array of numbers. Convert average to a number with average = parseFloat(average) for example.

Sending a value from html to controller in angularjs. Issue with scope?

I have have a web app set up to display charts using the highcharts-ng directive.
I have the same type of chart with the same series data displaying on multiple views. The only difference between the charts is the height value which I would like to be able to set when I initialise my chart in my html markup.
This is how I have set things up:
The highcharts-ng directive is installed through bower.
I initialise my chart as follows:
<div ng-controller="AgeChartController" >
<highchart diagramHeight="500" id="{{link + '_chart'}}" config="ageChartConfig">
</highchart></div>
In my AgeChartController I do the following:
Pull data from JSON file
Get chart height attribute from diagramHeight
Construct Highcharts options object and send diagramHeight to this options object
angular.module('socialDashboard')
.controller('AgeChartController', function ($scope, $http, $attrs) {
var seventeenCount = 0;
var eighteenCount = 0;
var twentyFiveCount = 0;
var thirtyFiveCount = 0;
var chartHeight = 0;
var posts = [];
$http.get('dummy_content.json')
.then(function(res){
posts = res.data;
for (var i = 0; i < posts.length; i++) {
if (posts[i].age <= 17) {
seventeenCount++;
}
else if ((posts[i].age >= 18) && (posts[i].age <= 24)) {
eighteenCount++;
}
else if ((posts[i].age >= 25) && (posts[i].age <= 34)) {
twentyFiveCount++;
}
else if (posts[i].age >= 35) {
thirtyFiveCount++;
}
}
chartHeight = $attrs.diagramHeight;
$scope.ageChartConfig = {
options: {
chart: {
type: 'bar',
height: chartHeight,
backgroundColor: false
}
},
title: {
text: false
},
xAxis: {
categories: ['< 17', '18 - 24', '25 - 34', '> 35']
},
yAxis: {
gridLineWidth: 0,
title: {
text: 'Post count'
},
labels:
{
enabled: false
}
},
plotOptions: {
series: {
dataLabels: {
enabled: true
}
}
},
legend: {
layout: 'vertical',
floating: true,
backgroundColor: '#FFFFFF',
align: 'right',
verticalAlign: 'top',
y: 60,
x: -60
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' +
this.x + ': ' + this.y;
}
},
navigation: {
buttonOptions: {
enabled: false
}
},
series: [{
name: 'Post count',
showInLegend: false,
data: [{
color: '#9365b8',
y: seventeenCount
}, {
color: '#2c82c9',
y: eighteenCount
}, {
color: '#41a85f',
y: twentyFiveCount
}, {
color: '#fac51c',
y: thirtyFiveCount
}]
}],
loading: false
};
});
});
However when I declare my chart elsewhere with diagramHeight set to 200:
<div ng-controller="AgeChartController">
<highchart diagramHeight="200" id="{{link + '_chart'}}" config="ageChartConfig">
</highchart></div>
Only one of the two values get pulled and my chart is set the same across all charts (height 500). Why is this? Does this have something to do with my scope? I'm pretty new to angular and still getting my head around scope.
You should use angular factory to configure chart
app.factory('chartname', function () {
var agechart={ // your all chart option here
.
.
}
return agechart;
});
You can use above factory in any controller now just like
app.controller("controllername",function(chartname){
$scope.ageChartConfig=chartname;
});

Render Two charts separate charts using angular js directives

I am trying to render two seperate charts using seperate directives for each charts, since the data is different ( also I am no expert in AngualrJs ). But only one chart was rendering to view. Please can someone help with what I have to do so that I can see both charts.Thanks.
'use strict';
angular.module('AngularApp',['AngularApp.directives']);
/*Controllers*/
var HighChartController = function HighChartController($scope) {
$scope.templateUrl = '/_layouts/AngularControls/TestController/View2.html';
$scope.type = '107';
$scope.initData = function () {
$scope.data = [
['Fire', 47.0],
['Wind', 33.0],
['Natural', 20.0]
];
}
$scope.loadChart = function () {
$scope.data1 = [60];
$scope.data2 = [40];
}
$scope.initData();
$scope.loadChart();
}
/* Directives */
angular.module('AngularApp.directives', []).
directive('drawPieChart', function () {
return function (scope, element, attrs) {
var container = $(element).attr("id");
scope.$watch('data', function () {
console.log('data');
drawPlot();
}, true);
var drawPlot = function () {
var chart;
chart = new Highcharts.Chart({
chart: {
renderTo: container,
margin: [0, 0, 0, 0],
spacingTop: 0,
spacingBottom: 0,
spacingLeft: 0,
spacingRight: 0
},
title: {
text: null
},
credits: {
enabled: false
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage}%</b>',
percentageDecimals: 1
},
plotOptions: {
pie: {
size: '100%',
dataLabels: {
enabled: false
}
}
},
series: [{
type: 'pie',
name: 'Browser share',
data: scope.data
}]
});
}
}
});
angular.module('AngularApp.directives', []).
directive('drawBarChart', function () {
return function (scope, element, attrs) {
var container = $(element).attr("id");
scope.$watch('data', function () {
drawPlot();
}, true);
var drawPlot = function () {
var chart = new Highcharts.Chart({
chart: {
type: 'column',
renderTo: container,
marginRight: 50,
events: {
}
},
title: {
text: 'Test Scores',
style: {
color: 'black',
fontWeight: '700',
fontFamily: 'Arial',
fontSize: 20
}
},
xAxis: {
categories: [],
title: {
text: null
},
gridLineWidth: 0,
minorGridLineWidth: 0,
labels: {
style: {
color: 'black',
fontWeight: '700',
fontFamily: 'Arial',
fontSize: 11,
width: 90
}
}
},
yAxis: {
min: 0,
max: 100,
gridLineWidth: 0,
minorGridLineWidth: 0,
labels: {
enabled: false
},
title: {
text: null
}
},
tooltip: {
valueSuffix: ' million'
},
plotOptions: {
series: {
stacking: 'percent'
},
bar: {
dataLabels: {
enabled: false
}
}
},
legend: {
enabled: false,
layout: 'vertical',
align: 'right',
verticalAlign: 'bottom',
x: -40,
y: 100,
floating: true,
borderWidth: 1,
backgroundColor: '#FFFFFF',
shadow: true
},
credits: {
enabled: false
},
series: [{
name: 'null',
data: scope.data2,
borderRadius: 0,
color: "gray"
}, {
name: 'Values',
data: scope.data1,
color: "green",
borderRadius: 0
}]
});
}
}
});
Here is the markup
<div id="barChartContainer" draw-bar-chart =""></div>
</div>
<div id="pieChartContainer" draw-pie-chart="">
</div>
As Oledje mentioned, you declared the AngularApp.directives twice, but there was also an issue with how you are actually referencing the data for the charts in the directive code. I would recommended that you create an isolated scope for each directive and map the properties for the chart data in the scope definition.
So instead of
.directive('drawPieChart', function () {
return function (scope, element, attrs) {
var container = $(element).attr("id");
scope.$watch('data', function () {
console.log('data');
drawPlot();
}, true);
var drawPlot = function () {...};
};
}
You should do
.directive('drawPieChart', function () {
return {
restrict: 'E',
scope: {
chartData: "="
},
link: function (scope, element, attrs) {
scope.$watch('chartData', function (newVal,oldVal) {
if (newVal) {
drawPlot();
}
}, true);
var drawPlot = function () {
// use scope.chartData for the data
};
}
};
}
And then you also need the corresponding HTML
<draw-pie-chart chart-data="pieChartData">
And in your Controller do $scope.pieChartData=[];
Here is a jsFiddle with all of my changes: http://jsfiddle.net/callado4/9far5/5/ (look at the history to see how I progressed)
I think that your problem is that you declare a module twice.
try write not
angular.module('AngularApp.directives', []).
directive('drawPieChart'...)
angular.module('AngularApp.directives', []).
directive('drawBarChart'...)
but
angular.module('AngularApp.directives', []).
directive('drawPieChart'...).
directive('drawBarChart'...)
or
var app = angular.module('AngularApp.directives', []);
app.controller('Ctrl', ...)
app.directive('drawPieChart'...);
app.directive('drawBarChart'...);
Examples:
http://jsfiddle.net/GDQ6B/2/
http://jsfiddle.net/EYz9U/1/

Extjs Tool tip for chart category label

Here is the Label object
,
label: {
rotate: {
degrees: 90
},
renderer: function(v){
var toolTip = Ext.create('Ext.tip.ToolTip', {
target: this,
html: v,
anchor: 'left',
dismissDelay: 0,
showDelay: 0,
autoHide: false
});
toolTip.on('show', function(){
var timeout;
toolTip.getEl().on('mouseout', function(){
timeout = window.setTimeout(function(){
toolTip.hide();
}, 500);
});
toolTip.getEl().on('mouseover', function(){
window.clearTimeout(timeout);
});
Ext.get(targetId).on('mouseout', function(){
timeout = window.setTimeout(function(){
toolTip.hide();
}, 500);
});
});
if(v.length>10)
return Ext.util.Format.substr(v,0,10) +'...' ;
}
}
This code is not not creating the tool tip. No error occurs. Is there any other method to create the category label tool tip.
Thanks,
Anish

Resources