Even more charts and tables.

This commit is contained in:
Sander Dorigo 2014-10-30 18:06:29 +01:00
parent ad479a5c7f
commit ffcd1fde0f
7 changed files with 428 additions and 22 deletions

View File

@ -174,6 +174,10 @@ class GoogleChartController extends BaseController
}
/**
* @return \Illuminate\Http\JsonResponse
* @throws \Firefly\Exception\FireflyException
*/
public function recurringTransactionsOverview()
{
@ -260,4 +264,158 @@ class GoogleChartController extends BaseController
return Response::json($chart->getData());
}
/**
* @param Account $account
*/
public function accountBalanceChart(Account $account)
{
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('Day of month', 'date');
$chart->addColumn('Balance for ' . $account->name, 'number');
/*
* Loop the date, then loop the accounts, then add balance.
*/
$start = Session::get('start');
$end = Session::get('end');
$current = clone $start;
while ($end >= $current) {
$row = [clone $current];
if ($current > Carbon::now()) {
$row[] = null;
} else {
$row[] = $account->balance($current);
}
$chart->addRowArray($row);
$current->addDay();
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param Account $account
*
* @return \Illuminate\Http\JsonResponse
*/
public function accountSankeyOutChart(Account $account)
{
// collect all relevant entries.
$set = [];
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('From', 'string');
$chart->addColumn('To', 'string', 'domain');
$chart->addColumn('Weight', 'number');
$transactions = $account->transactions()->with(
['transactionjournal', 'transactionjournal.transactions', 'transactionjournal.budgets', 'transactionjournal.transactiontype',
'transactionjournal.categories']
)->before(Session::get('end'))->after(
Session::get('start')
)->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$amount = floatval($transaction->amount);
$type = $transaction->transactionJournal->transactionType->type;
if ($amount < 0 && $type != 'Transfer') {
// from account to a budget (if present).
$budgetName = isset($transaction->transactionJournal->budgets[0]) ? $transaction->transactionJournal->budgets[0]->name : '(no budget)';
$set[] = [$account->name, $budgetName, $amount * -1];
// from budget to category.
$categoryName = isset($transaction->transactionJournal->categories[0]) ? ' ' . $transaction->transactionJournal->categories[0]->name
: '(no cat)';
$set[] = [$budgetName, $categoryName, $amount * -1];
}
}
// loop the set, group everything together:
$grouped = [];
foreach ($set as $entry) {
$key = $entry[0] . $entry[1];
if (isset($grouped[$key])) {
$grouped[$key][2] += $entry[2];
} else {
$grouped[$key] = $entry;
}
}
// add rows to the chart:
foreach ($grouped as $entry) {
$chart->addRow($entry[0], $entry[1], $entry[2]);
}
$chart->generate();
return Response::json($chart->getData());
}
/**
* @param Account $account
*
* @return \Illuminate\Http\JsonResponse
*/
public function accountSankeyInChart(Account $account)
{
// collect all relevant entries.
$set = [];
/** @var \Grumpydictator\Gchart\GChart $chart */
$chart = App::make('gchart');
$chart->addColumn('From', 'string');
$chart->addColumn('To', 'string', 'domain');
$chart->addColumn('Weight', 'number');
$transactions = $account->transactions()->with(
['transactionjournal', 'transactionjournal.transactions' => function ($q) {
$q->where('amount', '<', 0);
}, 'transactionjournal.budgets', 'transactionjournal.transactiontype', 'transactionjournal.categories']
)->before(Session::get('end'))->after(
Session::get('start')
)->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$amount = floatval($transaction->amount);
$type = $transaction->transactionJournal->transactionType->type;
if ($amount > 0 && $type != 'Transfer') {
$otherAccount = $transaction->transactionJournal->transactions[0]->account->name;
$categoryName = isset($transaction->transactionJournal->categories[0]) ? $transaction->transactionJournal->categories[0]->name
: '(no cat)';
$set[] = [$otherAccount, $categoryName, $amount];
$set[] = [$categoryName, $account->name, $amount];
}
}
// loop the set, group everything together:
$grouped = [];
foreach ($set as $entry) {
$key = $entry[0] . $entry[1];
if (isset($grouped[$key])) {
$grouped[$key][2] += $entry[2];
} else {
$grouped[$key] = $entry;
}
}
// add rows to the chart:
foreach ($grouped as $entry) {
$chart->addRow($entry[0], $entry[1], $entry[2]);
}
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@ -0,0 +1,110 @@
<?php
use Carbon\Carbon;
/**
* Class GoogleTableController
*/
class GoogleTableController extends BaseController
{
/**
* @param Account $account
*/
public function transactionsByAccount(Account $account)
{
$chart = App::make('gchart');
$chart->addColumn('ID', 'number');
$chart->addColumn('ID_Edit', 'string');
$chart->addColumn('ID_Delete', 'string');
$chart->addColumn('Date', 'date');
$chart->addColumn('Description_URL', 'string');
$chart->addColumn('Description', 'string');
$chart->addColumn('Amount', 'number');
$chart->addColumn('From_URL', 'string');
$chart->addColumn('From', 'string');
$chart->addColumn('To_URL', 'string');
$chart->addColumn('To', 'string');
$chart->addColumn('Budget_URL', 'string');
$chart->addColumn('Budget', 'string');
$chart->addColumn('Category_URL', 'string');
$chart->addColumn('Category', 'string');
/*
* Find transactions:
*/
$accountID = $account->id;
$transactions = $account->transactions()->with(
['transactionjournal', 'transactionjournal.transactions' => function ($q) use ($accountID) {
$q->where('account_id', '!=', $accountID);
}, 'transactionjournal.budgets', 'transactionjournal.transactiontype',
'transactionjournal.categories']
)->before(Session::get('end'))->after(
Session::get('start')
)->orderBy('date', 'DESC')->get();
/** @var Transaction $transaction */
foreach ($transactions as $transaction) {
$date = $transaction->transactionJournal->date;
$descriptionURL = route('transactions.show', $transaction->transaction_journal_id);
$description = $transaction->transactionJournal->description;
$amount = floatval($transaction->amount);
if ($transaction->transactionJournal->transactions[0]->account->id == $account->id) {
$opposingAccountURI = route('accounts.show', $transaction->transactionJournal->transactions[1]->account->id);
$opposingAccountName = $transaction->transactionJournal->transactions[1]->account->name;
} else {
$opposingAccountURI = route('accounts.show', $transaction->transactionJournal->transactions[0]->account->id);
$opposingAccountName = $transaction->transactionJournal->transactions[0]->account->name;
}
if (isset($transaction->transactionJournal->budgets[0])) {
$budgetURL = route('budgets.show', $transaction->transactionJournal->budgets[0]->id);
$budget = $transaction->transactionJournal->budgets[0]->name;
} else {
$budgetURL = '';
$budget = '';
}
if (isset($transaction->transactionJournal->categories[0])) {
$categoryURL = route('categories.show', $transaction->transactionJournal->categories[0]->id);
$category = $transaction->transactionJournal->categories[0]->name;
} else {
$budgetURL = '';
$budget = '';
}
if ($amount < 0) {
$from = $account->name;
$fromURL = route('accounts.show', $account->id);
$to = $opposingAccountName;
$toURL = $opposingAccountURI;
} else {
$to = $account->name;
$toURL = route('accounts.show', $account->id);
$from = $opposingAccountName;
$fromURL = $opposingAccountURI;
}
$budcat = 'Budcat';
$id = $transaction->transactionJournal->id;
$edit = route('transactions.edit', $transaction->transactionJournal->id);
$delete = route('transactions.delete', $transaction->transactionJournal->id);
$chart->addRow(
$id, $edit, $delete, $date, $descriptionURL, $description, $amount, $fromURL, $from, $toURL, $to, $budgetURL, $budget, $categoryURL, $category
);
}
// <th>Date</th>
// <th>Description</th>
// <th>Amount (&euro;)</th>
// <th>From</th>
// <th>To</th>
// <th>Budget / category</th>
// <th>ID</th>
$chart->generate();
return Response::json($chart->getData());
}
}

View File

@ -161,11 +161,19 @@ Route::group(['before' => 'auth'], function () {
Route::get('/categories/edit/{category}',['uses' => 'CategoryController@edit','as' => 'categories.edit']);
Route::get('/categories/delete/{category}',['uses' => 'CategoryController@delete','as' => 'categories.delete']);
// chart controller
// google chart controller
Route::get('/chart/home/account', ['uses' => 'GoogleChartController@allAccountsBalanceChart']);
Route::get('/chart/home/budgets', ['uses' => 'GoogleChartController@allBudgetsHomeChart']);
Route::get('/chart/home/categories', ['uses' => 'GoogleChartController@allCategoriesHomeChart']);
Route::get('/chart/home/recurring', ['uses' => 'GoogleChartController@recurringTransactionsOverview']);
Route::get('/chart/account/{account}', ['uses' => 'GoogleChartController@accountBalanceChart']);
Route::get('/chart/sankey/{account}/out', ['uses' => 'GoogleChartController@accountSankeyOutChart']);
Route::get('/chart/sankey/{account}/in', ['uses' => 'GoogleChartController@accountSankeyInChart']);
// google table controller
Route::get('/table/account/{account}/transactions', ['uses' => 'GoogleTableController@transactionsByAccount']);
Route::get('/chart/home/info/{accountnameA}/{day}/{month}/{year}', ['uses' => 'ChartController@homeAccountInfo', 'as' => 'chart.info']);

View File

@ -7,7 +7,7 @@
<i class="fa fa-fw {{$subTitleIcon}} fa-fw"></i> {{{$account->name}}}
</div>
<div class="panel-body">
<div id="overviewChart"><img src="http://placehold.it/650x300" title="Placeholder" alt="" /></div>
<div id="overview-chart"></div>
</div>
</div>
</div>
@ -71,7 +71,7 @@
Out
</div>
<div class="panel-body">
<div id="accountOutSankey"><img src="http://placehold.it/550x300" title="Placeholder" alt="" /></div>
<div id="account-out-sankey"></div>
</div>
</div>
</div>
@ -81,7 +81,7 @@
In
</div>
<div class="panel-body">
<div id="accountInSankey"><img src="http://placehold.it/550x300" title="Placeholder" alt="" /></div>
<div id="account-in-sankey"></div>
</div>
</div>
</div>
@ -94,20 +94,8 @@
<i class="fa fa-repeat fa-fw"></i> Transactions
</div>
<div class="panel-body">
<div id="account-transactions"></div>
<table id="transactionByAccountTable" class="table table-striped table-bordered" >
<thead>
<tr>
<th>Date</th>
<th>Description</th>
<th>Amount (&euro;)</th>
<th>From</th>
<th>To</th>
<th>Budget / category</th>
<th>ID</th>
</tr>
</thead>
</table>
{{--
<table class="table table-striped table-condensed">
@ -170,5 +158,12 @@
</script>
{{HTML::script('assets/javascript/datatables/jquery.dataTables.min.js')}}
{{HTML::script('assets/javascript/datatables/dataTables.bootstrap.js')}}
<!-- load the libraries and scripts necessary for Google Charts: -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
{{HTML::script('assets/javascript/firefly/gcharts.options.js')}}
{{HTML::script('assets/javascript/firefly/gcharts.js')}}
{{HTML::script('assets/javascript/firefly/accounts.js')}}
@stop

View File

@ -1,10 +1,24 @@
$(function () {
if (typeof(googleLineChart) == "function") {
googleLineChart('chart/account/' + accountID, 'overview-chart');
}
//
if(typeof(googleSankeyChart) == 'function') {
googleSankeyChart('chart/sankey/' + accountID + '/out','account-out-sankey');
googleSankeyChart('chart/sankey/' + accountID + '/in','account-in-sankey');
}
if(typeof(googleTable) == 'function') {
googleTable('table/account/' + accountID + '/transactions','account-transactions');
}
if ($('#accountTable').length == 1) {
drawDatatable();
}
if ($('#overviewChart').length == 1) {
drawOverviewChart();
}
//if ($('#overviewChart').length == 1) {
// drawOverviewChart();
//}
});

View File

@ -1,4 +1,4 @@
google.load('visualization', '1.0', {'packages': ['corechart']});
google.load('visualization', '1.1', {'packages': ['corechart', 'sankey', 'table']});
function googleLineChart(URL, container) {
$.getJSON(URL).success(function (data) {
@ -115,6 +115,120 @@ function googlePieChart(URL, container) {
*/
chart.draw(gdata, defaultPieChartOptions);
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
}
function googleSankeyChart(URL, container) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
*/
gdata = new google.visualization.DataTable(data);
/*
Format as money
*/
console.log(gdata.getNumberOfRows())
if (gdata.getNumberOfRows() < 1) {
console.log('remove');
$('#' + container).parent().parent().remove();
return;
} else if (gdata.getNumberOfRows() < 6) {
defaultSankeyChartOptions.height = 100
} else {
defaultSankeyChartOptions.height = 400
}
/*
Create a new google charts object.
*/
var chart = new google.visualization.Sankey(document.getElementById(container));
/*
Draw it:
*/
chart.draw(gdata, defaultSankeyChartOptions);
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});
}
function googleTable(URL, container) {
$.getJSON(URL).success(function (data) {
/*
Get the data from the JSON
*/
var gdata = new google.visualization.DataTable(data);
/*
Create a new google charts object.
*/
var chart = new google.visualization.Table(document.getElementById(container));
/*
Do something with formatters:
*/
var x = gdata.getNumberOfColumns();
var columnsToHide = new Array;
var URLFormatter = new google.visualization.PatternFormat('<a href="{0}">{1}</a>');
var EditButtonFormatter = new google.visualization.PatternFormat('<div class="btn-group btn-group-xs"><a href="{0}" class="btn btn-default btn-xs"><span class="glyphicon glyphicon-pencil"></span></a><a class="btn btn-xs btn-danger" href="{1}"><span class="glyphicon glyphicon-trash"></span></a></div>');
var money = new google.visualization.NumberFormat({decimalSymbol: ',', groupingSymbol: '.', prefix: '\u20AC '});
for (var i = 0; i < x; i++) {
var label = gdata.getColumnLabel(i);
console.log('Column ' + i + ':' + label);
/*
Format a string using the previous column as URL.
*/
if (label == 'Description' || label == 'From' || label == 'To' || label == 'Budget' || label == 'Category') {
URLFormatter.format(gdata, [i - 1, i], i);
columnsToHide.push(i - 1);
}
if(label == 'ID') {
EditButtonFormatter.format(gdata, [i+1,i+2],i);
columnsToHide.push(i+1,i+2);
}
/*
Format with buttons:
*/
/*
Format as money
*/
if (label == 'Amount') {
money.format(gdata, i);
}
}
//var formatter = new google.visualization.PatternFormat('<a href="#">{1}</a>');
//formatter.format(gdata, [5, 6], 6);
//formatter.format(gdata, [7, 8], 8);
var view = new google.visualization.DataView(gdata);
// hide certain columns:
view.hideColumns(columnsToHide);
/*
Draw it:
*/
chart.draw(view, defaultTableOptions);
}).fail(function () {
$('#' + container).addClass('google-chart-error');
});

View File

@ -52,8 +52,15 @@ var defaultPieChartOptions = {
width: '100%',
height: '100%'
},
height:200,
height: 200,
legend: {
position: 'none'
}
};
var defaultSankeyChartOptions = {
height: 400
}
var defaultTableOptions = {
allowHtml: true
};