2021年7月16日金曜日

マップのサンプル解説 (6) - 近隣の医療機関をレポートする

 こちらの記事の続きになります。

マップ上で検索の起点となる位置を指定し、その位置の周囲に立地している医療機関をレポートに一覧します。近隣の医療機関を検索するためにOracle SpatialのSDO_NNファンクションを使用します。


マップのサンプルではNearest Neighbor Searchのページに実装されています。

このファンクションを利用するためには、ジオメトリ列に索引が作成されている必要があります。そのため、最初に表C19_MEDICAL_FACILITIESの列GEOMETRYに空間索引を作成します。

SQLワークスペースオブジェクト・ブラウザを開き、作成メニューより索引を実行します。


表名C19_MEDICAL_FACILITIES索引のタイプ空間を選択し、へ進みます。


索引名はデフォルトで設定されるC19_MEDICAL_FACILITIES_SXをそのまま使います。索引列GEOMETRY (SDO_GEOMETRY)を選択し、表にはポイント・オブジェクトのみが含まれるONにします。列の登録をクリックします。

空間メタデータの設定画面が表示されます。座標系、ディメンションの設定はデフォルトのまま変更しません。空間メタデータの追加をクリックします。


実行をクリックすると、空間メタデータの追加を行います。索引の作成はこの後に実施します。


空間索引の作成画面に戻ります。へ進みます。


索引の作成を実行します。


以上で医療機関の位置を示す列GEOMETRYに空間索引が作成されました。

続いてページの作成に進みます。

こちらの記事で作成したレポート上で選択のページをコピーします。ページ番号10ページ名近隣の医療機関とします。


ページが作成されたら作業の開始です。

マップ・リージョンにマップ上でクリックされた位置のジオメトリを保持するページ・アイテムP10_CLICK_POSITIONを作成します。タイプ非表示設定保護された値OFFにします。


ページ・アイテムP10_CLICK_POSITIONが変更されたときに対話モード・レポートのリージョン医療機関とマップ自体をリフレッシュします。P10_CLICK_POSITION上で動的アクションの作成を行います。識別名前Refresh after Changeとします。ページ・アイテム上で動的アクションの作成を実行するとタイミングイベント変更選択タイプアイテムアイテムP10_CLICK_POSITIONとなります。ですので、確認だけして設定はそのままにします。


Trueアクションとして、識別アクションリフレッシュを指定します。影響を受ける要素選択タイプリージョンリージョンに対話モード・レポートのリージョン医療機関を指定します。P10_CLICK_POSITIONが変更されたとき、つまり、マップ上をクリックしたときにレポートが更新されます。


新規にアクションの作成を行うか、作成したアクションを重複させるかして、Trueアクションを作成し、マップ・リージョンもリフレッシュします。


対話モード・レポートのリージョン医療機関検索範囲候補数を指定するためのページ・アイテムを作成します。

リージョン医療機関ページ・アイテムの作成を実行します。識別名前P10_MAX_DISTANCEタイプ数値フィールドを選択します。ラベル検索範囲(km)とします。


ページ・アイテムの値が変更されたときにレポートとマップをリフレッシュする動的アクションRefresh after Change2を作成します。P10_CLICK_POSITIONに作成した動的アクションRefresh after Changeと同じ手順になります。


続いてページ・アイテムP10_NEIGHBOR_COUNTを作成します。タイプ数値フィールドレベル候補数とします。動的アクションもP10_CLICK_POSITION、P10_MAX_DISTANCEと同様に作成します。動的アクションの作成を行い、名前Refresh and Change3とします。レポートとマップのリージョンをリフレッシュするアクションを作成します。


マップ上の位置をクリックしたときに、クリックした位置のジオメトリをページ・アイテムP10_CLICK_POSITIONに保存する動的アクションを作成します。

マップ・リージョンで動的アクションの作成を行います。識別名前Click on Mapとします。タイミングイベントマップがクリックされました [マップ]選択タイプリージョンリージョンとして..マップを選択します。


Trueアクション識別アクション値の設定とします。設定タイプの設定にはJavaScript Expressionを選択し、JavaScript式として以下を記述します。

JSON.stringify({"type":"Point", "coordinates": [this.data.lng, this.data.lat]})

影響を受ける要素選択タイプアイテムとし、アイテムに位置を保存するページ・アイテムであるP10_CLICK_POSITIONを選択します。実行オプション初期化時に実行OFFにします。


マップ上にクリックした位置を表示するレイヤーを作成します。マップ・リージョンのレイヤー上でレイヤーの作成を実行します。識別名前検索起点とします。レイヤー・タイプポイントです。ソース位置ローカル・データベースタイプSQL問合せとし、以下をSQL問合せとして記述します。

select
0 as id
, mdsys.sdo_util.from_geojson( :P10_CLICK_POSITION ) as geometry
from sys.dual
where :P10_CLICK_POSITION is not null

送信するページ・アイテムとしてP10_CLICK_POSITIONを指定します。

列のマッピングジオメトリ列のデータ型SDO_GEOMETRYを選択し、ジオメトリ列にはGEOMETRYを選択します。主キー列IDです。ポイント・オブジェクトスタイルSVG形状Pin Circleを選びますが、形状の選択画面では円のピンとなっています。シェイプ・スケール2を指定します。外観塗りつぶしの色として青色#007affストロークの色#ffffffを指定します。ストロークの幅1を指定します。


続いて、検索範囲を表示するレイヤーを作成します。さきほどと同様にレイヤーの作成を行い、識別名前検索範囲レイヤー・タイプポリゴンとします。SQL問合せとして以下を記述します。

select
0 as id,
mdsys.sdo_util.circle_polygon(
point => mdsys.sdo_util.from_geojson( :P10_CLICK_POSITION ),
radius => :P10_MAX_DISTANCE * 1000,
arc_tolerance => 1 ) as geometry
from sys.dual
where :P10_MAX_DISTANCE is not null and :P10_CLICK_POSITION is not null

送信するページ・アイテムとして、P10_CLICK_POSITIONP10_MAX_DISTANCEを指定します。列のマッピングは上記のSELECT文で返される列より指定します。ジオメトリ列のデータ型SDO_GEOMETRYジオメトリ列GEOMETRY主キー列IDです。外観塗りつぶしの色#d8aa12塗りつぶしの不透明度.2とします。


対話モード・レポート医療機関ソースSQL問合せに、近隣の医療機関に検索結果を限定するWHERE句を追加します。また、検索の起点から医療機関の距離を返す列DISTANCEも追加します。近隣の検索にはOracle SpatialのSDO_NNファンクションを活用しています。距離の算出にはSDO_NN_DISTANCEファンクションを使用しています。

select f.facility_id, f.zip_code, f.facility_name, f.facility_addr, f.geometry
, m.ans_type ans_type_m, e.ans_type ans_type_e, h.ans_type ans_type_h
, sdo_nn_distance(1) distance
from c19_medical_facilities f
left outer join (
select ans_type, facility_type, facility_id
from c19_medical_facility_statuses
where facility_type = 'M') m
on f.facility_id = m.facility_id
left outer join (
select ans_type, facility_type, facility_id
from c19_medical_facility_statuses
where facility_type = 'E') e
on f.facility_id = e.facility_id
left outer join (
select ans_type, facility_type, facility_id
from c19_medical_facility_statuses
where facility_type = 'H') h
on f.facility_id = h.facility_id
where
(
:P10_CLICK_POSITION is not null
and
sdo_nn(
geometry
, mdsys.sdo_util.from_geojson ( :P10_CLICK_POSITION )
, case
when :P10_MAX_DISTANCE is not null then
'distance=' || :P10_MAX_DISTANCE || ' '
end
|| 'unit=km'
, 1
) = 'TRUE'
)
and
(
:P10_NEIGHBOR_COUNT is null
or
rownum <= :P10_NEIGHBOR_COUNT
)

送信するページ・アイテムとして、P10_CLICK_POSITIONP10_MAX_DISTANCEP10_NEIGHBOR_COUNTを指定します。


追加された列DISTANCEの表示を調整します。リージョン医療機関を開き、DISTANCEを選択します。ヘッダー距離に変更します。外観書式マスク999G999G999G999G990D00を指定し、小数点2桁までを表示対象とします。


マップ・リージョンも対話モード・レポートと同じ変更を行います。ソースSQL問合せ、および、送信するページ・アイテム対話モード・レポートと同じ値にします。


最後にコピー元のページに実装されていた機能が動作するように、若干のコードの修正を行います。

ページ・プロパティJavaScriptファンクションおよびグローバル変数の宣言の記載を以下に変更します。ページ・アイテム名がP7_FACILITY_IDのままだったので、P10_FACILITY_IDに変更しています。それ以外でP7_FACILITY_IDとなっている部分は、ページのコピーが作成される際にP10_FACILITY_IDに変更されています。

function showFeature( pId ) {
apex.item( "P10_FACILITY_ID").setValue( pId );
apex.event.trigger( $("#medical-facilities-region"), "refresh_and_center" );
}


以上で完了です。ページを実行して記事の最初にあるGIF動画のような動作を確認してみましょう。

この記事をもって、マップ・リージョンのサンプルの解説記事は終了です。

索引がある最初の記事はこちらになります。