Bing Maps上に地震の震源地を表示するプログラムを作る

2013年2月20日(水)
薬師寺 国安

「構成マネージャ」の設定

この状態では、まだBing Maps SDKが使用できませんので、これを使用できるようにします。まず、VS2012のメニューから「ビルド(B)/構成マネージャ(O)」と選択します。「プラットフォーム」がAny CPUになっていますので、プルダウンメニューから、該当するプラットフォームを選択します。筆者の環境では×86を選択する必要がありました(図11)。

[閉じる]ボタンをクリックすると、ソリューションエクスプローラー内の「参照設定」にあった「Bing Maps for C#, C++, or Visual Basic (Beta)」と「Microsoft Visual C++ Runtime Package」の先頭の黄色いアイコンが消えています。これでBing Maps SDKの使用が可能になりました。

図11:「構成マネージャ」からプラットフォームを設定する(クリックで拡大)

コントロールの配置

表示されるデザイン画面の要素に名前空間を追加します。xmlns:bm=”Using:と入力すると値の一覧が表示されますので、Bing.Mapsを選択します(図12)。

bm:Mapコントロールを配置すれば、Bing.Mapsの地図が表示されるはずです。もし地図が表示されない場合は、一度VS2012を再起動してください。

コントロールを配置し、その子要素として、Buttonコントロールを2個、過去のデータのファイル名を表示するListBoxコントロールを1個配置します。

書き出されるXAMLコードをリスト1のように編集します。レイアウトは図13になります。

図12:xmlns:bm=”Using:と入力してBing.Mapsの値が表示されている(クリックで拡大)

リスト1 書き出され編集されたXAMLコード(MainPage.xaml)

  • (1) bmという名前空間を定義しています。
  • (2) 要素を配置し、CredentialsプロパティにBing Maps Account Centerで取得したBing Maps Keyを指定します。Bing Maps Keyの取得方法は後述しています。
  • (3) 要素を配置し、背景色にDarkGreenを指定します。その子要素として、要素を配置し、OrientationプロパティにHorizontalと指定します。この要素の子要素として、名前がdataSaveButtonという
<Page
  x:Class="Win8_EarthQuakeJapan.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:Win8_EarthQuakeJapan"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:bm="using:Bing.Maps"■(1)
  mc:Ignorable="d">

  <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <bm:Map Credentials="Bing Maps Account Center で取得したキー" x:Name="myMap"/>■(2)
    <AppBar Background="DarkGreen" Height="100" Margin="0,668,0,0">■(3)
      <StackPanel Orientation="Horizontal">■(3)
        <Button Width="152" x:Name="dataSaveButton"  Foreground="Gold" Style="{StaticResource SaveAppBarButtonStyle}" />■(3)
        <Button Content="過去のデータ一覧" Height="50" Width="218" x:Name="dataShowButton" Background="Black" Margin="40,0,0,0" BorderBrush="Crimson" Foreground="Crimson"/>■(3)
        <ListBox Name="ListBox1" Margin="40,0,0,0" BorderBrush="Navy" Width="433"/>■(3)
      </StackPanel>■(3)
    </AppBar>■(3)
  </Grid>
</Page>
図13:各コントロールを配置した。拡大縮小ボタンと、地図の表示モード選択ボックスは、実行時に自動的に表示されます(クリックで拡大)

Bing Maps Keyの取得方法

Bing Mapsを使用するには下記URLのBing Maps Account Centerに行って専用のライセンスキーを取得する必要があります。
→ Bing Maps Account Center

ライセンスキーの取得にはWindows Live IDが必要です。持っていない方はCreateからWindows Live IDを作成してSign Inしてください。お持ちの方はそのままSign Inしてください。筆者はIDを持っているため、ここではSign Inから入ります(図14)。

図14:Bing Maps Account Center でSign Inする(クリックで拡大)

表示される画面の左にあるCreate or view keysをクリックします(図15)。

図15:Create or view keysをクリックする(クリックで拡大)

Create keyの画面が表示されますので、必要な項目を入力してSubmitしてください。筆者は既にキーを持っていますので、下記にキーが表示されています(図16)。Key typeはBasicとなっています。BasicでPublic websiteの場合は、「アプリケーションが制限なしに利用され、500,000 のトランザクションの任意の種類の 12 ヶ月の期間内を超えない、公開ウェブサイトです。」となっているようです。

図16:筆者のApplication Keyが表示されている(クリックで拡大)

ドキュメントライブラリへのアクセス許可の設定

今回のサンプルは、XMLファイルをドキュメントライブラリ内に作成して、読み込んだりしますので「ドキュメントライブラリ」へのアクセス許可が必要です。ソリューションエクスプローラー内にpackage.appxmanifestというファイルがありますので、このファイルをダブルクリックします。「機能」タブをクリックして、「画像ライブラリ」にチェックを付けます(図17)。

図17:package.appxmanifestを開き「機能」タブから、「画像ライブラリ」にチェックを付ける(クリックで拡大)

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト2のコードを記述します。

ロジックコードを記述する

リスト2 (MainWindow.xaml.vb)

Option Strict On

Bing Mapsに関するクラスの含まれるBing.Maps名前空間をインポートします。

Imports Bing.Maps

最新のHTTPアプリケーション用のプログラミングインターフェイスを提供するクラスの含まれる、System.Net.Http名前空間をインポートします。

Imports System.Net.Http

コアシステムの機能とその UI についてのランタイム情報にアクセスするアプリケーションを提供するクラスの含まれる、Windows.UI名前空間をインポートします。描く円の色を指定する場合等に、この名前空間に含まれるクラスを使用します。

Imports Windows.UI

図形に関するクラスの含まれる、Windows.UI.Xaml.Shapes名前空間をインポートします。

Imports Windows.UI.Xaml.Shapes

ファイル、フォルダ、およびアプリケーションの設定を管理するクラスの含まれる、Windows.Storage名前空間をインポートします。

Imports Windows.Storage

Public NotInheritable Class MainPage
  Inherits Page
 
  Dim zIndexNo As Integer = 0
  Dim zIndexNo2 As Integer = 0
  Dim myResponse As String

文字列型の新しいリストであるmyFile2メンバ変数を宣言します。

  Dim myFile2 As New List(Of String)

「なまず地震情報取得API」のUriで初期化された新しいUriのインスタンス、myUriメンバ変数を宣言します。返されるデータ形式はXML形式となります。

  Dim myUri As Uri = New Uri("http://api.nmzu.jp/history.xml", UriKind.Absolute)

ページがアクティブになった時の処理

ピクチャライブラリ内にCreateFolderAsyncメソッドで、EarthQuakeDataというサブフォルダを作成します。その際、CreationCollisionOption.OpenIfExistsを指定すると、同名フォルダが存在ずる場合は、そのフォルダ名を返し、無い場合は新規に作成してくれます。

GetFilesAsyncメソッドでEarthQuakeDataサブフォルダ内のファイルを取得し、コレクション変数earthQuakeDataに格納します。
Countプロパティでファイルの個数を取得し、ファイルが無い場合は、dataShowButtonの使用を不可とし、それ以外は使用を可とします。

地図上の地震の震源地に●印を表示するDataShowプロシージャを実行します。

非同期処理で行われるため、メソッドの先頭にAsyncを追加します。

  Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    Dim myStorageFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim mySubFolder = Await myStorageFolder.CreateFolderAsync("EarthQuakeData", CreationCollisionOption.OpenIfExists)
    Dim earthQuakeData = Await mySubFolder.GetFilesAsync
    If earthQuakeData.Count = 0 Then
      dataShowButton.IsEnabled = False
    Else
      dataSaveButton.IsEnabled = True
    End If
    DataShow()
  End Sub

地図上の地震の震源地に●印を表示する処理

HttpClientクラスの新しいインスタンスmyHttpClientオブジェクトを作成します。HttpClientクラスは、URI で識別されるリソースに HTTP 要求を送信し、そのリソースから HTTP 応答を受信するためのクラスです。

HttpClientクラスのGetStringAsyncメソッドで、指定したURIにGET送信し、非同期操作で応答本体を文字列として受け取ります。

地図の表示形式を「道路表示」にしておきます。各変数を宣言し、2013/01/01といった形式で、現在の日付を生成して変数myDateに格納しておきます。数値を、01、02といった形式で表示するには、Tostring(“00”)と指定します。

XElement.Parseメソッドで、文字列として読み込まれたXML(myResponse)を読み取ります。

読み込んだXMLから、DescenDantsメソッドで全ての子孫要素の内容を、変数resultに格納しながら、反復処理を行います。メンバ変数zIndexNoの値を1ずつ加算します。

要素の各子要素の値を各変数に格納していきます。結果XMLの構造はリスト3のようになります。

リスト3 結果XMLの構造

<?xml version="1.0" encoding="UTF-8"?>
<nmzu_api_responce>
  <api>
    <name>namazu disaster information API</name>
    <version>1</version>
  </api>
  <results>
    <jishin_info>
      <entry>
        <jishin_code>sSk6</jishin_code>
        <url>http://nmzu.jp/sSk6</url>
        <detection_date>2013/01/26 06:57</detection_date>
        <epicenter>
          <coordinate>
            <latitude>36.9</latitude>
            <longitude>139.4</longitude>
          </coordinate>
          <name>栃木県北部</name>
        </epicenter>
        <intensity_no>1</intensity_no>
        <magnitude>2.6</magnitude>
        <tweet_info>
          <account>@nmzu</account>
          <id>294928388777467904</id>
        </tweet_info>
      </entry>
      <entry>
        <jishin_code>XAdy</jishin_code>
        <url>http://nmzu.jp/XAdy</url>
        <detection_date>2013/01/26 04:41</detection_date>
        <epicenter>
          <coordinate>
            <latitude>42.3</latitude>
            <longitude>143</longitude>
          </coordinate>
          <name>日高地方東部</name>
        </epicenter>
        <intensity_no>1</intensity_no>
        <magnitude>3.6</magnitude>
        <tweet_info>
          <account>@nmzu</account>
          <id>294894162795442178</id>
        </tweet_info>
      </entry>
      ~<entry></entry>繰り返し~
    </jishin_info>
  </results>
</nmzu_api_responce>

上記結果XML内の、要素の子要素要素の子要素での子要素要素の子要素での子要素要素の値を使用します。

MapのCenterプロパティにDouble型に変換したmyLatitude(要素の値を格納)とmyLongitude(要素の値を格納)の値で初期化された、新しいLocationを指定します。

新しいEllipseのインスタンスmyEllipseオブジェクトを作成します。枠線の色をNavyに指定します。WidthとHeightは30とします。直径30pixelの円が描かれます。

新しいStackPanelのインスタンスmyStackpanelオブジェクトを作成します。SetValueメソッドのZIndexPropertyに1ずつ加算されるzIndexNoの値を指定します。StackPanelが円よりも前面に表示されます。myStackPanelオブジェクトの背景色にGainsBoroを指定します。初期状態ではmyStackPanelオブジェクトを非表示としておきます。

次に、TextBlockの新しいインスタンスmyTextBlockオブジェクトを作成します。パディングに5を指定し、Textプロパティに改行を含めた、「発生日時」、「震源地」、「マグニチュード」、「震度」を指定します。文字色はNavyで、文字サイズは20とします。myStackPanelオブジェクトにmyTextBlockオブジェクトを追加します。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内に要素の位置を設定します。この場合、myLatitudeとmyLongitudeの位置にmyStackPaneオブジェクトをセットします。MapLayerクラスは、地図上の要素の位置を保持しているマップレイヤーを表すクラスです。MapにAddメソッドでmyStackPanelオブジェクトを追加します。

現在の日付より-1日した日付を作成し、変数_myDate2に格納しておきます。-1日した日付は、AddDays(-1).Day.ToString(“00”)で取得できます。日付で条件分岐を行います。

「発生日時が」変数_myDate2(現在の日付より1日前)であった場合は、円をOrangeで塗りつぶします。変数「発生日時が」変数myDate(現在の日付)であった場合は、円をRedで塗りつぶします。それ以外はYellowで塗りつぶします。

MapLayerクラスのSetPositionメソッドで、マップレイヤー内に要素の位置を設定します。この場合、myLatitudeとmyLongitudeの位置にmyEllipse(円)オブジェクトをセットします。MapにAddメソッドでmyEllipseオブジェクトを追加します。

円がタップされた時はmyStackPanelオブジェクトを表示します。「発生日時」、「震源地」、「マグニチュード」、「震度」の書かれたTextBlockが表示されます。
myStackPanelオブジェクトがタップされた時は、myStackPanelオブジェクトを非表示にします。「発生日時」、「震源地」、「マグニチュード」、「震度」の書かれたTextBlockも非表示になります。例外が発生した場合は、メッセージを表示して処理を抜けるErrorShowプロシージャを実行します。

  Private Async Sub DataShow()
  Try
    Dim myHttpClient As New HttpClient
    myResponse = Await myHttpClient.GetStringAsync(myUri)
 
    myMap.MapType = MapType.Road
 
    Dim detectionDate As String = String.Empty
    Dim myLocation As String = String.Empty
    Dim myLatitude As String = String.Empty
    Dim myLongitude As String = String.Empty
    Dim myMagnitude As String = String.Empty
    Dim myIntensity As String = String.Empty
    Dim nowYear As Integer = Date.Now.Year
    Dim nowMonth As Integer = Date.Now.Month
    Dim nowDay As Integer = Date.Now.Day
    Dim myDate As String = CStr(nowYear.ToString & "/" & nowMonth.ToString("00") & "/" & nowDay.ToString("00"))
 
    Dim xmldoc As XElement = XElement.Parse(myContent)
 
    For Each result In From c In xmldoc.Elements("item") Select c
      zIndexNo + = 1
      myLocation = result.Element("epicenter_location_name").Value
      detectionDate = result.Element("detection_date").Value
      myLatitude = result.Element("epicenter_coor_lat").Value
      myLongitude = result.Element("epicenter_coor_long").Value
      myMagnitude = result.Element("magnitude").Value
      myIntensity = result.Element("intensity").Value
      myMap.Center = New Location(CDbl(myLatitude), CDbl(myLongitude))
      Dim myEllipse As New Ellipse
      myEllipse.Width = 20
      myEllipse.Height = 20
      myEllipse.Stroke = New SolidColorBrush(Colors.Blue)
 
      Dim myStackPanel As New StackPanel
      myStackPanel.SetValue(Canvas.ZIndexProperty, zIndexNo)
      myStackPanel.Background = New SolidColorBrush(Colors.Gainsboro)
      myStackPanel.Visibility = Xaml.Visibility.Collapsed
      Dim myTextBlock As New TextBlock
      myTextBlock.Padding = New Thickness(5)
      myTextBlock.Text = "発生日時=" & detectionDate & vbCrLf & "震源地=" & myLocation & vbCrLf & "マグニチュード=" & myMagnitude & vbCrLf & "震度=" & myIntensity
      myTextBlock.Foreground = New SolidColorBrush(Colors.Navy)
      myTextBlock.FontSize = 20
      myStackPanel.Children.Add(myTextBlock)
 
      MapLayer.SetPosition(myStackPanel, New Location(CDbl(myLatitude), CDbl(myLongitude)))
      myMap.Children.Add(myStackPanel)
 
      Dim _myDate As DateTime = Date.Now
 
      Dim _Year = _myDate.Year
      Dim _Month = _myDate.AddDays(0).Month.ToString("00")
      Dim _Day = _myDate.AddDays(-1).Day.ToString("00")
 
      Dim _myDate2 As String = _Year & "-" & _Month & "-" & _Day
      If detectionDate.Contains(_myDate2) = True Then
        myEllipse.Fill = New SolidColorBrush(Colors.Orange)
      ElseIf detectionDate.Contains(myDate) = True Then
        myEllipse.Fill = New SolidColorBrush(Colors.Red)
      Else
        myEllipse.Fill = New SolidColorBrush(Colors.Yellow)
      End If
 
      MapLayer.SetPosition(myEllipse, New Location(CDbl(myLatitude), CDbl(myLongitude)))
      myMap.Children.Add(myEllipse)
 
      AddHandler myEllipse.Tapped, Sub()
                                     myStackPanel.Visibility = Xaml.Visibility.Visible
                                   End Sub
 
      AddHandler myStackPanel.Tapped, Sub()
                                        myStackPanel.Visibility = Xaml.Visibility.Collapsed
                                      End Sub
    Next
  Catch
      DataShow()
  End Try
End Sub
  • Bing Maps上に地震の震源地を表示するWindowsアプリ

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています