ラベル Map の投稿を表示しています。 すべての投稿を表示
ラベル Map の投稿を表示しています。 すべての投稿を表示

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_POSITIONとP10_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_POSITION、P10_MAX_DISTANCE、P10_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動画のような動作を確認してみましょう。

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

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

完

マップのサンプル解説 (5) - マップに表示されている医療機関をレポートする

 こちらの記事の続きです。

マップに表示されている医療機関をレポートに表示します。



マップのサンプルではCircle Searchのページに実装されています。こちらの記事で作成したレポート上で選択のページをコピーします。ページ番号は9、ページ名はマップ上の医療機関とします。


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

マップ・リージョンにページ・アイテムP9_BBOXを作成します。このページ・アイテムは、マップ・リージョンに表示されている領域のジオメトリを保存します。タイプは非表示、設定の保護された値はOFFにします。


マップ・リージョンのAttributesを開き、詳細の境界ボックス・アイテムとしてP9_BBOXを指定します。この設定により、マップに表示されている領域がP9_BBOXに保存されます。


マップの表示倍率が低いと多数の医療機関がマップ上に表示されます。それらすべての医療機関をレポートに一覧する代わりに、マップの倍率を上げるよう警告を表示します。

最初にレイアウトを調整するためのリージョンを作成します。リージョンの作成を実行し、Content Bodyの直下に配置します。識別のタイトルをレポートとします。タイプは静的コンテンツ、外観のテンプレートとしてBlank with Attributes (No Grid)を選択します。


対話モード・レポートのリージョン医療機関のレイアウトの親リージョンをレポートに変更します。


警告を表示するリージョンを作成します。リージョンの作成を実行し、識別のタイトルをレポートなしとします。ソースのテキストとして以下を記述します。
詳細のレポートを表示するには、マップの表示領域が広すぎます。
レポートを表示するにはマップを拡大してください。
レイアウトの親リージョンはレポートとし、外観のテンプレートにAlertを選択します。


これで、レポートの準備はできました。

マップの表示領域が変わったときに(ズームイン、ズームアウトされたとき)動的アクションを起動し、医療機関のレポートをリフレッシュします。

マップ・リージョンで動的アクションの作成を実行します。

識別の名前をRefresh Reportとします。タイミングのイベントはマップが変更されました [マップ]です。選択タイプはリージョン、リージョンは..マップを選びます。クライアント側の条件として、タイプにJavaScript式を選び、JavaScript式に以下を記述します。

$v("P9_BBOX") !== ""
&&
apex.region("medical-facilities-region").call("getMapCenterAndZoomLevel").zoom >= 12

P9_BBOXに値が設定されていて、かつ、マップの倍率が12を超えているときに、マップに表示されている医療機関をレポートに一覧します。


最初のTrueアクションとして、識別のアクションをリフレッシュ、影響を受ける要素の選択タイプをリージョン、リージョンに..医療機関を指定します。このアクションによって医療機関のレポートが更新されます。


警告のリージョンを非表示にします。TRUEアクションの作成を実行し、識別のアクションを非表示とします。影響を受ける要素の選択タイプをリージョン、リージョンを..レポートなしとします。


動的アクションのクライアント側の条件に一致しない場合、警告のリージョンを表示させます。作成したTrueアクションでコンテキスト・メニューを開き反対のアクションの作成を実行します。


TRUEアクションの作成を実行し、医療機関のレポート表示します。識別のアクションは表示、影響を受ける要素の選択タイプをリージョンとし、リージョンに..医療機関を選びます。


このアクションについても、反対のアクションの作成を実行します。


P9_BBOXとして保存されるジオメトリが検索結果に反映されるよう、レポートおよびマップのソースであるSQL問合せを更新します。

対話モード・レポートの医療機関のソースのSQL問合せは以下になります。P9_BBOXとして設定されている領域に接しているか含まれる位置に存在する医療機関に限定されるよう、WHERE句でSDO_ANYINTERACTファンクションが使用されています。

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
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
:P9_BBOX is not null
and
sdo_anyinteract(
geometry,
mdsys.sdo_util.from_geojson( :P9_BBOX )
) = 'TRUE'

送信するページ・アイテムにP9_BBOXを指定します。


マップのソースのSQL問合せには以前の作業でWHERE句が付けられています。今回の用途では不要なので削除します。以下のSQLになります。

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
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

送信するページ・アイテムに設定されているP9_FACILITY_IDは不要なので削除します。


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

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

マップのサンプル解説 (4) - 円形ツールを使う

こちらの記事の続きです。

マップ上で円形ツールを使って選択した医療機関をレポートに表示します。


マップのサンプルではCircle Searchのページに実装されています。ひとつ前の記事で作成したレポート上で選択のページをコピーします。ページ番号は8、ページ名はマップ上で選択とします。

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

対話モード・レポートにページ・アイテムP8_CIRCLE_GEOJSONを作成します。タイプは非表示、設定の保護された値はOFFにします。マップ上で円形ツールを使って指定した領域をGeoJSONの形式で保持するために使用します。


円形ツールで指定した領域をP8_CIRCLE_GEOJSONに保存する動的アクションを作成します。

マップ・リージョンで動的アクションの作成を実行します。識別の名前をCircle Finished、タイミングのイベントはマップが変更されました[マップ]、選択タイプはリージョン、リージョンに..マップを選択します。

クライアント側の条件として、タイプにJavaScript式を選び、JavaScript式として以下を記述します。

this.data && this.data.changeType === "circle-drawn"

詳細のイベント有効範囲を動的にします。


最初のTrueアクションとして、値の設定を作成します。設定のタイプの設定はJavaScript Expressionを選択します。JavaScript式として以下を記載します。

( this.data.circle ? JSON.stringify( this.data.circle.data.geometry ) : "" )

影響を受ける要素の選択タイプをアイテム、アイテムとしてP8_CIRCLE_GEOJSONを指定します。これで this.data.circle.data.geometry として取得される円形ツールで指定した領域が、GeoJSON形式でページ・アイテムP8_CIRCLE_GEOJSONに設定されます。


ページ・アイテムP8_CIRCLE_GEOJSONに領域の情報が設定されたので、対話モード・レポートのリージョンとマップ・リージョンをリフレッシュして、検索結果に反映させるアクションを作成します。

TRUEアクションの作成を実行し、識別のアクションをリフレッシュとします。影響を受ける要素の選択タイプはリージョン、リージョンとして対話モード・レポートのリージョンである医療機関を指定します。


同様の手順で、マップ・リージョンをリフレッシュするアクションを作成します。


最後にTRUEアクションとしてJavaScriptコードの実行を作成します。円形ツールで選択した領域をクリアします。設定のコードには以下を記述します。

apex.region( "medical-facilities-region" ).call ( "clearCircle" );


円形ツールによって指定された領域に含まれる医療機関のみが検索されるよう、対話モード・レポートとマップ・リージョンのSQL問合せを更新します。Oracle SpatialのSDO_ANYINTERACTファンクションを使用します。

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
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
:P8_CIRCLE_GEOJSON is null
or
sdo_anyinteract(
geometry,
mdsys.sdo_util.from_geojson( :P8_CIRCLE_GEOJSON)
) = 'TRUE'

対話モード・レポートのSQL問合せを更新します。送信するページ・アイテムにP8_CIRCLE_GEOJSONを追加します。


マップ・リージョンのSQL問合せも更新します。送信するページ・アイテムにP8_CIRCLE_GEOJSONを追加します。


円形ツールで指定した領域をマップ上に表示するために、新規にレイヤーを作成します。

レイヤーの作成を実行し、識別の名前を検索範囲とします。レイヤー・タイプはポリゴンです。ソースのSQL問合せに以下のSELECT文を記述します。

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

送信するページ・アイテムにP8_CIRCLE_GEOJSONを指定します。


列のマッピングのジオメトリ列のデータ型にSDO_GEOMETRYを選択し、ジオメトリ列はGEOMETRYとします。主キー列にIDを選択します。外観の塗りつぶしの色にベージュ#d8aa12を指定し、塗りつぶしの不透明度は .2 とします。


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

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