Published
Edited
Mar 13, 2021
Insert cell
Insert cell
Insert cell
Global = {
return {
ToolBarHeight: 40,
Height: 540
};
}
Insert cell
md`## Framework`
Insert cell
Insert cell
working = html`
<div id="workspace">
<div id="toolbar" class="flex space-x-5" style="height: ${
Global.ToolBarHeight
}px">
<button id="toolbar_blockly" type="button" class="flex text-xs leading-4 font-medium px-0.5 focus:outline-none transition-colors duration-150 border-turquoise text-gray-900 dark:text-white">
<span class="border-b-2 border-transparent py-2.5">图形编辑器</span>
</button>
<button id="toolbar_codemirror" type="button" class="flex text-xs leading-4 font-medium px-0.5 focus:outline-none transition-colors duration-150 border-transparent text-gray-500 hover:text-gray-900 focus:text-gray-900 dark:text-gray-400 dark:hover:text-white">
<span class="border-b-2 border-transparent py-2.5">Javascript</span>
</button>
<button type="button" class="flex text-xs leading-4 font-medium px-0.5 focus:outline-none transition-colors duration-150 border-transparent text-gray-500 hover:text-gray-900 focus:text-gray-900 dark:text-gray-400 dark:hover:text-white">
<span class="border-b-2 border-transparent py-2.5">保存代码</span>
</button>
<button type="button" class="flex text-xs leading-4 font-medium px-0.5 focus:outline-none transition-colors duration-150 border-transparent text-gray-500 hover:text-gray-900 focus:text-gray-900 dark:text-gray-400 dark:hover:text-white">
<span class="border-b-2 border-transparent py-2.5">还原代码</span>
</button>
</div>

<div class="grid grid-flow-row grid-cols-2 gap-1" style="height: ${
Global.Height
}px;">
<!-- Editor -->
<div id="blockly-edit-area" class="bg-gray-300">
<div id="blockly_editor" class="max-width" style="height: ${
Global.Height
}px;">
</div>
<div id="codemirror_editor" style="display: none;">${await createCodeMirrorWidget(
{
width: width / 2,
height: Global.Height,
oninput: (inst, obj) => {
execution(window.editor.getValue());
}
}
)}
</div>
</div>

<!-- Execution -->
<div id="execution-area">
<canvas id="canvas" width="${width / 2}px" height="${
Global.Height
}px"></canvas>
</div>
</div>
</div>
`
Insert cell
function registerBlocklyCanvasExtensions(Blockly) {
const category = {
name: "画板",
kind: "category",
colour: 20,
contents: [
{
name: "路径",
kind: "category",
colour: 120,
contents: [
canvasBeginPath(Blockly),
canvasClosePath(Blockly),
canvasMoveTo(Blockly),
canvasLineTo(Blockly)
]
},
{
name: "形状",
kind: "category",
colour: 160,
contents: [canvasRect(Blockly), canvasBlocklyArc(Blockly), canvasTriangle(Blockly), canvasBezierCurve(Blockly), canvasQuadraticCurve(Blockly), canvasText(Blockly)]
},
{
name: "绘制",
kind: "category",
colour: 180,
contents: [canvasStroke(Blockly), canvasFill(Blockly)]
},
]
};

return category;
}
Insert cell
function execution(code) {
const canvas = document.getElementById('canvas');
const context = canvas.getContext("2d");

try {
eval(code);
} catch (e) {
console.log(e);
}
}
Insert cell
function setupToolbar() {
const toolbarBlockly = document.querySelector("#toolbar_blockly");
const toolbarCodeMirror = document.querySelector("#toolbar_codemirror");

const blockly_editor = document.querySelector("#blockly_editor");
const codemirror_editor = document.querySelector("#codemirror_editor");

toolbarBlockly.onclick = () => {
blockly_editor.style.display = "block";
codemirror_editor.style.display = "none";
};

toolbarCodeMirror.onclick = () => {
blockly_editor.style.display = "none";
codemirror_editor.style.display = "block";
};
}
Insert cell
workspace = {
const container = document.querySelector('#blockly_editor');
removeAllChildNodes(container);

setupToolbar();

const workspace = Blockly.inject('blockly_editor', {
media: 'https://unpkg.com/blockly/media/',
toolbox: extendedToolboxConfiguration(Blockly, [
registerBlocklyCanvasExtensions(Blockly)
]),
grid: { spacing: 20, length: 3, colour: '#ccc', snap: true },
zoom: {
controls: true,
wheel: true,
startScale: 1.0,
maxScale: 1.6,
minScale: 1.0,
scaleSpeed: 0.4
},
trashcan: true
});

return workspace;
}
Insert cell
{
workspace.addChangeListener(() => {
const code = `function draw(context) {\n${Blockly.JavaScript.workspaceToCode(
workspace
)}}
context.clearRect(0, 0, canvas.width, canvas.height);
draw(context);`;

window.editor.setValue(BeautifyJS.js_beautify(code));

execution(code);
});

return "Ready";
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {
canvasBeginPath,
canvasMoveTo,
canvasLineTo,
canvasStroke,
canvasFill,
canvasRect,
canvasBlocklyArc,
canvasClosePath,
canvasTriangle,
canvasBezierCurve,
canvasQuadraticCurve,
canvasText
} from '@oiar/blockly-canvas-extensions'
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more