Oracle APEX 21.2にて追加された地図に関連する機能は3つあります。
- ページ・アイテムのタイプとしてマップの表示が追加されました。
- ミニマップというコンポーネントが使用できるようになりました。
- ページ・アイテムのタイプとしてジオコーディングされた住所が追加されました。また、関連する動的アクションのイベントとしてジオコーディング・レスポンスと結果の選択が追加されています。
- 動的アクションのアクションとしてジオコーディングのトリガーが追加されています。
残念なことにジオコーダーが対応する地域に日本は含まれていません。ですので、上記の3、4のジオコーディングに関する機能は、日本の住所については無効です。
以下はカード・リージョンとミニマップを組み合わせた実装例です。
新規に追加された地図の機能の実装することにより、それらの使い方を紹介します。
データの準備
アマノ技研さんより提供されているGeospatial Dataの
地方公共団体の位置データをデータベースにロードし、役所の位置を地図上に表示します。
2021年11月2日時点では
asti-datr0304po.zipというファイルがダウンロードされました。このZIPファイルに含まれる
r0304puboffice_utf8.csvをデータベースにロードします。
SQLワークショップのユーティリティに含まれるデータ・ワークショップを開き、データのロードを実行します。
ファイルの選択をクリックし、アマノ技研さんよりダウンロードしたファイル
r0304puboffice_utf8.csvをアップロードします。
ロード先として新規表を選択し、表名としてDEMO_FACILITY_LOCATIONSを入力します。主キーとしてID列を選択し、列のデータ型の使用にチェックを入れます。
設定の列見出しの最初の行にヘッダーが含まれるにチェックを入れ、ファイル・エンコーディングにはUnicode(UTF-8)を選択します。列デリミタとしてタブ、囲み文字の"は自動的に検出されます。
以上を設定して、データのロードをクリックします。
ロード結果を確認します。アプリケーションは別途作成するので、この画面からは作成しません。テーブルの表示を実行してロードされた内容を表示してみます。
表のタブより、列の定義を確認します。緯度(LAT)、経度(LON)がNUMBER型で保存されていることは必須です。
データのタブより、列BUILDINGと列ADDRESSに、庁舎の名前と住所が保存されていること、緯度(LAT)、経度(LON)に数値が保存されていることを確認します。
データの準備は以上で完了です。
続いて空のアプリケーションを作成します。アプリケーション・ビルダーより作成を実行し、新規アプリケーションを選択してアプリケーション作成ウィザードを呼び出します。名前は任意ですが、今回の作業では役所の位置とし、それ以外は特に設定は行わずアプリケーションの作成を実行します。
以上で空のアプリケーションが作成されます。
このアプリケーションに、新しい地図の機能を使ったページを作成します。
ページ・アイテムによる地図の表示
タイプがマップの表示であるページ・アイテムを使って、役所の位置を示す地図を表示させます。対話モード・レポートによって役所の一覧を表示し、役所を選択し開いたフォームに地図を含めます。
ページの作成を実行し、ページ作成ウィザードを起動します。
フォームを選択します。
フォーム付きレポートを選択します。
レポート・タイプに対話モード・レポートを選びます。レポート・ページ名は役所一覧、フォーム・ページ名は役所情報とします。フォーム・ページ・モードにモーダル・ダイアログを選びます。次へ進みます。
ナビゲーションのプリファレンスとして、
新規ナビゲーション・メニュー・エントリの作成を選択します。
新規ナビゲーション・メニュー・エントリは
役所一覧になります。
次へ進みます。
データ・ソースとしてローカル・データベース、ソース・タイプとしてSQL問合せを選択します。SQL SELECT文を入力には以下を記述します。
select
jiscode
,name
,namekana
,building
,zipcode
,address
,tel
,source
,apex_spatial.point(lon,lat) map
from demo_facility_locations
APEXが提供しているAPIのAPEX_SPATIAL.POINTを使って、緯度経度の数値からSDO_GEOMETRY型を返すようにしています。
apex_spatial.point(lon,lat) map
GeoJSON(のポイント)の文字列をVARCHAR2型として返しても位置として認識されます。
'{"type":"Point","coordinates":[' || lon || ',' || lat || ']}' map
次へ進みます。
フォームが認識する主キー列として、JISCODE (Number)を選択します。作成をクリックします。
以上で対話モード・レポートとフォームのページが作成されます。
ページ・デザイナで作成されたフォームのページを開き、マップを表示するページ・アイテムを作成します。列MAPはSDO_GEOMETRY型のためか、自動的にはフォームにページ・アイテムとして作成されません。
アイテムの作成を実行し、作成したページ・アイテムの識別の名前をP3_MAPとします。タイプにマップの表示を選択します。ラベルは地図とします。
設定に含まれているプロパティがマップ(地図)に関係します。背景、ズーム・レベル、マーカーの表示、マーカーの色、ツールチップ、マップ・コントールの表示、対話型マップ、高さを設定します。ツールチップに列のデータを含めるには、&P3_BUILDING.といった置換文字列を使うことができます。これらのプロパティの設定によって、マップの表示が変わります。今回の作業には含まれませんが、色々とプロパティを変更して地図の表示を確認してみてもよいでしょう。
ページ・アイテムのマップと、次に説明するミニマップは同じコンポーネントを使っています。そのため、ミニマップも同じ設定項目を持っています。
ページ・アイテムP3_MAPのソースとして、フォーム・リージョンに役所情報、列にMAP、データ型にSDO_GEOMETRYを指定します。問合せのみをON、主キーはOFF、セッション・ステートの保持はリクエストごと(メモリーのみ)を選択します。
以上で地図を表示するページ・アイテムの作成ができました。動作を確認します。
役所一覧のページを表示します。
任意の役所の鉛筆アイコンをクリックし、フォームを表示します。ページ・アイテムP3_MAPとして保持している座標が、ページ・アイテムとして表示される地図の中心になります。
マップ・コントールや対話マップがONになっているため、拡大縮小、表示エリアの移動を行うコントロールが表示されています。またツールチップも表示されます。
ミニマップによる地図の表示
ページ・アイテムとして座標値を保持し、その座標値を中心とした地図を表示することができました。ただし、ページ・アイテムによるマップの表示は(動的アクションの)リフレッシュができません。そのため、ページ・アイテムに保持されている座標値を変更した後に、地図の表示を更新するにはページの送信を行う必要があります。
ミニマップを使い、ページの送信をせずに表示される地図を更新します。以下の動画のように動作するページを作成します。
ポップアップLOVに使用する共有コンポーネントのLOVを作成します。共有コンポーネントのLOVを開きます。
作成をクリックします。
LOVの作成として最初からを選びます。次へ進みます。
名前をLOV_FACILITIESとします。タイプにはDynamicを選択します。次へ進みます。
データ・ソースはローカル・データベース、ソース・タイプはTableを選択します。表/ビューの名前としてDEMO_FACILITIY_LOCATIONS (表)を選択します。次へ進みます。
戻り値としてJISCODE、表示列としてBUILDINGを選択します。作成をクリックします。
LOVとして
LOV_FACILITIESが作成されます。作成されたLOVを編集するために開きます。
追加表示列を増やすために
列の選択をクリックします。
今回はすべての列を表示列に含めます。更新をクリックします。最低限BUILDING、LAT、LONの列が必要です。
変更の適用をクリックします。
以上で共有コンポーネントのLOVが作成できました。
作成したLOVを使ったポップアップLOVを作成し、選択した役所をミニマップで表示するページを作成します。ページの作成を実行します。
空白ページを選択します。
名前はミニマップとします。ページ・モードは標準です。オプションの静的コンテンツ・リージョンを開いて、リージョン1の名前を地図にします。次へ進みます。
ナビゲーションのプリファレンスとして新規ナビゲーション・メニュー・エントリの作成を選択します。次へ進みます。
確認の画面に遷移します。終了をクリックすると、静的コンテンツのリージョンをひとつだけ含むページが作成されます。
ページ・プロパティのJavaScriptに含まれるファイルURLとして、ミニマップの実装となるJavaScriptのファイルを指定します。ファイル名は以下になります。
#APEX_FILES#libraries/apex/widget.miniMap.js
地図に表示する役所を選択するポップアップLOVとなるページ・アイテムを作成します。
アイテムの作成を実行します。識別の名前はP4_FACILITY、タイプとしてポップアップLOVを選択します。ラベルは役所とします。設定は特に調整しませんが、追加出力には以下を指定します。
LAT:P4_LAT,LON:P4_LON,BUILDING:P4_BUILDING
ポップアップLOVで役所を選択した際に、その緯度、経度、役所の名前をぞれぞれページ・アイテムP4_LAT、P4_LON、P4_BUILDINGへ設定します。これらのページ・アイテムに設定された値をミニマップに渡します。
LOVのタイプに共有コンポーネントを選択し、LOVとして作成済みのLOV_FACILITIESを選択します。追加値の表示はOFF、NULL値の表示もOFFとします。
追加出力を保存するページ・アイテムP4_LAT、P4_LON、P4_BUILDINGを作成します。タイプは非表示、設定の保護された値はOFFにします。以下のスクリーンショットはP4_LATですが、同様の設定でP4_LON、P4_BUILDINGを作成します。
作成済みの静的コンテンツのリージョン地図のソースのHTMLコードとして、ミニマップを組み込みます。
<div id="myMap" style="width:100%;height:300px"></div>
リージョンのAttributesを開き、設定の出力形式をHTMLにします。
ポップアップLOVP4_FACILITYにて役所が選択されたときに、IDがmyMapの要素に地図を書き出す動的アクションを作成します。P4_FACILITYで動的アクションの作成を実行します。
動的アクションの識別の名前を役所の選択とします。ページ・アイテムを対象として動的アクションを作成しているため、タイミングはデフォルトでイベントが変更、選択タイプがアイテム、アイテムがP4_FACILITYとなります。
TRUEアクションとしてJavaScriptコードの実行を選択します。設定のコードとして以下を記述します。
$( "#myMap" ).miniMap( {
center: [ $v("P4_LON"), $v("P4_LAT") ],
background: "osm-bright",
zoom: 14,
marker: true,
markerColor: "red",
controls: true,
interactive: true,
tooltip: $v("P4_BUILDING")
} );
以上で実装完了、といきたいところなのですが、若干の問題が残っています。
ポップアップLOVのP4_FACILITYで表示する役所を選択すると、LAT、LON、BUILDINGの値がページ・アイテムP4_LAT、P4_LON、P4_BUILDINGに設定されますが、この処理より先に動的アクションのJavaScriptコードが実行されてしまいます。結果としてひとつ前に選択されていた役所が地図に表示されます。
ポップアップLOVによるページ・アイテムの設定が行われた後に、JavaScriptによるマップの表示が行われるよう、TRUEアクションを追加します。
TRUEアクションのJavaScriptコードの実行の前に、アクションを作成します。識別のアクションとしてサーバー側のコードを実行を選択します。設定の言語はPL/SQL、PL/SQLコードとして何もしないという意味のnull;を記述します。送信するアイテムとして、P4_LAT、P4_LON、P4_BUILDINGを指定し、実行オプションの結果を待機をONにします。
以上で作業は完了です。ページを実行すると、最初のGIF動画のような動作を確認できます。
カードにミニマップを組み込む
今回の記事の最初のGIF動画になっている、カード・リージョンのカードにそれぞれミニマップを表示させます。ファセット検索の対象として、カード・リージョンを使ったページを作成します。
ページの作成を実行し、ページ作成ウィザードを開始します。レポートを選択します。
ファセット検索を選択します。
ページ名は役所検索とします。次へ進みます。
ナビゲーションのプリファレンスとして新規ナビゲーション・メニュー・エントリの作成を選択します。次へ進みます。
レポート・ソースの表/ビューの名前としてDEMO_FACILITY_LOCATIONSを選択します。表示形式にカードを選択します。適当な列がファセットとして認識されるよう、リフレッシュをクリックします。次へ進みます。
表示形式としてグリッドを選択します。タイトル列はBUILDINGとします。それ以外の列は指定せず、作成をクリックします。
ファセット検索のページが作成され、ページ・デザイナで開かれます。最初に
ページ・プロパティの
JavaScriptの
ファイルURLにミニマップへのリンクを記述します。
#APEX_FILES#libraries/apex/widget.miniMap.js
カード・リージョン検索結果のAttributesを開き、サブタイトルの列をADDRESSとします。本体の拡張フォーマットをONにし、HTML式として以下を記述します。
<div class="card-map"
data-center="[&LON.,&LAT.]"
data-background="osm-bright"
data-zoom="14"
data-marker="true"
data-marker-color="red"
data-controls="true"
data-interactive="true"
data-tooltip="&BUILDING."
style="width:100%;height:150px">
</div>
ミニマップの表示には上限がありページ区切りのタイプがスクロールの場合、ブラウザ側で以下のエラーが発生します。
Warning; Too many active WebGL contexts. Oldest context will be lost.
カード・リージョンのページ区切りのタイプをページにします。1ページ当たりのカードを5とします。
以上でカード・リージョンへのミニマップの組み込みは完了です。組み込まれたミニマップを描画する動的アクションを作成します。
リージョン検索結果で動的アクションの作成を行います。
動的アクションの識別の名前はカードの変更とします。タイミングのイベントとしてページ変更[カード]を選択します。選択タイプはリージョン、リージョンには検索結果を選択します。
TRUEアクションの識別のアクションとしてJavaScriptコードの実行を選択し、設定のコードに以下を記述します。実行オプションの初期化時に実行はONにします。
$(".card-map").miniMap();
以上でそれぞれのカードにマップが表示されるようになりました。ページを実行すると、本記事の先頭にあるGIF動画のような動作を確認できます。
ジオコーディングの使用
残念ながらジオコーディングは日本が対象に含まれていません。以下、簡単な使い方だけを紹介します。米国のRestonにあるオラクルのオフィスと以前に本社だったSan Mateoのオラクルのオフィスを表示させています。
ポップアップLOVを使ったミニマップのときと同じ手順で空白ページを作成します。ページの名前をジオコーディングとします。
市の情報を保持するページ・アイテムを作成します。識別の名前はP6_CITY、タイプはテキスト・フィールドとします。ラベルは市とします。ソースのセッション・ステートの保持はリクエストごと(メモリーのみ)を選択します。ページをリロードしたときにページ・アイテムの値を空白にリセットしたいので、このような設定にしています。
住所の情報を保持する
ページ・アイテムを作成します。
識別の
名前は
P6_STREET、
タイプは
テキスト・フィールドとします。
ラベルは
住所とします。
ソースの
セッション・ステートの保持は
リクエストごと(メモリーのみ)を選択します。
[Enter]を押すと送信を
ONにします。住所を入力してEnterを入力すると、ページ・アイテムP6_CITYとP6_STREETの値から緯度経度の座標値を求めるジオコーディングが行われます。
ジオコーディングされた座標を保持する
ページ・アイテムを作成します。
識別の
名前を
P6_GEOCODINGとします。
タイプとして
ジオコーディングされた住所を選択します。
ラベルは
地図とします。
設定の
国タイプは
Static、
国として
United Statesを選択します。この国の選択肢にJapanはありません。これはOracle Maps Cloudの
eLocation Serviceが対応していないことが理由になります。そのため、米国の住所でジオコーディングを行います。
通りアイテムとしてP6_STREET、市アイテムとしてP6_CITYを選択します。ジオコーディングのトリガーをAutomaticとします。セッション・ステートの保持はリクエストごと(メモリーのみ)を選択します。
以上でジオコーディングを行うページが作成できました。
ページを実行し、市としてReston、住所にOracleを入力し、Enterを押してジオコーディングを行います。
ブラウザのJavaScriptコンソールを開き、ページ・アイテムP6_GEOCODINGの内容を印刷してみます。
$v("P6_GEOCODING");
JavaScriptコンソールにGeoJSON形式のポイント・データが印刷されます。
{"type": "Point", "coordinates": [-77.35322, 38.95358]}
同様に、市としてSan Mateo、住所にOracleを入力し、ジオコーディングを実行します。
P6_GEOCODINGの値は以下になります。
{"type": "Point", "coordinates": [-122.26387, 37.53239]}
ジオコーディングについては、
動的アクションの
タイミングとして
ジオコーディング・レスポンスおよび
結果の選択があります。また
アクションとしては
ジオコーディングのトリガーが新規に追加されています。これらの使い方は、Oracle Spatialを使うワークショップで使用していたOracle Elocation Geocoderプラグインと同等だろうと思います。この
ワークショップを日本語で紹介した記事が参考になるでしょう。
以上でOracle APEX 21.2の地図関連の拡張の紹介は終了です。
作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/new212-map.sql
役所の位置データや表DEMO_FACILITY_LOCATIONSのDDLは含んでいません。データのみの二次配布が禁止されていることもありますが、ご自身で用途などをアマノ技研さんへ申告した上で利用されるのが良いかと思います。
少し長い記事になりましたが、Oracle APEXのアプリケーション作成の参考になれば幸いです。
追記
今回のminiMapの実装を含むJavaScriptファイルとして、以下を指定しています。
#APEX_FILES#libraries/apex/widget.miniMap.js
Oracle APEXは通常MinifyされたJavaScriptファイルも提供しています。その場合のパスは以下になります。
#APEX_FILES#libraries/apex/minified/widget.miniMap.min.js
今回のケースではMinifyされたJavaScriptファイルを指定する方が適切です。ただしMinifyされていないファイルには、ライブラリの使い方などが記載されています。例えばwidget.miniMap.jsの先頭には、以下の記載が含まれています。
* miniMap is a basic implementaion of the underlying mapboxgl library to display maps pointing to given coordinates
*
* The markup expected by this widget is simply a empty div element. Optionally all provided options could also
* be set by using data-* attributes.
*
* Supported options:
* - background: String which supplies name of the background map,
* "default" uses "osm-bright" and for dark mode "osm-dark-matter"
* Valid values: "default", "osm-bright", "osm-positron", "bi-world-map",
* "osm-dark-matter", "world-map"
* - center: An array containing the coordinates with latitude & longitude
* [ longitude, latitude ], [ -122.26516, 37.52938 ]
* - zoom: [Defaults 16] The zoom level of the map, range between 0 and 18
* additional values will add to the existing selection.
* - marker: [Defaults true] Whether to show a marker or not
* - markerColor: Color of the marker, if empty default color of mapbox is used
* - controls: [Defaults false] Whether to show controls or not
* - interactive: [Defaults true] Whether to have an interactive map or not
* - tooltip: If supplied, shows a tooltip popup above a marker, which is visible when the marker was clicked
* The tooltip also supports HTML markup and APEX template directives
*
* File URL to reference: #IMAGE_PREFIX#libraries/apex/#MIN_DIRECTORY#widget.miniMap#MIN#.js
完