はじめに
Google が公開しているオープンソースビジュアルプログラミング環境の Blockly をカスタマイズして、オリジナルの開発環境を作っていく手順をまとめました。
同時に、GitHubでプルリクベースの開発の流れも含めてまとめています。
出来る限り前提知識なしでもわかるよう手順を省略せずに書いています。
使用した環境
- Mac Book Pro 2017
- Core i5 3.1GHz
- 16GB
- MacOS Catalina 10.15
- Visual Studio Code 1.39.2
- GitHub Free
- Chrome 77.0.3865.120
GitHub にサインイン
- GitHub にサインインします。(アカウントがない場合はサインアップします。 → Create an account)
BlocklyのソースをGitHubからクローンする
デモファイルを開き動作確認
-
ブラウザで開けるように拡張機能 Open in Browser をインストールします。
(左の縦に並んでいるアイコンの3つの□がつながっているものをクリックし、open in browser で検索して install ボタンを押す)
index.htmlの中身は次のようになっています。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Fixed Blockly</title>
<script src="../../blockly_compressed.js"></script>
<script src="../../blocks_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%;
}
</style>
</head>
<body>
<h1><a href="https://developers.google.com/blockly/">Blockly</a> >
<a href="../index.html">Demos</a> > Fixed Blockly</h1>
<p>This is a simple demo of injecting Blockly into a fixed-sized 'div' element.</p>
<p>→ More info on <a href="https://developers.google.com/blockly/guides/configure-blockly/web/fixed-size">injecting fixed-sized Blockly</a>…</p>
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="controls_repeat_ext"></block>
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="text"></block>
<block type="text_print"></block>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{media: '../../media/',
toolbox: document.getElementById('toolbox')});
</script>
</body>
</html>
動作させるために必要なファイルは、
blockly_compressed.js
blocks_compressed.js
msg/js/en.js
mediaフォルダ配下のファイル
のようです。
これをコピーしてカスタマイズしていけばよさそうです。
リポジトリの作成
作業用リポジトリの作成
- GitHubにログインして my-blocky というリポジトリを作ります。
作業用リポジトリでの開発準備
-
control + ` でターミナルを表示して、git clone コピーしたURL で my-blocky リポジトリをクローンします。
-
デモの index.html から必要な部分を、作成した index.html に持ってきます。
持ってきた内容は次の通りです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blockly Demo: Fixed Blockly</title>
<script src="blockly_compressed.js"></script>
<script src="blocks_compressed.js"></script>
<script src="en.js"></script>
</head>
<body>
<div id="blocklyDiv" style="height: 480px; width: 600px;"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="controls_repeat_ext"></block>
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="text"></block>
<block type="text_print"></block>
</xml>
<script>
var demoWorkspace = Blockly.inject('blocklyDiv',
{
media: 'media/',
toolbox: document.getElementById('toolbox')
});
</script>
</body>
</html>
- ターミナルで必要ファイルを blockly のフォルダから my-blockly のフォルダにコピーします。
cp ../blockly/blockly_compressed.js .
cp ../blockly/blocks_compressed.js .
cp ../blockly/msg/js/en.js .
cp -r ../blockly/media media/
一旦動く形にできたので、プルリクを作ってコミットします。
ブランチを作成してコミット
-
ブランチ名を入力しEnterで確定します。今回は add_minimum_runtime としました。
※左下の表示が master から add_minimum_runtime に切り替わります。 -
command + Enter でコミットします。
※ git add していないので確認を求められますが、全てのファイルをコミットするので、Yes を選択します。
GitHubにプッシュ
-
GitHub上に add_minimun_runtime というブランチがないため、確認を求められますが、今回作成するので OK を選択します。
-
GitHub にログインするためのユーザIDとパスワードを入力します。(既に入力済みの場合は出ない、2段階認証している場合はパスワードにトークンを入力)
-
プルリクエストを出す
緑のボタン(Compare & pull request)を押します。
Writeの枠内には内容をチェックする人に伝えたい内容を入れますが、今回は自分なので空欄のままにして、Create pull request ボタンを押します。
- master にマージする
CommitsやFiles changedタブの内容を見ておかしな変更がないかを確認してOKなら Merge pull request ボタンを押します。(もし問題があればWriteに指摘内容を記入して Comment ボタンを押します。その後修正をプッシュして再度確認という流れになります)
Confirm merge ボタンを押すとマージ完了です
↓
- ローカルブランチをmasterに戻してGitHubと同期する
- 左下の add_minimum_runtime をクリックして、master を選択します。
- master の右にある矢印が丸くなったマークをクリックして同期します。
確認が出た場合は、OK を押します。
日本語化してみる
blockly の msg/jsフォルダ内に ja.js ファイルがあり、日本語の内容が入っているようです。先ほど使った en.js を ja.js に置き換えて日本語に変えてみましょう。
ブランチを作成
cp ../blockly/msg/js/ja.js .
いろいろなカスタマイズ
blocklyフォルダ内の demos/index.html を開くと、いろいろなデモの一覧が確認できます。
これらを参考にしながら、カスタマイズしていきます。
全画面表示にする
Resizable blockly のデモを参考にします。
https://developers.google.com/blockly/guides/configure/web/resizable
をみると、HTML内の BlocklyDiv を BlocklyArea で囲んで window のリサイズイベントを設定するようです。
うまくいかなかったので、position: fixed を使う形で実装しました。
変更内容は以下で確認できます。
https://github.com/nakazawaken1/my-blockly/pull/3/files
ブロックと連動した JavaScript等のコードを表示する
組み立てたブロックをJavaScriptプログラムとして取り出すには
javascript_compressed.js
を追加で読み込み、
Blockly.JavaScript.workspaceToCode(workspace)
とすると戻り値として、JavaScriptのソースが返ります。
https://developers.google.com/blockly/guides/configure/web/code-generators
にある通り、他の言語として、現状python、php、lua、dartに対応しています。
blockly/generatorsフォルダにそれぞれの元になるファイルが格納されています。
他の言語でもこれらに対応するファイルを自分で用意すれば対応可能のようです。
コードに変換するタミングをブロックが変更されたときにしたいので、調べてみると
workspace.addChangeListener で登録した処理がブロック変更時に呼ばれるようです。
以下のようにして変更時にソースを更新するようにしました。
var source = document.getElementById('source'); //ソース表示先
var language = document.getElementById('language'); //言語選択のselectタグ
var task = null; //1秒以内の連続実行を抑制
var updatePreview = function () { //ソースコード更新
if (task != null) clearTimeout(task);
task = setTimeout(function () {
source.textContent = Blockly[language.value].workspaceToCode(workspace);
}, 1000);
};
workspace.addChangeListener(updatePreview); //ブロックが変更された時ソースコード更新
language.addEventListener('change', updatePreview, false); //言語を切り替えた時ソースコード更新
add_preview というブランチを作り、表示処理を実装しました。
https://github.com/nakazawaken1/my-blockly/pull/4/files
使用するブロックのみ表示する
今までデモで用意されてきたブロックのまま進めてきましたが、必要ないブロックを消したり、他のブロックを表示する方法を確認します。
今の状態だと上から、条件分岐、比較演算、繰り返し、数値、数値計算、文字列、出力が表示されています。
対応するソースは以下になっています。
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="controls_repeat_ext"></block>
<block type="math_number">
<field name="NUM">123</field>
</block>
<block type="math_arithmetic"></block>
<block type="text"></block>
<block type="text_print"></block>
</xml>
子供に数字の演算だけをさせたいというときなどは数値、数値計算、出力があればよさそうです。
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<block type="math_number">
<field name="NUM">1</field>
</block>
<block type="math_arithmetic"></block>
<block type="text_print"></block>
</xml>
ブロックを種類(カテゴリ)分けする
デモに入っていないブロックもたくさん定義されていて、
https://github.com/google/blockly/wiki
に英語ですが分類別に紹介されています。
ちなみに、ブロックを分類ごとに分けて表示するには、blockタグをcategoryタグで囲むようです。
name属性で分類名、colour属性で色を指定できます。colorではないので注意してください。
利用者側で作れるブロックである変数、関数を使用する際はcustom属性にそれぞれ、VARIABLE、PROCEDUREを指定するようです。
あと、 expanded="true"をつけると展開した状態で起動します。ただし、blockを囲むカテゴリは同時には複数展開できないようです。
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox" style="display: none">
<category name="制御構造" expanded="true">
<category name="条件" colour="%{BKY_LOGIC_HUE}">
<block type="controls_if"></block>
<block type="logic_compare"></block>
</category>
<category name="繰り返し" colour="%{BKY_LOOPS_HUE}">
<block type="controls_repeat_ext"></block>
</category>
</category>
<category name="数値" colour="%{BKY_MATH_HUE}" expanded="true">
<block type="math_number">
<field name="NUM">1</field>
</block>
<block type="math_arithmetic"></block>
</category>
<category name="文字" colour="%{BKY_TEXTS_HUE}">
<block type="text"></block>
<block type="text_print"></block>
<block type="string_length"></block>
</category>
<category name="変数" colour="%{BKY_VARIABLES_HUE}" custom="VARIABLE">
</category>
<category name="関数" colour="%{BKY_PROCEDURES_HUE}" custom="PROCEDURE">
</category>
</xml>
カテゴリタグをつけると画面右下にゴミ箱が出てきて、ブロックを置く領域がスクロールできるようになります。
色の指定方法
colour="%{BKY_LOGIC_HUE}"のように色を指定していますが、
色は0〜360で指定するHSVカラーモデルという仕組みを使っているようです。
https://developers.google.com/blockly/guides/create-custom-blocks/block-colour
もともと用意されているブロックの色と合わすために、定数が定義されています。
BKY_LOGIC_HUE
BKY_LOOPS_HUE
BKY_MATH_HUE
BKY_TEXTS_HUE
BKY_LISTS_HUE
BKY_COLOUR_HUE
BKY_VARIABLES_HUE
BKY_VARIABLES_DYNAMIC_HUE
BKY_PROCEDURES_HUE
実際の数字は ja.js 内に定義されていました。
Blockly.Msg["MATH_HUE"] = "230";
Blockly.Msg["LOOPS_HUE"] = "120";
Blockly.Msg["LISTS_HUE"] = "260";
Blockly.Msg["LOGIC_HUE"] = "210";
Blockly.Msg["VARIABLES_HUE"] = "330";
Blockly.Msg["TEXTS_HUE"] = "160";
Blockly.Msg["PROCEDURES_HUE"] = "290";
Blockly.Msg["COLOUR_HUE"] = "20";
Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310";
BKY_は自動的に付加されるようです。
枠線(グリッド)を表示する
workspace を作成する Blockly.inject の第二引数で、grid を設定することで枠線を表示できます。
var workspace = Blockly.inject('blocklyDiv',
{
media: 'media/',
toolbox: document.getElementById('toolbox'),
grid:
{
spacing: 12, //間隔
length: 12, //線の長さ
colour: '#eee', //線の色
snap: true //ブロックを
},
});
spacing はマス目の大きさ、length は線の長さで小さい値にするとマス目ではなく点になります。
length: 2で下記のようになります。
いろいろな設定を変えてみる
Blockly.inject の第二引数で様々な設定ができるようです。
https://developers.google.com/blockly/guides/get-started/web#configuration
zoom:
{
controls: true, //拡大、縮小、元のサイズボタンを表示
wheel: true, // マウスホイールでの拡大縮小有効
startScale: 3.0, //初期倍率
maxScale: 3, //最大倍率
minScale: 0.3, //最小倍率
scaleSpeed: 1.2 //ズームするスピード
}
- ブロックが並んでいる部分をツールボックスと呼ぶようで、その配置を変えるのが horizontalLayout と toolboxPosition です。
既定値の horizontalLayout:false, toolboxPosition:'start' で左、
horizontalLayout:false, toolboxPosition:'end' で右、
horizontalLayout:true, toolboxPosition:'start' で上、
horizontalLayout:true, toolboxPosition:'end' で下に配置できます。(下記画像)
- scrollbars: true でカテゴリタグがなくてもスクロール可能となり、falseで不可となります。
ここまでの内容を含めたプルリクを作成しました。
https://github.com/nakazawaken1/my-blockly/pull/5/files
...以下作成中