Google Blockly 是一款基于Web的、开源的、可视化程序编辑器。你可以通过拖拽块
的形式快速构建程序,而这些所拖拽的每个块
就是组成程序的基本单元。可视化编程完成,Blockly 直接支持 JavaScript、Python、PHP、Lua、Dart 语言源码的导出。此外,还可以将 Blockly 编辑器快速集成到Web、Android或iOS环境中。
因近期参与一个机器人项目,可视化编程是项目需求之一。故以Web版本(HTML 和 JavaScrip)为例,整理一下 Blockly 的使用方法及各功能点。
1. Blockly 介绍
Blockly 是一个向Web或Andorid/iOS应用添加可视化代码编辑器的库,Blockly使用相互联锁的、图形化的块来表示代码中的概念,如:如变量、逻辑表达式、循环等。这样,用户就可以应用编程原理,而不必担心具体的语法、或命令行。
1.1 构建Blockly应用
对于用户来说,Blockly 只是用更直观的可视化的方式来生成代码。而对于开发都而言,Blockly只是一个文本框,其包含了语法正确的、用户生成的代码。
Blockly可以将“块”导出为代码,其支持以下主流语言:
- JavaScript
- Python
- PHP
- Lua
- Dart
构建一个Blockly应用一般包括以下步骤:
- 集成Blockly编辑器 - 最简单的Blockly编辑器包含了一个“工具箱”来存储的块(block)类型,和一个用于安装块的“工作区”。详细集成方法请参考使用 Blockly,或官方文档Web和Android
- 创建应用块 - 集成Blockly后,就需要创建一些用户代码块,并将其添加到Blockly“工具箱”。创建自定义块参考官方文档Create Custom Blocks Overview
- 构建应用的其余部分 - Blockly只是解决一代码生成的部分,而应用的核心是如果使用代码,这部分还需要开发者自行实现
1.2 Blockly与其它方案的比较
Blockly 正在被越来越多可视化编程环境所使用。使用Blockly做为可视化编程方案具体有以下几点优势:
- 代码可导出 - 用户可基于“块”提取出通用编程语言,并可平滑过渡到基于文本的编程。
- 开源 - Blockly 开放所有源码,你可以复制、修改、并将其应用到你的网站或Andorid等应用中
- 可扩展 - 你可以按需要调整 Blockly,包括根据你的API添加新自定义“块”、移不需要的块和功能等。
- 高可用 - Blockly 不是玩具,你可以用它来实现复杂的编程任务
- 国际化 - Blockly 已被翻译40+种语言
尽管有以上优势,但 Blockly 不可能成为所有应用的解决方案。以下是一些其它可视化编程方案,可按自己需要选用:
- Scratch Blocks: MIT设计和实现的一个Blockly代码库,Scratch Blocks提供了一个简化的编程模型,非常适合于初学者
- Droplet:支持Pencil Code的图形化编程编辑器,它的显著特点是能够从代码转换成块。
- Snap:一个从无到有的图形化编程语言,它不是一个库,而是一个集成执行环境的完整应用
2. 使用 Blockly
接下来,我们基于HTML
和JavaScript
,来介绍将Blockly做为代码编辑器集成到Web应用中的过程。除Web应用外,Blockly还可以集成到Android或iOS应用中,详细请参考官方文档:
2.1 概述
Blockly 被设计的可以很容易地安装到你的Web应用中。用户可以拖动“块”,而Blockly通过“块”生成代码,而应用无需为生成代码做任何事情。对应用来说 Blockly 仅是一个用户指定类型语言(JavaScript, Python, PHP, Lua, Dart 或其它)的文本输入框。
Blockly 是一个完全客户端应用,它无需服务端的任何支持(除非你要使用云存储等服务端功能),且没有第三方的依赖(除非你想重新编译内核),一切都是开源的。
2.2 获取源码
Blockly 源码托管在 GitHub,可以通过 GitHub 下载或在线查看源码:
下载源码并解压后,可以在浏览器打开demos/fixed/index.html
文件,验证 Blockly 的块是否可以拖动等。
2.3 注入 Blockly
安装 Blockly 并验证其可用后,就可以引入 Blockly。如,将 Blockly 在Web页面的一个固定尺寸的div
:
更高级的用法可以让 Blockly 调整大小,以填满页面:
2.4 配置
上面的示例的Blockly.inject
行中,第二个参数是一个键/值对字典。其用于配置Blockly,可用的配置项有:
-
collapse
- boolean。允许“块”折叠或展开。如果工具箱有类别,默认为true
;其它情况为false
-
comments
- boolean。允许“块”有注释。如果工具箱有类别,默认为true
;其它情况为false
-
css
- boolean。如果设置false
,则不注入 CSS;默认为true
-
disable
- boolean。使“块”不可用。如果工具箱有类别,默认为true
;其它情况为false
-
grid
- object。配置一个网格,使块可以捕获到。见Grid -
horizontalLayout
- boolean。设置true
则工具箱使用水平布局;false
则使用垂直布局。默认为false
-
maxBlocks
- number。最大可创建的“块”数量。默认为Infinity
-
media
- string。Blockly 媒体文件目录路径。默认为"https://blockly-demo.appspot.com/static/media/"
-
oneBasedIndex
- boolean。设置为true
则字符串操作索引会从1
开始;false
则从0
开始。默认为true
-
readOnly
- boolean。设置为true
,则禁止用户编辑。影响“工具箱”和“垃圾桶”。默认为false
-
rtl
- boolean。设置为true
,则镜像化编辑器。默认为false
。见RTL Demo -
scrollbars
- boolean。设置工作区是否可滚动。如果工具箱有类别,默认为true
;其它情况为false
-
sounds
- boolean。设置为false
,则点击或删除时不会播放声音。默认为true
-
toolbox
- XML节点或string。用户可用“分类”和“块”的结构树。 -
toolboxPosition
- string。设置为start
,则工具箱在上部(水平显示时)或左则(垂直显示时)或右则(垂直LTR显示时)。设置为end
,则在相对僧。默认为start
-
trashcan
- boolean。显示或隐藏“垃圾桶”。如果工具箱有类别,默认为true
;其它情况为false
-
zoom
- object。工作区缩放配置。见Zoom
在以上配置中,最重要的选项是toolbox
。它是一个XML节点树,用于指定工具箱中有哪些可用的“块”、块如何分布、及是否有类别。
- 更多信息参考工具箱配置
另外,除 Blockly 的默认“块”外,定义块需要通过调用你Web应用的API来构建。
- 更多信息参考创建自定义块
2.5 代码生成
Blockly 是编程语言,也就不能“运行” Blockly 程序。但是你可以将 Blockly 转为用户所需要的JavaScript、Python、PHP、Dart或其它语言
- 更多信息参考代码生成
2.6 “块”的导入、导出
如果你需要将“块”导出,以在其它应用中使用或在以后还原。可以调用以下XML:
var xml = Blockly.Xml.workspaceToDom(workspace); var xml_text = Blockly.Xml.domToText(xml);
调用后,会生成一个最小化的包含用户“块”的XML。如果想使导出的XML更可读,那么可以使用Blockly.Xml.domToPrettyText
来代替上面方法。
恢复己导出的XML,像下面这样即可:
var xml = Blockly.Xml.textToDom(xml_text); Blockly.Xml.domToWorkspace(xml, workspace);
2.7 云存储
Blockly 带有一个可选的云存储功能。它允许用户保存、加载、共享和发布程序。如果你的项目是在云端托管,那么你可以利用此服务的优势。
- 更多信息参考云存储
===============================================
Blockly 的配置
本文基于Web Blockly,整理一下可视化编程工具-Blockly 的常用配置,包括:工作区配置、添加自定义块、配置工具箱、配置代码生成器等。
1. 固定尺寸工作区
把 Blockly 放到网页上最简单的方法是将其注入到一个空div
中。
1.1 引入 Blockly 脚本
首先,引入 Blockly 脚本及核心“块”:
<script src="blockly_compressed.js"></script> <script src="blocks_compressed.js"></script>
注意:实际路径可能与上面不同,请按 Blockly 的实际位置调整上面路径
1.2 引入语言文件
引入包含用户语言的消息定义(本例中使用了英语):
<script src="msg/js/en.js"></script>
1.3 确定引入位置
在页面创建一个空div
元素,并设置其尺寸:
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
1.4 添加工具栏
在页面任意位置定义好“工具栏”结构:
</xml id="toolbox" style="display: none"> </block type="controls_if"></block> </block type="controls_repeat_ext"></block> </block type="logic_compare"></block> </block type="math_number"></block> </block type="math_arithmetic"></block> </block type="text"></block> </block type="text_print"></block> </xml>
1.5 初始化
最后,在页面底部(</page>
之前)创建调用脚本,完成 Blockly 的初始化:
<script> var workspace = Blockly.inject('blocklyDiv', {toolbox: document.getElementById('toolbox')}); </script>
workspace
变量当前并不会使用,但当需要保存“块”或生成代码时,它会变得非常重要。如果有多个 Blockly 实例注入到同一个页面时,应保存其返回的工作区保存在不同的变更中。
2. 可调尺寸工作区
一个好的Web应用将调整 Blockly 的大小以填充屏幕的可用空间,而不是将其固定成一个尺寸。以下演示了一种创建可调尺寸的 Blockly 的方法,这本示例中只需简单的三步,就可以创建一个非固定尺寸的工作区:
2.1 定义区域
使用HTML的table
元素或div
及CSS,创建一个空区域,并确保该区域有一个唯一的ID(本例中为blocklyArea
)
一个在线示例,在页底部使用table
进行定义
2.2 注入
与创建固定尺寸工作区一样引入 Blockly,添加脚本、blocklyDiv
元素、工具栏、及初始化脚本。
2.3 定位
最后一步是将blocklyDiv
元素定位到blocklyArea
元素上。这样,就需要移除blocklyDiv
元素的height
、width
样式,并添加绝对定位:
<div id="blocklyDiv" style="position: absolute"></div<
然后用一个同样位于blocklyDiv
之上的blocklyArea
取代注入脚本:
<script> var blocklyArea = document.getElementById('blocklyArea'); var blocklyDiv = document.getElementById('blocklyDiv'); var workspace = Blockly.inject(blocklyDiv, {toolbox: document.getElementById('toolbox')}); var onresize = function(e) { // Compute the absolute coordinates and dimensions of blocklyArea. var element = blocklyArea; var x = 0; var y = 0; do { x += element.offsetLeft; y += element.offsetTop; element = element.offsetParent; } while (element); // Position blocklyDiv over blocklyArea. blocklyDiv.style.left = x + 'px'; blocklyDiv.style.top = y + 'px'; blocklyDiv.style.width = blocklyArea.offsetWidth + 'px'; blocklyDiv.style.height = blocklyArea.offsetHeight + 'px'; }; window.addEventListener('resize', onresize, false); onresize(); Blockly.svgResize(workspace); </script>
3. 添加自定义块(Block
)
虽然 Blockly 已经定义了大量的标准块,但大多数应用仍然需要定义和实现一些自己业务相关的“块”
“块”有三个组件构成:
-
块(
- 定义块的外观和行为,包括文本、颜色、字段和连接Block
)定义对象 -
工具箱(
- 工具箱XML中对块类型的引用,这样用户才能将其添加到工作区中Toolbox
引用 -
生成器函数
- 用于生成块的代码字符串。该函数总是使用JavaScript编写,虽然目标语言可能不是JavaScrpit,基至运行环境也可能不是Web
3.1 块定义
Blockly 通过页面中脚本文件加载“块”,在blocks/
目录下包含了几个标准块示例。如果需要创建一个新的块,就需要创建个包含块定义的脚本文件,并将其添加到引用页的<script ...<
标签中。
一个块定义类型如下:
JSON
定义格式:
Blockly.Blocks['string_length'] = { init: function() { this.jsonInit({ "message0": 'length of %1', "args0": [ { "type": "input_value", "name": "VALUE", "check": "String" } ], "output": "Number", "colour": 160, "tooltip": "Returns number of letters in the provided text.", "helpUrl": "http://www.w3schools.com/jsref/jsref_length_string.asp" }); } };
JavaScript
定义格式:
Blockly.Blocks['string_length'] = { init: function() { this.appendValueInput('VALUE') .setCheck('String') .appendField('length of'); this.setOutput(true, 'Number'); this.setColour(160); this.setTooltip('Returns number of letters in the provided text.'); this.setHelpUrl('http://www.w3schools.com/jsref/jsref_length_string.asp'); } };
以上两咱定义形式是等价的。其中:
-
string_length
- 所定义的“块”的名称。由于所有的块会共享一个命名空间,所以可以使用使用一个类别名来区分分类(本例中是string
),拉下来是块的功能定义(本例中是length
) -
init
- 这个函数用于定义块外观、形状等
上面模块完成定义后,效果如下:
更多关于块定义,请参考:块自定
3.2 添加工具箱引用
完成定义后,需要使用类型名,将其添加到工具箱中:
<xml id="toolbox" style="display: none"> <category name="Text"> <block type="string_length"></block> </category> ... </xml>
3.3 添加生成器函数
最后,要将块解析成代码,需要定义一个与之对应的生成器函数。生成器函数由于生成语言的不同也会有所不同,标准的生成器函数格式如下:
Blockly.JavaScript['text_length'] = function(block) { // String or array length. var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_FUNCTION_CALL) || '\'\''; return [argument0 + '.length', Blockly.JavaScript.ORDER_MEMBER]; };
生成器函数会引用块,以对其进行处理。其输入(如上面的VALUE
)的是代码字符串,然后会将其链接到一个更大的表达式中。
4. 工具箱(Toolbox
)配置
工具箱是用户可以创建新“块”的侧边菜单。工具箱的结构使用XML来指定,它可以一个节点树,也可以是字符串的形式。所定义的XML会在 Blockly 注入到页面中时传递给它。除了手工输入XML外,还可以使用Blockly Developer Tools来自动生成。
4.1 工具箱定义
以下是一个最小化的工具箱定义示例,在示例中使用了节点定义形式:
<xml id="toolbox" style="display: none"> <block type="controls_if"></block> <block type="controls_whileUntil"></block> </xml> <script> var workspace = Blockly.inject('blocklyDiv', {toolbox: document.getElementById('toolbox')}); </script>
下面定义是字符串定义形式,两种方式是等价的:
<script> var toolbox = '<xml>'; toolbox += ' <block type="controls_if"></block>'; toolbox += ' <block type="controls_whileUntil"></block>'; toolbox += '</xml>'; var workspace = Blockly.inject('blocklyDiv', {toolbox: toolbox}); </script>
两种定义方式,都会生成如下工具箱:
4.2 类别
工具箱中的模块可以类别进行组织。以下示例中,包含了'Control'
和'Logic'
两个分类:
<xml id="toolbox" style="display: none"> <category name="Control"> <block type="controls_if"></block> <block type="controls_whileUntil"></block> <block type="controls_for"> </category> <category name="Logic"> <block type="logic_compare"></block> <block type="logic_operation"></block> <block type="logic_boolean"></block> </category> </xml>
完成定义后,其效果如下:
“分类”表示会改变 Blockly 的UI,以支持更大的应用。而“滚动条”的出现,就提供了一个无限大的工作空间。其它的,如:“垃圾桶”、“上下文菜单”等,都可以通过配置选项来设置。
定义分类时,可以通过一个colour
属性来指定该分类的颜色。颜色使用0~360
之间的数字表示:
<xml id="toolbox" style="display: none"> <category name="Logic" colour="210">...</category> <category name="Loops" colour="120">...</category> <category name="Math" colour="230">...</category> > <category name="Variables" colour="330" custom="VARIABLE"></category> <category name="Functions" colour="290" custom="PROCEDURE"></category> </xml>
设置颜色后,工具栏效果如下:
4.3 动态类别
以下有两个分类'Variables'
和'Functions'
用于指定形为,分类里面并没有内容,但定义分类时添加了'custom'
属性,值可以是'VARIABLE'
或'PROCEDURE'
。这些分类,将使用适合的“块”自动填充:
<category name="Variables" custom="VARIABLE"></category> <category name="Functions" custom="PROCEDURE"></category>
开发者还可以使用custom
属性来创建动态填充弹出类别。例如,要创建一个自定义的弹出颜色块:
- 创建自定义属性:
<category name="Colours" custom="COLOUR_PALETTE"></category>
- 定义提供给分类内容的回调。这个回调应该有一个工作区并返回一个XML块元素数组:
/** * Construct the blocks required by the flyout for the colours category. * @param {!Blockly.Workspace} workspace The workspace this flyout is for. * @return {!Array.<!Element>} Array of XML block elements. */ myApplication.coloursFlyoutCallback = function(workspace) { // Returns an array of hex colours, e.g. ['#4286f4', '#ef0447'] var colourList = myApplication.getPalette(); var xmlList = []; if (Blockly.Blocks['colour_picker']) { for (var i = 0; i < colourList.length; i++) { var blockText = '<xml>' + '<block type="colour_picker">' + '<field name="COLOUR">' + colourList[i] + '</field>' + '</block>' + '</xml>'; var block = Blockly.Xml.textToDom(blockText).firstChild; xmlList.push(block); } } return xmlList; };
- 在工作区注册回调:
myWorkspace.registerToolboxCategoryCallback( 'COLOUR_PALETTE', myApplication.coloursFlyoutCallback);
4.4 类别树
类别可以嵌套在其它类别中。如下所示,有两个顶级类别'Core'
和'Custom'
,每个类别中又包含了两个子类别:
<xml id="toolbox" style="display: none"> <category name="Core"> <category name="Control"> <block type="controls_if"></block> <block type="controls_whileUntil"></block> </category> <category name="Logic"> <block type="logic_compare"></block> <block type="logic_operation"></block> <block type="logic_boolean"></block> </category> </category> <category name="Custom"> <block type="start"></block> <category name="Move"> <block type="move_forward"></block> <block type="move_backward"></block> </category> <category name="Turn"> <block type="turn_left"></block> <block type="turn_right"></block> </category> </category> </xml>
4.5 块分组
XML可以包含自定义块或块分组。现在有以下4个块:
- 一个
logic_boolean
块: - 一个
math_number
块,用于修改时显示42而不是0: - 一个
controls_for
块,其中包括了3个math_number
块: - 一个
math_arithmetic
块,其中包括了两个math_number
“阴影块”:
以下工具栏中包括了上面4个块:
<xml id="toolbox" style="display: none"> <block type="logic_boolean"></block> <block type="math_number"> <field name="NUM">42</field> </block> <block type="controls_for"> <value name="FROM"> <block type="math_number"> <field name="NUM">1</field> </block> </value> <value name="TO"> <block type="math_number"> <field name="NUM">10</field> </block> </value> <value name="BY"> <block type="math_number"> <field name="NUM">1</field> </block> </value> </block> <block type="math_arithmetic"> <field name="OP">ADD</field> <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> </xml>
这些定制块或组的XML与Blockly的XML存储格式相同。因此,为此类块构造XML的最简单方法是使用Code application
来构建块,然后切换到XML
选项卡并复制结果。
“阴影块”是执行几个函数的占位符块,它们具有以下特征:
- 它们表示其父块的默认值
- 允许用户直接输入值,而不需要获取一个数字或字符串块。
- 与普通块不同,如果用户在其上删除一个块,则它们将被替换
- 它们会提示用户期望的值类型
阴影块不能直接用Code application
构造,但可以通过替换普通块的XML中的<block ...>
和</block>
为<shadow ...>
和</shadow>
来构造。
4.6 分隔器
添加一个<sep></sep>
标签到任意两个分类之间,将会创建一个“分隔器”。
默认情况下,两个相邻块之间的分隔间隔为24像素。可以通过修改sep
标签的gap
属性来调整距离:
<xml id="toolbox" style="display: none"> <block type="math_number"></block> <sep gap="32"></sep> <block type="math_arithmetic"> <field name="OP">ADD</field> </block> <sep gap="8"></sep> <block type="math_arithmetic"> <field name="OP">MINUS</field> </block> </xml>
通过调整块之间间隙,就可以在工具箱中创建逻辑块组:
4.7 按钮与标签
就像“块”一样,你也可以将一个按钮或标签放在工具栏的任何位置:
<xml id="toolbox" style="display: none"> <block type="logic_operation"></block> <label text="A label" web-class="myLabelStyle"></label> <label text="Another label"></label> <block type="logic_negate"></block> <button text="A button" callbackKey="myFirstButtonPressed"></button> <block type="logic_boolean"></block> </xml> <style> .myLabelStyle>.blocklyFlyoutLabelText { font-style: italic; fill: green; } </style>
还可以对按钮和标签使用CSS样式。在上面示例中,第一个label
标签使用了自定义样式,而button
则使用了默认样式。
按钮需要回调一个函数,但标签不用。设置按钮点击时的回调函数:
yourWorkspace.registerButtonCallback(yourCallbackKey, yourFunction).
4.8 禁用
工具箱中的“块”,可以在XML中通过disabled
属性将其禁用:
<xml id="toolbox" style="display: none"> <block type="math_number"></block> <block type="math_arithmetic"></block> <block type="math_single" disabled="true"></block> </xml>
禁用块可用于限制用户的选择。这可以用于用户完成某些成就后解锁块的场景:
4.9 Toolbox的修改
应用可以在任何时候通过调用以下函数来修改工具箱:
workspace.updateToolbox(newTree);
在初始配置下,newTree
可能是一个节点树或字符串。唯一的限制就是不能修改模式,也就是说在初始工具箱中定义的类别,那么新工具箱也必须有;同样的,初始工具箱中没有的类别,在新工具箱中也不能有。
别外,更新工具栏可能会导致一些较小的UI重置:
- 在一个工具箱类别,“弹出”如果当前是开启状态,那么会关闭
- 在没有类别的工具箱中,用户更改的任何字段(如下拉列表)都将恢复到默认值
- 任何超长工具箱,如果超出了页面,其滚动条会跳到顶端
5. 代码生成器
大多数 Blockly 应用都需要将用户程序转换为JavaScript、Python、PHP、Lua、Dart或其它语言,这一转换过程是由 Blockly 客户端完成的。
5.1 生成代码
首先,引入所需生成语言的生成器。Blockly 中包含了以下生成器:
javascript_compressed.js
python_compressed.js
php_compressed.js
lua_compressed.js
dart_compressed.js
生成器类需要在blockly_compressed.js
之后引入。如:
<script src="blockly_compressed.js"></script> <script src="javascript_compressed.js"></script>
应用调用时,用户块可以随时从应用中导出到代码:
var code = Blockly.JavaScript.workspaceToCode(workspace);
将以上代码中的JavaScript
替换为Python
、PHP
、Lua
、或Dart
就可以生成相应的代码。
5.2 实时生成
生成的操作非常快,所以频繁调用生成函数也不会有问题。这样就可以通过添加 Blockly 事件监听来实时生成代码:
function myUpdateFunction(event) { var code = Blockly.JavaScript.workspaceToCode(workspace); document.getElementById('textarea').value = code; } workspace.addChangeListener(myUpdateFunction);
6. 网格(Grid
)
6.1 使用网格
Blockly 的主工作区可以有一个网格。而网格可以对块进行分隔,从而实现更整洁的布局。当工作区较大时,这会非常有用。
注入 Blockly 时,可以在其配置选项中启用网格:
var workspace = Blockly.inject('blocklyDiv', {toolbox: document.getElementById('toolbox'), grid: {spacing: 20, length: 3, colour: '#ccc', snap: true}, trashcan: true});
6.2 网格配置参数
Spacing
网格最重要的配置项就是spacing
,它定义了网格中点的距离。其默认值是0
,其结果是不会有网格。以下演示了分别设置为10、20、40时的效果:
Length
length
是定义网格端点形状的数字。长度为0的结果是一个看不见的网格,长度为1(默认值)会是点,一个更长的长度会导致交叉,长度等于或大于spacing
时将没有间隔。下面是将length
分别设置为1、5和20的示例:
Colour
colour
属性定义了网格端点的颜色,可以使用任何与CSS兼容的格式,如:#f00
、#ff0000
或rgb(255, 0, 0)
,其默认值是#888
。
以下为将colour
分别设置为#000
、#ccc
和#f00
的效果:
Snap
snap
属性是一个布尔值,用于设置当放置在工作空间时块是否应该锁定到最近的网格点。其默认值为false
7. 缩放(Zoom
)
7.1 使用缩放
Blockly 的主工作区大小是可调的,其大小可以由用户动态控制,或由开发者设置为静态的。
zoom
是 Blocly 的初始化选项之一:
var workspace = Blockly.inject('blocklyDiv', {toolbox: document.getElementById('toolbox'), zoom: {controls: true, wheel: true, startScale: 1.0, maxScale: 3, minScale: 0.3, scaleSpeed: 1.2}, trashcan: true});
7.2 缩放配置参数
controls
设置为true
时,会显示zoom-centre、zoom-in、and zoom-out三个按钮,默认为false
。
wheel
设置为true
时允许鼠标滚轮缩放,默认为false
startScale
初始放大基数。对于多层应用来说,startScale
会在第一层设置一个高级值,这样在子层就可以根据这个值进行更复杂的缩放。默认为1.0
maxScale
最大可放大倍数,默认为3
minScale
最小可缩小倍数,默认为0.3
scaleSpeed
每次放大或缩小时,维放速度比。即:scale = scaleSpeed ^ steps
。注意,缩小时使用减,而放大时使用加。默认为1.2
8. 事件
工作区上的每个更改都会触发事件。这些事件完全描述了每次更改前后的状态。
8.1 事件监听
工作区对象(workspace
)中有addChangeListener
和removeChangeListener
两个方法,可用于监听事件流。
在以下示例中,会检测用户创建的第一条注释,然后发出警报,并停止监听,从而不进一步触发警报:
function onFirstComment(event) { if (event.type == Blockly.Events.CHANGE && event.element == 'comment' && !event.oldValue && event.newValue) { alert('Congratulations on creating your first comment!') workspace.removeChangeListener(onFirstComment); } } workspace.addChangeListener(onFirstComment);
此外,Blockly 还提供了另一种监听事件流的方法,可以在每个“块”中定义一个'onchange'
函数,该函数会在块发生变化时被调用。
8.2 事件类型
所有事件都具有以下共同属性:
-
type
- string。Blockly.Events.CREATE
、Blockly.Events.DELETE
、Blockly.Events.CHANGE
、Blockly.Events.MOVE
、Blockly.Events.UI
之一 -
workspaceId
- string。工作区UUID。工作区可以通过Blockly.Workspace.getById(event.workspaceId)
找到 -
blockId
- string。块的UUID。块可以通过workspace.getBlockById(event.blockId)
找到 -
group
- string。UUID 分组。有些事件是不可分割的组中的一部分。例如,在堆栈中插入语句
Blockly.Events.CREATE
Create
事件,其有两个附加属性:
-
xml
- object。定义新块及任何连接子块的XML -
ids
- array。包含新块及任何连接子块Id的数组
Blockly.Events.DELETE
Delete
事件,其有两个附加属性:
-
oldXml
- object。所删除块及任何连接子块的XML -
ids
- array。包含所删除块及任何连接子块Id的数组
Blockly.Events.CHANGE
Change
事件,其有4个附加属性:
-
element
- string。'field'
、'comment'
、'collapsed'
、'disabled'
、'inline'
、'mutate'
之一 -
name
- string。所更改字段的名称 -
oldValue
- value。原始值 -
newValue
- value。修改后的值
Blockly.Events.MOVE
Move
事件,其有以下6个附加属性:
-
oldParentId
- string。其旧父块的UUID,当为顶级块时为Undefined
-
oldInputName
- string。旧输入值,当为顶级块时为Undefined
-
oldCoordinate
- object。当为顶级块时,则为X和Y坐标;否则为Undefined
-
newParentId
- string。其新父块的UUID,当为顶级块时为Undefined
-
newInputName
- string。新输入值,当为顶级块时为Undefined
-
newCoordinate
- object。当为顶级块时,则为X和Y坐标;否则为Undefined
Blockly.Events.UI
UI
事件,其有以下3个附加属性:
-
element
- string。'selected'
、'category'
、'click'
、'commentOpen'
、'mutatorOpen'
、'warningOpen'
值之一 -
oldValue
- value。原始值 -
newValue
- value。修改后的值
9. 云存储
你的应用是托管在云端的,那么你可以使用 Blockly 的云存储功能,并利用这一服务的优势来保存、加载、分享、或发布你的程序。
9.1 设置应用引擎
首先,需要将 Blockly 发布到应用引擎上:
- 下载并安装Python SDK
- 登录Google App Engine并创建应用
- 编辑
appengine/app.yaml
,并将blockly-demo
中的应用Id修改为上一步所创建的Id - 复制(或软链接)以下文件及目录到
appengine/static/
:demos/
msg/
media/
*_compressed.js
- 可选:如果你需要在服务器上使用
blockly_uncompressed.js
,则同样需要将其复制到appengine/static/
。复制core
到appengine/static/
,并复制closure-library/
到上级目录appengine/
- 可选:如果需要运行 Blockly Playground,那需要像第5步一样,复制
blocks
、generators
和tests
几个目录到指定位置 - 运行 Google App Engine Launcher,并添加你的
appengine
,然后点击“Deploy”按钮。如果习惯使用命令行,那么执行:appcfg.py --oauth2 update appengine/
上传 Blockly 后,就可以在浏览器中输入步骤2中创建的URL。然后就能到看到Demo列表,包括云存储Demo。
9.2 云端通讯
在云存储Demo的demos/storage/index.html文件中有以下特点。
首先,有一个加载云存储API的脚本:
<script src="/storage.js"></script>
请注意,该脚本假设只有页面上只有一个 Blockly 工作区。还有下面这些消息定义,应该根据你需要修改这些定义:
BlocklyStorage.HTTPREQUEST_ERROR = 'There was a problem with the request.\n'; BlocklyStorage.LINK_ALERT = 'Share your blocks with this link:\n\n%1'; BlocklyStorage.HASH_ERROR = 'Sorry, "%1" doesn\'t correspond with any saved Blockly file.'; BlocklyStorage.XML_ERROR = 'Could not load your saved file.\n' + 'Perhaps it was created with a different version of Blockly?';
将这些消息解析成其它语言的示例,可以参考 Blockly Games 中的json目录
保存当前块调用BlocklyStorage.link()
即可:
<button onclick="BlocklyStorage.link()">Save Blocks</button>
在页面加载时重新保存,仅需在 Blockly 注入页面,通过根据URL中的Hash调用BlocklyStorage.retrieveXml
:
if ('BlocklyStorage' in window && window.location.hash.length > 1) { BlocklyStorage.retrieveXml(window.location.hash.substring(1)); }
9.3 本地存储
storage.js
API 还有浏览器本地存储能力。这可以用于替代云存储,或二者结合使用。
从本地存储中恢复块,只需要在 Blockly 注入后超时调用BlocklyStorage.restoreBlocks
即可:
window.setTimeout(BlocklyStorage.restoreBlocks, 0);
在用户离开时自动备份到本地存储,可调用BlocklyStorage.backupOnUnload
实现,且其可以通过监听页面的unload
事件来自动调用:
BlocklyStorage.backupOnUnload();
示例
一个云存储在线示例
相关推荐
深度学习的3D可视化工具Zetane——windows版本
在本文中,我们将深入探讨"MFC可视化编程实例——Windows标准控件的使用"这一主题,主要涉及MFC(Microsoft Foundation Classes)框架下如何利用可视化设计工具创建和操作常见的Windows控件。通过压缩包中的AppEx1...
【可视化编程实验——计算器】 在计算机科学领域,可视化编程是一种以图形化用户界面为中心的编程方式,它使得程序员可以通过拖拽、连接图标等直观方式进行编程,降低了编程的复杂度和入门门槛。本实验中,我们关注...
然而,随着"ESP8266可视化编程工具"的出现,这个过程变得更加友好和直观。 该工具的核心特性是其用户界面的简洁和易用性,旨在降低编程的门槛,让更多的人能够轻松地参与到ESP8266的项目开发中。可视化编程意味着...
Fork——GIt的高效可视化管理工具
《可视化编程应用——Visual Basic电子课件》是深入学习VB编程技术的重要资源,涵盖了从基础知识到实际应用的全面内容。本课件旨在帮助初学者快速掌握Visual Basic编程环境,理解VB程序设计语言基础,以及如何利用VB...
Basic4Android是Android平台上一个简单而又强大的可视化快速安卓应用开发工具,它可被用来开发和测试数据库通信,甚至可以被用来开发2D的即时游戏。Basic4Android兼容了Google的AdMob数据库,所以开发者可以在他们...
所谓“可视化”不过是支持该语言的IDE(编程工具)所提供的功能,让你在编程窗口等一些“看到”程序的时候可以使用拖拽等可视化操作。 C++是一门语言,而VC只是一个实现了C++的可视化编程的IDE。在设计界面时,只需将...
本项目是一款基于Blockly的树莓派可视化编程软件设计源码,包含164个文件,涵盖57个JavaScript文件、26个PNG图像文件、21个Python文件、17个DEB安装包文件、6个CUR资源文件、5个音频文件(MP3、OGG、WAV)、5个动画...
Blockly是由Google开发的一种开源的可视化图形编程语言,它以积木块的形式展示编程语句,降低了编程的门槛,特别适合青少年学习。与传统的编程方式相比,Blockly使得编程过程更加直观和易于理解,有助于激发青少年对...
**CSS可视化编程工具详解** ...总之,CSS可视化编程工具是提升CSS工作流的重要辅助,它们通过图形化的界面,降低了CSS的学习曲线,提高了工作效率,使得开发者能够更加专注于设计本身,而不是被语法细节所困扰。
mysql可视化编程mysql可视化编程mysql可视化编程mysql可视化编程mysql可视化编程
在标题中提到的“可视化编程工具”,指的是用于简化ExtJS开发过程的一种图形化工具,这种工具允许开发者通过拖拽和配置组件来创建应用的界面,从而提高开发效率。 描述中提到了“extJS汉化中文版”,这表明这个工具...
PyQT GUI与数据可视化编程
VC可视化编程_windows编程
谷歌Blockly是一款开源的可视化编程工具,它为开发者提供了构建图形化编程界面的能力。这个项目旨在简化编程教育,使初学者能够通过拖放积木块的方式来编写程序,而无需面对复杂的文本语法。Blockly是用JavaScript...
8. **进阶话题**:对于有兴趣深入学习的学员,可能会探讨如何将可视化编程与传统编程结合,以及如何扩展可视化工具的功能,比如自定义组件或插件的开发。 通过这个“可视化编程”课程,无论是完全没接触过编程的...
通过C++编写的程序能够实现进程调度的可视化,即在用户界面上直观地展示进程调度的过程,这对于学习者来说是一种很好的学习手段,可以直观地理解进程是如何在操作系统中被调度和管理的。 在本次课程设计中,主要...
9. **数据故事讲述**:有效的可视化不仅仅是画图,更重要的是如何通过图形传达一个故事或见解。 通过这两个压缩包,读者可以跟随书中的步骤,逐步实践这些知识点,从而提升自己的Python数据可视化技能。无论是数据...