index.html 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Blockly Demo: Graph</title>
  6. <script src="https://www.google.com/jsapi"></script>
  7. <script src="../../blockly_compressed.js"></script>
  8. <script src="../../blocks_compressed.js"></script>
  9. <script src="../../javascript_compressed.js"></script>
  10. <script src="../../msg/js/en.js"></script>
  11. <style>
  12. body {
  13. background-color: #fff;
  14. font-family: sans-serif;
  15. }
  16. h1 {
  17. font-weight: normal;
  18. font-size: 140%;
  19. }
  20. #funcText {
  21. margin-top: 1em;
  22. margin-left: 1.5em;
  23. font-family: sans-serif;
  24. }
  25. #funcText>img {
  26. height: 3px;
  27. width: 15px;
  28. vertical-align: middle;
  29. margin-right: .5em;
  30. }
  31. #y1 {
  32. background-color: #36c;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <h1><a href="https://developers.google.com/blockly/">Blockly</a> &gt;
  38. <a href="../index.html">Demos</a> &gt; Graph</h1>
  39. <p>This is a demo of giving instant feedback as blocks are changed.</p>
  40. <p>&rarr; More info on <a href="https://developers.google.com/blockly/guides/configure/web/code-generators#generating_code">Realtime generation</a>&hellip;</p>
  41. <table>
  42. <tr>
  43. <td>
  44. <div id="visualization" style="width: 400px"></div>
  45. </td>
  46. <td>
  47. <div id="blocklyDiv" style="height: 400px"></div>
  48. </td>
  49. </tr>
  50. </table>
  51. <div id="funcText">
  52. <img id="y1" src="../../media/1x1.gif">
  53. ...
  54. </div>
  55. <xml id="toolbox" style="display: none">
  56. <category name="Math">
  57. <block type="math_number"></block>
  58. <block type="math_arithmetic">
  59. <value name="A">
  60. <shadow type="math_number">
  61. <field name="NUM">1</field>
  62. </shadow>
  63. </value>
  64. <value name="B">
  65. <shadow type="math_number">
  66. <field name="NUM">1</field>
  67. </shadow>
  68. </value>
  69. </block>
  70. <block type="math_single">
  71. <value name="NUM">
  72. <shadow type="math_number">
  73. <field name="NUM">9</field>
  74. </shadow>
  75. </value>
  76. </block>
  77. <block type="math_trig">
  78. <value name="NUM">
  79. <shadow type="math_number">
  80. <field name="NUM">45</field>
  81. </shadow>
  82. </value>
  83. </block>
  84. <block type="math_constant"></block>
  85. <block type="math_number_property">
  86. <value name="NUMBER_TO_CHECK">
  87. <shadow type="math_number">
  88. <field name="NUM">0</field>
  89. </shadow>
  90. </value>
  91. </block>
  92. <block type="math_round">
  93. <value name="NUM">
  94. <shadow type="math_number">
  95. <field name="NUM">3.1</field>
  96. </shadow>
  97. </value>
  98. </block>
  99. <block type="math_modulo">
  100. <value name="DIVIDEND">
  101. <shadow type="math_number">
  102. <field name="NUM">64</field>
  103. </shadow>
  104. </value>
  105. <value name="DIVISOR">
  106. <shadow type="math_number">
  107. <field name="NUM">10</field>
  108. </shadow>
  109. </value>
  110. </block>
  111. <block type="math_constrain">
  112. <value name="VALUE">
  113. <shadow type="math_number">
  114. <field name="NUM">50</field>
  115. </shadow>
  116. </value>
  117. <value name="LOW">
  118. <shadow type="math_number">
  119. <field name="NUM">1</field>
  120. </shadow>
  121. </value>
  122. <value name="HIGH">
  123. <shadow type="math_number">
  124. <field name="NUM">100</field>
  125. </shadow>
  126. </value>
  127. </block>
  128. <block type="math_random_int">
  129. <value name="FROM">
  130. <shadow type="math_number">
  131. <field name="NUM">1</field>
  132. </shadow>
  133. </value>
  134. <value name="TO">
  135. <shadow type="math_number">
  136. <field name="NUM">100</field>
  137. </shadow>
  138. </value>
  139. </block>
  140. <block type="math_random_float"></block>
  141. </category>
  142. <category name="Variables">
  143. <block type="graph_get_x"></block>
  144. </category>
  145. <category name="Logic">
  146. <block type="logic_compare"></block>
  147. <block type="logic_operation"></block>
  148. <block type="logic_negate"></block>
  149. <block type="logic_boolean"></block>
  150. <block type="logic_ternary"></block>
  151. </category>
  152. </xml>
  153. <xml id="startBlocks" style="display: none">
  154. <block type="graph_set_y" deletable="false" x="100" y="100">
  155. <value name="VALUE">
  156. <block type="math_arithmetic">
  157. <field name="OP">POWER</field>
  158. <value name="A">
  159. <block type="graph_get_x"></block>
  160. <shadow type="math_number">
  161. <field name="NUM">1</field>
  162. </shadow>
  163. </value>
  164. <value name="B">
  165. <block type="math_number">
  166. <field name="NUM">2</field>
  167. </block>
  168. <shadow type="math_number">
  169. <field name="NUM">1</field>
  170. </shadow>
  171. </value>
  172. </block>
  173. </value>
  174. </block>
  175. </xml>
  176. <script>
  177. // Load the Google Chart Tools Visualization API and the chart package.
  178. if (typeof google == 'object') {
  179. google.load('visualization', '1', {packages: ['corechart']});
  180. } else {
  181. alert('Unable to load Google\'s chart API.\n' +
  182. 'Are you connected to the Internet?');
  183. }
  184. // Define the custom blocks and their JS generators.
  185. Blockly.Blocks['graph_get_x'] = {
  186. // x variable getter.
  187. init: function() {
  188. this.jsonInit({
  189. "message0": "x",
  190. "output": "Number",
  191. "colour": Blockly.Blocks.variables.HUE,
  192. "tooltip": Blockly.Msg.VARIABLES_GET_TOOLTIP,
  193. "helpUrl": Blockly.Msg.VARIABLES_GET_HELPURL
  194. });
  195. }
  196. };
  197. Blockly.JavaScript['graph_get_x'] = function(block) {
  198. // x variable getter.
  199. return ['x', Blockly.JavaScript.ORDER_ATOMIC];
  200. };
  201. Blockly.Blocks['graph_set_y'] = {
  202. // y variable setter.
  203. init: function() {
  204. this.jsonInit({
  205. "message0": "y = %1",
  206. "args0": [
  207. {
  208. "type": "input_value",
  209. "name": "VALUE",
  210. "check": "Number"
  211. }
  212. ],
  213. "colour": Blockly.Blocks.variables.HUE,
  214. "tooltip": Blockly.Msg.VARIABLES_SET_TOOLTIP,
  215. "helpUrl": Blockly.Msg.VARIABLES_SET_HELPURL
  216. });
  217. }
  218. };
  219. Blockly.JavaScript['graph_set_y'] = function(block) {
  220. // y variable setter.
  221. var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
  222. Blockly.JavaScript.ORDER_ASSIGNMENT) || '';
  223. return 'y = ' + argument0 + ';';
  224. };
  225. /**
  226. * Create a namespace for the application.
  227. */
  228. var Graph = {};
  229. /**
  230. * Main Blockly workspace.
  231. * @type {Blockly.WorkspaceSvg}
  232. */
  233. Graph.workspace = null;
  234. /**
  235. * Cached copy of the function string.
  236. * @type {?string}
  237. * @private
  238. */
  239. Graph.oldFormula_ = null;
  240. /**
  241. * Drawing options for the Chart API.
  242. * @type {!Object}
  243. * @private
  244. */
  245. Graph.options_ = {
  246. //curveType: 'function',
  247. width: 400, height: 400,
  248. chartArea: {left: '10%', width: '85%', height: '85%'}
  249. };
  250. /**
  251. * Visualize the graph of y = f(x) using Google Chart Tools.
  252. * For more documentation on Google Chart Tools, see this linechart example:
  253. * https://developers.google.com/chart/interactive/docs/gallery/linechart
  254. */
  255. Graph.drawVisualization = function() {
  256. var formula = Blockly.JavaScript.workspaceToCode(Graph.workspace);
  257. if (formula === Graph.oldFormula_) {
  258. // No change in the formula, don't recompute.
  259. return;
  260. }
  261. Graph.oldFormula_ = formula;
  262. // Create and populate the data table.
  263. var data = google.visualization.arrayToDataTable(Graph.plot(formula));
  264. // Create and draw the visualization, passing in the data and options.
  265. new google.visualization.LineChart(document.getElementById('visualization')).
  266. draw(data, Graph.options_);
  267. // Create the "y = ..." label. Find the relevant part of the code.
  268. formula = formula.substring(formula.indexOf('y = '));
  269. formula = formula.substring(0, formula.indexOf(';'));
  270. var funcText = document.getElementById('funcText');
  271. funcText.replaceChild(document.createTextNode(formula), funcText.lastChild);
  272. };
  273. /**
  274. * Plot points on the function y = f(x).
  275. * @param {string} code JavaScript code.
  276. * @return {!Array.<!Array>} 2D Array of points on the graph.
  277. */
  278. Graph.plot = function(code) {
  279. // Initialize a table with two column headings.
  280. var table = [];
  281. var y;
  282. // TODO: Improve range and scale of graph.
  283. for (var x = -10; x <= 10; x = Math.round((x + 0.1) * 10) / 10) {
  284. try {
  285. eval(code);
  286. } catch (e) {
  287. y = NaN;
  288. }
  289. if (!isNaN(y)) {
  290. // Prevent y from being displayed inconsistently, some in decimals, some
  291. // in scientific notation, often when y has accumulated rounding errors.
  292. y = Math.round(y * Math.pow(10, 14)) / Math.pow(10, 14);
  293. table.push([x, y]);
  294. }
  295. }
  296. // Add column heading to table.
  297. if (table.length) {
  298. table.unshift(['x', 'y']);
  299. } else {
  300. // If the table is empty, add a [0, 0] row to prevent graph error.
  301. table.unshift(['x', 'y'], [0, 0]);
  302. }
  303. return table;
  304. };
  305. /**
  306. * Force Blockly to resize into the available width.
  307. */
  308. Graph.resize = function() {
  309. var width = Math.max(window.innerWidth - 440, 250);
  310. document.getElementById('blocklyDiv').style.width = width + 'px';
  311. Blockly.svgResize(Graph.workspace);
  312. };
  313. /**
  314. * Initialize Blockly and the graph. Called on page load.
  315. */
  316. Graph.init = function() {
  317. Graph.workspace = Blockly.inject('blocklyDiv',
  318. {collapse: false,
  319. disable: false,
  320. media: '../../media/',
  321. toolbox: document.getElementById('toolbox')});
  322. Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'),
  323. Graph.workspace);
  324. Graph.workspace.clearUndo();
  325. // When Blockly changes, update the graph.
  326. Graph.workspace.addChangeListener(Graph.drawVisualization);
  327. Graph.workspace.addChangeListener(Blockly.Events.disableOrphans);
  328. Graph.resize();
  329. };
  330. window.addEventListener('load', Graph.init);
  331. window.addEventListener('resize', Graph.resize);
  332. </script>
  333. </body>
  334. </html>