2024年12月18日水曜日

LottieのアニメーションをOracle APEXのアプリケーションに表示する

LottieのアニメーションをOracle APEXのアプリケーションに表示してみます。以下の4種類の実装をアプリケーションに組み込みます。

  • JSONデータを扱うlottie-webを使う
  • バイナリ形式のdotLottieも扱えるdotlottie-webを使う
  • カスタム要素のlottie-playerを使う
  • lottie-playerに加えてlottie-interactivityも使う
これらを実装したAPEXアプリケーションは以下のように動作します。


表示に使用しているLottieのアニメーションは、LottieFilesのStarter Planをサブスクライブして作成しました。

アニメーションのダウンロード形式としてdotLottieおよびLottie JSONを選んで、それぞれMyFirstLottie.lottieMyFirstLottie.jsonという名前でファイルを作成しています。Optimized形式でダウンロードするためには、有料プランのサブスクライブが必要なようです。


以下より、作成したAPEXアプリケーションについて説明します。

空のAPEXアプリケーションから実装を始めます。アプリケーションの名前Play Lottieとしています。

共有コンポーネント静的アプリケーション・ファイルに、Lottieのアニメーション・ファイルをアップロードします。dotLottieとJSON形式のファイルを、それぞれMyFirstLottie.lottieMyFirstLottie.jsonとしてアップロードします。


今回はセッション・オーバーライドを使ってJavaScriptの開発を行います。すべての静的アプリケーション・ファイルチェックを入れ(スクリーンショットには開発したJavaScriptのファイルも表示されています)、Zipとしてダウンロードをクリックします。


チェックした静的アプリケーション・ファイルを含むZIPファイルが、f<アプリケーションID>_static_application_files.zipというファイル名でダウンロードされます。

このファイルを適当なディレクトリに展開し、そのディレクトリを開発ツールで開きます。以下はVS Codeの使用を想定しています。今回の作業では、Lottieというディレクトリに静的アプリケーション・ファイルを展開しました。

セッション・オーバーライドを使った開発を行うために、VS CodeにはLive Serverの拡張を導入しておきます。


Lottie直下にLive Serverの起動に使用するファイルとしてindex.htmlを作成します。

このファイル自体はアプリケーションに組み込まないので、HTMLであれば内容は何でも構いません。

<html><body>Live Server Started.</body></html>

index.html上でコンテキスト・メニューを開きLive Serverを開始します。


ブラウザがhttp://localhost:5500/index.htmlとして、作成したindex.htmlを開きます。


APEXアプリケーションの開発者ツール・バーセッションより、セッション・オーバーライドを開きます。

セッション・オーバーライドの有効化オンファイルパスアプリケーション・ファイルhttp://localhost:5500/を設定します。

以上でJavaScriptの開発準備ができました。これ以降、実行中のAPEXアプリケーションはデータベースに保存されている静的アプリケーション・ファイルの代わりに、ローカルのファイル・システム上のファイルを参照します。


最初にlottie-webを実装します。ページ番号として空白ページを作成します。画面上のコンポーネントは以下のように配置します。


ページ・プロパティHTMLヘッダーimportmapを設定します。
<script type="importmap">
{
    "imports": {
        "lottie-web": "https://esm.sh/lottie-web"
    }
}
JavaScriptファイルURLとして以下を記述します。

[module, defer]#APP_FILES#js/app-lottie#MIN#.js

JavaScriptのコードをページに埋め込むことはせず、すべてファイルに記述します。ファイル名はapp-lottie#MIN#.jsとして置換文字列#MIN#を含めています。アプリケーションのデバッグ・モードが有効のときは#MIN#空白となり、app-lottie.jsが参照されます。デバッグ・モードが無効の時は#MIN#.minに置き換わりapp-lottie.min.jsとしてミニファイされたファイルが参照されます。ローカルにあるファイルapp-lottie.jsにコードを記述しているときに、内容を変更するたびにミニファイはしないと思うので、セッション・オーバーライドを使ってアプリケーションを開発しているときは、つねにデバッグ・モードにしておきます。そうしないと、app-lottie.jsの記述を変更したのに(app-lottie.min.jsが参照されているため)修正が反映されない、または、そもそもミニファイされたファイルapp-lottie.min.jsが存在しないため、JavaScriptのコードがロードされないこともあり得ます。


ボタンをまとめる静的コンテンツのリージョンを作成します。このリージョンにボタンをクリックしたときに呼び出すapex.actionを紐づけるため、静的IDとしてlottie-controlsを設定します。apex.actionはファイルapp-lottie.jsに記述します。


ボタンPLAYPAUSESTOPを作成します。動作アクション動的アクションで定義を選択します。動的アクションは作成せず、その代わりに詳細カスタム属性としてdata-action=を設定します。data-action=には、それぞれのボタンに合わせて"PLAY""PAUSE""STOP"を与えます。ボタンをクリックすると、data-actionに与えた名前のapex.actionが実行されます。


lottie-webで発生したイベントの情報を表示するページ・アイテムとしてP2_EVENTを作成します。


Lottieのアニメーションを表示する要素を記述します。

静的コンテンツのリージョンを作成し、ソースHTMLコードとして以下を記述します。

<div id="lottie-container" style="width: 600px; height: 600px;"><div>

余計な装飾を省くため、外観テンプレートBlank with Attributes (No Grid)を選択します。


ページ上のコンポーネントの配置と設定は以上で完了です。

VS Codeでフォルダjsを作成し、その下にファイルapp-lottie.jsを作成します。ファイルの内容は以下になります。

/*
* lottie-webの実装
* Ref: https://airbnb.io/lottie/#/web
*/
import lottie from 'lottie-web';
apex.debug.info('app-lottie.js is loaded.');
/* 発生したイベントを表示するページ・アイテム */
const eventItem = apex.item("P2_EVENT");
/* アニメーションを表示する要素 */
const lottieContainer = document.getElementById('lottie-container');
/* アニメーションのデータ */
const lottieFile = apex.env.APP_FILES + 'MyFirstLottie.json';
apex.debug.info(lottieFile);
/* アニメーションの表示を開始 */
const animation = lottie.loadAnimation({
container: lottieContainer,
renderer: 'svg',
loop: true,
autoplay: true,
path: lottieFile,
name: 'myFirstLottie'
});
/*
* メソッドの一部をボタンに割り付ける。
*/
const controlElm = document.getElementById('lottie-controls');
const controls = apex.actions.createContext('controls', controlElm);
controls.add([
{
name: "PLAY",
action: (event, element, args) => {
animation.play();
}
},
{
name: "PAUSE",
action: (event, element, args) => {
animation.pause();
}
},
{
name: "STOP",
action: (event, element, args) => {
animation.stop();
}
}
]);
/* 発生するイベントの一部を確認 */
/* loop = true */
animation.addEventListener('loopComplete', (event) => {
eventItem.setValue(JSON.stringify(event));
});
/* loop <> true */
animation.addEventListener('complete', (event) => {
eventItem.setValue(JSON.stringify(event));
});
view raw app-lottie.js hosted with ❤ by GitHub


lottie-webを使った実装は以上で完了です。

続いてページ番号3にdotlottie-webを使った実装を行います。ページ上に配置するコンポーネントはlottie-webのときと同じです。

dotlottie-webを参照するため、ページ・プロパティHTMLヘッダーimportmapを記述します。
<script type="importmap">
    {
        "imports": {
            "@lottiefiles/dotlottie-web": "https://esm.sh/@lottiefiles/dotlottie-web"
        }
    }
</script>
JavaScriptファイルURLに以下を記述します。dotlottie-webを使った実装はファイルapp-dotlottie.jsに記述します。

[module,defer]#APP_FILES#js/app-dotlottie#MIN#.js


dotlottie-webでは、アニメーションを表示する要素はキャンバスになります。静的コンテンツソースHTMLコードの記述を以下に変えます。

<canvas id="lottie-canvas" style="width: 600px; height: 600px;"></canvas>


dotlottie-webを使ってLottieのアニメーションを描画するコードは以下になります。ファイルjs/app-dotlottie.jsとして作成します。

/*
* dotLottie-webの実装
* https://developers.lottiefiles.com/docs/dotlottie-player/dotlottie-web/
*/
import { DotLottie } from '@lottiefiles/dotlottie-web';
apex.debug.info('app-dotlottie.js is loaded.');
/* 発生したイベントを表示するページ・アイテム */
const eventItem = apex.item("P3_EVENT");
/* アニメーションを表示する要素 */
const lottieCanvas = document.getElementById('lottie-canvas');
/* アニメーションのデータ */
const lottieFile = apex.env.APP_FILES + 'MyFirstLottie.lottie';
/* アニメーションの表示を開始 */
const animation = new DotLottie({
canvas: lottieCanvas,
loop: true,
autoplay: true,
src: lottieFile
});
/*
* メソッドの一部をボタンに割り付ける。
* https://developers.lottiefiles.com/docs/dotlottie-player/dotlottie-web/methods/
*/
const controlElm = document.getElementById('lottie-controls');
const controls = apex.actions.createContext('controls', controlElm);
controls.add([
{
name: "PLAY",
action: (event, element, args) => {
animation.play();
}
},
{
name: "PAUSE",
action: (event, element, args) => {
animation.pause();
}
},
{
name: "STOP",
action: (event, element, args) => {
animation.stop();
}
}
]);
/*
* 発生するイベントの一部を確認
* https://developers.lottiefiles.com/docs/dotlottie-player/dotlottie-web/events/
*/
animation.addEventListener('loop', (event) => {
eventItem.setValue(JSON.stringify(event));
});
animation.addEventListener('stop', (event) => {
eventItem.setValue(JSON.stringify(event));
});


dotlottie-webを使った実装は以上で完了です。

ページ番号にカスタム要素lottie-playerを使った実装を行います。とても簡単です。

ページ・プロパティJavaScriptファイルURLに以下を記述します。

https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js


静的コンテンツソースHTMLコードに以下を記述します。アプリケーション・アイテムとしてAPEX_PATHを作成し、APEX_UTIL.HOST_URL('APEX_PATH')の結果が設定されるようにアプリケーションの計算を設定しておきます。この手順については、こちらの記事に含まれています。

セッション・オーバーライドが有効のときは&APEX_PATH.#APP_FILES#が無効なURLに置き換わります。そのため、セッション・オーバーライドオフにして動作確認をします。
<lottie-player
    id="firstLottie"
    src="&APEX_PATH.#APP_FILES#MyFirstLottie.json"
    style="width: 600px; height: 600px;"
    loop
    autoplay
    controls
></lottie-player>

以上でカスタム要素lottie-playerを使った実装は完了です。

最後にページ番号lottie-interactivityを使った実装を行います。

ページ・プロパティJavaScriptファイルURLに以下を記述します。

https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js
https://unpkg.com/@lottiefiles/lottie-interactivity@latest/dist/lottie-interactivity.min.js

静的コンテンツソースHTMLコードに、4つのlottie-playerを配置するコードを記述します。画面の上下スクロールに合わせて、それぞれのアニメーションの動作を変更します。

<lottie-player
id="firstLottie"
src="&APEX_PATH.#APP_FILES#MyFirstLottie.json"
style="width:400px; height: 400px;"
></lottie-player>
<div id="MyContainerId">
<lottie-player
id="secondLottie"
src="&APEX_PATH.#APP_FILES#MyFirstLottie.json"
style="width:400px; height: 400px;"
></lottie-player>
</div>
<lottie-player
id="thirdLottie"
src="&APEX_PATH.#APP_FILES#MyFirstLottie.json"
style="width:400px; height: 400px;"
></lottie-player>
<lottie-player
id="fourthLottie"
src="&APEX_PATH.#APP_FILES#MyFirstLottie.json"
style="width:400px; height: 400px;"
></lottie-player>


ページ・プロパティJavaScriptページ・ロード時に実行に、以下を記述します。画面のスクロールに合わせて変更する動作を、それぞれのlottie-playerに対して設定しています。

LottieInteractivity.create({
mode: 'scroll',
player: '#firstLottie',
actions: [
{
visibility: [0, 1],
type: 'seek',
frames: [0, 100],
},
],
});
LottieInteractivity.create({
player: "#secondLottie",
mode: "scroll",
container: "#MyContainerId",
actions: [
{
visibility: [0, 1.0],
type: 'seek',
frames: [90, 123],
},
]
});
LottieInteractivity.create({
player: '#thirdLottie',
mode: 'scroll',
actions: [
{
visibility: [0, 0.3],
type: "stop",
frames: [50]
},
{
visibility: [0.3, 1.0],
type: "seek",
frames: [50, 240]
}
]
});
LottieInteractivity.create({
player: "#fourthLottie",
mode: "scroll",
actions: [
{
visibility: [0, 0.2],
type: "stop",
frames: [0]
},
{
visibility: [0.2, 0.45],
type: "seek",
frames: [0, 45]
},
{
visibility: [0.45, 1.0],
type: "loop",
frames: [45, 60]
}
]
});

以上でlottie-interactivityを使った実装も完了です。

ローカルのファイル・システムにあるapp-lottie.jsおよびapp-dotlottie.jsは、共有コンポーネント静的アプリケーション・ファイルとしてアップロードします。アップロードしたJavaScriiptファイルをスクリプト・エディタで開いて保存すると、自動的にミニファイされたファイルが作成されます。


今回の記事は以上になります。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/play-lottie.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。