Use highcharts instead of nvd3.
This commit is contained in:
parent
2131d1f39a
commit
fa981d4a32
@ -15,7 +15,8 @@
|
||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
var accountantApp = angular.module("accountantApp", [
|
||||
"mgcrea.ngStrap"
|
||||
"mgcrea.ngStrap",
|
||||
"highcharts-ng"
|
||||
])
|
||||
|
||||
.config(function($interpolateProvider, $httpProvider) {
|
||||
|
@ -28,105 +28,151 @@ accountantApp.controller(
|
||||
// Placeholder for saved value to cancel entry edition
|
||||
$scope.savedItem = null;
|
||||
|
||||
$scope.entriesLoaded = function(entries) {
|
||||
var entriesReversed = entries.slice().reverse();
|
||||
|
||||
var categories = [];
|
||||
|
||||
var chartValues = [];
|
||||
|
||||
var pieChartValuesTmp = {};
|
||||
var pieChartValues = [];
|
||||
|
||||
angular.forEach(entriesReversed, function(entry) {
|
||||
var category = entry.category;
|
||||
var value = entry.value ? Number(entry.value) : null;
|
||||
var sold = entry.sold ? Number(entry.sold) : null;
|
||||
var operation_date = entry.operation_date;
|
||||
|
||||
if(operation_date && sold) {
|
||||
chartValues.push([entry.operation_date, sold]);
|
||||
}
|
||||
|
||||
if(category && category != '') {
|
||||
if(categories.indexOf(category) == -1) {
|
||||
categories.push(category);
|
||||
}
|
||||
|
||||
if(value && value < 0.0) {
|
||||
var oldValue = 0.0;
|
||||
|
||||
if(pieChartValuesTmp[category]) {
|
||||
oldValue = pieChartValuesTmp[category];
|
||||
// Configure pie chart for categories.
|
||||
$scope.categoriesChartConfig = {
|
||||
options: {
|
||||
chart: {
|
||||
type: 'pie',
|
||||
animation: {
|
||||
duration: 500
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
startAngle: -90
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
valueDecimals: 2,
|
||||
valueSuffix: '€'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: "Categories"
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: "Répartition dépenses/recettes"
|
||||
},
|
||||
series: [{
|
||||
name: "Value",
|
||||
data: [],
|
||||
innerSize: '33%',
|
||||
size: '60%',
|
||||
dataLabels: {
|
||||
formatter: function() {
|
||||
return this.point.name;
|
||||
},
|
||||
distance: -40
|
||||
}
|
||||
}, {
|
||||
name: "Value",
|
||||
data: [],
|
||||
innerSize: '66%',
|
||||
size: '60%',
|
||||
dataLabels: {
|
||||
formatter: function() {
|
||||
return this.point.name !== null && this.y > 100 ? this.point.name : null;
|
||||
},
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
pieChartValuesTmp[category] = oldValue - value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$scope.chartValues = chartValues;
|
||||
// Load categories, mainly to populate the pie chart.
|
||||
$scope.loadCategories = function() {
|
||||
$http.get("/api/categories", {
|
||||
params: {
|
||||
account: $scope.account.id,
|
||||
begin: $scope.begin.format('YYYY-MM-DD'),
|
||||
end: $scope.end.format('YYYY-MM-DD')
|
||||
}
|
||||
}).success(function(data) {
|
||||
var expenses = [], revenues = [];
|
||||
var colors = Highcharts.getOptions().colors;
|
||||
|
||||
// Second pass: transform to an array readable by jqplot.
|
||||
var pieChartValues = [];
|
||||
angular.forEach(pieChartValuesTmp, function(value, key) {
|
||||
pieChartValues.push([key, value]);
|
||||
});
|
||||
var config = $scope.categoriesChartConfig;
|
||||
|
||||
$scope.pieChartValues = pieChartValues;
|
||||
angular.forEach(angular.fromJson(data), function(category) {
|
||||
brightness = 0.2;
|
||||
|
||||
//$scope.categories.length = 0;
|
||||
//$scope.categories.concat(categories);
|
||||
$scope.categories = categories;
|
||||
expenses.push({
|
||||
name: category.category,
|
||||
y: -category.expenses,
|
||||
color: Highcharts.Color(config.series[0].data[1].color).brighten(brightness).get()
|
||||
});
|
||||
|
||||
nv.addGraph($scope.drawChart);
|
||||
nv.addGraph($scope.drawPieChart);
|
||||
//$scope.drawPieChart(pieChartValues, "#expense-categories-chart-placeholder");
|
||||
//$scope.drawPieChart();
|
||||
revenues.push({
|
||||
name: category.category,
|
||||
y: category.revenues,
|
||||
color: Highcharts.Color(config.series[0].data[0].color).brighten(brightness).get()
|
||||
});
|
||||
});
|
||||
|
||||
// Note: expenses and revenues must be in the same order than in series[0].
|
||||
config.series[1].data = revenues.concat(expenses);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.getAccountStatus = function(account, month) {
|
||||
if(account != null && month != null) {
|
||||
// Note: Month is 0 indexed.
|
||||
var begin = moment({year: month.year, month: month.month - 1, day: 1});
|
||||
var end = begin.clone().endOf('month');
|
||||
// Note: Month is 0 indexed.
|
||||
$scope.begin = moment({year: month.year, month: month.month - 1, day: 1});
|
||||
$scope.end = $scope.begin.clone().endOf('month');
|
||||
|
||||
$http.get("/api/accounts/" + account.id,
|
||||
{params: {
|
||||
begin: begin.format('YYYY-MM-DD'),
|
||||
end: end.format('YYYY-MM-DD')
|
||||
}}).success($scope.getAccountStatus_success);
|
||||
}
|
||||
};
|
||||
$http.get("/api/accounts/" + account.id, {
|
||||
params: {
|
||||
begin: $scope.begin.format('YYYY-MM-DD'),
|
||||
end: $scope.end.format('YYYY-MM-DD')
|
||||
}
|
||||
}).success(function(status) {
|
||||
var colors = Highcharts.getOptions().colors;
|
||||
|
||||
$scope.getAccountStatus_success = function(status) {
|
||||
$scope.accountStatus = status;
|
||||
var config = $scope.categoriesChartConfig;
|
||||
|
||||
// Update pie chart subtitle with Balance.
|
||||
config.subtitle = {
|
||||
text: "Balance: " + status.balance
|
||||
};
|
||||
|
||||
config.series[0].data = [{
|
||||
name: "Revenues",
|
||||
y: status.revenues,
|
||||
color: colors[2]
|
||||
}, {
|
||||
name: "Expenses",
|
||||
y: -status.expenses,
|
||||
color: colors[3],
|
||||
}];
|
||||
|
||||
$scope.loadCategories();
|
||||
});
|
||||
};
|
||||
|
||||
// Function to load entries from server for a specific account and month.
|
||||
$scope.loadEntries = function(account, month) {
|
||||
if(account) {
|
||||
$scope.account = account;
|
||||
}
|
||||
if(account) {
|
||||
$scope.account = account;
|
||||
}
|
||||
|
||||
// Clean up selected entry.
|
||||
$scope.selectedItem = null;
|
||||
$scope.savedItem = null;
|
||||
// Clean up selected entry.
|
||||
$scope.selectedItem = null;
|
||||
$scope.savedItem = null;
|
||||
|
||||
if(account && month) {
|
||||
// Note: Month is 0 indexed.
|
||||
var begin = moment({year: month.year, month: month.month - 1, day: 1});
|
||||
var end = begin.clone().endOf('month');
|
||||
if(account && month) {
|
||||
// Note: Month is 0 indexed.
|
||||
var begin = moment({year: month.year, month: month.month - 1, day: 1});
|
||||
var end = begin.clone().endOf('month');
|
||||
|
||||
$http.get("/api/entries",
|
||||
{params: {
|
||||
account: account.id,
|
||||
begin: begin.format('YYYY-MM-DD'),
|
||||
end: end.format('YYYY-MM-DD')
|
||||
}}).success($scope.loadEntries_success);
|
||||
} else {
|
||||
$scope.loadEntries_success(null);
|
||||
}
|
||||
$http.get("/api/entries", {
|
||||
params: {
|
||||
account: account.id,
|
||||
begin: begin.format('YYYY-MM-DD'),
|
||||
end: end.format('YYYY-MM-DD')
|
||||
}
|
||||
}).success($scope.loadEntries_success);
|
||||
} else {
|
||||
$scope.loadEntries_success(null);
|
||||
}
|
||||
};
|
||||
|
||||
// Load entries success callback
|
||||
@ -362,97 +408,6 @@ accountantApp.controller(
|
||||
}
|
||||
};
|
||||
|
||||
// Function to draw the sold evolution chart.
|
||||
$scope.drawChart = function() {
|
||||
// Clear previous chart
|
||||
var entries = $scope.chartValues;
|
||||
console.debug("drawChart", entries);
|
||||
|
||||
var width = 700;
|
||||
var height = 300;
|
||||
|
||||
//if(entries && entries.length > 1) {
|
||||
// Prepare for today vertical line.
|
||||
var today = new Date();
|
||||
today.setHours(0);
|
||||
today.setMinutes(0);
|
||||
|
||||
// FIXME Alexis Lahouze 2015-06-12 Date format.
|
||||
|
||||
// Find first and last days to set limits of the x axis.
|
||||
var firstDate = moment(entries[0][0]).subtract(1, 'day').format();
|
||||
var lastDate = moment(entries[entries.length - 1][0]).add(1, 'day').format();
|
||||
|
||||
var chart = nv.models.lineChart().options({
|
||||
x: function(d) { return new Date(d[0]); },
|
||||
y: function(d) { return new Number(d[1]); },
|
||||
transitionDuration: 250,
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
width: width,
|
||||
height: height,
|
||||
});
|
||||
|
||||
chart.lines.interpolate("monotone");
|
||||
|
||||
chart.xAxis
|
||||
.axisLabel("Date")
|
||||
.tickFormat(function(d) {
|
||||
return d3.time.format("%x")(new Date(d));
|
||||
});
|
||||
//chart.xAxis.scale().range([firstDate, lastDate]);
|
||||
|
||||
chart.yAxis
|
||||
.axisLabel("Solde")
|
||||
.tickFormat(d3.format('.02f'));
|
||||
|
||||
// FIXME add vertical line for today
|
||||
graph = d3.select("#entries-chart-placeholder").datum([
|
||||
{ color: "orange", key: "Zero", values:[
|
||||
[firstDate, "0"],
|
||||
[lastDate, "0"]
|
||||
]},
|
||||
{ color: "red", key: "Authorized overdraft", values : [
|
||||
[firstDate, new Number($scope.account.authorized_overdraft)],
|
||||
[lastDate, new Number($scope.account.authorized_overdraft)]
|
||||
]},
|
||||
{ color: "darkblue", key: "Sold evolution", values: entries},
|
||||
])
|
||||
.transition().duration(1200)
|
||||
.attr("width", width)
|
||||
.attr("height", height)
|
||||
.call(chart);
|
||||
|
||||
nv.utils.windowResize(chart.update);
|
||||
|
||||
return chart;
|
||||
};
|
||||
|
||||
// Function to draw the expense category pie chart.
|
||||
$scope.drawPieChart = function() {
|
||||
// FIXME retrieve width and height from DOM
|
||||
var width = 300;
|
||||
var height = 300;
|
||||
|
||||
var chart = nv.models.pieChart()
|
||||
.x(function(d) { console.debug(d); return d[0]; })
|
||||
.y(function(d) { return d[1]; })
|
||||
.width(width)
|
||||
.height(height)
|
||||
.showLabels(true);
|
||||
|
||||
d3.select("#expense-categories-chart-placeholder")
|
||||
.datum($scope.pieChartValues)
|
||||
.transition().duration(1200)
|
||||
.attr('width', width)
|
||||
.attr('height', height)
|
||||
.call(chart);
|
||||
|
||||
nv.utils.windowResize(chart.update);
|
||||
|
||||
return chart
|
||||
};
|
||||
|
||||
$rootScope.$on("monthsLoadedEvent", function(event, args){
|
||||
$scope.loadEntries(args.account, args.month);
|
||||
});
|
||||
@ -460,8 +415,4 @@ accountantApp.controller(
|
||||
$rootScope.$on("monthsLoadedEvent", function(event, args){
|
||||
$scope.getAccountStatus(args.account, args.month);
|
||||
});
|
||||
|
||||
$scope.$on("entriesLoadedEvent", function(event, args) {
|
||||
$scope.entriesLoaded(args.entries);
|
||||
});
|
||||
});
|
||||
|
@ -20,25 +20,10 @@
|
||||
<!-- Chart row -->
|
||||
<div class="row">
|
||||
<!-- Sold evolution chart placeholder -->
|
||||
<div class="col-md-7">
|
||||
<svg id="entries-chart-placeholder" style="stroke-width: 1px"/>
|
||||
</div>
|
||||
<highchart id="entries-chart" config="entriesChartConfig" class="col-md-8"></highchart>
|
||||
|
||||
<!-- Expense category piechart -->
|
||||
<div class="col-md-3">
|
||||
<svg id="expense-categories-chart-placeholder" style='height:300px'/>
|
||||
</div>
|
||||
|
||||
<!-- Balance -->
|
||||
<div class="col-md-2">
|
||||
<div class="row">
|
||||
<table class="table">
|
||||
<tr><td>Dépenses :</td><td>[[accountStatus.expenses]]</td></tr>
|
||||
<tr><td>Recettes :</td><td>[[accountStatus.revenues]]</td></tr>
|
||||
<tr><td>Balance :</td><td><span ng-class="entryValueClass(accountStatus.balance)">[[accountStatus.balance]]</span></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<highchart id="expense-categories-chart" config="categoriesChartConfig" class="col-md-4"></highchart>
|
||||
</div>
|
||||
|
||||
<!-- Row with entry table -->
|
||||
|
Loading…
Reference in New Issue
Block a user