not really known
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.

259 lines
8.7 KiB

  1. // Copyright (c) 2015, 16 Walter Bender
  2. //
  3. // This program is free software; you can redistribute it and/or
  4. // modify it under the terms of the The GNU Affero General Public
  5. // License as published by the Free Software Foundation; either
  6. // version 3 of the License, or (at your option) any later version.
  7. //
  8. // You should have received a copy of the GNU Affero General Public
  9. // License along with this library; if not, write to the Free Software
  10. // Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
  11. // Based on ta-stats.py by Walter Bender
  12. // TODO: CLEAN UP THIS LIST
  13. // Assign each block to a bin.
  14. const TACAT = {
  15. 'clear': 'forward', 'forward': 'forward', 'back': 'forward',
  16. 'left': 'forward', 'right': 'forward', 'arc': 'arc',
  17. 'x': 'coord', 'y': 'coord', 'heading': 'coord',
  18. 'settranslucency': 'pen', 'sethue': 'pen',
  19. 'setxy': 'setxy', 'seth': 'setxy', 'penup': 'pen',
  20. 'setpensize': 'pen', 'setcolor': 'pen', 'pensize': 'pen',
  21. 'color': 'pen', 'setshade': 'pen', 'setgray': 'pen',
  22. 'gray': 'pen', 'fillscreen': 'pen', 'beginfill': 'fill',
  23. 'fill': 'fill', 'setfont': 'fill', 'hollowline': 'fill',
  24. 'endfill': 'fill', 'plus': 'number', 'minus': 'number',
  25. 'multiply': 'number', 'power': 'number', 'divide': 'number', 'oneOf': 'number',
  26. 'pendown': 'pen', 'shade': 'pen', 'mod': 'number', 'int': 'number',
  27. 'sqrt': 'number', 'identity': 'number', 'and': 'boolean',
  28. 'or': 'boolean', 'not': 'boolean', 'greater': 'boolean',
  29. 'less': 'boolean', 'equal': 'boolean', 'random': 'random',
  30. 'repeat': 'repeat', 'forever': 'repeat', 'if': 'ifthen',
  31. 'ifthenelse': 'ifthen', 'while': 'ifthen', 'until': 'ifthen',
  32. 'action': 'action', 'do': 'action', 'nameddo': 'action',
  33. 'listen': 'action', 'broadcast': 'action', 'calc': 'action',
  34. 'doArg': 'action', 'calcArg': 'action', 'dispatch': 'action',
  35. 'namedcalc': 'action', 'nameddoArg': 'action', 'namedcalcArg': 'action',
  36. 'storein': 'box', 'namedbox': 'box', 'incrementOne': 'box',
  37. 'luminance': 'sensor', 'mousex': 'sensor', 'mousey': 'sensor',
  38. 'drum': 'action',
  39. 'start': 'action', 'mousebutton': 'sensor', 'keyboard': 'sensor',
  40. 'readpixel': 'sensor', 'see': 'sensor', 'time': 'sensor',
  41. 'sound': 'sensor', 'volume': 'sensor',
  42. 'resistance': 'sensor', 'voltage': 'sensor', 'video': 'media',
  43. 'wait': 'media', 'camera': 'media', 'journal': 'media',
  44. 'audio': 'media', 'show': 'media', 'setscale': 'media',
  45. 'savepix': 'media', 'savesvg': 'media', 'mediawait': 'media',
  46. 'mediapause': 'media', 'mediastop': 'media', 'mediaplay': 'media',
  47. 'speak': 'media', 'sinewave': 'media', 'description': 'media',
  48. 'push': 'extras', 'pop': 'extras', 'printheap': 'extras',
  49. 'clearheap': 'extras', 'isheapempty': 'extras', 'chr': 'extras',
  50. 'int': 'number', 'myfunction': 'python', 'userdefined': 'python',
  51. 'box': 'box', 'kbinput': 'sensor', 'showHeap': 'extras',
  52. 'emptyHeap': 'extras',
  53. 'loadblock': 'python', 'loadpalette': 'python',
  54. 'matrix': 'ignore', 'hidden': 'ignore',
  55. 'rest2': 'ignore', 'rhythm': 'ignore',
  56. 'text': 'ignore', 'number': 'ignore', 'vspace': 'ignore'};
  57. // Assign each bin to a palette.
  58. const TAPAL = {
  59. 'forward': 'turtlep', 'arc': 'turtlep', 'coord': 'turtlep',
  60. 'setxy': 'turtlep', 'pen': 'penp', 'fill': 'penp',
  61. 'random': 'numberp', 'boolean': 'numberp', 'repeat': 'flowp',
  62. 'ifthen': 'flowp', 'action': 'boxp', 'box': 'boxp',
  63. 'sensor': 'sensorp', 'media': 'mediap', 'extras': 'extrasp',
  64. 'number': 'numberp', 'python': 'extrasp', 'ignore': 'numberp'};
  65. // Assign a score for each bin.
  66. const TASCORE = {
  67. 'forward': 3, 'arc': 3, 'setxy': 2.5, 'coord': 4, 'turtlep': 5,
  68. 'pen': 2.5, 'fill': 2.5, 'penp': 5,
  69. 'number': 2.5, 'boolean': 2.5, 'random': 2.5, 'numberp': 0,
  70. 'repeat': 2.5, 'ifthen': 7.5, 'flowp': 10,
  71. 'box': 7.5, 'action': 7.5, 'boxp': 0,
  72. 'media': 5, 'mediap': 0,
  73. 'python': 5, 'extras': 5, 'extrasp': 0, 'ignore': 0,
  74. 'sensor': 5, 'sensorp': 0};
  75. // The list of palettes.
  76. const PALS = ['turtlep', 'penp', 'numberp', 'flowp', 'boxp', 'sensorp', 'mediap', 'extrasp'];
  77. const PALLABELS = [_('turtle'), _('pen'), _('number'), _('flow'), _('action'), _('sensors'), _('media'), _('extras')];
  78. function analyzeProject(blocks) {
  79. // Parse block data and generate score based on rubric
  80. var blockList = [];
  81. for (var blk = 0; blk < blocks.blockList.length; blk++) {
  82. if (blocks.blockList[blk].trash) {
  83. continue;
  84. }
  85. switch(blocks.blockList[blk].name) {
  86. case 'start':
  87. case 'fill':
  88. case 'hollowline':
  89. if (blocks.blockList[blk].connections[1] == null) {
  90. continue;
  91. }
  92. break;
  93. case 'action':
  94. if (blocks.blockList[blk].connections[2] == null) {
  95. continue;
  96. }
  97. break;
  98. default:
  99. if (blocks.blockList[blk].connections[0] == null && last(blocks.blockList[blk].connections) == null) {
  100. continue;
  101. }
  102. break;
  103. }
  104. blockList.push(blocks.blockList[blk].name);
  105. }
  106. scores = [];
  107. for (var i = 0; i < PALS.length; i++) {
  108. scores.push(0);
  109. }
  110. cats = [];
  111. pals = [];
  112. for (var b = 0; b < blockList.length; b++) {
  113. if (blockList[b] in TACAT) {
  114. if (!(TACAT[blockList[b]] in cats)) {
  115. cats.push(TACAT[blockList[b]]);
  116. }
  117. } else {
  118. console.log(blockList[b] + ' not in catalog');
  119. }
  120. }
  121. for (var c = 0; c < cats.length; c++) {
  122. if (cats[c] in TAPAL) {
  123. if (!(TAPAL[cats[c]] in pals)) {
  124. pals.push(TAPAL[cats[c]]);
  125. }
  126. }
  127. }
  128. for (var c = 0; c < cats.length; c++) {
  129. if (cats[c] in TASCORE) {
  130. scores[PALS.indexOf(TAPAL[cats[c]])] += TASCORE[cats[c]];
  131. }
  132. }
  133. for (var p = 0; p < pals.length; p++) {
  134. if (pals[p] in TASCORE) {
  135. scores[PALS.indexOf(pals[p])] += TASCORE[pals[p]];
  136. }
  137. }
  138. return scores;
  139. }
  140. function scoreToChartData(scores) {
  141. var normalizedScores = [];
  142. var maxScore = 0;
  143. var scale;
  144. for (var i = 0; i < scores.length; i++) {
  145. if (scores[i] > maxScore) {
  146. maxScore = scores[i];
  147. }
  148. }
  149. if (maxScore > 0) {
  150. scale = 100 / maxScore;
  151. } else {
  152. scale = 1;
  153. }
  154. if (scale > 1) {
  155. scale = 1;
  156. }
  157. for (var i = 0; i < scores.length; i++) {
  158. normalizedScores.push(scores[i] * scale);
  159. }
  160. var data = {
  161. labels: PALLABELS,
  162. datasets: [
  163. {
  164. label: '',
  165. fillColor: 'rgba(220,220,220,0.4)',
  166. strokeColor: 'rgba(220,220,220,1)',
  167. pointColor: 'rgba(220,220,220,1)',
  168. pointStrokeColor: '#fff',
  169. pointHighlightFill: '#fff',
  170. pointHighlightStroke: 'rgba(220,220,220,1)',
  171. data: normalizedScores,
  172. },
  173. ]
  174. };
  175. return data;
  176. }
  177. function getChartOptions(callback) {
  178. return {
  179. // Callback for rendering chart into a bitmap
  180. onAnimationComplete: callback,
  181. //Boolean - Whether to show lines for each scale point
  182. scaleShowLine : true,
  183. //Boolean - Whether we show the angle lines out of the radar
  184. angleShowLineOut : true,
  185. //Boolean - Whether to show labels on the scale
  186. scaleShowLabels : false,
  187. // Boolean - Whether the scale should begin at zero
  188. scaleBeginAtZero : true,
  189. //String - Colour of the angle line
  190. angleLineColor : 'rgba(0,0,0,.2)',
  191. //Number - Pixel width of the angle line
  192. angleLineWidth : 10,
  193. //String - Point label font declaration
  194. pointLabelFontFamily : 'Arial',
  195. //String - Point label font weight
  196. pointLabelFontStyle : 'normal',
  197. //Number - Point label font size in pixels
  198. pointLabelFontSize : 30,
  199. //String - Point label font colour
  200. pointLabelFontColor : '#666',
  201. //Boolean - Whether to show a dot for each point
  202. pointDot : true,
  203. //Number - Radius of each point dot in pixels
  204. pointDotRadius : 18,
  205. //Number - Pixel width of point dot stroke
  206. pointDotStrokeWidth : 6,
  207. //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
  208. pointHitDetectionRadius : 20,
  209. //Boolean - Whether to show a stroke for datasets
  210. datasetStroke : true,
  211. //Number - Pixel width of dataset stroke
  212. datasetStrokeWidth : 12,
  213. //Boolean - Whether to fill the dataset with a colour
  214. datasetFill : true,
  215. //String - A legend template
  216. legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
  217. }
  218. }