プログラミング教室の教材を作るために Scratch ブロックの画像が欲しかったんですが、いちいちスクリーンショットを撮るのも面倒だし、ラスタ画像ファイルだと解像度の問題で取り回しが不便なので、ベクタ画像出力かつ更新が簡単な方法を探していたらドンピシャのライブラリがありました。
ScratchのWikiやフォーラムでも使われている blob8108 氏作の Block Plugin(scratchblocks)です。このライブラリはブラウザ上で動作するブロック画像ジェネレータとしても公開されていますが、Webページに組み込めば Scratchスクリプトからブロック画像を生成してHTMLにSVGとして埋め込むことができます。
教材の製本も視野に入れると、画像編集ツールを介さずにHTMLで完結できればCSS組版とも相性が良さそうです。
使い方
ライブラリのインクルード
現在の最新バージョンはver3.1なので、以下のJSファイルをインクルードします。
<script src="https://scratchblocks.github.io/js/scratchblocks-v3.1-min.js"></script>
ブロック表記を英語以外(今回は日本語)にするためにはさらに以下の翻訳データをインクルードします。
<script src="https://scratchblocks.github.io/js/translations-v3.1-min.js"></script>
描画
実際に描画してみたサンプルを GitHub Pages で公開しておきました。
https://ag-k.github.io/scratchblocks-html-sample-ja/
サンプルコード全体は以下で参照できます。
https://github.com/ag-k/scratchblocks-html-sample-ja/blob/master/index.html
以下は各描画方法の説明です。
ベーシックな描画方法
HTMLの要素としてScratchスクリプトを記述しておき、scratchblocks.renderMatching() で指定したセレクタに該当する要素をまとめて描画します。
指定するセレクタは自由ですが、preタグだとそのままスクリプトが書けるので便利です。
<pre id="blocks1" class="blocks">
@greenFlag がクリックされたとき
x座標を (0) 、y座標を (0) にする
ずっと
(10)回繰り返す
@turnright (10) 度回す
(5) 歩動かす
end
次のコスチュームにする
end
</pre>
<pre id="blocks2" class="blocks">
このスプライトがクリックされたとき
もし <(向き) = [90]> なら
ペンを下ろす
でなければ
ペンを上げる
end
</pre>
scratchblocks.renderMatching('pre.blocks', {
languages: ['ja', 'en'],
render: function(doc, cb) {
doc.render(function(svg) {
var el = document.createElement('div');
el.appendChild(svg);
cb(el);
});
},
});
インラインで描画
scratchblocks.renderMatching() の第2引数 option に inline: true を指定するとインラインでブロックを描画できます。
scratchblocks.renderMatching() の第2引数 option に inline: true を指定すると、<code class=b>スタンプ</code>のようにインラインでブロックを描画できます。
scratchblocks.renderMatching("code.b", {
languages: ['ja', 'en'],
inline: true
});
サイズを拡大して描画
今のところブロックが描画サイズは固定になっているようですが、大きくして使いたい場面があったので、描画結果のサイズを変更する方法を考えました。ブロックはSVG形式で描画されるので、Document.render() から取得できるSVG要素を拡大してやれば良さそうなのですが、scratchblocks.renderMatching() に渡した場合、SVG要素のサイズが取得できませんでした(clientWidth, clientHeight, viewBox が0)。
一方、Document.render() を単体で使う場合は SVG要素のサイズが取得できたので、scratchblocks.parse() でスクリプトをパースしたオブジェクトを Document.render() でレンダリングし、結果のSVG要素を指定されたスケールに拡大するようにしました。
<code id="big_blocks">
@greenFlag がクリックされたとき
x座標を (0) 、y座標を (0) にする
ずっと
(10)回繰り返す
@turnright (10) 度回す
(5) 歩動かす
end
次のコスチュームにする
end
</code>
<code id="middle_blocks">
@greenFlag がクリックされたとき
x座標を (0) 、y座標を (0) にする
ずっと
(10)回繰り返す
@turnright (10) 度回す
(5) 歩動かす
end
次のコスチュームにする
end
</code>
<code id="small_blocks">
@greenFlag がクリックされたとき
x座標を (0) 、y座標を (0) にする
ずっと
(10)回繰り返す
@turnright (10) 度回す
(5) 歩動かす
end
次のコスチュームにする
end
</code>
var renderScaledBlocks = function(target, scale) {
var doc = scratchblocks.parse(target.innerHTML, {
languages: ['ja', 'en'],
});
doc.render(function(svg) {
target.innerHTML = "";
target.appendChild(svg);
svg.setAttribute("width", svg.clientWidth * scale);
svg.setAttribute("height", svg.clientHeight * scale);
svg.setAttribute("viewBox", "0 0 " + svg.clientWidth / scale + " " + svg.clientHeight / scale );
});
};
var titleBlocks = document.getElementById('big_blocks');
renderScaledBlocks(titleBlocks, 2.0);
var middleBlocks = document.getElementById('middle_blocks');
renderScaledBlocks(middleBlocks, 1.5);
var smallBlocks = document.getElementById('small_blocks');
renderScaledBlocks(smallBlocks, 1.0);
SVGの拡大方法については以下の記事を参照しました。
ASCII.jp:HTML5のInline SVGをJavaScriptで操作 (2/5)|古籏一浩のJavaScriptラボ
[SVG] viewBoxについての考察
つまづきどころ
おすすめ作業フロー
HTMLでスクリプト手書きは結構面倒なので、Scratch プロジェクトのブロックからscratchblockのスクリプトを生成するジェネレータを活用するとラクです。以下の手順で作業するのが良さそうです。
- Scratchでプロジェクトを作成
- ブロックを組んで動作確認
- generator :: scratchblocks でScratchプロジェクトをscratchblockスクリプトに変換
- scratchblockスクリプトをHTMLに貼り付け