atelier:mitsuba

i love UI/UX, Blend, XAML, Behavior, P5, oF, Web, Tangible Bits and Physical computing. なにかあればお気軽にご連絡ください。atelier@c-mitsuba.com

SilverlightとHTML5の融合

Silverlight Advent Calendar 2011 21日目の記事だよ!
http://atnd.org/events/22001

Silverlight Advent Calendar 2011 3回目ですね!(やりすぎ


Silverlight 1.0って触ったことありますか?


その昔、SLはJavaScriptで開発してたんだよ。
XAMLなんてサクラエディタで手書きしてたんだよ。
なんていうと、 Σ(・ω・ノ)ノ!な人がわりといます。



C#でかけるようになったんだって2.0からやねんで!(ばんばん!

で、ですね。SL 2.0の頃にはHTML5なんてものはなく、JSで出来ることなんてちょっとしたアニメーションをjQueryでぽちぽちやったり、XMLHTTPRequest叩いたりしてたもんですよ。
HTML+JSでリッチとか。。。なんて言われてたころはSilverlightが銀色に光輝いていたものです(しみじみ。。
今となってはHTML5がどんどん力をつけてます。でもまだまだSilverlightの画面の作りやすさには敵いません。
そこで!SL 2.0の頃に培われたJSのちからを今こそ復活させましょう!



今回はSL2.0で実装されたHTML Bridgeを使ってHTML5のGeolocation APIを叩いて、その値をSL4で表示しました。
出来上がりはこんな感じです。
http://c-mitsuba.com/temp/HTML5Geo2SL/HTML5Geo2SLTestPage.html



まずはHTML5+JSで位置情報を取得しましょう。

<script type="text/javascript">
function showLocation(position) {
  var latitude = position.coords.latitude;
  var longitude = position.coords.longitude;
  alert("Latitude : " + latitude + " Longitude: " + longitude);
}

function errorHandler(err) {
  if(err.code == 1) {
    alert("Error: Access is denied!");
  }else if( err.code == 2) {
    alert("Error: Position is unavailable!");
  }
}
function getLocation(){

   if(navigator.geolocation){
      // timeout at 60000 milliseconds (60 seconds)
      var options = {timeout:60000};
      navigator.geolocation.getCurrentPosition(showLocation, errorHandler, options);
   }else{
      alert("Sorry, browser does not support geolocation!");
   }
}
</script>

こんな感じのコードでgeoLocation()を実行すると、緯度経度が取れます。
ちょうどこのへんですね。
position.coords.latitude;
position.coords.longitude;

実際にTestPage.htmlは以下のように記述しました。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >

<head>
    <title>HTML5Geo2SL</title>
    <style type="text/css">
    html, body {
	    height: 100%;
	    overflow: auto;
    }
    body {
	    padding: 0;
	    margin: 0;
    }
    #silverlightControlHost {
	    height: 100%;
	    text-align:center;
    }
    </style>
    <script type="text/javascript" src="Silverlight.js"></script>
    <script type="text/javascript">
        function onSilverlightError(sender, args) {
            var appSource = "";
            if (sender != null && sender != 0) {
              appSource = sender.getHost().Source;
            }
            
            var errorType = args.ErrorType;
            var iErrorCode = args.ErrorCode;

            if (errorType == "ImageError" || errorType == "MediaError") {
              return;
            }

            var errMsg = "Silverlight アプリケーションのハンドルされないエラー " +  appSource + "\n" ;

            errMsg += "コード: "+ iErrorCode + "    \n";
            errMsg += "カテゴリ: " + errorType + "       \n";
            errMsg += "メッセージ: " + args.ErrorMessage + "     \n";

            if (errorType == "ParserError") {
                errMsg += "ファイル: " + args.xamlFile + "     \n";
                errMsg += "行: " + args.lineNumber + "     \n";
                errMsg += "位置: " + args.charPosition + "     \n";
            }
            else if (errorType == "RuntimeError") {           
                if (args.lineNumber != 0) {
                    errMsg += "行: " + args.lineNumber + "     \n";
                    errMsg += "位置: " +  args.charPosition + "     \n";
                }
                errMsg += "メソッド名: " + args.methodName + "     \n";
            }

            throw new Error(errMsg);
        }


        function getLocationButton() {

            if (navigator.geolocation) {
                // timeout at 60000 milliseconds (60 seconds)
                var options = { timeout: 60000 };
                navigator.geolocation.getCurrentPosition(showLocation, errorHandler, options);
            } else {
                alert("Sorry, browser does not support geolocation!");
            }
        }

        function showLocation(position) {
            var latitude = position.coords.latitude;
            var longitude = position.coords.longitude;


            slControl = document.getElementById('SilverlightControl');
            slControl.content.MySilverlightObject.HTML5Geolocation(latitude, longitude);
            //alert("Latitude : " + latitude + " Longitude: " + longitude);

        }

        function errorHandler(err) {
            if (err.code == 1) {
                alert("Error: Access is denied!");
            } else if (err.code == 2) {
                alert("Error: Position is unavailable!");
            }
        }

    </script>
</head>
<body>
    <div id='htmlControl'>
        <input id="Button1" type="button" value="HTML5による位置情報の取得" onclick="return getLocationButton()" />
    </div>

    <form id="form1" runat="server" style="height:100%">
    <div id="silverlightControlHost">
        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="50%" height="50%" id="SilverlightControl">
		  <param name="source" value="ClientBin/HTML5Geo2SL.xap"/>
		  <param name="onError" value="onSilverlightError" />
		  <param name="background" value="white" />
		  <param name="minRuntimeVersion" value="4.0.60310.0" />
		  <param name="autoUpgrade" value="true" />
		  <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.60310.0" style="text-decoration:none">
 			  <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Microsoft Silverlight の取得" style="border-style:none"/>
		  </a>
	    </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
    </form>
</body>
</html>


これだけだと位置情報を取得するボタンしかでないので、XAML書きますね。
せっかくなのでBing Mapも使いました。キーはとってないけど。
http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=2949

まずは参照に
Microsoft.Maps.MapControl.Common.dll
Microsoft.Maps.MapControl.dll
を追加します。

で、MainPage.xaml

<UserControl x:Class="HTML5Geo2SL.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:Map="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Latitude:"/>
                <TextBlock x:Name="Latitude" Text="0"/>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Longitude:"/>
                <TextBlock x:Name="Longitude" Text="0"/>
            </StackPanel>
        </StackPanel>
        <Map:Map x:Name="Map" d:LayoutOverrides="Width" Margin="0,36,0,0">
            <Map:Pushpin x:Name="pin" ToolTipService.ToolTip="HTML5Geo" />
        </Map:Map>
    </Grid>
</UserControl>

で、MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;
using Microsoft.Maps.MapControl;

namespace HTML5Geo2SL
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(Page_Loaded);
        }

        void Page_Loaded(object sender, RoutedEventArgs e)
        {
        	//JSからSLアプリを参照できるように名前をつける
            HtmlPage.RegisterScriptableObject("MySilverlightObject", this);
        }

        //JSで実行できるメソッドを明言する
        [ScriptableMember]
        public void HTML5Geolocation(double Lat, double Lon)
        {
            Latitude.Text = Lat.ToString();
            Longitude.Text = Lon.ToString();

            //MessageBox.Show(Lon.ToString());
            
            pin.Location = new Location(Lat, Lon);

            Map.Center = new Location(Lat, Lon);
        }
    }
}


C#の以下と

HtmlPage.RegisterScriptableObject("MySilverlightObject", this);

以下は

public void HTML5Geolocation(double Lat, double Lon){}

JSの以下に紐づいています。

slControl.content.MySilverlightObject.HTML5Geolocation(latitude, longitude);

簡単ですね!

これでJSのボタンをクリックすると、HTML5で位置情報を取得し、取得した位置情報を引数にC#のコードをJSから実行して、SLのPushpinとMapを操作することができます。

出来上がりはこんなかんじ

ボタンを押すと、Locationとっていい?て聞かれます。



SLの作りやすさとHTML5の先進さを混ぜるとこんなこともできちゃうんですねー
いい感じに住み分けができるといいなー。

JSかわいいよJSヾ(>ヮ<)ノ゙