ビジュアルプログラミング環境の作りかた

こんにちは! 

EYSの中澤です。 

システムサポート課で音楽教室を運営するシステムの課題対応、機能追加を行っています。 

また、プログラミング教室のカリキュラムを考えています。 

今回は、子供のプログラミング学習のみならず、IoTや非エンジニア向けのサービスで使用されているビジュアルプログラミング環境のつくりかたをまとめました。 

数字の1〜9のブロックと足し算のブロックを作って計算結果を教えてくれる環境を作ります。 

ScratchやMakeCodeのベースとなっているGoogleのオープンソースプロジェクトBlocklyをつかうことで、HTML, JavaScript, CSSのみで、GUI関連の処理を実装しなくても作れるようになっています。 

ソース 

https://github.com/google/blockly

ドキュメント 

https://developers.google.com/blockly/

必要なファイルは blockly_compressed.js です。今回はCDNのファイルを参照します。 

まず、数字の1のブロックを表示してみましょう。 

以下の内容で、htmlファイルを作成します。 

<meta charset=”UTF-8″> 

<title>たしざん</title> 

<script src=”https://cdn.jsdelivr.net/npm/blockly@3.20191014.3/blockly.min.js”></script> 

<div id=”canvas”></div> 

<xml xmlns=”https://developers.google.com/blockly/xml” id=”toolbox” style=”display: none”> 

    <block type=”digit1″></block> 

</xml> 

<script> 

    Blockly.Blocks.digit1 = { 

        init: function (block) { 

            this.jsonInit({ 

                “type”: “digit1”, 

                “message0”: “1”, 

                “output”: “Number”, 

                “colour”: 230, 

                “tooltip”: “”, 

                “helpUrl”: “” 

            }) 

        } 

    } 

    var workspace = Blockly.inject(‘canvas’, { 

        toolbox: document.getElementById(‘toolbox’), 

        zoom: { startScale: 1.5 } 

    }) 

</script> 

作成したHTMLをブラウザで開くと、下記のように表示されます。 

 灰色部分(ツールボックスといいます)のブロックを右側にドラッグすることでブロックを並べることができます。 

 Blockly.Blocksにブロックを定義して、xmlタグ内に定義したブロックをblockタグで並べるとでツールボックに表示される仕組みです。 

 ブロックのプロパティは次のとおりです。 

プロパティ 説明 
type ブロックの種類ごとの名前で重複しないように
自由に設定できる 
message0 ブロックに表示する内容 
output ブロックから出力される値の型 
colour ブロックの色0〜360で指定
(HSV色空間の色相を指定) 
tooltip ブロックにカーソルを合わせた際に
表示される説明 
helpUrl ブロックを右クリックしてHelpを選ぶと表示される
説明ページのURL 

ブロックの大きさは Blockly.inject の第2引数で zoom.startScale で指定できます。 

次に、同様にして、9までのブロックを追加します。 

カラフルにしてみました。 

次は足し算をするブロックを追加します。 

    Blockly.Blocks.addition = { 

        init: function (block) { 

            this.jsonInit({ 

                “type”: “addition”, 

                “message0”: “%1 たす %2”, 

                “args0”: [ 

                    { 

                        “type”: “input_value”, 

                        “name”: “left_value”, 

                        “check”: “Number” 

                    }, 

                    { 

                        “type”: “input_value”, 

                        “name”: “right_value”, 

                        “check”: “Number” 

                    } 

                ], 

                “inputsInline”: true, 

                “output”: “Number”, 

                “colour”: 0, 

                “tooltip”: “2つのすうじをたします”, 

                “helpUrl”: “” 

            }) 

        } 

    } 

 足し算をするには足す数と足される数の2つをセットしなければなりません。 

 そのために、arg0というプロパティを用意して、2つの値を受け取る枠を定義します。これらを入力といいます。各入力のプロパティには type, name, checkがあります。 

プロパティ 設定できる値  説明 
type  input_value  1つの値の枠を作る 
input_statement  複数のつなげたブロック用の枠を作る 
input_dummy  枠は作らず文字のみ表示するときに使う 
name  ブロック内で固有の名前を自由に設定できる 
check  受け付ける値の方を指定(省略可)

また、message0 を 「%1 たす %2 」としていますが、%1には1つ目の入力枠が設定され、%2には2つ目の入力枠が設定されます。 

最後に結果を表示するブロックを追加します。 

これで、足し算のプログラムをブロックで組めるようになりました。 

あとは実行できるようにします。 

実行するには、ブロックで作ったプログラムを実行可能なプログラムのソースコード(JavaScript等)に変換してから実行する形になります。 

ただ、そうするためには、それぞれのブロックがどのようなソースコードに変換されるかを定義する必要があります。 

たとえば1のブロックの定義は次のようになります。 

            Blockly.JavaScript.digit1 = function(block) { 

                return [ ‘1’, Blockly.JavaScript.ORDER_NONE ] 

            } 

全ブロックに対して、JavaScriptに変換する定義をつけ、実行ボタンと押したときの処理を作れば完成です。 

じっこう(id=run)を押したときの処理は次のように書きます。 

    document.getElementById(‘run’).addEventListener(‘click’, function() { 

        try { 

            eval(Blockly.JavaScript.workspaceToCode(workspace)) 

        } catch(e) { 

            alert(e) 

        } 

    }) 

Blockly.JavaScript.workspaceToCode でブロックの内容をJavaScriptのプログラムに変換することができます。 

Blocklyの仕組みを使えば、任意の処理を行うブロックを作って、任意のプログラミング言語に変換、実行することが可能です。 

最後に全ソースコードを載せておきます。(addition.html) 

<meta charset=”UTF-8″> 

<title>たしざん</title> 

<script src=”https://cdn.jsdelivr.net/npm/blockly@3.20191014.3/blockly.min.js”></script> 

<div id=”canvas”></div> 

<xml xmlns=”https://developers.google.com/blockly/xml” id=”toolbox” style=”display: none”> 

    <block type=”addition”></block> 

    <block type=”display”></block> 

    <block type=”digit1″></block> 

    <block type=”digit2″></block> 

    <block type=”digit3″></block> 

    <block type=”digit4″></block> 

    <block type=”digit5″></block> 

    <block type=”digit6″></block> 

    <block type=”digit7″></block> 

    <block type=”digit8″></block> 

    <block type=”digit9″></block> 

</xml> 

<button id=”run” type=”button” style=”font-size:20pt; border-radius:1em; position:fixed; bottom: 1em; right: 1em”>じっこう</button> 

<div id=”dialog” style=”position:fixed;top:0;left:0;right:0;bottom:0;opacity:0.8;background-color:white;transition-duration:1s;color:black;font-size:20pt;text-align:center;padding-top:4em;z-index:9999999;display:none”></div> 

<script> 

    for (var i = 1; i < 10; i++) { 

        (function (j) { 

            Blockly.Blocks[‘digit’ + j] = { 

                init: function (block) { 

                    this.jsonInit({ 

                        “type”: “digit” + j, 

                        “message0”: j.toString(), 

                        “output”: “Number”, 

                        “colour”: j * 40, 

                        “tooltip”: “”, 

                        “helpUrl”: “” 

                    }) 

                } 

            } 

            Blockly.JavaScript[‘digit’ + j] = function(block) { 

                return [ j.toString(), Blockly.JavaScript.ORDER_NONE ] 

            } 

        })(i) 

    } 

    Blockly.Blocks.addition = { 

        init: function (block) { 

            this.jsonInit({ 

                “type”: “addition”, 

                “message0”: “%1 たす %2”, 

                “args0”: [ 

                    { 

                        “type”: “input_value”, 

                        “name”: “left_value”, 

                        “check”: “Number” 

                    }, 

                    { 

                        “type”: “input_value”, 

                        “name”: “right_value”, 

                        “check”: “Number” 

                    } 

                ], 

                “inputsInline”: true, 

                “output”: “Number”, 

                “colour”: 0, 

                “tooltip”: “2つのすうじをたします”, 

                “helpUrl”: “” 

            }) 

        } 

    } 

    Blockly.JavaScript.addition = function(block) { 

        var left_value = Blockly.JavaScript.valueToCode(block, ‘left_value’, Blockly.JavaScript.ORDER_NONE) || 0 

        var right_value = Blockly.JavaScript.valueToCode(block, ‘right_value’, Blockly.JavaScript.ORDER_NONE) || 0 

        return [ left_value + ‘ + ‘ + right_value, Blockly.JavaScript.ORDER_NONE ] 

    } 

    Blockly.Blocks.display = { 

        init: function (block) { 

            this.jsonInit({ 

                “type”: “display”, 

                “message0”: “%1 のけいさんけっか”, 

                “args0”: [ 

                    { 

                        “type”: “input_value”, 

                        “name”: “value” 

                    } 

                ], 

                “colour”: 230, 

                “tooltip”: “”, 

                “helpUrl”: “” 

            }) 

        } 

    } 

    Blockly.JavaScript.display = function(block) { 

        var value = Blockly.JavaScript.valueToCode(block, ‘value’, Blockly.JavaScript.ORDER_NONE) || 0 

        return “var e = document.getElementById(‘dialog’);e.textContent = ‘けいさんけっかは ‘ + (” + value + “) + ‘ です!’;e.style.display = ”” 

    } 

    var workspace = Blockly.inject(‘canvas’, { 

        toolbox: document.getElementById(‘toolbox’), 

        zoom: { startScale: 1.5 } 

    }) 

    document.getElementById(‘run’).addEventListener(‘click’, function() { 

        try { 

            eval(Blockly.JavaScript.workspaceToCode(workspace)) 

        } catch(e) { 

            alert(e) 

        } 

    }) 

    document.getElementById(‘dialog’).addEventListener(‘click’, function(e) { 

        e.target.style.display = ‘none’ 

    }) 

</script> 

EYSではシステム開発だけではなく、プログラミング教育のオリジナル教材を作成しています。興味のある方はぜひご連絡ください。 

中澤謙一
中澤 謙一
 大学に入りプログラミングに没頭、MS-DOSというOSの存在を知るところから始めてC言語の標準ライブラリを自前実装しながら言語を学習。  インターネットはまだアナログ回線が主流だった頃、大学の研究室の専用線を使ってFreeBSDのサーバを立てC++Builderに関するホームページを公開してニューラルネットワークや遺伝的アルゴリズムのプログラムを公開していた。  JavaのServletが使われだした頃、オンラインでコンパイル実行できるプログラミング学習サイトを作ったことをきっかけにプログラミング教育に興味を持つ。  その後SI系の仕事を10年ほどしていたが、本当にやりたいことを中心に仕事をしたいと一念発起し、単身で兵庫から上京して現在に至る。

Share

facebook twitter