mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-10 15:35:53 -06:00
Even more charts and tables.
This commit is contained in:
parent
ad479a5c7f
commit
ffcd1fde0f
@ -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());
|
||||
|
||||
}
|
||||
}
|
110
app/controllers/GoogleTableController.php
Normal file
110
app/controllers/GoogleTableController.php
Normal 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 (€)</th>
|
||||
// <th>From</th>
|
||||
// <th>To</th>
|
||||
// <th>Budget / category</th>
|
||||
// <th>ID</th>
|
||||
|
||||
|
||||
$chart->generate();
|
||||
return Response::json($chart->getData());
|
||||
}
|
||||
}
|
@ -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']);
|
||||
|
@ -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 (€)</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
|
@ -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();
|
||||
//}
|
||||
|
||||
});
|
||||
|
||||
|
@ -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');
|
||||
});
|
||||
|
@ -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
|
||||
};
|
Loading…
Reference in New Issue
Block a user