SVGアニメーションページ
テンプレートアプリのMain.razorでは、さらに、サイドメニューを持つレイアウトのページが定義されています。今回は、 新規ページを作成して、メニューから表示するようにします。
作成するページは、SVG画像を使った時計のようにアニメーションするページです。
新規ページ
プロジェクトのPagesフォルダに、Razorコンポーネントとして、Svg.razorファイルを新規作成します。
Svg.razorのコードは、次のようにしました。
@page "/svg" @implements IDisposable <svg width="400" height="260"> <circle cx="150" cy="150" r="100" stroke="yellow" stroke-width="3" fill-opacity="0" /> <line x1="150" y1="150" x2=@cx y2=@cy stroke="black" /> <circle cx=@cx cy=@cy r="10" stroke-width="0" fill="red" /> </svg> @code { // 円周の座標 private int cx = 0; private int cy = 0; // 角度 private int angle = -90; private Timer aTimer; // 0秒後、1秒毎にCallbackが実行される(1) protected override void OnInitialized() => aTimer = new Timer(Callback, null, 0, 1000); // 座標の更新(2) private void Callback(Object _) { cx = (int)(Math.Cos(angle * Math.PI / 180f) * 100f) + 150; cy = (int)(Math.Sin(angle * Math.PI / 180f) * 100f) + 150; angle += 6; InvokeAsync(StateHasChanged); } public void Dispose() => aTimer.Dispose(); // timerオブジェクトの破棄 }
SVG要素
<svg>から始まる要素が、SVG要素となります。SVG(Scalable Vector Graphics)は、ベクターイメージ用の画像形式の1つで、XMLベースで記述します。モダンブラウザであれば、SVGの描画をサポートしていて、HTML要素として記述するだけで、画像を描画することができます。今回は、赤と黄の円画像<circle>と、黒の直線<line>を記述しています。SVG要素の属性についての詳細は、参考文献で確認してください。
タイマー処理
今回は、1秒毎に円画像と直線の座標を計算して描画しています。1秒毎の処理には、Timerクラス(System.Threading.Timer)を用いました。.NETで提供されるTimerクラスはいくつかありますが、ここでは、System.Threading.Timerクラスを選択しました。
System.Threading.Timerクラスでは、コンストラクタで、呼び出されるメソッドとそのメソッドに渡すパラメータ、それと最初の実行までの時間と、実行される周期を指定します。先ほどのSvg.razorでは、Callbackメソッドを0秒後と1秒間隔で呼び出されるようにしています(1)。時間の単位は、ミリ秒です。
円周に表示する赤い円画像の座標は、三角関数から求めます。また、1秒ごとに中心と円画像の座標との角度を6°加算し、1分で1周(360°)するようにしました(2)。
なお、IDisposableインターフェイスを実装して(@implements IDisposable)、ページが破棄される際に、Disposeメソッドでtimerオブジェクトのリソースを破棄するようにしています。
メニュー追加
メニューに、先ほど作成したページを表示する項目を追加します。
~略~ <nav class="flex-column"> ~略~ <div class="nav-item px-3"> <NavLink class="nav-link" href="svg"> <span class="oi oi-list-rich" aria-hidden="true"></span> SVGの描画 </NavLink> </div> </nav> ~略~
これで、以下のようにメニューに追加されます。
開始、停止ボタン
メニューの「SVGページの描画」を選ぶと、アニメーションがすぐに開始されたはずです。これを少し変更して、ボタンのクリックで、開始/停止するようにしてみましょう。
まず、HTML部分に、次のような開始と停止ボタンを追加します。
~略~ <button class="btn btn-primary" @onclick="OnStart">開始</button> <button class="btn btn-primary" @onclick="OnStop">停止</button> ~略~
button要素の@onclick属性で、ボタンクリック時に実行されるメソッドを定義しています。ここでは、開始ボタンでOnStart、停止ボタンでOnStopメソッドが呼び出されます。この2つのメソッドの定義は、次のようになります。
~略~ @code { // 0秒後のみCallbackが実行される(3) protected override void OnInitialized() => aTimer = new Timer(Callback, null, 0, Timeout.Infinite); ~略~ // 0秒後、1秒毎にCallbackが実行される private void OnStart() => aTimer.Change(0, 1000); // Callbackが実行されない private void OnStop() => aTimer.Change(Timeout.Infinite, Timeout.Infinite); }
TimerクラスのChangeメソッドは、タイマーの開始されるまでの時刻と、メソッドの呼び出し周期を変更することができます。パラメータにTimeout.Infiniteを設定すると、メソッドがまったく呼び出されなくなり、アニメーションが停止します。
なお、ページの初期化時にタイマーが開始されないように、Timerオブジェクトのコンストラクタの周期のパラメータを変更します(3)。
最後に
.NET MAUI Blazorでは、BlazorWebViewコントロールを用いて、Razorコンポーネントをレンダリングしています。Webサーバやブラウザを介することなく、直接.NETコンポーネントが利用できます。
(MAUIではない)Blazorアプリケーションでは、PWA(Progressive Web Apps)と呼ばれる、Webアプリをネイティブアプリのようにインストールできる技術に対応していますが、.NET MAUI Blazorでは、Web技術を活用したネイティブアプリの開発が可能です。