Source Viewer-Grumap.razor.src

Powered by Google Code Prettify
戻る
        
@page "/grumap"
@using System.Xml.Linq
@using Microsoft.Extensions.Configuration
@inject IJSRuntime JSRuntime
@inject IConfiguration Config

<div style="display:flex;justify-content:center;align-items:center;flex-direction:column">
    <h2 style="text-align:center">グルメマップもどき</h2>
    <div style="padding-right:2em;width:100%;text-align:right"><span style="font-size:x-small;font-weight:bold">Presented by Sumomo Lab.</span></div>
    <div style="padding-right:2em;width:100%;display:flex;justify-content:right"><a href="http://webservice.recruit.co.jp/"><img src="http://webservice.recruit.co.jp/banner/hotpepper-s.gif" alt="ホットペッパー Webサービス" width="135" height="17" border="0" title="ホットペッパー Webサービス"></a></div>
</div>
<br/>
<a href="ShowCode?FileName=Grumap.razor.src&Return=grumap">本体ソース</a>&nbsp;
<br/>
<!-- MAPエリア -->
<div id="myMap" style="width:100%;height:600px">
</div>
<br/>
<hr/>
<!-- 検索範囲 変数をbindすることにより、相互に連動する -->
検索範囲:<select @bind="range">
    <option value="1">300m</option>
    <option value="2">500m</option>
    <option value="3">1km</option>
    <option value="4">2km</option>
    <option value="5">5km</option>
</select>
<button class="btn btn-primary" @onclick="btnRtv_Clicked">検索</button>
<br/>
検索種別:<br/>
@if (Genres != null) {  // ジャンル取得済みなら、ジャンル一覧を表示
    int cnt = 0;
    @foreach(var g in Genres) {
        if (cnt != 0 && (cnt % 5) == 0) {
            <br/>
        }
        <!-- 変数をbindすることにより、List中の項目の指定プロパティと連動させる -->
        <label style="width:200px;"><input type="checkbox" @bind="g.Checked"/>@g.Name</label>
        cnt++;
    }
    <br/>
    <span>緯度:</span><span>@Latitude</span><span>,経度:</span><span>@Longitude</span>
    <br/>
    <pre>@Message</pre>
}


@code{
    // Viewとの共有変数
    protected List<Genre> Genres;  // ジャンル一覧
    protected int range = 3;    // 検索範囲
    protected string Message;  // メッセージ
    protected double Latitude;  // 緯度
    protected double Longitude; // 経度
    // ローカル
    private string HpAPIBaseUrl = ""; // Hotpepper Web APIのベースURL
    private string APIKey = "";    // HotPepper Service ID
    private HttpClient htcli;

    /// <summary>
    /// 初期化完了時処理
    /// </summary>
    /// <returns></returns>
    protected override async Task OnInitializedAsync() {
        htcli = new HttpClient();
        // configファイルからAPIアクセス情報を取得
        APIKey = Config.GetSection("HotpepperAPI").GetValue<string>("APIKey");
        HpAPIBaseUrl = Config.GetSection("HotpepperAPI").GetValue<string>("BaseUrl");
        // ジャンル一覧をWeb APIで取得
        Genres = new List<Genre>();
        var xmlstr = await htcli.GetStringAsync($"{HpAPIBaseUrl}genre/v1/?key={APIKey}");
        XDocument doc = XDocument.Parse(xmlstr);
        XNamespace ns = "http://webservice.recruit.co.jp/HotPepper/";
        foreach(var ele in doc!.Root!.Elements(ns+"genre")) {
            Genres.Add(new Genre() {
                Code = ele.Element(ns+"code")!.Value.Replace("\n","").Replace("\r","").Trim(),
                Name = ele.Element(ns+"name")!.Value.Replace("\n","").Replace("\r","").Trim()
            });
        }
    }
    /// <summary>
    /// 画面表示完了時処理
    ///     Javascriptを呼び出すので、こちらで実行
    /// </summary>
    /// <param name="firstRender">最初の呼び出しか</param>
    /// <returns></returns>
    protected override async Task OnAfterRenderAsync(bool firstRender) {
        if (firstRender) {
            // MAPの初期化
            await JSRuntime.InvokeVoidAsync("BingMapLib.Functions.loadMap","myMap");
            // MAPクリック時の処理を設定(C#コード呼び出し)
            await JSRuntime.InvokeVoidAsync("BingMapLib.Functions.AttachEvents",
                    "click",
                    DotNetObjectReference.Create(this),
                    "OnMapClick"
            );
            // 現在地の取得
            await JSRuntime.InvokeVoidAsync("BingMapLib.Functions.GetCurrentPosition",
                DotNetObjectReference.Create(this),
                "GetLocationCompleted",
                "GetLocationFailed"
            );
        }
    }
    /// <summary>
    /// MAPクリック時の処理
    ///     Javascriptから呼び出される
    /// </summary>
    /// <param name="latitude">緯度</param>
    /// <param name="longitude">経度</param>
    /// <returns></returns>
    [JSInvokable]
    public async Task OnMapClick(double latitude, double longitude) {
        // 緯度経度のC#コード側への保存
        Latitude = latitude;
        Longitude = longitude;
        // Pushpinの追加
        await JSRuntime.InvokeVoidAsync("BingMapLib.Functions.AddPushpin",latitude,longitude,"検索開始位置","#8080ff");
        this.StateHasChanged();
    }
    /// <summary>
    /// 検索ボタンクリック時処理
    /// </summary>
    /// <returns></returns>
    protected async Task btnRtv_Clicked() {
        if (Latitude == 0) {
            Message = "検索開始位置が指定されていません。";
            return;
        }
        // URLの作成
        string url = $"{HpAPIBaseUrl}gourmet/v1/?key={APIKey}&lat={Latitude}&lng={Longitude}&range={range}&count=20";
        // チェックされたジャンルをパラメータに追加
        foreach(var g in Genres!) {
            if (g.Checked) {
                url += $"&genre={g.Code}";
            }
        }
        // Web APIを使用して、周辺の店舗を取得する
        string xml = await htcli.GetStringAsync(url);
        XDocument doc = XDocument.Parse(xml);
        XNamespace ns = "http://webservice.recruit.co.jp/HotPepper/";
        List<ShopInfo> Shops = new List<ShopInfo>();
        // 取得したXMLから情報をセット
        foreach(var ele in doc.Root!.Elements(ns+"shop")) {
            ShopInfo shop = new ShopInfo() {
                Name = ele.Element(ns+"name")!.Value.Replace("\n","").Replace("\r","").Trim(),
                Genre = ele.Element(ns+"genre")!.Element(ns+"name")!.Value.Replace("\n","").Replace("\r","").Trim(),
                OpenTime = ele.Element(ns+"open")!.Value.Replace("\n","").Replace("\r","").Trim(),
                Latitude = Convert.ToDouble(ele.Element(ns+"lat")!.Value.Replace("\n","").Replace("\r","").Trim()),
                Longitude = Convert.ToDouble(ele.Element(ns+"lng")!.Value.Replace("\n","").Replace("\r","").Trim()),
                Url = ele.Element(ns+"urls")!.Element(ns+"pc")!.Value.Replace("\r","").Trim()
            };
            Shops.Add(shop);
        }
        // 店舗マーカーをMAP上に表示
        await JSRuntime.InvokeVoidAsync("BingMapLib.Functions.ClearRestrans");
        int cnt = 1;
        foreach(var itm in Shops) {
            await JSRuntime.InvokeVoidAsync("BingMapLib.Functions.AddRestran",
                new {
                    latitude = itm.Latitude,
                    longitude = itm.Longitude,
                    color = "#ff0cc0",
                    name = itm.Name,
                    number = cnt.ToString(),
                    desc = $"営業時間:{itm.OpenTime}<br/>URL:<a href='{itm.Url}' target='_blank'>店舗ホームページ</a>"
                }
            );
            cnt++;
        }
        this.StateHasChanged();
    }
    /// <summary>
    /// 現在地取得完了
    /// </summary>
    /// <param name="e"></param>
    /// <returns></returns>
    [JSInvokable]
    public async Task GetLocationCompleted(GeoInfo e) {
        await JSRuntime.InvokeVoidAsync("BingMapLib.Functions.SetMapCenter",e.Coords!.Latitude,e.Coords!.Longitude);
        this.StateHasChanged();
    }
    /// <summary>
    /// 現在地取得失敗
    /// </summary>
    /// <param name="e"></param>
    [JSInvokable]
    public void GetLocationFailed(GeoError e) {
        Message = $"現在地取得エラー:{e.Code}:{e.Message}";
        this.StateHasChanged();
    }
    /// <summary>
    /// ジャンル情報
    /// </summary>
    public class Genre {
        /// <summary>
        /// ジャンルがチェックされているか(画面連動用)
        /// </summary>
        /// <value>チェック状態</value>
        public bool Checked { get; set; }
        /// <summary>
        /// ジャンルコード
        /// </summary>
        /// <value>ジャンルコード</value>
        public string Code { get; set; }
        /// <summary>
        /// ジャンル名
        /// </summary>
        /// <value>ジャンル名</value>
        public string Name { get; set; }
    }
    /// <summary>
    /// 店舗情報
    /// </summary>
    public class ShopInfo {
        /// <summary>
        /// 店舗名
        /// </summary>
        /// <value>店舗名</value>
        public string Name { get; set; }
        /// <summary>
        /// ジャンル名
        /// </summary>
        /// <value>ジャンル名</value>
        public string Genre {get; set; }
        /// <summary>
        /// 営業時間
        /// </summary>
        /// <value>営業時間</value>
        public string OpenTime { get; set; }
        /// <summary>
        /// 店舗ホームページURL
        /// </summary>
        /// <value>URL</value>
        public string Url { get; set; }
        /// <summary>
        /// 緯度
        /// </summary>
        /// <value>緯度</value>
        public double Latitude { get; set;}
        /// <summary>
        /// 経度
        /// </summary>
        /// <value>経度</value>
        public double Longitude { get; set; }
    }
    // 位置情報
    public class GeoInfo {
        public Coords Coords { get; set; }
        public long Timestamp { get; set; }
    }
    public class Coords {
        public double Latitude {get; set;}	// 緯度
        public double Longitude {get; set;}	// 経度
    }
    // エラー情報
    public class GeoError {
        public int Code { get; set; }
        public string Message { get; set; }
    }
}