OpenStreetMap
とMapboxを
ASP.NET Core
web appで利用
する
地図アプリの基本とコンテンツの受け渡
し
Profile
2021/3/27
システム構築のプロセス評価、改善、策定、
開発フレームワークの設計、実装管理、プリ
セールスやプロジェクトの立ち上げなど
ブログ
http://blog.processtune.com
プロフィール
Tetsuro Takao on Facebook, Twitter
or http://mvp.Microsoft.com
コミュニティ
.NETラボの運営スタッフ
https://dotnetlab.connpass.com
Microsoft MVP
Developer Technologies
[July 2010 – June 2021]
地図アプリの基本
作成開始時のサービスへの登録
2021/3/27
Map APIs
各サービスの仕組み
2021/3/27
エッジ側PC
token
token
token
Google Maps Platform API
2021/3/27
クレジットカードの登録が必要ですが、
月300ドル(2021年3月時点最新情報)
まで無料枠が付きます
Google Maps Platform APIのコスト
2021/3/27
Microsoft Azure MapsとBing Maps
2021/3/27
Microsoft Azure MapsのFree枠
2021/3/27
月に25万件の基本的なマッピングおよびトラフィックのトランザクションが提供
され、さらに5,000件のタイムゾーンクエリ、および25,000件の他のすべての
サービスのクエリが提供され、1秒間に50件以下のクエリに制限されます。
Bing Mapsのカバレッジ
2021/3/27
Mapbox
2021/3/27
Mapbox
2021/3/27
Mapbox Streetsタイルセットを使用する際は、MapboxとOpenStreetMapに帰属していること
を明示する必要があります。また、 それらの明示にはMapbox、OpenStreetMapおよび
Improve this mapのリンクを含む必要があります。
Google
2021/3/27
開発者のアカウント管理
ダミーデータ
ロードテストやサービスディスカ
バリーのブルーテストができない
Leafletを使う
JavaScriptライブラリ
2021/3/27
Mapbox SDK
2021/3/27
インフォメーション・アーキテクチャを理解する
コンテンツの配信と地図の利用の本質
2021/3/27
地図アプリが果たす役割
2021/3/27
位置 五十音順
時系列 分類
連続量
地図アプリのコンテンツ
2021/3/27
ロケーションのプロッ
ト
ポイント間の距離計算
経路探索
ロケーション・アドレ
ス変換
ストリートビュー
販売店
アルバ
ム・タ
イトル
発売日
ジャン
ル
連続量
アルバムの場合
地図アプリのコンテンツ
2021/3/27
ロケーションのプロッ
ト
ポイント間の距離計算
経路探索
ロケーション・アドレ
ス変換
ストリートビュー
配達先 顧客名 配達日
配達品目 配達回数
配送サービスの場合
静的コンテンツの必要性
なぜ地図アプリに丸投げする部分が多い方がいいのか?
2021/3/27
Webサーバーは安くない
2021/3/27
• ストレージにコンテンツを配置するだけならスクリプトなどによる自動化が可能
Webサーバーのメンテナンス・コスト
• ストレージのコストに比べるとWebサーバーのホスティングは高額
Webサーバーのコンピューティング・コスト
• クラウド・ネイティブな環境では、Webサーバーの運用だけで制御はできないのでルーティングやロギ
ング、サービス・ディスカバリの構成管理はストレージより高コストになる
Webサーバーのスケーリング・コスト
• キャッシュや動的レンダリングに関してはWebサーバーは最適だが、静的コンテンツの配信に関して
はWebサーバーでなくともストレージが行える
Webサーバーの静的コンテンツの配信コスト
Webpack, Browserify or Blazor WebAssembly
2021/3/27
依存機能へのパスの解決が必要なシーン ≒ 静的HTMLのホスティング
CDNが用意されているライブラリを使う CDNを構築する
BlogやSPAなど
SPAs App modules Renderers
地図アプリのデータを作成する
インフォメーション・アーキテクチャに則ったモデリングを行う
2021/3/27
サンプル作成→実行
2021/3/27
デバッグ(ブレークポイントの追加と変数の内容確
認)
2021/3/27
デバッグ(ファイルの読み込みとリスト表示)
2021/3/27
nullだった変数にリストが入る
ページの追加(アイコンの選択)
2021/3/27
ページの追加(ナビゲーションバーの設定)
2021/3/27
ページの追加(ページの追加と表示の確認)
2021/3/27
@page "/leafletmap“
<h1>Leafletの地図</h1>
ページの追加(Blazorの処理順)
2021/3/27
Program.cs
•Main
•_imports.razor
•App.razor
Index.html
•header
•link
•script
Shared
•MainLayout.razor
•…css
•…razor(MainLayout
の部品)
WebAssembly
表示
•LeafletMap.razor
ページの追加(Mapboxポータル:Dashboard)
2021/3/27
ページの追加(Mapbox APIのCDN)
2021/3/27
Program.cs
• Main
• _imports.razor
• App.razor
Index.html
• header
• link
• script
Shared
• MainLayout.razor
• …css
• …razor(MainLayoutの部
品)
WebAssembly
表示
• LeafletMap.razor
ページの追加(Mapbox APIの呼び出し)
2021/3/27
Program.cs
• Main
• _imports.razor
• App.razor
Index.html
• header
• link
• script
Shared
• MainLayout.razor
• …css
• …razor(MainLayoutの部
品)
WebAssembly
表示
• LeafletMap.razor
ページの追加(index.htmlのheadタグ)
2021/3/27
ページの追加(ページレンダリング後のMapbox API呼び出
し)
2021/3/27
タイルの変更とオープンデータの利用
2021/3/27
function renderingMap() {
lat = 35.661971;
lon = 139.703795;
userDistance = null;
mymap = L.map('mapid').setView([lat, lon], 10);
var base = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativ
ecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox/streets-v11',
tileSize: 512,
zoomOffset: -1,
accessToken: 'pk.eyJ1IjoidGV0c3Vyby10YWthbyIsImEiOiJja2IxbTA5dGwwMXNzMnBxenM0eTQ4MW11In0.wEJvokR0fJkTptr9utKL7g'
}).addTo(mymap);
if(userDistance == null){userDistance = 5;}
previewCircle = L.circle([lat, lon], userDistance * 1000, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
});
previewCircle.addTo(mymap).bindPopup("距離[" + userDistance + " km]");
mymap.on('click', onMapClick);
};
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-
xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-
gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>
Reference
2021/3/27
dotnet new
https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet-new
ASP.NET Core Blazor WebAssembly をデバッグする
https://docs.microsoft.com/ja-jp/aspnet/core/blazor/debug?view=aspnetcore-5.0&tabs=visual-studio
OPEN ICONIC
https://useiconic.com/open
ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す
https://docs.microsoft.com/ja-jp/aspnet/core/blazor/call-javascript-from-dotnet?view=aspnetcore-5.0

OpenStreetMap and Mapbox

Editor's Notes

  • #2 地図のレンダリングはGoogle Maps APIもBing Maps APIもJavaScriptで制御します。そのため、一度この仕組みを覚えてしまえばどちらのマップもうまく制御することができるようになります。 このような仕組みを学習するひとつの方法として、open-source JavaScript libraryであるLeafletを使うことができます。このLeafletがOpenStreetMapという地理情報のオープンデータを読み込み、Mapboxというタイルで地図をレンダリングする仕組みを解説します。 Leafletで地図をレンダリングできれば、コンテンツとして地図上に情報を表現することができます。 このコンテンツをどのようにASP.NET Core web appで構築し、どのようにJSONで受け渡すかを解説します。 重要なことは地図をレンダリングすることではありません。地図にコンテンツをレンダリングすることです。
  • #3 【読む】
  • #5 各社・各組織のマップ APIはSDKがあるにせよ無いにせよ、まずマップAPIを呼び出すために認証が必要になるので、それぞれの問題解決領域のアカウントが必要になります。 認証自体は登録すればトークンが発行されるのですが、重要なのはライフサイクル管理です。マイクロソフトの場合、トークンは既定で90日に設定されていますが、短くも長くも変更できます。AWSのCogniteは1時間から10年まで設定できます。いずれにせよ、各Map APIのトークンの生存期間とそれを利用するWeb appなどのドメインのトークンのライフサイクルを計画する必要があります。
  • #6 まずはGoogle Maps Platforms APIのお話から
  • #7 Billingに行ってFree枠を常に見るようにします。
  • #9 Azure Map →TomTom(地図情報以外をブリジストンに売却ゼンリンと提携) および Moovit(トラッキング)→インテル買収 Bing Map → Here日本の地図情報がない
  • #10 Azure Map →TomTom(地図情報以外をブリジストンに売却ゼンリンと提携) および Moovit(トラッキング)→インテル買収 Bing Map → Here日本の地図情報がない
  • #12 Azure Map →TomTom(地図情報以外をブリジストンに売却ゼンリンと提携) および Moovit(トラッキング)→インテル買収 Bing Map → Here日本の地図情報がない
  • #13 マイクロサービスには必ず認証が必要になります。これを外してUIを作っても構いませんが、特にチーム開発でブルー/グリーンテストを行う場合、サービスサイドから認証を経てUIに一貫する担当割の方がマイクロサービス的には自然です。先述のようにダミーデータを使ったうえで認証部分を分離してUIのみを作るのはマイクロサービスを採用しているチームの開発には向いていません。
  • #14 LeafletはオープンソースのJavascriptライブラリです。【クリック】
  • #15 もちろんMapboxにもSDKは用意されています。
  • #16 地図が表示できて、Map APIの使い方もわかりました。さて、何を配信しましょう?という話になります。【クリック】
  • #17 リチャードソールワーマンの著書「インフォメーション・アングザエティ(1989)」の改訂版「インフォメーション・アングザエティ2(2000)」で階層から連続量に変更されたものの情報にはこの5つの属性のうちいくつかまたは全部つけることができるという基本概念はインフォメーション・アーキテクチャのコアとなる考え方です。 地図アプリとはこのうち位置に関する人間の行為(たとえば検索や探索、関連付け概観など)を丸投げできる機能という部分が最も重要なポイントです。
  • #18 左側は機能でありコンテンツではありません。右側はコンテンツですが、連続量の属性は無く、位置属性としても販売しているお店のみがMap APIで実現できる機能となります。これも、店舗情報があればの話であってアルバムの楽曲情報のみの場合、販売店の情報すらありませんので地図アプリとしては活用できないコンテンツとなってしまいます。
  • #19 配送サービスしか地図アプリを使えないということではありませんが、インフォメーション・アーキテクチャに則った情報の整理を行っていれば、地図アプリに丸投げできる部分が多くなるということです。
  • #20 地図が表示できて、Map APIの使い方もわかりました。さて、何を配信しましょう?という話になります。【クリック】
  • #22 ここで、Mapアプリケーションの本題ではありませんが、Mapアプリケーションを設計する上で非常に重要な概念のお話をします。 ここに挙げたWeb pack, Browserify or Blazor WebAssemblyを見てピンとくる人はここからの話の間は休憩しておいておください。これらはすべて依存機能へのパスを解決してくれます。 これらのアーキテクチャは依存機能へのパスの解決だけが目的ではありませんが、依存機能へのパスの解決が必要なシーンに非常に有力なアーキテクチャになります。 Map系のCDNはCDNの観点から言えばアプリケーションモジュールに分類されます。
  • #23 地図が表示できて、Map APIの使い方もわかりました。さて、何を配信しましょう?という話になります。【クリック】
  • #24 まずは、とにかく地図を表示するアプリケーションを作ってみましょう。毎度のことですが、.NETのアプリケーション作成はびっくりするぐらい簡単です。PowerShellを立ち上げて、目的のディレクトリに移動します。「dotnet new」とタイプするとテンプレートの一覧が表示されますので作りたいアプリケーションのショートネームをタイプします。毎回mvcをやってたので、今回はBlazorでやってみます。 作成されたプロジェクトをVisual Studio Codeで開きます。初回はビルド設定がなされてないので作成するか聞かれるので「はい」を選択します。つづいてF5を押下するとブラウザが立ち上がりページが表示されます。 【クリック】
  • #25 次にデバッグも簡単です。機能拡張にC#【クリック】とJavaScript Debugger【クリック】がインストールされてない場合はインストールします。debuggerはNightlyをインストールします。続いてエクスプローラーからPagesのCounter.razorを開いてcodeブロックのIncrementCountメソッドのcurrentCount++の行にブレークポイントを置きます(14行目の14の左をクリックします)【クリック】。そしてF5を押下してブラウザ側で左のナビゲーションバーのCounterを選んでCounterページが開いたら【クリック】[Click me]ボタンを押してVisual Studio Codeに戻ります。カーソルをcurrentCount++の上に重ねると、currentCount変数に入っている「0」が確認できます【クリック】。F10で1行進めてもう一度カーソルを重ねると「1」にカウントアップされていることを確認できます。【クリック】ブラウザに戻るとインクリメントされた値が表示されています【クリック】
  • #26 次はJSONのサンプルも確認します。多くのWebアプリケーションはJSONでデータのやり取りを行います。特にAPIとの連携、本セッションではMap APIとのやり取りを行いますが、Open APIやMicrosoft Graph、FacebookやTwitterなどもJSONでやりとりを行います。今度はエクスプローラーでFetchData.razorを選択しcodeブロックのOnInitializedAsyncメソッドのforcasts変数にデータを読み込んでいる42行目にブレークポイントを置きます。先ほどと同じように実行し止まったら1行進めて変数の内容が変わることを確認してください。【クリック】
  • #27 ここまでのステップはMicrosoftの公式のドキュメントに記載されていますので本資料の巻末のリンクを参照してください。ここからちょっと変えています。まず、地図を表示するページを追加します。最初はタイルもJavaScriptライブラリもMapboxを使います。 まず、ナビゲーションバーにリンクを追加します。テンプレートはOPEN ICONICを使っているので、好きなアイコンを指定してください。今回は地図なので「oi oi-map」を指定しています。【クリック】このページでmap文字を検索してアイコンをクリックしてcss class名をコピーします。
  • #28 Mapboxの地図ですが、Leafletの地図として4番目のメニューに追加しています。Visual Studio CodeのエクスプローラーからSharedのNavMenu.razorを選択し、他のメニューをコピーしてhrefとメニュー項目の文字を変更します。classはさきほどコピーしてきたclassをWindowsキー+Vで貼り付けます。 次にhrefで指定したページ「leafletmap」を追加します。【クリック】
  • #29 Visual Studio CodeのエクスプローラーのPagesを右クリックして[新しいファイル]を選択してページ「LeafletMap.razor」を追加します。先頭に「@page “/leafletmap”」と「<h1>Leafletの地図</h1>」だけを追加してナビゲートすることを確認してください。
  • #30 Map APIはJavaScriptから呼び出すので、WebAssemblyが生成される前に定義する必要があります。つまり、index.htmlのheadタグ内で指定する必要があります。
  • #31 JavaScriptはMapboxポータルのSDKで簡単に作成することができます。
  • #33 これもコピーしますが、BlazorがWebAssemblyを生成してページが描画された最後にMap APIを呼び出す必要があります。そのため、地図のコンテナ(プレースホルダ)になるdivタグはLeafletMap.razorに貼り付けますが、scriptタグ部分はファンクションにしてindex.htmlのheadタグに定義してページが描画された後に呼び出します。
  • #34 そこで、index.htmlにleafletMapInitializeファンクションとして埋め込んでおきます。scriptはWebAssemblyが生成される前に読み込む必要があるため、個別のLeafletMap.razorに埋め込むことはできません。
  • #35 最後にLeafletMap.razorにMapbox APIの呼び出し部分を定義します。まず、JSインターオペラビリティとして用意されているIJSRuntimeインターフェイスをインジェクションします。【クリック】次にMapboxポータルからコピーしてきたプレースホルダ用のdivタグを貼り付けて【クリック】最後にOnAfterRenderAsyncメソッドを実装します。
  • #36 タイルと地図データはMapboxだけで十分です。ここではMap APIの仕組み理解をより一層深めるために、タイルやオープンデータを使って地図をレンダリングします。