mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 10:47:00 +00:00 
			
		
		
		
	Even more charts and tables.
This commit is contained in:
		| @@ -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) { | ||||
| @@ -119,3 +119,117 @@ function googlePieChart(URL, container) { | ||||
|         $('#' + 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 | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user