PHP/JavaScript webapp to analyse spending habits
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

analyser.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. var previousPoint = null;
  2. var plots = {};
  3. var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
  4. function colourTableRows(table) {
  5. $('tr', table).removeClass('alt');
  6. $('tr:visible:even', table).addClass('alt');
  7. }
  8. function showTooltip(x, y, contents) {
  9. $('<div id="tooltip">' + contents + '</div>').css( {
  10. position: 'absolute',
  11. display: 'none',
  12. top: y + 5,
  13. left: x + 5,
  14. border: '1px solid #fdd',
  15. padding: '2px',
  16. 'background-color': '#fee',
  17. }).appendTo("body").fadeIn(200);
  18. }
  19. function getDateKey(date) {
  20. return date.getFullYear() + '-' + (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1);
  21. }
  22. function showSelectedMonths(start, end, incoming, outgoing) {
  23. $('#historytable tr.data').remove();
  24. $('#historytable').show();
  25. var startDate = new Date(start), endDate = new Date(end);
  26. if (startDate.getDate() > 1) {
  27. startDate.setDate(1);
  28. startDate.getMonth() == 11 && startDate.setYear(startDate.getFullYear() + 1);
  29. startDate.setMonth(startDate.getMonth() == 11 ? 0 : startDate.getMonth() + 1);
  30. }
  31. var startKey = getDateKey(startDate), endKey = getDateKey(endDate);
  32. if (startKey == endKey) {
  33. $('#historytable h3').text('Transactions for ' + months[startDate.getMonth()] + ' ' + startDate.getFullYear());
  34. } else if (startDate.getFullYear() == endDate.getFullYear()) {
  35. $('#historytable h3').text('Transactions for ' + months[startDate.getMonth()] + '-' + months[endDate.getMonth()] + ' ' + startDate.getFullYear());
  36. } else {
  37. $('#historytable h3').text('Transactions for ' + months[startDate.getMonth()] + ' ' + startDate.getFullYear() + ' - ' + months[endDate.getMonth()] + ' ' + endDate.getFullYear());
  38. }
  39. var pieData = {};
  40. var table = $('#historytable table');
  41. var include = false;
  42. $.each(data, function(month, monthData) {
  43. if (month == startKey) { include = true; }
  44. if (include) {
  45. $.each(monthData, function(index, trans) {
  46. if (incoming != trans.Amount > 0) { return; }
  47. var category = trans.Category ? trans.Category : 'Unsorted';
  48. var tr = $('<tr/>').addClass('data').addClass('category' + category.replace(/[^a-zA-Z]*/g, '')).appendTo(table);
  49. $('<td/>').text(trans.Date.date.split(' ')[0]).appendTo(tr);
  50. $('<td/>').text(trans.Type ? trans.Type : 'Other').appendTo(tr);
  51. $('<td/>').text(trans.Category ? trans.Category : '').appendTo(tr);
  52. $('<td/>').text(trans.Description).appendTo(tr);
  53. $('<td/>').text(trans.Amount).appendTo(tr);
  54. if (category != '(Ignored)') {
  55. if (!pieData[category]) { pieData[category] = 0; }
  56. pieData[category] += Math.abs(trans.Amount);
  57. }
  58. });
  59. }
  60. if (month == endKey) { include = false; }
  61. });
  62. colourTableRows(table);
  63. var seriesData = [];
  64. $.each(pieData, function(category, amount) {
  65. seriesData.push({ label: category + ' (' + Math.round(amount) + ')', data: amount });
  66. });
  67. seriesData.sort(function(a, b) { return b.data - a.data; });
  68. plots.expense = $.plot($('#expense'), seriesData, {
  69. series: { pie: { show: true, innerRadius: 0.5, highlight: { opacity: 0.5 } } },
  70. grid: { clickable: true }
  71. });
  72. }
  73. $(function() {
  74. var transData = [{label: 'Income', data: []}, {label: 'Expense', data: []}, {label: 'Difference', data: []}];
  75. var min = new Date().getTime(), max = 0;
  76. $.each(data, function(month, entries) {
  77. var split = month.split('-');
  78. var timestamp = new Date(split[0], split[1] - 1).getTime();
  79. var sum = [0, 0];
  80. $.each(entries, function() {
  81. if (this.Category == '(Ignored)') { return; }
  82. sum[this.Amount < 0 ? 1 : 0] += this.Amount;
  83. });
  84. transData[0].data.push([timestamp, sum[0]]);
  85. transData[1].data.push([timestamp, sum[1]]);
  86. transData[2].data.push([timestamp, sum[0] + sum[1]]);
  87. min = Math.min(min, timestamp);
  88. max = Math.max(max, timestamp);
  89. });
  90. plots.history = $.plot($('#history'), transData, {
  91. xaxis: { mode: 'time', timeformat: '%y/%m'},
  92. series: {
  93. lines: { show: true, fill: true },
  94. points: { show: true }
  95. },
  96. grid: {
  97. hoverable: true,
  98. clickable: true,
  99. markings: [{ color: '#000', lineWidth: 1, xaxis: { from: min, to: max }, yaxis: { from: 0, to: 0 } }]
  100. },
  101. selection: { mode : "x" }
  102. });
  103. $("#history").bind("plothover", function (event, pos, item) {
  104. if (item) {
  105. var id = {dataIndex: item.dataIndex, seriesIndex: item.seriesIndex};
  106. if (previousPoint == null || previousPoint.dataIndex != id.dataIndex || previousPoint.seriesIndex != id.seriesIndex) {
  107. previousPoint = id;
  108. $("#tooltip").remove();
  109. var x = item.datapoint[0],
  110. y = item.datapoint[1].toFixed(2);
  111. var date = new Date(x);
  112. var seriesTitles = ["Money in", "Money out", "Balance change"];
  113. showTooltip(item.pageX, item.pageY, (seriesTitles[item.seriesIndex]) + " during " + months[date.getMonth()] + " " + date.getFullYear() + " = " + y);
  114. }
  115. } else {
  116. $("#tooltip").remove();
  117. previousPoint = null;
  118. }
  119. });
  120. $('#history').bind('plotselected', function(event, ranges) {
  121. var startDate = parseInt(ranges.xaxis.from.toFixed());
  122. var endDate = parseInt(ranges.xaxis.to.toFixed());
  123. $.history.load('start:' + startDate + ';end:' + endDate + ';type:expenses');
  124. });
  125. $('#history').bind('plotclick', function(event, pos, item) {
  126. if (item) {
  127. $.history.load('start:' + item.datapoint[0] + ';end:' + item.datapoint[0] + ';type:' + (item.seriesIndex == 0 ? 'income' : 'expenses'));
  128. }
  129. });
  130. $('#expense').bind('plotclick', function(event, pos, item) {
  131. $('#historytable .data').hide();
  132. $('#historytable .category' + item.series.label.replace(/[^a-zA-Z]*/g, '')).show();
  133. colourTableRows($('#historytable'));
  134. });
  135. $.history.init(function(hash) {
  136. var match = /start:([0-9]+);end:([0-9]+);type:(income|expenses)/.exec(hash);
  137. if (match != null) {
  138. showSelectedMonths(parseInt(match[1]), parseInt(match[2]), match[3] == 'income', match[3] == 'expenses');
  139. plots.history.setSelection({ xaxis: { from: parseInt(match[1]), to: parseInt(match[2]) }});
  140. }
  141. });
  142. });