Calorie counting web application written in the Go language

grassfed.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. (function ($) {
  2. $.each(['show', 'hide'], function (i, ev) {
  3. var el = $.fn[ev];
  4. $.fn[ev] = function () {
  5. this.trigger(ev);
  6. return el.apply(this, arguments);
  7. };
  8. });
  9. })(jQuery);
  10. $(function () {
  11. var chart = $('#goalChart')[0];
  12. var trends = $('#trendsChart')[0];
  13. var doughnutChart;
  14. var lineChart;
  15. var trendData;
  16. function startEngine() {
  17. // Pull the information we need first.
  18. loadStatistics();
  19. loadTrends();
  20. loadHistory();
  21. // Set focus.
  22. $('input[name="products"][type="text"]').focus();
  23. }
  24. // Check to see if the profile is not hidden. If it is not then start your engines!
  25. if (!$('div#profile').is(':hidden')) {
  26. startEngine();
  27. }
  28. else {
  29. $('div#profile').on('show', function () {
  30. startEngine();
  31. });
  32. }
  33. $('form#entry').on('submit', function (e) {
  34. e.preventDefault();
  35. // Get the current values.
  36. var product = $('input[name="product"][type="text"]').val();
  37. var calories = parseInt($('input[name="calories"][type="number"]').val());
  38. $.post('/me/add', { 'product': product, 'calories': calories })
  39. .done(function (response) {
  40. if (response) {
  41. // Reset the values.
  42. $('input[name="product"][type="text"]').val('');
  43. $('input[name="calories"][type="number"]').val(0);
  44. // Record the moment in history.
  45. prependProduct(response.Id, response.Product, response.Calories);
  46. // Update the chart.
  47. var previousCalories = parseInt($('input[name="current"][type="hidden"]').val());
  48. $('input[name="current"][type="hidden"]').val(previousCalories + response.Calories);
  49. updateCalorieChart();
  50. loadTrends();
  51. // Reset focus.
  52. $('input[name="products"][type="text"]').focus();
  53. }
  54. });
  55. return false;
  56. });
  57. $('form#recordWeight').on('submit', function (e) {
  58. e.preventDefault();
  59. var weight = $('input[name="weight"][type="number"]').val();
  60. $.post('/me/weight', { 'weight': weight })
  61. .done(function (response) {
  62. if (response) {
  63. // Reset the values.
  64. $('input[name="weight"][type="number"]').val('');
  65. loadTrends();
  66. }
  67. });
  68. });
  69. $(document).on('click', 'button.delete-history', function (e) {
  70. e.preventDefault();
  71. var moment = parseInt($(this).parents('div.media').attr('data-moment'));
  72. $.ajax({
  73. url: '/me/history/' + moment,
  74. type: 'DELETE'
  75. })
  76. .done(function (response) {
  77. if (response) {
  78. var media = $('div.media[data-moment="' + moment + '"]');
  79. var panel = $(media).parents('div.panel');
  80. var previousCalories = parseInt($('input[name="current"][type="hidden"]').val());
  81. var calories = parseInt($(media).find('span.calories').text());
  82. // Remove the current media element which has been trashed.
  83. $(media).remove();
  84. // Update our calorie chart.
  85. $('input[name="current"][type="hidden"]').val(previousCalories - calories);
  86. updateCalorieChart();
  87. loadTrends();
  88. // Check if there are any more media elements in the panel. If not remove the panel.
  89. if ($(panel).find('div.media').length == 0) {
  90. $(panel).remove();
  91. }
  92. }
  93. });
  94. });
  95. $(document).on('change', 'input[name="calories"][type="range"]', function (e) {
  96. var goal = $(this).val();
  97. // Send the new goal to the server.
  98. setGoal(goal);
  99. // Update the text for immediate feedback.
  100. $('span.goal').text(goal);
  101. // Update the chart.
  102. updateCalorieChart();
  103. loadTrends();
  104. });
  105. function prependProduct(id, product, calories) {
  106. var momentDate = new Date().toDateString();
  107. var panelTitle = $('h3.panel-title:contains("' + momentDate + '")');
  108. var panelBody;
  109. if (panelTitle.length > 0) {
  110. panelBody = $(panelTitle).parents('div.panel').find('div.panel-body');
  111. }
  112. else {
  113. $('div#history').prepend(
  114. $('<div class="panel panel-default">')
  115. .append('<div class="panel-heading"><h3 class="panel-title">' + momentDate + '</h3></div>')
  116. .append('<div class="panel-body">'));
  117. panelBody = $('h3.panel-title:contains("' + momentDate + '")').parents('div.panel').find('div.panel-body');
  118. }
  119. $(panelBody).prepend(
  120. $('<div class="media" data-moment="' + id + '">')
  121. .append('<div class="media-object pull-right"><button class="btn btn-danger delete-history"><span class="glyphicon glyphicon-fire"></span></button></div>')
  122. .append('<div class="media-body">')
  123. .append('<h4 class="media-heading">' + product + ' (<span class="calories">' + calories + '</span> calories)</h4>'));
  124. }
  125. function getDailyCalories() {
  126. return parseInt($('input[name="calories"][type="range"]').val());
  127. }
  128. function getCurrentCalories() {
  129. return parseInt($('input[name="current"][type="hidden"]').val());
  130. }
  131. function setGoal(calories) {
  132. $.post('/me/goal', { 'calories': calories });
  133. }
  134. function loadStatistics() {
  135. $.get('/me/stats')
  136. .done(function (response) {
  137. if (response) {
  138. $('input[name="calories"][type="range"]').val(response.Goal);
  139. $('span.goal').text(response.Goal);
  140. $('input[name="current"][type="hidden"]').val(response.Current);
  141. $('.streak').text(response.Streak);
  142. $('.streak-unit').text('days');
  143. }
  144. updateCalorieChart();
  145. });
  146. }
  147. function loadTrends() {
  148. $.get('/me/trends')
  149. .done(function (response) {
  150. if (response) {
  151. goals = [];
  152. calories = [];
  153. weights = [];
  154. for (var i = 0; i < response.Labels.length; i++) {
  155. goals.push(response.Goals[i]);
  156. calories.push(response.History[i]);
  157. weights.push(response.Weights[i]);
  158. }
  159. updateTrendChart(
  160. response.Labels,
  161. goals,
  162. calories,
  163. weights);
  164. }
  165. });
  166. }
  167. function loadHistory() {
  168. $.get('/me/history')
  169. .done(function (response) {
  170. if (response) {
  171. var history = $('div#history');
  172. var moments = [];
  173. var lastDate;
  174. var panel;
  175. for (var i = 0; i < response.length; i++) {
  176. if (response[i]) {
  177. var momentDate = new Date(response[i].Date).toDateString();
  178. var moment = $('<div class="media" data-moment="' + response[i].Id + '">')
  179. .append('<div class="media-object pull-right"><button class="btn btn-danger delete-history"><span class="glyphicon glyphicon-fire"></span></button></div>')
  180. .append('<div class="media-body">')
  181. .append('<h4 class="media-heading">' + response[i].Product + ' (<span class="calories">' + response[i].Calories + '</span> calories)</h4>');
  182. if (!lastDate || lastDate != momentDate) {
  183. lastDate = momentDate;
  184. if (panel) {
  185. $(panel).find('div.panel-body').append(moments);
  186. $(history).append(panel);
  187. moments = [];
  188. panel = null;
  189. }
  190. panel = $('<div class="panel panel-default">')
  191. .append('<div class="panel-heading"><h3 class="panel-title">' + lastDate + '</h3></div>')
  192. .append('<div class="panel-body">');
  193. }
  194. moments.push(moment);
  195. }
  196. }
  197. if (panel) {
  198. $(panel).find('div.panel-body').append(moments);
  199. $(history).append(panel);
  200. }
  201. }
  202. });
  203. }
  204. function updateTrendChart(labels, goals, calories, weights) {
  205. //if (!lineChart) {
  206. var ctxTrends = trends.getContext("2d");
  207. lineChart = new Chart(ctxTrends).Line(
  208. {
  209. labels: labels,
  210. datasets: [
  211. {
  212. label: 'Goal',
  213. fillColor: 'rgba(220, 220, 220, 0.2)',
  214. strokeColor: 'rgba(220, 220, 220, 1)',
  215. pointColor: 'rgba(220, 220, 220, 1)',
  216. pointStrokeColor: '#fff',
  217. pointHighlightFill: '#fff',
  218. pointHighlightStroke: 'rgba(220, 220, 220, 1)',
  219. data: goals
  220. },
  221. {
  222. label: 'Calories',
  223. fillColor: 'rgba(196, 46, 42, 0.2)',
  224. strokeColor: 'rgba(196, 46, 42, 0.5)',
  225. pointColor: 'rgba(220, 220, 220, 1)',
  226. pointStrokeColor: '#fff',
  227. pointHighlightFill: '#fff',
  228. pointHighlightStroke: 'rgba(220, 220, 220, 1)',
  229. data: calories
  230. },
  231. {
  232. label: 'Weight',
  233. fillColor: 'rgba(51, 51, 204, 0.2)',
  234. strokeColor: 'rgba(51, 51, 204, 0.5)',
  235. pointColor: 'rgba(51, 51, 204, 1)',
  236. pointStrokeColor: '#fff',
  237. pointHighlightFill: '#fff',
  238. pointHighlightStroke: 'rgba(220, 220, 220, 1)',
  239. data: weights
  240. }
  241. ]
  242. },
  243. {
  244. animateScale: true,
  245. pointDot: false
  246. });
  247. //}
  248. };
  249. function updateCalorieChart() {
  250. var goal = getDailyCalories();
  251. var count = getCurrentCalories();
  252. var goalColor = "#ddd";
  253. var countColor = "#46bfbd";
  254. if (count >= goal) {
  255. countColor = "#f7464a";
  256. }
  257. if (!doughnutChart) {
  258. var ctxCalories = chart.getContext("2d");
  259. doughnutChart = new Chart(ctxCalories).Doughnut(
  260. [
  261. {
  262. value: count,
  263. color: "#46bfbd",
  264. highlight: "#46bfbd",
  265. label: "Today"
  266. },
  267. {
  268. value: Math.max(goal - count, 0),
  269. color: "#ddd",
  270. highlight: "#ddd",
  271. label: "Remaining"
  272. }
  273. ],
  274. {
  275. animateScale: true
  276. });
  277. }
  278. if (doughnutChart) {
  279. doughnutChart.segments[0].value = count;
  280. doughnutChart.segments[0].color = countColor;
  281. doughnutChart.segments[0].fillColor = countColor;
  282. doughnutChart.segments[0].highlight = countColor;
  283. doughnutChart.segments[1].value = Math.max(goal - count, 0);
  284. doughnutChart.segments[1].color = goalColor;
  285. doughnutChart.segments[1].fillColor = goalColor;
  286. doughnutChart.segments[1].highlight = goalColor;
  287. doughnutChart.update();
  288. }
  289. }
  290. });