2024年12月16日月曜日

Oracle APEXのアプリケーションにKepler.glを組み込む

Oracle APEXのアプリケーションにKepler.glを組み込んでみます。Kepler.glは、Uberが開発したオープンソースの位置情報データ可視化ツールです。

Kepler.glはReactのコンポーネントとして開発されていますが、GitHubのリポジトリのexamplesumd-clientの実装が含まれています。

上記のumd-clientindex.htmlを参考にして、Kepler.glのOracle APEXへの組み込みを行います。

Kepler.glに表示させるデータセットは、データベースへ保存できるようにします。また、データベースに保存したデータセットを表示できるようにします。これらの実装はAPI ReferenceのAdvanced usagesのSaving and Loading Maps with Schema Managerのセクションを参考に実装します。

作成したAPEXアプリケーションは以下のように動作します。データベースにロードしているサンプル・データは以下より取得しています。
https://github.com/uber-web/kepler.gl-data


最初にKepler.glで扱うデータセットを保存する表KEPLER_DATASETSを作成します。以下のDDLを実行します。列CONFIGにはKeplerGLSchema.getCofigToSave()を呼び出して得られる値、列DATASETにはKeplerGLSchema.getDatasetToSave()を呼び出して得られる値を保存します。
create table kepler_datasets (
    id         number generated by default on null as identity
               constraint kepler_datasets_id_pk primary key,
    name       varchar2(80 char) not null,
    config     clob check (config is json),
    dataset    clob check (dataset is json)
);
空白のページをベースにKepler.glを組み込みます。以下よりページ番号を2として説明を進めます。ページ番号が異なる場合は、P2といった接頭辞を置き換えてください。

ボタンは3つ作成します。ボタンLOADにより、ページ・アイテムP2_NAMEで指定したデータセットをKepler.glに読み込みます。ボタンSAVEはKepler.glで扱っているデータセットをデータベースに保存します。同名のデータセットがある場合は上書きします。ボタンDELETEで保存されているデータセットを削除します。ページ遷移が発生するとKepler.glは初期化されるため、これらはすべてページ遷移が発生しない動的アクションとして実装します(DELETEは例外で、Kepler.glを初期化するためJavaScript中でページ遷移を呼び出しています)。


ページ・プロパティJavaScriptファイルURLに以下を記述します。umd-clientのindex.htmlに準じていますが、バージョンについては新しいものを選んでいます。
https://unpkg.com/react@18.3.1/umd/react.production.min.js
https://unpkg.com/react-dom@18.3.1/umd/react-dom.production.min.js
https://unpkg.com/redux@4.2.1/dist/redux.js
https://unpkg.com/react-redux@8.1.3/dist/react-redux.min.js
https://unpkg.com/styled-components@6.1.13/dist/styled-components.min.js
https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js
https://unpkg.com/kepler.gl@3.1.0-alpha.1/umd/keplergl.min.js
Kepler.glの3.0以降はMapBoxの代わりにMapLibreを使います。そのため、MapLibreのライブラリをロード対象に含めています。


ファンクションおよびグローバル変数の宣言に以下を記述します。概ねindex.htmlのscript要素に記述されているコードと同じですが、MapBox関連のコードを削除しています。また、Kepler.glを表示する幅と高さは、APEXのリージョンに収まるように調整しています。



ページ・ロード時に実行に以下を記述します。Kepler.glであるReactコンポーネントを、IDappのDIV要素に描画します。



CSSファイルURLに以下を記述します。
https://d1a3f4spazzrp4.cloudfront.net/kepler.gl/uber-fonts/4.0.0/superfine.css
https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css
https://unpkg.com/kepler.gl@3.1.0-alpha.1/umd/keplergl.min.css


Kepler.glを描画する静的コンテンツのリージョンを作成します。ソースHTMLコードに以下を記述します。

<div id="app"></div>

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


以上でKepler.glがページに描画され、単体で使えるようになります。

これから、Kepler.glとデータベースを連携させる実装を追加します。

Kepler.glが扱う構成データとデータセットを、それぞれ保持するページ・アイテムを作成します。構成データはP2_CONFIG、データセットはP2_DATASETに保持します。ブラウザのJavaScriptからデータベースにこれらの値を送信する時、逆にデータベース・サーバーから取り出した値をブラウザに送信する時に、これらのページ・アイテムに値を保存します。

これらのページ・アイテムのタイプ非表示とします。動的アクションで値を設定するため、設定保護された値オフにします。セッション・ステートデータ型CLOBストレージリクエストごと(メモリーのみ)を選択します。


ボタンLOADの動的アクションとして、以下の処理が行われます。

最初のTRUEアクションで画面にスピナーを表示させ、画面操作のブロックを開始します。以下のJavaScriptを実行します。
/* スピナーを開始し、画面操作をブロックする */
spinner = apex.widget.waitPopup();

続いてボタンLOAD無効化します。


サーバー側のコードとして以下を実行し、ページ・アイテムP2_NAMEで指定された名前の構成データとデータセットを、ページ・アイテムP2_CONFIGP2_DATASETに取り出します。データを取り出すまで後続の処理を待たせるため、結果を待機オンにします。
select config, dataset into :P2_CONFIG, :P2_DATASET
from kepler_datasets where name = :P2_NAME;
送信するアイテムとしてP2_NAME戻すアイテムとしてP2_CONFIGP2_DATASETを指定します。


ページ・アイテムP2_CONFIGP2_DATASETに読み込んだデータを、Kepler.glに渡します。以下のJavaScriptコードを実行します。



データベースからKepler.glへの、データセットのロード処理の実装は以上です。

ボタンSAVEで実行されるTRUEアクションは、JavaScriptコードの実行のみです。以下のコードを実行します。


構成データとデータセットをデータベースに書き込むために、AjaxコールバックUPSERT_DATASETを呼び出しています。

AjaxコールバックのPL/SQLコードとして以下を記述します。



Kepler.glからデータベースへの、データセットの保存処理の実装は以上です。

ボタンDELETEの処理では、最初にPL/SQLコードとして以下を実行し、ページ・アイテムP2_NAMEのデータを削除します。

delete from kepler_datasets where name = :P2_NAME;


データを削除したのち、ページを再描画して初期化します。以下のJavaScriptコードを実行します。
const thisPage = 'f?p=' + apex.env.APP_ID + ':' + apex.env.APP_PAGE_ID + ':' + apex.env.APP_SESSION + ':::::';
apex.navigation.redirect(thisPage, true);

ボタンDELETEの実装は以上で完了です。

以上でAPEXアプリケーションへのKepler.glの組み込みは完了です。

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

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