VexFlow 描画エリアと5線譜と小節

提供:yonewiki
2023年2月3日 (金) 00:18時点におけるYo-net (トーク | 投稿記録)による版 (→‎五線譜)

VexFlow 使い方に戻る。

概要

 タイトルを5線譜にしようかと思ったのだけれど、その根本にある描画エリアを説明しなければならないのだけど、描画エリアだけを説明するのも内容が少なすぎる。そして、5線譜を繋ぐだけの小節についても説明した方が手っ取り早いと思ったのです。なので「部屋とYシャツと私」みたいなタイトルにしました。その前にコードの書き方を説明しておきます。

 

コードの書き方

 WebSiteに複数の楽譜を掲載することもあると思いますが、VexFlowはコードの中にHTMLタグの任意で指定したIDが付与されているタグに対して、楽譜へ置き換えるように動作します。


 つまり、id="VefFlow"を標的とすると置き換えられるのは、

<div id="VexFlow"></div>

 のようなHTMLです。これで置き換えられる部分がわかったと思います。次はコード側の標的の設定の仕方を紹介しなければなりませんが、また少しあとで、紹介します。


 複数の楽譜を描画する場合は、上記のような異なるIDを持つタグを作成します。コード側では、複数の楽譜で似たような変数を使いますが、重複していたら相互に影響しあってしまいます。そこで、楽譜ごとに関数にすることで変数を隠蔽することができます。ひとつのWebPageでJavaScriptの変数が影響し合うことはないです。そこで便利なのが、以下のような即時実行関数です。

(function(){
  //ここにコード
})();

 ここにコードと書いてある部分に一つの楽譜についてのコードを記述します。JavaScriptがわかっていないと、こういったアイデアが生まれにくいので、VexFlowを操るのは大変だと思います。自分も初心者程度の知識しかありませんので、少なくとも自分と同じくらいまで学習された方がよろしいでしょう。


 この先の説明では即時実行関数の中に記述するということを説明することは、ほとんど無いと思います。以後お見知りおきを。


HTMLタグの置き換えと描画エリア

 先に説明したようなHTMLのタグを置き換える指定と、描画エリアの指定は以下のように行います。

const f = new Factory({ renderer: { elementId: 'VexFlow', width: 1900, height: 195 } });


動作 Keyword 指定値の例
置き換えするタグのID名 elementId 'VexFlow'


 上記の elementId: の後ろの ' ' シングルクォーテーションで囲われた文字列が置き換え対象のタグID名です。同じIDを持つタグが複数あるとおかしくなるので唯一である必要があります。使われなさそうなID名になるような癖をつけておいた方がよいでしょう。例えば、例では VexFlow ですが、yonet202301_Output00 とかドメイン名+年月+'Output'+通し番号とかね。


動作 Keyword 指定値の例
描画エリア横幅 width 1900
描画エリア高さ幅 height 195


 この命令のように new を使ってオブジェクトを生成する手法を使う場合、VexFlow独自のオブジェクト名である場合は、個別にオブジェクトを使うことを宣言する必要があります。Factoryの場合は


const {
  Factory,
} = Vex.Flow;


 のように宣言します。


 ここまでの説明をまとめたプログラムコードは以下のようになります。まだ何も起こらないコードです。

<script src="https://cdn.jsdelivr.net/npm/vexflow@4.1.0/build/cjs/vexflow.js"></script>//1pageで一度だけ記述する行
<div id="VexFlow"></div>
<script>
(function(){
  const {
    Factory,
  } = Vex.Flow;

  const f = new Factory({ renderer: { elementId: 'VexFlow', width: 1900, height: 195 } });
})();
</script>

 何もおこらないので、上記のコードは実行しないで下さい。時間の無駄です。

 

五線譜

 上記で土台は出来上がっていることになりますので、少しコードを追加すると五線譜が描けます。


<div id="yonet202301_Output01"></div>
<script>
(function(){
  const {
    Factory,
    Stave,
  } = Vex.Flow;

  const f = new Factory({ renderer: { elementId: 'yonet202301_Output01', width: 1000, height: 195 } });
  const ctx = f.getContext();
  const stave1 = new Stave(10, 50, 400).setContext(ctx).draw();
})();
</script>

 Stave オブジェクトを利用しますので、4行目の宣言のところに Stave を追加しました。そして、10,11行目を追加しています。最初に作ったFactoryのオブジェクトの格納変数 f のメンバ関数 f.getContext() で描画デバイスコンテキストを取得できます。このコンテキストは先に準備した描画エリアと、これから準備する描画パーツを結び付ける役割を持つ、筆のようなものです。筆を通じて描画の信号が伝わるイメージです。ctx は、デバイスコンテキスト変数と呼んだりすることになります。


 ctxを引数にとるメンバ関数を利用しつつ、Stave オブジェクトを生成しています。その生成時の引数が(10, 50, 400)という謎な数値です。引数の意味ですが、


  • 第一引数:横方向の余白px値 10px
  • 第二引数:縦方向の余白px値 50px
  • 第三引数:5線譜の横幅px値 400px


 という意味です。オブジェクトに同一のオブジェクトが返却される関数になっているので、続けて、ドットを使ってメンバ関数を指定できます。但し順番には意味があります。手前から順番に設定する必要がある場合があります。その意味で .setContext(ctx).draw() という関数が指定されています。前もって作った ctx のデバイスコンテキスト変数を引数にとって描画処理を指示したことになります。

 

小節

 小節は5線譜を2回描くだけです。


<div id="yonet202301_Output02"></div>
<script>
(function(){
  const {
    Factory,
    Stave,
  } = Vex.Flow;

  const f = new Factory({ renderer: { elementId: 'yonet202301_Output02', width: 1000, height: 195 } });
  const ctx = f.getContext();
  const stave1 = new Stave(10, 50, 400).setContext(ctx).draw();
  const stave2 = new Stave(410, 50, 400).setContext(ctx).draw();
})();
</script>

 

 

VexFlow 使い方に戻る。