toolbox 深度、Blockly.inject、JSON/XML、執行生成碼
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<script>
const toolbox = {kind: 'categoryToolbox', contents: [
{kind: 'category', name: '控制', colour: '120', contents: [
{kind: 'block', type: 'controls_if'},
{kind: 'block', type: 'controls_repeat_ext'}
]},
{kind: 'category', name: '變數', colour: '330',
custom: 'VARIABLE'}
]};
const workspace = Blockly.inject('blocklyDiv', {
toolbox: toolbox,
grid: {spacing: 20, length: 3},
zoom: {controls: true, wheel: true},
trashcan: true
});
</script>
| 元件 | kind | 用途 |
|---|---|---|
| 工具箱根 | categoryToolbox | 含多個分類 |
| 分類 | category | 一組積木(可設 name/colour) |
| 積木 | block | 單一積木(type + fields 預設值) |
| 分隔線 | sep | 分類間分隔 |
| 動態分類 | custom: 'VARIABLE' | 變數/函式等動態清單 |
{kind: 'block', type: 'alarm_when',
fields: {SENSOR: 'temperature', THRESHOLD: 40}}
// 拖出來就是「temperature > 40」的預設狀態
import * as Blockly from 'blockly/core';
import {save, load} from 'blockly/serialization/workspaces';
// 儲存
const state = save(workspace);
localStorage.setItem('myWorkspace', JSON.stringify(state));
// 載入
const loaded = JSON.parse(localStorage.getItem('myWorkspace'));
load(loaded, workspace);
import {workspaceToDom, domToWorkspace} from 'blockly/xml';
const xml = Blockly.Xml.workspaceToDom(workspace);
const text = Blockly.Xml.domToText(xml); // 儲存成字串
// 載入:
const dom = Blockly.Xml.textToDom(text);
Blockly.Xml.domToWorkspace(dom, workspace);
// 1. 生成
const code = Blockly.JavaScript.workspaceToCode(workspace);
// 2. 執行(瀏覽器,注意安全)
try { new Function(code)(); }
catch (e) { console.error(e); }
// 3. 或輸出給使用者複製
document.getElementById('output').textContent = code;
// 4. 或送後端/硬體(POST code 字串)
fetch('/api/run', {method: 'POST', body: code});
// 工作區任何變更都觸發
workspace.addChangeListener((e) => {
if (e.isUiEvent) return; // 忽略純 UI 事件
const code = Blockly.JavaScript.workspaceToCode(workspace);
updatePreview(code); // 即時預覽
autosave(workspace); // 自動存檔
});
「積木 → JSON 設定」工具(完整流程): 1. 載入 blockly + 自訂 JsonGenerator(單元 23) 2. inject:toolbox 含 alarm_when 等自訂積木 3. change listener:每次變更 → jsonGenerator.workspaceToCode() 4. 顯示在右側 pre#output 5. 「儲存」→ JSON 序列化存 localStorage 6. 「下載」→ 把 JSON 設定存成 .json 檔 完成標竿: 使用者拼「temperature > 40 → sound」→ 即時看到 JSON → 下載 → 韌體直接套用。