Separate charts in different controllers.

This commit is contained in:
Alexis Lahouze 2015-08-19 12:09:03 +02:00
parent a23d653738
commit 803b2baeab
2 changed files with 305 additions and 339 deletions

View File

@ -24,21 +24,298 @@ accountantApp
); );
}]) }])
.controller(
"CategoryChartController", [
"$rootScope", "$scope", "$http", "$routeParams",
function($rootScope, $scope, $http, $routeParams) {
var colors = Highcharts.getOptions().colors;
$scope.revenueColor = colors[2];
$scope.expenseColor = colors[3];
// Configure pie chart for categories.
$scope.config = {
options: {
chart: {
type: 'pie',
animation: {
duration: 500
}
},
plotOptions: {
pie: {
startAngle: -90
},
series: {
allowPointSelect: 0
}
},
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.percentage >= 2.5 ? this.point.name : null;
},
}
}]
};
$scope.brightenColor = function(color) {
brightness = 0.2;
return Highcharts.Color(color).brighten(brightness).get()
};
// Load categories, mainly to populate the pie chart.
$scope.load = function(begin, end) {
$scope.config.loading = true;
$http.get("/api/categories", {
params: {
account: $routeParams.accountId,
begin: begin.format('YYYY-MM-DD'),
end: end.format('YYYY-MM-DD')
}
}).success(function(data) {
var expenses = [], revenues = [];
var expenseColor = $scope.brightenColor($scope.expenseColor);
var revenueColor = $scope.brightenColor($scope.revenueColor);
angular.forEach(angular.fromJson(data), function(category) {
expenses.push({
name: category.category,
y: -category.expenses,
color: expenseColor
});
revenues.push({
name: category.category,
y: category.revenues,
color: revenueColor
});
});
// Note: expenses and revenues must be in the same order than in series[0].
$scope.config.series[1].data = revenues.concat(expenses);
$scope.config.loading = false;
});
};
/*
* Get account status.
*/
$scope.getAccountStatus = function(begin, end) {
$http.get("/api/accounts/" + $routeParams.accountId, {
params: {
begin: begin.format('YYYY-MM-DD'),
end: end.format('YYYY-MM-DD')
}
}).success(function(account) {
// Emit accountLoadedEvent.
$scope.$emit("accountLoadedEvent", account);
// Update pie chart subtitle with Balance.
$scope.config.subtitle = {
text: "Balance: " + account.balance
};
$scope.config.series[0].data = [{
name: "Revenues",
y: account.revenues,
color: $scope.revenueColor
}, {
name: "Expenses",
y: -account.expenses,
color: $scope.expenseColor,
}];
});
};
// Reload categories and account status on range selection.
$rootScope.$on("rangeSelectedEvent", function(e, args) {
$scope.load(args.begin, args.end);
$scope.getAccountStatus(args.begin, args.end);
});
}])
.controller(
"SoldChartController", [
"$rootScope", "$scope", "$http", "$routeParams",
function($rootScope, $scope, $http, $routeParams) {
$scope.setExtremes = function(e) {
begin = moment.utc(e.min);
end = moment.utc(e.max);
$scope.selectRange(begin, end);
};
// Configure chart for entries.
$scope.config = {
options: {
chart: {
zoomType: 'x'
},
rangeSelector: {
buttons: [{
type: 'month',
count: 1,
text: "1m"
}, {
type: "month",
count: 3,
text: "3m"
}, {
type: "month",
count: 6,
text: "6m"
}, {
type: "year",
count: 1,
text: "1y"
}, {
type: "all",
text: "All"
}],
selected: 0,
},
navigator: {
enabled: true
},
tooltip: {
crosshairs: true,
shared: true,
valueDecimals: 2,
valueSuffix: '€'
},
scrollbar: {
liveRedraw: false
}
},
series: [{
type: "ohlc",
name: "Sold",
data: [],
dataGrouping : {
units : [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]]
}
}],
title: {
text: "Sold evolution"
},
xAxis: {
type: "datetime",
dateTimeLabelFormats: {
month: "%e. %b",
year: "%Y"
},
minRange: 3600 * 1000 * 24 * 14, // 2 weeks
events: {
afterSetExtremes: $scope.setExtremes
},
currentMin: moment.utc().startOf('month'),
currentMax: moment.utc().endOf('month')
},
yAxis: {
plotLines: [{
color: "orange",
width: 2,
value: 0.0
}, {
color: "red",
width: 2,
value: 0.0
}]
},
useHighStocks: true
};
$scope.selectRange = function(begin, end) {
$scope.$emit("rangeSelectedEvent", {begin: begin, end: end});
};
$scope.loadSolds = function() {
$scope.config.loading = true;
$http.get("/api/solds", {
params: {
account: $routeParams.accountId,
}
}).success(function(data) {
$scope.config.series[0].data = [];
angular.forEach(data, function(entry) {
$scope.config.series[0].data.push([
moment.utc(entry.operation_date).valueOf(),
entry.open, entry.high, entry.low, entry.close
]);
});
$scope.$emit("rangeSelectedEvent", {
begin: $scope.config.xAxis.currentMin,
end: $scope.config.xAxis.currentMax
});
$scope.config.loading = false;
});
};
// Reload solds when an entry is saved.
$rootScope.$on("entrySavedEvent", function(e, entry) {
$scope.loadSolds();
});
// Update authorized overdraft on account loading.
$rootScope.$on("accountLoadedEvent", function(e, account) {
$scope.config.yAxis.plotLines[1].value = account.authorized_overdraft;
});
// Select beginning and end of month.
$scope.loadSolds();
}])
.controller( .controller(
"EntryController", [ "EntryController", [
"$scope", "$http", "$rootScope", "$filter", "$routeParams", "notificationService", "Entries", "$scope", "$http", "$rootScope", "$filter", "$routeParams", "notificationService", "Entries",
function($scope, $http, $rootScope, $filter, $routeParams, notificationService, Entries) { function($scope, $http, $rootScope, $filter, $routeParams, notificationService, Entries) {
// Range for entries.
$scope.begin = moment.utc().startOf('month');
$scope.end = moment.utc().endOf('month');
// Entry store and selection // Entry store and selection
$scope.entries = []; $scope.entries = [];
$scope.categories = [];
$scope.account = null;
// Function to reset the new entry. // Function to reset the new entry.
$scope.addEntry = function() { $scope.addEntry = function() {
if(!$scope.inserted) { if(!$scope.inserted) {
@ -48,291 +325,16 @@ accountantApp
} }
}; };
$scope.setExtremes = function(e) {
begin = moment.utc(e.min);
end = moment.utc(e.max);
$scope.selectRange(begin, end);
};
$scope.selectRange = function(begin, end) {
$scope.begin = begin;
$scope.end = end;
$scope.$emit("rangeSelectedEvent", {begin: begin, end: end});
};
// Configure pie chart for categories.
$scope.categoriesChartConfig = {
options: {
chart: {
type: 'pie',
animation: {
duration: 500
}
},
plotOptions: {
pie: {
startAngle: -90
},
series: {
allowPointSelect: 0
}
},
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.percentage >= 2.5 ? this.point.name : null;
},
}
}]
};
// Configure chart for entries.
$scope.soldChartConfig = {
options: {
chart: {
zoomType: 'x'
},
rangeSelector: {
buttons: [{
type: 'month',
count: 1,
text: "1m"
}, {
type: "month",
count: 3,
text: "3m"
}, {
type: "month",
count: 6,
text: "6m"
}, {
type: "year",
count: 1,
text: "1y"
}, {
type: "all",
text: "All"
}],
selected: 0,
},
navigator: {
enabled: true
},
tooltip: {
crosshairs: true,
shared: true,
valueDecimals: 2,
valueSuffix: '€'
},
scrollbar: {
liveRedraw: false
}
},
series: [{
type: "ohlc",
name: "Sold",
data: [],
dataGrouping : {
units : [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]]
}
}],
title: {
text: "Sold evolution"
},
xAxis: {
type: "datetime",
dateTimeLabelFormats: {
month: "%e. %b",
year: "%Y"
},
minRange: 3600 * 1000 * 24 * 14, // 2 weeks
events: {
afterSetExtremes: $scope.setExtremes
},
currentMin: $scope.begin,
currentMax: $scope.end
},
yAxis: {
plotLines: [{
color: "orange",
width: 2,
value: 0.0
}, {
color: "red",
width: 2,
value: 0.0
}]
},
useHighStocks: true
};
// Load categories, mainly to populate the pie chart.
$scope.loadCategories = function() {
$scope.categoriesChartConfig.loading = true;
$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;
var config = $scope.categoriesChartConfig;
angular.forEach(angular.fromJson(data), function(category) {
brightness = 0.2;
expenses.push({
name: category.category,
y: -category.expenses,
color: Highcharts.Color(config.series[0].data[1].color).brighten(brightness).get()
});
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.categoriesChartConfig.loading = false;
$scope.loadSolds();
});
};
$scope.loadSolds = function() {
$scope.soldChartConfig.loading = true;
$http.get("/api/solds", {
params: {
account: $scope.account.id,
}
}).success(function(data) {
var config = $scope.soldChartConfig;
config.series[0].data = [];
angular.forEach(data, function(entry) {
config.series[0].data.push([
moment.utc(entry.operation_date).valueOf(),
entry.open, entry.high, entry.low, entry.close
]);
});
$scope.soldChartConfig.loading = false;
$scope.loadEntries();
});
};
/*
* Hook on account selected event to display account status.
*/
$rootScope.$on("accountSelectedEvent", function(event, args) {
$scope.getAccountStatus($routeParams.accountId);
});
$rootScope.$on("rangeSelectedEvent", function(event, args) {
$scope.getAccountStatus($routeParams.accountId);
});
/*
* Get account status.
*/
$scope.getAccountStatus = function(accountId) {
$scope.categoriesChartConfig.loading = true;
$http.get("/api/accounts/" + accountId, {
params: {
begin: $scope.begin.format('YYYY-MM-DD'),
end: $scope.end.format('YYYY-MM-DD')
}
}).success(function(account) {
$scope.account = account;
$scope.categoriesChartConfig.loading = false;
$scope.$emit("accountLoadedEvent", account);
});
};
$rootScope.$on("accountLoadedEvent", $scope.loadCategories);
$rootScope.$on("accountLoadedEvent", function(e, account) {
var colors = Highcharts.getOptions().colors;
var config = $scope.categoriesChartConfig;
// Update pie chart subtitle with Balance.
config.subtitle = {
text: "Balance: " + account.balance
};
config.series[0].data = [{
name: "Revenues",
y: account.revenues,
color: colors[2]
}, {
name: "Expenses",
y: -account.expenses,
color: colors[3],
}];
$scope.soldChartConfig.yAxis.plotLines[1].value = account.authorized_overdraft;
});
// Function to load entries from server for a specific account and month. // Function to load entries from server for a specific account and month.
$scope.loadEntries = function() { $scope.loadEntries = function(begin, end) {
// Clean up selected entry. // Clean up selected entry.
$scope.selectedItem = null; $scope.selectedItem = null;
$scope.savedItem = null; $scope.savedItem = null;
$scope.entries = Entries.query({ $scope.entries = Entries.query({
account: $scope.account.id, account: $routeParams.accountId,
begin: $scope.begin.format('YYYY-MM-DD'), begin: begin.format('YYYY-MM-DD'),
end: $scope.end.format('YYYY-MM-DD') end: end.format('YYYY-MM-DD')
}, function(data) { }, function(data) {
$scope.$emit("entriesLoadedEvent", {entries: data}); $scope.$emit("entriesLoadedEvent", {entries: data});
}); });
@ -369,7 +371,7 @@ accountantApp
}; };
/* /*
* Save an entry and emit entrySavedEvent, or entryCreatedEvent. * Save an entry and emit entrySavedEvent.
*/ */
$scope.saveEntry = function($data, $index) { $scope.saveEntry = function($data, $index) {
// Check if $data is already a resource. // Check if $data is already a resource.
@ -390,60 +392,20 @@ accountantApp
promise = promise.then(function(data) { promise = promise.then(function(data) {
$scope.inserted = false; $scope.inserted = false;
notificationService.success("Entry #" + data.id + " created."); return data;
});
} else {
promise = promise.then(function(data) {
notificationService.success("Entry #" + data.id + " saved.");
}); });
} }
promise = promise.then(function(data) { return promise.then(function(data) {
$scope.getAccountStatus($routeParams.accountId); notificationService.success("Entry #" + data.id + " saved.");
$scope.$emit("entrySavedEvent", data);
return data;
}); });
return promise;
}; };
$scope.removeEntry = function(entry) { // Reload entries on range selection.
$scope.removingEntry = entry; $rootScope.$on("rangeSelectedEvent", function(e, args) {
$("#remove_entry").modal({ $scope.loadEntries(args.begin, args.end);
keyboard: false,
});
};
$scope.hideRemoveEntryPopup = function() {
$scope.removingEntry = null;
$("#remove_entry").modal("hide");
};
// Removes an entry.
$scope.confirmRemoveEntry = function() {
// Cancel current editing.
if ($scope.removingEntry) {
$scope.removingEntry.$delete(function (result) {
// Send the "entry removed" event.
$scope.$emit("entryRemovedEvent", $scope.removingEntry);
$scope.hideRemoveEntryPopup();
});
}
};
$rootScope.$on("entryRemovedEvent", function(e, entry) {
new PNotify({
type: "success",
title: "Delete",
text: "Entry #" + entry.id + " deleted."
});
}); });
$scope.closeModal = function(modalScope) {
// Close the modal dialog
if(modalScope && modalScope.dismiss) {
modalScope.dismiss();
}
};
$scope.getAccountStatus($routeParams.accountId);
}]); }]);

View File

@ -19,10 +19,14 @@
<!-- Chart row --> <!-- Chart row -->
<div class="row"> <div class="row">
<!-- Sold evolution chart placeholder --> <!-- Sold evolution chart placeholder -->
<highchart id="sold-chart" config="soldChartConfig" class="col-md-8"></highchart> <div class="col-md-8" ng-controller="SoldChartController">
<highchart id="sold-chart" config="config"></highchart>
</div>
<!-- Category piechart --> <!-- Category piechart -->
<highchart id="categories-chart" config="categoriesChartConfig" class="col-md-4"></highchart> <div class="col-md-4" ng-controller="CategoryChartController">
<highchart id="categories-chart" config="config"></highchart>
</div>
</div> </div>
<div class="row"> <div class="row">