AngularJS Nvd3 Chart - Call the callback on every statechange - angularjs

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 ?

Related

Set background color of Angular-nvD3

I am using Angular-nvD3 in my Charts and I would like to change the background of this chart like the picture example. Can anyone help me please?
Here its the HTML code:
<div class="col-md-6">
<nvd3 options="optionsrigidez" data="datarigidez" class="with-3d-shadow with-transitions"></nvd3>
</div>
And here its the angular params:
1. Options:
$scope.optionsrigidez = {
chart: {
type: 'lineChart',
height: 250,
reduceXTicks: true, // if false a tick will show for every data point
margin: {
top: 20,
right: 20,
bottom: 40,
left: 55
},
x: function (d) { return d.x; },
y: function (d) { return d.y; },
useInteractiveGuideline: true,
dispatch: {
stateChange: function (e) { console.log("stateChange"); },
changeState: function (e) { console.log("changeState"); },
tooltipShow: function (e) { console.log("tooltipShow"); },
tooltipHide: function (e) { console.log("tooltipHide"); }
},
yDomain: [0.0, 100.0],
showLegend: false,
xAxis: {
axisLabel: 'Data da análise',
tickFormat: function (d) {
return daysOfReport[d];
},
rotateLabels: -1
},
yAxis: {
axisLabel: 'kV',
tickFormat: function (d) {
return d3.format('.01f')(d);
},
axisLabelDistance: -10
},
callback: function (chart) {
//console.log("!!! lineChart callback !!!");
}
},
title: {
enable: true,
text: 'Rigidez Dielétrica - Calota'
},
caption: {
enable: true,
html: '<b>Gráfico 3.</b> É uma medida da capacidade do óleo resistir à solicitação elétrica. Revela também a presença de impurezas polares como a água e outros oxigenados e sólidos (NBR 6869). Fonte: <a href="http://www.filtroil.ind.br/analise-de-oleo-isolante">Filtroil.<a/>',
css: {
'text-align': 'justify',
'margin': '10px 13px 0px 7px'
}
}
};
Data:
function rigidez_function() {
var rigidez = [];
for (var i = 0; i < $scope.RelatorioOleo_analisesFQ.length; i++) {
rigidez.push({ x: i, y: $scope.RelatorioOleo_analisesFQ[i].calota });
}
//Line chart data should be sent as an array of series objects.
return [
{
values: rigidez, //values - represents the array of {x,y} data points
key: 'Rigidez Dielétrica', //key - the name of the series.
color: '#5A5A5A', //color - optional: choose your own line color.
strokeWidth: 2,
//classed: 'dashed'
}
];
};
$scope.datarigidez = rigidez_function();
Probably a bit late, but yes you can!
You have to create a MultiChart and draw the colored zones as 'stacked areas'. I've created a plunk here: http://plnkr.co/hW3Anw
chart: {
type: 'multiChart',
height: 450,
margin : {
top: 30,
...
testdata[1].type = "area"
testdata[1].yAxis = 1
testdata[1].values = [{x: 0, y: -0.5}, {x: 55, y: -0.5}]
testdata[2].type = "area"
testdata[2].yAxis = 1
testdata[2].values = [{x: 0, y: -5}, {x: 55, y: -5}]
...

google.visualization.LineChart is not loading second time

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]

Filter by range date for angular-nvd3 directive?

I create an nvd3 graph with the angular-nvd3 directive:
<nvd3 id="analytics-community" options="vm.community.options" data="vm.community.data" config="vm.graphConfig" class="with-3d-shadow with-transitions"></nvd3>
However it does not seem possible to filter the data attribute using |filter:something as it ends up looping infinitely and angular breaks with infinite loop error.
Graph options are setup with:
vm.graphOptions = {
chart: {
type: 'lineChart',
height: 300,
margin : {
top: 50,
right: 50,
bottom: 50,
left: 50
},
x: function(d) {
return d3.time.format.iso.parse(d.key);
},
y: function(d) {
return d.value;
},
useInteractiveGuideline: false,
dispatch: {
stateChange: function(e) { },
changeState: function(e) { },
tooltipShow: function(e) { },
tooltipHide: function(e) { }
},
xScale: d3.time.scale(),
xAxis: {
axisLabel: 'Date',
tickFormat: function (d) {
return d3.time.format('%b %Y')(new Date(d));
}
},
yAxis: {
axisLabel: 'Count',
tickFormat: function(d) {
return d;
}
}
}
};
And the data is set-up with:
vm.community.data = [
{
key: 'Members',
values: vm.statsModel.registeredMembers
},
{
key: 'Students',
values: vm.statsModel.registeredStudents
},
{
key: 'Alumni',
values: vm.statsModel.registeredAlumni
}
];
Where vm.statsModel.registeredMembers is like:
[
{
key: "2015-06-15",
value: 458
},
{
key: "2015-06-23",
value: 459
},
{
key: "2015-06-27",
value: 460
}
]
Any ideas?
Setting the xDomain in vm.graphOptions.chart worked:
vm.graphOptions.chart.xDomain = [new Date(vm.selectedItem.date), dateToday]
Where vm.selectedItem.date = new Date().setMonth(new Date().getMonth() - 6) for 6 months ago... and dateToday = new Date()
So I just $watch for changes on vm.selectedItem which changes with a select box and update xDomain.

Angular nvd3 not showing

I am trying to display a real-time line-graph using angular.js nvd3 [1]. It should plot altitude vs. time.
The problem I am having is with getting the x-axis to show the time data array correctly. This is what it looks like:
http://i.imgur.com/PQeskpf.png
and this is the data that I am trying to show:
$scope.chart1data = [
{
"key": "Altitude",
"values": [{x:"2013-03-04_12:00:00",y:50},{x:'2013-03-04_13:00:00',y:1000}]
}
];
chart options:
$scope.chart1options = {
chart: {
type: 'lineChart',
height: 350,
x: function(d){ return d.x; },
y: function(d){ return d.y; },
useInteractiveGuideline: true,
dispatch: {
stateChange: function(e){ console.log("stateChange"); },
changeState: function(e){ console.log("changeState"); },
tooltipShow: function(e){ console.log("tooltipShow"); },
tooltipHide: function(e){ console.log("tooltipHide"); }
},
xAxis: {
axisLabel: 'Time',
tickformat: function(d) {
return d3.time.format('%Y-%m-%d_%H:%M:%S')(new Date(d))
}
},
yAxis: {
axisLabel: 'Altitude (m)',
tickFormat: function(d){
return d3.format('.02f')(d);
},
axisLabelDistance: 100
}
}
};
If anyone knows how to get the x axis to show month/date-hour:minute for each data point, and have it scaled by time I could really use some help!
[1] http://krispo.github.io/angular-nvd3/#/quickstart

AngularJS : link between directive and controller

I'm trying to call a function of my directive in my controller. I would like to reshape a curve. At the moment, I can do within the Directive. But I need to outsource the call. Do you know how can I proceed?
My directive :
.directive('drawCharts', function () {
return function (scope, element, attrs) {
scope.$watch('curveArray', function () {
drawPlot();
}, true);
var drawPlot = function () {
/* Define var for interactive chart */
var tickInterval = scope.intervalMillisecond;
var typeLine = 'line';
var chart = function (curveArrayShow, typeLine, optionLineBool, yAxisCurveArrayShow, pointStart, pointEnd) {
var optionLine = { dataLabels: { enabled: optionLineBool, y: -20 }};
new Highcharts.Chart({
chart: {
pinchType: 'x',
renderTo: 'container',
type: typeLine,
backgroundColor:'rgba(255, 255, 255, 0.95)',
events: {
load: function(event) {
//alert ('Chart loaded : ' + event);
//scope.isLoading = false;
}
}
},
legend: {
enabled: false
},
title: {
text: ''
},
xAxis: [{
type: 'datetime',
labels: {
format: '{value: <b>%d/%m</b> %H:%M}',
staggerLines: 1
},
opposite: true,
plotLines: [{
color: '#FF0000', // Red
width: 2,
value: new Date().getTime() // Position, you'll have to translate this to the values on your x axis
}],
min: pointStart,
max: pointEnd,
minPadding: 0,
maxPadding: 0,
startOnTick: false, // allow to start not from tick
endOnTick: false,
tickInterval: tickInterval
}],
yAxis: yAxisCurveArrayShow,
tooltip: {
style:{ zindex: 10 },
xDateFormat: '%d/%m %H:%M',
shared: true,
},
plotOptions: {
column: { borderWidth: 1, borderColor: '#000000' },
spline: {
marker: {
radius: 4,
lineColor: '#666666',
lineWidth: 1
}
},
series: {
dataLabels: {
enabled: optionLineBool,
style: {font: 'bold 11px Arial', textShadow: '0 0 3px white, 0 0 3px white'}
},
marker: {
lineColor: null,
radius: 6,
states: {
hover: {
radius: 10
}
}
}
},
line: optionLine
},
series: curveArrayShow
}}
var pointStart = scope.intervalResearchTime.startDateTime + scope.intervalMillisecond; //remove padding that adding for serie type column
var pointEnd = scope.intervalResearchTime.endDateTime - scope.intervalMillisecond; //remove padding that adding for serie type column
chart(scope.curveArray, typeLine, false, scope.yAxisCurveArray, pointStart, pointEnd);
}
};
In my controller i need to update my chart. So i would like to call the function :
$scope.redrawCurve = function(_index) {
/* My algorithm ...... */
chart(curveArrayShow, typeLine, false, $scope.yAxisCurveArray, pointStart, pointEnd);
};
Thx,
Alex
My suggestion is to use event to notify the directive to redraw the plot, like this:
Controller:
$scope.redrawCurve = function(_index) {
/* My algorithm ...... */
$scope.$broadcast('redraw', arg1, arg2, /* other necessary arguments */);
};
Directive:
scope.$on('redraw', function(arg1, arg2, /* other necessary arguments */) {
drawPlot();
});

Resources