mirror of
https://github.com/google/blockly.git
synced 2026-01-14 12:27:10 +01:00
* Add a new method to be called when the contents of the workspace change and the scrollbars need to be adjusted but the the chrome (trash, toolbox, etc) are expected to stay in the same place. Change a bunch of calls to svgResize to either be removed or call the new method instead. This is a nice performance win since the offsetHeight/Width call in svgResize can be expensive, especially when called as often as we do - there was some layout thrashing. This also paves the way for moving calls to recordDeleteAreas (which is also expensive) to a more cacheable spot than on every mouse down/touch event. of things (namely the scrollbars) * Fix size of graph demo when it first loads by calling svgResize. The graph starts with fixed width and was relying on a resize event to fire (which I believe was removed in commit217c681b86). * Fix the resizing of the code demo. The demo's tab min-width used to match the toolbox's width was only being set on a resize event, but commit217c681b86changed how that worked. * Fix up some comments. * Use specific workspaces rather than Blockly.getMainWorkspace(). * Make workspace required for resizeSvgContents and update some calls to send real workspaces rather than ones that are null. Remove the private tag on terminateDrag_ because it is only actually called from outside the BlockSvg object. * Remove a rogue period. * Recategorize BlockSvg.terminateDrag_ to @package instead of @private so that other developers don't use it, but it still can be used by other Blockly classes. * Add a TODO to fix issue #307. * Add @package to workspace resizeContents.
357 lines
9.7 KiB
HTML
357 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/installation/code-generators#realtime_generation">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">
|
|
<block type="math_number"></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">
|
|
<block type="graph_get_x"></block>
|
|
</category>
|
|
<category name="Logic">
|
|
<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.Blocks['graph_get_x'] = {
|
|
// x variable getter.
|
|
init: function() {
|
|
this.jsonInit({
|
|
"message0": "x",
|
|
"output": "Number",
|
|
"colour": Blockly.Blocks.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.Blocks['graph_set_y'] = {
|
|
// y variable setter.
|
|
init: function() {
|
|
this.jsonInit({
|
|
"message0": "y = %1",
|
|
"args0": [
|
|
{
|
|
"type": "input_value",
|
|
"name": "VALUE",
|
|
"check": "Number"
|
|
}
|
|
],
|
|
"colour": Blockly.Blocks.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,
|
|
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.resize();
|
|
};
|
|
|
|
window.addEventListener('load', Graph.init);
|
|
window.addEventListener('resize', Graph.resize);
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|