mirror of
https://github.com/google/blockly.git
synced 2026-01-05 08:00:09 +01:00
353 lines
9.7 KiB
HTML
353 lines
9.7 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Blockly Demo: Graph</title>
|
|
<script src="https://www.google.com/jsapi"></script>
|
|
<script src="../../blockly_compressed.js"></script>
|
|
<script src="../../blocks_compressed.js"></script>
|
|
<script src="../../javascript_compressed.js"></script>
|
|
<script src="../../msg/js/en.js"></script>
|
|
<style>
|
|
body {
|
|
background-color: #fff;
|
|
font-family: sans-serif;
|
|
}
|
|
h1 {
|
|
font-weight: normal;
|
|
font-size: 140%;
|
|
}
|
|
#funcText {
|
|
margin-top: 1em;
|
|
margin-left: 1.5em;
|
|
font-family: sans-serif;
|
|
}
|
|
#funcText>img {
|
|
height: 3px;
|
|
width: 15px;
|
|
vertical-align: middle;
|
|
margin-right: .5em;
|
|
}
|
|
#y1 {
|
|
background-color: #36c;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1><a href="https://developers.google.com/blockly/">Blockly</a> >
|
|
<a href="../index.html">Demos</a> > Graph</h1>
|
|
|
|
<p>This is a demo of giving instant feedback as blocks are changed.</p>
|
|
|
|
<p>→ More info on <a href="https://developers.google.com/blockly/guides/configure/web/code-generators#generating_code">Realtime generation</a>…</p>
|
|
|
|
<table>
|
|
<tr>
|
|
<td>
|
|
<div id="visualization" style="width: 400px"></div>
|
|
</td>
|
|
<td>
|
|
<div id="blocklyDiv" style="height: 400px"></div>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div id="funcText">
|
|
<img id="y1" src="../../media/1x1.gif">
|
|
...
|
|
</div>
|
|
|
|
<xml id="toolbox" style="display: none">
|
|
<category name="Math" colour="%{BKY_MATH_HUE}">
|
|
<block type="math_number">
|
|
<field name="NUM">123</field>
|
|
</block>
|
|
<block type="math_arithmetic">
|
|
<value name="A">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="B">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_single">
|
|
<value name="NUM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">9</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_trig">
|
|
<value name="NUM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">45</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_constant"></block>
|
|
<block type="math_number_property">
|
|
<value name="NUMBER_TO_CHECK">
|
|
<shadow type="math_number">
|
|
<field name="NUM">0</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_round">
|
|
<value name="NUM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">3.1</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_modulo">
|
|
<value name="DIVIDEND">
|
|
<shadow type="math_number">
|
|
<field name="NUM">64</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="DIVISOR">
|
|
<shadow type="math_number">
|
|
<field name="NUM">10</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_constrain">
|
|
<value name="VALUE">
|
|
<shadow type="math_number">
|
|
<field name="NUM">50</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="LOW">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="HIGH">
|
|
<shadow type="math_number">
|
|
<field name="NUM">100</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_random_int">
|
|
<value name="FROM">
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="TO">
|
|
<shadow type="math_number">
|
|
<field name="NUM">100</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
<block type="math_random_float"></block>
|
|
</category>
|
|
<category name="Variables" colour="%{BKY_VARIABLES_HUE}">
|
|
<block type="graph_get_x"></block>
|
|
</category>
|
|
<category name="Logic" colour="%{BKY_LOGIC_HUE}">
|
|
<block type="logic_compare"></block>
|
|
<block type="logic_operation"></block>
|
|
<block type="logic_negate"></block>
|
|
<block type="logic_boolean"></block>
|
|
<block type="logic_ternary"></block>
|
|
</category>
|
|
</xml>
|
|
|
|
<xml id="startBlocks" style="display: none">
|
|
<block type="graph_set_y" deletable="false" x="100" y="100">
|
|
<value name="VALUE">
|
|
<block type="math_arithmetic">
|
|
<field name="OP">POWER</field>
|
|
<value name="A">
|
|
<block type="graph_get_x"></block>
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
<value name="B">
|
|
<block type="math_number">
|
|
<field name="NUM">2</field>
|
|
</block>
|
|
<shadow type="math_number">
|
|
<field name="NUM">1</field>
|
|
</shadow>
|
|
</value>
|
|
</block>
|
|
</value>
|
|
</block>
|
|
</xml>
|
|
|
|
<script>
|
|
// Load the Google Chart Tools Visualization API and the chart package.
|
|
if (typeof google == 'object') {
|
|
google.load('visualization', '1', {packages: ['corechart']});
|
|
} else {
|
|
alert('Unable to load Google\'s chart API.\n' +
|
|
'Are you connected to the Internet?');
|
|
}
|
|
|
|
// Define the custom blocks and their JS generators.
|
|
Blockly.defineBlocksWithJsonArray([{
|
|
"type": "graph_get_x",
|
|
"message0": "x",
|
|
"output": "Number",
|
|
"colour": Blockly.Msg['VARIABLES_HUE'],
|
|
"tooltip": Blockly.Msg['VARIABLES_GET_TOOLTIP'],
|
|
"helpUrl": Blockly.Msg['VARIABLES_GET_HELPURL']
|
|
}]);
|
|
|
|
Blockly.JavaScript['graph_get_x'] = function(block) {
|
|
// x variable getter.
|
|
return ['x', Blockly.JavaScript.ORDER_ATOMIC];
|
|
};
|
|
|
|
Blockly.defineBlocksWithJsonArray([{
|
|
"type": "graph_set_y",
|
|
"message0": "y = %1",
|
|
"args0": [
|
|
{
|
|
"type": "input_value",
|
|
"name": "VALUE",
|
|
"check": "Number"
|
|
}
|
|
],
|
|
"colour": Blockly.Msg['VARIABLES_HUE'],
|
|
"tooltip": Blockly.Msg['VARIABLES_SET_TOOLTIP'],
|
|
"helpUrl": Blockly.Msg['VARIABLES_SET_HELPURL']
|
|
}]);
|
|
|
|
Blockly.JavaScript['graph_set_y'] = function(block) {
|
|
// y variable setter.
|
|
var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
|
|
Blockly.JavaScript.ORDER_ASSIGNMENT) || '';
|
|
return 'y = ' + argument0 + ';';
|
|
};
|
|
|
|
/**
|
|
* Create a namespace for the application.
|
|
*/
|
|
var Graph = {};
|
|
|
|
/**
|
|
* Main Blockly workspace.
|
|
* @type {Blockly.WorkspaceSvg}
|
|
*/
|
|
Graph.workspace = null;
|
|
|
|
/**
|
|
* Cached copy of the function string.
|
|
* @type {?string}
|
|
* @private
|
|
*/
|
|
Graph.oldFormula_ = null;
|
|
|
|
/**
|
|
* Drawing options for the Chart API.
|
|
* @type {!Object}
|
|
* @private
|
|
*/
|
|
Graph.options_ = {
|
|
//curveType: 'function',
|
|
width: 400, height: 400,
|
|
chartArea: {left: '10%', width: '85%', height: '85%'}
|
|
};
|
|
|
|
/**
|
|
* Visualize the graph of y = f(x) using Google Chart Tools.
|
|
* For more documentation on Google Chart Tools, see this linechart example:
|
|
* https://developers.google.com/chart/interactive/docs/gallery/linechart
|
|
*/
|
|
Graph.drawVisualization = function() {
|
|
var formula = Blockly.JavaScript.workspaceToCode(Graph.workspace);
|
|
if (formula === Graph.oldFormula_) {
|
|
// No change in the formula, don't recompute.
|
|
return;
|
|
}
|
|
Graph.oldFormula_ = formula;
|
|
|
|
// Create and populate the data table.
|
|
var data = google.visualization.arrayToDataTable(Graph.plot(formula));
|
|
// Create and draw the visualization, passing in the data and options.
|
|
new google.visualization.LineChart(document.getElementById('visualization')).
|
|
draw(data, Graph.options_);
|
|
|
|
// Create the "y = ..." label. Find the relevant part of the code.
|
|
formula = formula.substring(formula.indexOf('y = '));
|
|
formula = formula.substring(0, formula.indexOf(';'));
|
|
var funcText = document.getElementById('funcText');
|
|
funcText.replaceChild(document.createTextNode(formula), funcText.lastChild);
|
|
};
|
|
|
|
/**
|
|
* Plot points on the function y = f(x).
|
|
* @param {string} code JavaScript code.
|
|
* @return {!Array.<!Array>} 2D Array of points on the graph.
|
|
*/
|
|
Graph.plot = function(code) {
|
|
// Initialize a table with two column headings.
|
|
var table = [];
|
|
var y;
|
|
// TODO: Improve range and scale of graph.
|
|
for (var x = -10; x <= 10; x = Math.round((x + 0.1) * 10) / 10) {
|
|
try {
|
|
eval(code);
|
|
} catch (e) {
|
|
y = NaN;
|
|
}
|
|
if (!isNaN(y)) {
|
|
// Prevent y from being displayed inconsistently, some in decimals, some
|
|
// in scientific notation, often when y has accumulated rounding errors.
|
|
y = Math.round(y * Math.pow(10, 14)) / Math.pow(10, 14);
|
|
table.push([x, y]);
|
|
}
|
|
}
|
|
// Add column heading to table.
|
|
if (table.length) {
|
|
table.unshift(['x', 'y']);
|
|
} else {
|
|
// If the table is empty, add a [0, 0] row to prevent graph error.
|
|
table.unshift(['x', 'y'], [0, 0]);
|
|
}
|
|
return table;
|
|
};
|
|
|
|
/**
|
|
* Force Blockly to resize into the available width.
|
|
*/
|
|
Graph.resize = function() {
|
|
var width = Math.max(window.innerWidth - 440, 250);
|
|
document.getElementById('blocklyDiv').style.width = width + 'px';
|
|
Blockly.svgResize(Graph.workspace);
|
|
};
|
|
|
|
/**
|
|
* Initialize Blockly and the graph. Called on page load.
|
|
*/
|
|
Graph.init = function() {
|
|
Graph.workspace = Blockly.inject('blocklyDiv',
|
|
{collapse: false,
|
|
disable: false,
|
|
media: '../../media/',
|
|
toolbox: document.getElementById('toolbox')});
|
|
Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'),
|
|
Graph.workspace);
|
|
Graph.workspace.clearUndo();
|
|
|
|
// When Blockly changes, update the graph.
|
|
Graph.workspace.addChangeListener(Graph.drawVisualization);
|
|
Graph.workspace.addChangeListener(Blockly.Events.disableOrphans);
|
|
Graph.resize();
|
|
};
|
|
|
|
window.addEventListener('load', Graph.init);
|
|
window.addEventListener('resize', Graph.resize);
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|