Blockly 的常用配置

2018年9月14日 402 次阅读 0 条评论 0 人点赞

本文基于 Web Blockly,整理一下可视化编程工具 - Blockly 的常用配置,包括:工作区配置、添加自定义块、配置工具箱、配置代码生成器等。

文章目录[隐藏]

1. 固定尺寸工作区

把 Blockly 放到网页上最简单的方法是将其注入到一个空 div 中。

1.1 引入 Blockly 脚本

首先,引入 Blockly 脚本及核心 “块”:

注意:实际路径可能与上面不同,请按 Blockly 的实际位置调整上面路径

1.2 引入语言文件

引入包含用户语言的消息定义(本例中使用了英语):

1.3 确定引入位置

在页面创建一个空div元素,并设置其尺寸:

1.4 添加工具栏

在页面任意位置定义好 “工具栏” 结构(请参阅定义工具箱以获取更多信息):

1.5 初始化

最后,调用下面的命令将 Blockly 注入到一个 id 为 blocklyDiv 的空 div 中。这个脚本应该在页面的底部,或者由 onload 事件调用以确保注入代码在页面关键元素加载完后执行。

workspace 变量当前并没有被使用,但当需要保存“块”或生成代码时,它会变得非常重要。如果有多个 Blockly 实例注入到同一个页面时,应确保每个返回的工作空间都存储在不同的变量中。

在浏览器中测试页面。你应该可以看到 Blockly 的编辑器填充到了 div 元素中,有七个块积木在工具箱里。这是在线示例

2. 可调尺寸工作区

一个好的 Web 应用将调整 Blockly 的大小以填充屏幕上的可用空间,而不是将其固定大小。有几种方法可以做到这一点,包括使用 iframe,CSS 和 JavaScript 定位。此页演示了一种强大而灵活的叠加方法。

本示例中只需简单的三步,就可以创建一个非固定尺寸的工作区:

2.1 定义区域

使用 HTML 的table元素或div及 CSS,创建一个空区域,页面调整大小时重新排版。并确保该区域有一个唯一的 ID(本例中为blocklyArea

这有一个在线示例,在页底部使用table进行定义。

2.2 注入

与创建固定尺寸工作区一样引入 Blockly,添加脚本、blocklyDiv元素、工具栏、及初始化脚本。

Blockly 现在应该是在页面上运行的,只是不在它应该在的位置上(可能是在屏幕外)。

2.3 定位

最后一步是将blocklyDiv元素放在blocklyArea元素上。这样,就需要移除blocklyDiv元素的heightwidth样式,并添加绝对定位:

然后将注入脚本替换成把 blocklyDiv 放置在 blocklyArea 的脚本:

这是 Blockly 的在线示例,它填满了整个浏览器屏幕的底部。

3. 添加自定义块(Block

虽然 Blockly 已经定义了大量的标准块,但大多数应用仍然需要定义和实现一些自己业务相关的 “块”。

“块” 由三个组件构成:

  • 块(Block)定义对象 - 定义块的外观和行为,包括文本、颜色、字段和连接
  • 工具箱(Toolbox)引用 - 工具箱 XML 中对块类型的引用,这样用户才能将其添加到工作区中
  • 生成器函数 - 用于生成块的代码字符串。该函数一般情况是使用 JavaScript 编写的,即使目标语言不是 JavaScrpit,基至运行环境也只不是 Web 环境。

3.1 块定义

Blockly 通过 Web 页面中的脚本文件加载 “块”,在blocks/目录下包含了几个标准块示例。假设你的块不适合现有的类别,就需要创建一个新的包含块定义的 JavaScript 文件,并将其添加到引用页的 <script ...> 标签中。

注意:大多数块都可以使用 Blockly Developer Tools 定义,而不是手动创建下面的代码。

(译者按:谷歌官方不建议手动去编写创建自定义块的代码,而是提供了相关的开发工具。下面的代码是为了熟悉了解对应字段的含义。)

一个典型的块定义类型如下:

JSON定义格式:

JavaScript定义格式:

以上两种定义形式是等价的。其中:

  • string_length - 这是所定义的 “块” 的类型名称。由于所有的块会共享一个相同的命名空间,因此最好使用一个类别名来区分类别(本例中是string),接下来是你的块函数(本例中是length
  • init - 此函数用于定义块的外观(如形状、颜色、字段等)

上面模块完成定义后,效果如下:

img

更多关于块定义详情,请参考:块自定

3.2 添加工具箱引用

完成定义后,需要使用类型名,将其添加到工具箱中:

3.3 添加生成器函数

最后,要将块解析成代码,需要定义一个与之相对应的生成器函数。生成器函数由于生成语言的不同也会有所不同,标准的生成器函数格式如下:

生成器函数会引用块,以对其进行处理。其输入(如上面的 VALUE 输入)的是代码字符串,然后会将其链接到一个更大的表达式中。

译者按:解析对应的代码需要在 HTML 上引用对应的脚本库。如要解析成 JavaScript 代码需如下引用

有关详细信息,请参阅使用自定义生成器

4. 工具箱(Toolbox)配置

工具箱是用户可以创建新 “块” 的侧边菜单。工具箱的结构使用 XML 来指定,它可以是一个节点树,也可以是字符串的形式。所定义的 XML 会在 Blockly 注入到页面中时传递给它。除了手工输入 XML 外,还可以使用 Blockly Developer Tools 来自动生成。

4.1 工具箱定义

以下是一个最小化的工具箱定义示例,在示例中使用了节点定义形式:

下面定义是字符串定义形式,两种方式是等价的:

两种定义方式,都会生成如下工具箱:

img

如果工具箱中的块比较少量,则可以直接显示它们而不需要使用类别(如上面的最小示例中所示)。在此简单模式下,所有可用块都直接显示在工具箱中,主工作区上没有滚动条,也不需要垃圾桶。

4.2 类别

工具箱中的模块可以类别进行组织。以下示例中,包含了'Control''Logic'两个分类,每个类别包含三个块:

下面是完成定义后生成的工具箱,单击“逻辑”类别,可以看到弹出窗口中的三个逻辑块,效果如下:

img

“分类”的存在改变了 Blockly 的 UI,以支持更大的应用。而 “滚动条” 的出现,就提供了一个无限大的工作空间。其它的,如:“垃圾桶”、“上下文菜单(用来添加注释或折叠块)”等,都可以通过配置选项来设置。

定义分类时,可以通过一个colour属性来指定该分类的颜色。颜色使用 0~360 之间的数字表示色调:

设置颜色后,工具栏效果如下:

img

4.3 动态类别

以下有两个分类'Variables''Functions'用于指定形为,分类里面并没有内容,但定义分类时添加了'custom'属性,值可以是'VARIABLE''PROCEDURE'。这些分类,将使用适合的 “块” 自动填充:

开发者还可以使用custom属性来创建动态填充弹出类别。例如,要创建一个自定义的弹出颜色块:

  • 创建自定义属性:

  • 定义提供给分类内容的回调。这个回调应该有一个工作区并返回一个 XML 块元素数组:

  • 在工作区注册回调:

4.4 类别树

类别可以嵌套在其它类别中。如下所示,有两个顶级类别 CoreCustom,每个类别中又包含了两个子类别,每个子类别同时又包含了若干块:

请注意,类别可以包含子类别和块。在上面的例子中,Custom 有两个子类别(MoveTurn),同时它自身又有一个块(start)。

加载 Blockly 时,默认情况下会显示折叠类别,但可以使用 来扩展类别。

4.5 块分组

XML 可以包含自定义块或块分组。现在有以下 4 个块:

  1. 一个简单的 logic_boolean 块:

img

  1. 一个 math_number 块,已修改为显示 42 而不是 0:

img

  1. 一个 controls_for 块,它连接了三个 math_number 块:

img

  1. 一个 math_arithmetic 块,连接了两个 math_number “阴影块”

img

以下工具栏中生成这四个块的代码:

这些定制块或组的 XML 与 Blockly 的 XML 存储格式相同。因此,为此类块构造 XML 的最简单方法是使用 Code application 来构建块,然后切换到 XML 选项卡并复制结果。工具箱会忽略 xyid 属性,并且可能会将其删除。

4.6 阴影块

阴影块是占位符块,它们可执行多种功能:

  • 指示其父块的默认值
  • 允许用户直接输入值,而不需要数字或字符串块
  • 它们与常规块不同,如果用户在其上放置块,则会被替换
  • 它们会提示用户预期的值类型

阴影块不能直接用 Code application 构造,但可以通过替换 XML 中的普通块 来构造。

4.7 分隔器

添加一个 标签到任意两个分类之间,将会创建一个 “分隔器”。

img

默认情况下,两个相邻块之间的分隔间隔为 24 像素。可以通过修改sep标签的gap属性来调整距离:

通过调整块之间的间隙,就可以在工具箱中创建逻辑块组:

img

4.8 按钮与标签

就像 “块” 一样,你也可以将一个按钮或标签放在工具栏的任何位置:

img

还可以对按钮和标签使用 CSS 样式。在上面示例中,第一个label标签使用了自定义样式,而button则使用了默认样式。

按钮需要回调函数,但标签不用。设置按钮点击时的回调函数:

函数接受的参数应该是可被点击的按钮。这个在线示例 Variables 类别中的“Create variable...”按钮是一个非常好的带回调的例子可以参考相关的代码。

4.9 禁用

工具箱中的 “块”,可以在 XML 中通过 disabled 属性将其禁用:

禁用块可用于限制用户的选择。这可以在某些场景中运用比如用户完成某些成就后解锁该块:

img

4.10 Toolbox 的修改

应用可以在任何时候通过调用以下函数来修改工具箱中的可用块:

在初始配置下,newTree可能是一个节点树或字符串。唯一的限制就是不能修改模式,也就是说在初始工具箱中定义的类别,那么新工具箱也必须有(尽管类别可能会被更改);同样的,初始工具箱中没有的类别,在新工具箱中也不能有。

注意,更新工具栏可能会导致一些较小的 UI 重置:

  • 在一个含有类别的工具箱,如果有弹出菜单,初始是合上的
  • 在没有类别的工具箱中,用户更改的任何字段(如下拉列表)都将恢复到默认值
  • 任何超长工具箱,如果超出了页面,其滚动条会跳到顶端

这是一个包含类别和块组的工具栏的在线示例

5. 代码生成器

大多数 Blockly 应用都需要将用户程序转换为 JavaScript、Python、PHP、Lua、Dart 或其它语言,这一转换过程是由 Blockly 客户端完成的。

5.1 生成代码

首先,引入所需生成语言的生成器。Blockly 中包含了以下生成器:

生成器类需要在blockly_compressed.js之后引入。(此处注意引用顺序)如:

应用调用时,用户块可以随时从应用中导出到代码:

将以上代码中的 JavaScript 替换为 PythonPHPLua、或 Dart 就可以生成相应的代码。

5.2 实时生成

Blockly 库生成代码的操作非常得快,所以频繁调用生成函数也不会有问题。这样就可以通过添加 Blockly 事件监听来实时生成代码:

有关更多信息,可参阅事件

6. 网格(Grid

6.1 使用网格

Blockly 的主工作区可以有一个网格。而网格可以对块进行分隔,从而实现更整洁清晰的布局。当工作区较大时,这会非常有用。

注入 Blockly 时,可以在其配置选项中启用网格,如下所示:

6.2 网格配置参数

Spacing(间距)

网格最重要的配置项就是 spacing,它定义了网格中点的距离。其默认值是0,其结果是不会有网格。以下演示了分别设置为 10、20、40 时的效果:

img

Length(长度)

length是定义网格端点形状的数字。长度为 0 的结果是一个看不见的网格,长度为 1(默认值)会是点,一个更长的长度会导致交叉,长度等于或大于spacing时将没有间隔。下面是将 length 分别设置为 1、5 和 20 的示例:

img

Colour(颜色)

colour 属性定义了网格端点的颜色,可以使用任何与 CSS 兼容的格式,如:#f00#ff0000rgb(255, 0, 0),其默认值是#888

以下为将 colour 分别设置为 #000#ccc#f00 的效果:

img

Snap(网格对齐)

snap 属性是一个布尔值,用于设置当放置在工作空间时块是否应该锁定到最近的网格点,使其网格对齐。默认值为false

img

7. 缩放(Zoom

7.1 使用缩放

Blockly 的主工作区大小是可调的,其大小可以由用户动态控制,或由开发者设置为静态的。

zoom 是 Blocly 的初始化配置项之一:

7.2 缩放配置参数

controls(控制)

设置为true时,会显示 zoom-centre(居中)、zoom-in(放大)和 zoom-out(缩小) 三个按钮,默认为 false

img

wheel(滚轮)

设置为 true 时允许鼠标滚轮缩放,默认为false

startScale

初始放大基数。对于多层应用来说,startScale 会在第一层设置一个高级值,这样在子层就可以根据这个值进行更复杂的缩放。默认为 1.0

maxScale

最大可放大倍数,默认为 3

minScale

最小可缩小倍数,默认为 0.3

scaleSpeed

每次放大或缩小时,缩放速度比。即:scale = scaleSpeed ^ steps。注意,缩小时使用减,而放大时使用加。默认为 1.2

8. 事件

工作区上的每个更改都会触发事件。这些事件完整地描述了每次更改前后的状态。

8.1 事件监听

工作区对象(workspace)中有 addChangeListenerremoveChangeListener 两个方法,可用于监听事件流。一个实时生成代码的例子,另一个最多块数量的限制例子。通常情况下,这两个例子都不关心触发事件是什么。他们只是查看工作区的当前状态。

更复杂的事件监听会查看触发事件。在以下示例中,会检测用户创建的第一条评论,然后发出警报,并停止监听,从而不进一步触发警报:

此外,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.BLOCK_CREATE

块创建事件,其有 2 个附加属性:

名称 类型 描述
xml object 定义新块及任何连接子块的 XML
ids array 包含新块及任何连接子块 Id 的数组

Blockly.Events.BLOCK_DELETE

块删除事件,其有 2 个附加属性:

名称 类型 描述
oldXml object 所删除块及任何连接子块的 XML
ids array 包含所删除块及任何连接子块 UUID 的数组

Blockly.Events.BLOCK_CHANGE

块变化事件,其有 4 个附加属性:

名称 类型 描述
element string field, comment, collapsed, disabled, inline, mutate 之一
name string 所更改字段的名称
oldValue value 原始值
newValue value 修改后的值

Blockly.Events.BLOCK_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.VAR_CREATE

变量创建事件,其有 2 个附加属性:

名称 类型 描述
varType string 变量的类型,如 'int' 或 'string'。不需要是唯一的。这将默认为“”,这是一种特定类型
varName string 变量名称,注意设定时变量相互之间和程序里要唯一
varId string 变量唯一 ID

Blockly.Events.VAR_DELETE

变量删除事件,其有 2 个附加属性:

名称 类型 描述
varType string 变量类型,如'int'或'string'。不需要是唯一的。这将默认为“”,这是一种特定类型。
varName string 变量名称。注意设定时变量相互之间和程序里要唯一
varId string 变量唯一 ID

Blockly.Events.VAR_RENAME

变量重命名事件,其有 2 个附加属性:

名称 类型 描述
oldName string 变量的当前名称。注意设定时变量相互之间和程序里要唯一
newName string 变量的新名称。注意设定时变量相互之间和程序里要唯一
varId string 变量唯一 ID

Blockly.Events.UI

UI 事件,其有 3 个附加属性:

名称 类型 描述
element string selected, category, click, commentOpen, mutatorOpen, warningOpen 值之一
oldValue value 原始值
newValue value 修改后的值

预计 UI 事件所代表的 UI 动作列表将随着时间的推移变得更加全面。例如滚动,缩放,拖动气泡等事件。

这里有个在线示例,同一个页面中两个 Blockly 实例,它们通过事件进行同步。

9. 云存储

如果你的应用是托管在云端的,那么你可以使用 Blockly 的云存储功能,并利用这一服务的优势来保存、加载、分享和发布你的程序。

9.1 设置应用引擎

首先,需要将 Blockly 发布到应用引擎上:

  1. 下载并安装 Python SDK
  2. 登录 Google App Engine 并创建应用。
  3. 编辑 appengine/app.yaml,并将 blockly-demo 中的应用 ID 修改为上一步所创建的 ID。
  4. 复制(或软链接)以下文件及目录到对应的

  1. 可选:如果你需要在服务器上使用 blockly_uncompressed.js,则同样需要将其复制到 appengine/static/。复制 coreappengine/static/,并复制 closure-library/ 到上级目录 appengine/
  2. 可选:如果需要运行 Blockly Playground,那需要像第 5 步一样,复制 blocksgeneratorstests 几个目录到指定位置。
  3. 运行 Google App Engine Launcher,并添加你的 appengine,然后点击 “Deploy” 按钮。如果习惯使用命令行,那么执行:appcfg.py --oauth2 update appengine/

上传 Blockly 后,就可以在浏览器中输入步骤 2 中创建的 URL。然后就能到看到 Demo 列表,包括云存储 Demo。

9.2 云端通讯

云存储 Demodemos/storage/index.html 文件中有以下特点。

首先,有一个加载云存储 API 的脚本:

请注意,该脚本假定页面上只有一个 Blockly 工作区。还有下面这些消息定义,应该根据你自身的需求进行修改:

将这些消息翻译成其它国家语言的示例,可以参考 Blockly Games 中的 json 目录

保存当前块调用一次 BlocklyStorage.link() 即可:

在页面加载时重新保存,仅需在 Blockly 注入页面,通过根据 URL 中的 Hash 调用 BlocklyStorage.retrieveXml

9.3 本地存储

storage.js API 还提供了浏览器本地存储能力。这可以用于替代云存储,或二者结合使用。

从本地存储中恢复块,只需要在 Blockly 注入后超时调用 BlocklyStorage.restoreBlocks 即可:

在用户离开页面时自动备份到本地存储,可调用 BlocklyStorage.backupOnUnload 实现,且其可以通过监听页面的 unload 事件来自动调用:

示例

一个云存储在线示例

标签: 暂无
最后编辑:2018年9月25日

我就是我,是颜色不一样的烟火。

文章评论(0)