CodeZine(コードジン)

特集ページ一覧

Silverlightで地図アプリを構築する

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2011/05/09 11:30
目次

XamMapにWCFサービスから取得した人口データをシンボルとして表示する

 XamMapにWCFサービスから取得した人口データをシンボルとして表示させます。さきほど都道府県境データをレイヤーとして表示させましたが、そのレイヤー上に、都道府県別に人口の多さに応じた円をシンボルとして表示させます。

画面側(XAML)の修正

 都道府県別に人口の多さに応じた円をシンボルとして表示させるために、MainPage.xamlのXamMapを

 次のように修正します。

MainPage.xaml
<UserControl x:Class="XamMapSample.MainPage" (略)>
<Grid x:Name="LayoutRoot" Background="White">
        <ig:XamMap Name="xamMap">
            <ig:XamMap.Layers>
              <!-- 追加:Importedイベントのハンドラ  -->
              <ig:MapLayer Name="Japan" Imported="Japan_Imported">
                    <ig:MapLayer.Reader>
                        <!-- 追加:Value=Population; ToolTip=Name -->
                        <ig:SqlShapeReader DataMapping="Data=Geom;Value=Population; ToolTip=Name"/>
                    </ig:MapLayer.Reader>

                    <!-- 追加:表示するシンボルのテンプレート -->
                    <ig:MapLayer.ValueTemplate>
                        <DataTemplate>
                            <Grid Width="{Binding Path=Value}" Height="{Binding Path=Value}">
                                <ToolTipService.ToolTip>
                                    <StackPanel>
                                        <TextBlock Text="{Binding Path=ToolTip, StringFormat='県名:{0}'}" />
                                        <TextBlock Text="{Binding Path=Value, StringFormat='人口:{0:#,##0}(十万人)'}" />
                                    </StackPanel>
                                </ToolTipService.ToolTip>
                                <Ellipse Fill="Aqua" Opacity="0.7"/>
                            </Grid>
                        </DataTemplate>
                    </ig:MapLayer.ValueTemplate>
                </ig:MapLayer>
            </ig:XamMap.Layers>
            <ig:MapNavigationPane x:Name="navi" Margin="10" VerticalAlignment="Top" ig:XamDock.Edge="InsideRight" />
        </ig:XamMap>
    </Grid>
</UserControl>

 このコードのポイントは3つあります。第1のポイントは、MapLayer要素にImportedイベントのハンドラを追加している点です。このイベントは、対象のレイヤーがインポートされたときに発生し、その際に地図上に表示するシンボルを設定することができます。

 第2のポイントは、SqlShapeReader要素のDataMappingプロパティに、「Value=Population; ToolTip=Name」を追加している点です。Value=Populationでは、シンボルに表示する際に利用する人口数を設定し、またToolTip=Nameではツールチップに表示する都道府県名を設定しています。

 第3のポイントは、表示するシンボルのテンプレートであるMapLayer.ValueTemplate要素を追加している点です。テンプレートには、都道府県名と人口を表示するためのツールチップ用のStackPanelと、人口数を円の大きさであらわすためのEllipseが定義されています。

 また、このStackPanelとEllipseは、Grid内に定義されています。そのGridのWidth(幅)とHeight(高さ)は、{Binding Path=Value}と人口数がバインドされています。これによって、人口数に応じたシンボルを表示することができるわけです。

コードビハインド側の修正

 続いて、画面側(XAML)のテンプレートに定義したシンボルに値を設定するために、MainPage.xaml.csを次のように修正します。

MainPage.xaml.cs
 (略)
namespace XamMapSample
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            (略)
        }
        
        //人口の単位(十万人)
        const double PoplationUnit = 100000;

        private void Japan_Imported(object sender, MapLayerImportEventArgs e)
        {
            var layer = sender as MapLayer;
            foreach (MapElement ele in layer.Elements.Where(t => t!=null))
            {
                //対象エリア(都道府県)の最大面積のポリゴンの
                //中心点を表示するシンボルの起点して設定する
                var plines = (ele as SurfaceElement).Polylines;
                var ordered = plines.OrderByDescending(c => c.GetPolygonArea());
                var poly = ordered.ElementAt(0);
                ele.SymbolOrigin = poly.GetCentroid();

                //人口の値を単位で割った値にする
                ele.Value = ele.Value / PoplationUnit;
            }
        }
    }
}

 さきほど、画面側(XAML)で定義した、レイヤーのImportedイベントのハンドラのJapan_Importedを実装しています。ポイントは2つあります。

 第1に、シンボルの中心点の求める方法です。レイヤー上のMapElement要素から、都道府県境をあらわすポリゴンを各都道府県毎に取得します。その際、北海道や鹿児島のように、複数のポリゴンからなる都道府県があり得るため、その中で最大の面積を持つポリゴンを取得します。そのポリゴンの中心点を、シンボルの中心点として設定しています。

 第2に、シンボルの値に人口を設定する方法です。画面側(XAML)では、人口の値が、そのままシンボルの幅と高さに設定されるようにバインドされていました。その場合、たとえば東京の1300万という値が、そのままシンボルに幅と高さに設定されると、画面上表示しきれない大きさになってしまいます。そこで、人口の値を画面上の程よい大きさで表示するため、人口を十万人単位で割った値として設定しています。

ポリゴン計算ユーティリティを追加

 最後に、Silverlightアプリケーションプロジェクトに、ポリゴン計算のためのメソッドを定義した、ユーティリティを追加します。

Util.cs
using System;
using System.Windows;
using System.Collections.Generic;

namespace XamMapSample
{
    public static class Util
    {
        //ポリゴンの符号付きの面積を取得する
        public static double GetPolygonSignedArea(this IList<Point> c)
        {
            int n = c.Count;
            double a = 0.0;

            if (n > 2)
            {
                for (int k = n - 2, j = n - 1, i = 0; i < n; k = j, j = i, ++i)
                {
                    a += c[j].X * (c[i].Y - c[k].Y);
                }
            }
            return a;
        }

        //ポリゴンの符号の面積を取得する
        public static double GetPolygonArea(this IList<Point> c)
        {
            return Math.Abs(0.5 * GetPolygonSignedArea(c));
        }

        //ポリゴンの中心点を取得する
        public static Point GetCentroid(this IEnumerable<Point> points)
        {
            double x = 0.0;
            double y = 0.0;
            double c = 0.0;

            foreach (Point point in points)
            {
                x += point.X;
                y += point.Y;
                c += 1.0;
            }

            return new Point(x / c, y / c);
        }
    }
}

 このユーティリティには、大きく次の2つのメソッドが定義されています。

  • ポリゴンの面積を取得する
  • ポリゴンの中心点を取得する

 それぞれのメソッドで行っている計算方法については、本稿の範囲を超えますので解説を避けます。ここでは、ポリゴンから値を計算するメソッドが拡張メソッドとして定義されていて、それをさきほどのレイヤーのImportedイベントのハンドラで利用している、という点だけ理解いただければ大丈夫です。

 以上で、XamMapにWCFサービスから取得した人口データをシンボルとして表示できるようになりました。さっそく実行してみましょう。次の画像のように都道府県の地図上に人口が円のシンボルとして表示されれば成功です。またシンボルにマウスオーバーすると、都道府県名と人口数がツールチップとして表示されます。

まとめ

 本稿では、XamMapの利用方法を、都道府県の白地図に人口のデータを表示するサンプルのアプリケーションを開発しながら解説しました。XamMapを利用すると、地図を利用したアプリケーションが簡単に開発できることがご理解いただけたのではないでしょうか。本稿が読者の皆様のアプリケーション開発にお役にたてば筆者として、それ以上うれしいことはありません。

参考リンク



  • LINEで送る
  • このエントリーをはてなブックマークに追加

あなたにオススメ

著者プロフィール

  • 菅原 英治(スガワラ エイジ)

    シグマコンサルティング株式会社 取締役副社長。SIerでのSE勤務を経て起業。「ジョイ・オブ・プログラミング」をモットーにIT業界を明るく楽しくしたい。

バックナンバー

連載:Infragistics NetAdvantageチュートリアル

もっと読む

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5