<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
		xmlns:xhtml="http://www.w3.org/1999/xhtml"
>

<channel>
	<title>クレコ &#187; JavaScript</title>
	<atom:link href="http://creco.net/tag/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://creco.net</link>
	<description>East or west, home is best.</description>
	<lastBuildDate>Fri, 27 Nov 2009 13:26:56 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/tag/javascript/feed/" />
		<item>
		<title>Google Maps API V3 と Gears Geolocation API 使って Android のブラウザで現在位置情報を取得する</title>
		<link>http://creco.net/2009/06/11/google_maps_api_v3_with_gears_geolocation_api/</link>
		<comments>http://creco.net/2009/06/11/google_maps_api_v3_with_gears_geolocation_api/#comments</comments>
		<pubDate>Thu, 11 Jun 2009 07:49:48 +0000</pubDate>
		<dc:creator>inagaki</dc:creator>
				<category><![CDATA[作ってみた]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Geolocation]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[GPS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ジオポ]]></category>

		<guid isPermaLink="false">http://creco.net/2009/06/11/google_maps_api_v3_with_gears_geolocation_api/</guid>
		<description><![CDATA[先日のGoogle Developer Day 2009 にて、GoogleさんからAndroid携帯である GDD Phone をいただいたので、早速Androidライフを楽しんでる毎日です。素敵なオモチャをありがとう [...]]]></description>
			<content:encoded><![CDATA[<p>先日の<a href="http://code.google.com/intl/ja/events/developerday/2009/home.html">Google Developer Day 2009</a> にて、GoogleさんからAndroid携帯である GDD Phone をいただいたので、早速Androidライフを楽しんでる毎日です。素敵なオモチャをありがとうございます！</p>
<p>ネイティブアプリの地図でGoogle Latitudeをいぢりたおしたりしてるんですが、地図大好きっ子としては自分で位置情報を活用したいところ。</p>
<p>そんな折、ジークルーの佐々木さんから</p>
<blockquote><p>@<a href="http://twitter.com/shinagaki">shinagaki</a> 自分が今日どこを歩いたかが履歴でMapに表示されるAndroidアプリって知らない？</p>
</blockquote>
<p>って遠まわしに作れって言われた気がしたので、Android界隈の位置情報について調べてみる。</p>
<p> <span id="more-535"></span>
</p>
<h3>Androidで位置情報を取得するにはどうすんの？</h3>
<p>調べてみたけど、ネイティブアプリでの情報しかなくて、実装が楽にできそうなブラウザでのAPI動作状況についてのサンプル例がなかった。</p>
<p>ネイティブアプリでは、<a href="http://code.google.com/intl/ja/android/add-ons/google-apis/maps-overview.html">Maps External Library &#8211; Google Projects for Android</a> に情報あるから、ネイティブアプリ作る人は見るといいよ。僕も、あとで見る。</p>
<p>Androidの搭載しているブラウザに、iPhone OS 3.0 のSafariブラウザみたくW3CのGeolocation APIをサポートして、ブラウザからGPS位置情報を取得できることを期待してたんですが、結果から言うとダメ。</p>
<p>ですが！Androidのブラウザ「Chrome Lite」はGoogle Gearsを搭載しているため、ひょっとしたらGearsのGeolocation API使えるかも！？ と思って実験。</p>
<h4>Google Gears での位置情報取得</h4>
<p><a href="http://code.google.com/intl/ja/apis/gears/api_geolocation.html">Geolocation API &#8211; Gears API &#8211; Google Code</a></p>
<p>サンプルのとおりに、 <strong>gears_init.js</strong> をおいて、</p>
<pre class="csharpcode">&lt;script type=<span class="str">&quot;text/javascript&quot;</span> src=<span class="str">&quot;gears_init.js&quot;</span>&gt;&lt;/script&gt;
&lt;script type=<span class="str">&quot;text/javascript&quot;</span>&gt;
<span class="kwrd">var</span> geo = google.gears.factory.create(<span class="str">'beta.geolocation'</span>);

<span class="kwrd">function</span> updatePosition(position) {
  alert(<span class="str">'Current lat/lon is: '</span> + position.latitude + <span class="str">','</span> + position.longitude);
}

<span class="kwrd">function</span> handleError(positionError) {
  alert(<span class="str">'Attempt to get location failed: '</span> + positionError.message);
}

geo.getCurrentPosition(updatePosition, handleError);
&lt;/script&gt;</pre>
<p>と書くだけで、位置情報取得できた！簡単。</p>
<h4>Google Maps API V3 を使って地図表示</h4>
<p>それに、Google Maps API V3 を組み合わせる。<br />
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</p>
<p><a href="http://code.google.com/intl/ja/apis/maps/documentation/v3/">The Google Maps API V3 &#8211; Google Maps JavaScript API V3 &#8211; Google Code</a></p>
<p>Google Maps API V3 ってのは、今までのMaps APIで効率が悪かったり、スマートフォンに最適化されてなかった部分を改善するため、一から書き直したAPIで、今までのMaps APIと書き方が異なる。</p>
<p>んでも、やってることは同じだし、まだ V3のほうができることが少ないので理解は早いと思います。</p>
<p>サンプルとしては、</p>
<pre class="csharpcode">&lt;script type=<span class="str">&quot;text/javascript&quot;</span> src=<span class="str">&quot;http://maps.google.com/maps/api/js?sensor=false&quot;</span>&gt;&lt;/script&gt;
&lt;script type=<span class="str">&quot;text/javascript&quot;</span>&gt;
  <span class="kwrd">function</span> initialize() {
    <span class="kwrd">var</span> myLatlng = <span class="kwrd">new</span> google.maps.LatLng(-34.397, 150.644);
    <span class="kwrd">var</span> myOptions = {
      zoom: 8,
      center: myLatlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    }
    <span class="kwrd">var</span> map = <span class="kwrd">new</span> google.maps.Map(document.getElementById(<span class="str">&quot;map_canvas&quot;</span>), myOptions);
  }
&lt;/script&gt;
&lt;/head&gt;
&lt;body style=<span class="str">&quot;margin:0px; padding:0px;&quot;</span> onload=<span class="str">&quot;initialize()&quot;</span>&gt;
  &lt;div id=<span class="str">&quot;map_canvas&quot;</span> style=<span class="str">&quot;width:100%; height:100%&quot;</span>&gt;&lt;/div&gt;
&lt;/body&gt;</pre>
<p>これで、全画面の地図表示。</p>
<ul>
<li>APIキーがいらない → Open Socialなアプリ作る場合に問題だった、ドメインごとにAPIキー発行する手間がなくなる。 </li>
<li>スマートフォンに対応 → iPhoneとAndroidのUIにあわせてコントローラーを配置してくれるし、地図の描画までが早い！ </li>
</ul>
<p>だから、iPhoneのネイティブアプリ作ってて地図周りだけ、UIWebView使ってるっていう人も恩恵あるんじゃないかな？</p>
<h3>実際に現在位置をTwitterにPOSTするJavaScriptを作ってみた<br />
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</h3>
<p><a href="http://inagaki.co.uk/test/gears.html">Google Maps API V3 with Gears Geolocation API</a> ＠inagaki.co.uk</p>
<p>実際にAndroidで試してみてください。</p>
<p>中身はコチラ。</p>
<pre class="csharpcode">&lt;html&gt;
&lt;head&gt;
&lt;meta name=<span class="str">&quot;viewport&quot;</span> content=<span class="str">&quot;initial-scale=1.0, user-scalable=no&quot;</span> /&gt;
&lt;meta http-equiv=<span class="str">&quot;content-type&quot;</span> content=<span class="str">&quot;text/html; charset=UTF-8&quot;</span>/&gt;
&lt;title&gt;Google Maps API V3 with Gears Geolocation API&lt;/title&gt;
&lt;script type=<span class="str">&quot;text/javascript&quot;</span> src=<span class="str">&quot;http://maps.google.com/maps/api/js?sensor=false&quot;</span>&gt;&lt;/script&gt;
&lt;script type=<span class="str">&quot;text/javascript&quot;</span> src=<span class="str">&quot;gears_init.js&quot;</span>&gt;&lt;/script&gt;
&lt;script type=<span class="str">&quot;text/javascript&quot;</span>&gt;

<span class="rem">/*</span>
<span class="rem"> * GeoPo Encode in JavaScript</span>
<span class="rem"> * @author : Shintaro Inagaki</span>
<span class="rem"> * @param location (Object)</span>
<span class="rem"> * @return geopo (String)</span>
<span class="rem"> */</span>
<span class="kwrd">function</span> geopoEncode(location){
    <span class="rem">// 64characters (number + big and small letter + hyphen + underscore)</span>
    <span class="kwrd">var</span> chars = <span class="str">&quot;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_&quot;</span>;

    <span class="kwrd">var</span> geopo = <span class="kwrd">new</span> String();
    <span class="kwrd">var</span> lat = parseFloat(location.lat); <span class="rem">// Parse as float</span>
    <span class="kwrd">var</span> lng = parseFloat(location.lng); <span class="rem">// Parse as float</span>
    <span class="kwrd">var</span> scale = parseInt(location.scale); <span class="rem">// Parse as int</span>

    <span class="rem">// Change a degree measure to a decimal number</span>
    lat = (lat + 90) / 180 * Math.pow(8, 10);
    lng = (lng + 180) / 360 * Math.pow(8, 10);

    <span class="rem">// Compute a GeoPo code from head and concatenate</span>
    <span class="kwrd">for</span>(<span class="kwrd">var</span> i = 0; i &lt; scale; i++) {
        geopo = geopo + chars.substr(Math.floor(lat / Math.pow(8, 9 - i) % 8) + Math.floor(lng / Math.pow(8, 9 - i) % 8) * 8, 1);
    }
    <span class="kwrd">return</span> geopo;
}

<span class="kwrd">var</span> geo = google.gears.factory.create(<span class="str">'beta.geolocation'</span>);

<span class="kwrd">function</span> displayMap(position) {
    <span class="kwrd">var</span> geocoder = <span class="kwrd">new</span> google.maps.Geocoder();
    <span class="kwrd">var</span> latLng = <span class="kwrd">new</span> google.maps.LatLng(position.latitude,position.longitude);
    <span class="kwrd">var</span> options = {
        zoom: 15,
        center: latLng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    }
    <span class="kwrd">var</span> map = <span class="kwrd">new</span> google.maps.Map(document.getElementById(<span class="str">&quot;map_canvas&quot;</span>), options);

    <span class="kwrd">var</span> geocodeAddress;

    <span class="kwrd">var</span> infowindow = <span class="kwrd">new</span> google.maps.InfoWindow();

    <span class="kwrd">var</span> marker = <span class="kwrd">new</span> google.maps.Marker({
        position: latLng,
        map: map,
        title:<span class="str">&quot;You are here.&quot;</span>
    });

    <span class="rem">// geopo</span>
    <span class="kwrd">var</span> location = <span class="kwrd">new</span> Object();
    location.lat = position.latitude;
    location.lng = position.longitude;
    location.scale = 7;

    <span class="kwrd">var</span> geopo = geopoEncode(location);

    <span class="kwrd">if</span> (geocoder) {
        geocoder.geocode({<span class="str">'latLng'</span>: latLng}, <span class="kwrd">function</span>(results, status) {
            <span class="kwrd">if</span> (status == google.maps.GeocoderStatus.OK) {
                <span class="kwrd">for</span>(i=1;i&lt;results.length;i++){
                    <span class="kwrd">if</span> (results[i].types.length &gt;= 2 &amp;&amp; results[i].types[1] == <span class="str">&quot;political&quot;</span>) {
                        <span class="kwrd">if</span>(results[i].formatted_address.indexOf(<span class="str">&quot;日本&quot;</span>) != -1){
                            geocodeAddress = results[i].formatted_address.substring(2);
                        }<span class="kwrd">else</span>{
                            geocodeAddress = results[i].formatted_address;
                        }
                        <span class="kwrd">break</span>;
                    }
                }
                <span class="kwrd">if</span>(geocodeAddress){
                    infowindow.set_content(<span class="str">'&lt;strong&gt;現在地：&lt;/strong&gt;&lt;br /&gt;&lt;span style=&quot;font-size:80%&quot;&gt;'</span>+geocodeAddress+<span class="str">'&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;GeoPo：&lt;/strong&gt;&lt;br /&gt;&lt;span style=&quot;font-size:80%&quot;&gt;http://geopo.at/'</span>+geopo+<span class="str">'&lt;/span&gt;&lt;hr /&gt;&lt;a href=&quot;http://twitter.com/home?status='</span>+encodeURIComponent(<span class="str">' L:'</span>+geocodeAddress+<span class="str">' http://geopo.at/'</span>+geopo)+<span class="str">'&quot; target=&quot;twitter&quot;&gt;TwitterにPOSTする&lt;/a&gt;'</span>);
                    infowindow.open(map, marker);
                } <span class="kwrd">else</span>{
                    alert(<span class="str">&quot;現在地が取得できませんでした＞＜&quot;</span>);
                }
            } <span class="kwrd">else</span> {
                alert(<span class="str">&quot;Geocoder failed due to: &quot;</span> + status);
            }
        });
    }

    google.maps.<span class="kwrd">event</span>.addListener(marker, <span class="str">'click'</span>, <span class="kwrd">function</span>() {
        infowindow.open(map,marker);
    });
}

<span class="kwrd">function</span> handleError(positionError) {
    alert(<span class="str">'Attempt to get location failed: '</span> + positionError.message);
}

geo.getCurrentPosition(displayMap, handleError);

&lt;/script&gt;
&lt;/head&gt;
&lt;body style=<span class="str">&quot;margin:0px; padding:0px;&quot;</span>&gt;
  &lt;div id=<span class="str">&quot;map_canvas&quot;</span> style=<span class="str">&quot;width: 100%; height: 100%;&quot;</span>&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>&#160;</p>
<h3>こんな風に現在位置が取れるよ<br />
<style type="text/css">
<p>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
</h3>
<h4>１．さきほどのURLにアクセスする</h4>
<p><a href="http://creco.net/wp-content/uploads/device01.png" rel="lightbox[535]"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="device01" border="0" alt="device01" src="http://creco.net/wp-content/uploads/device01-thumb.png" width="162" height="242" /></a></p>
<p>すると、Gearsで「現在地情報にアクセス」しますかというメッセージがでるので、OKを押してください。ドメインごとの許可ですかね？</p>
<h4>２． 現在地の地図を表示</h4>
<p><a href="http://creco.net/wp-content/uploads/device02.png" rel="lightbox[535]"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="device02" border="0" alt="device02" src="http://creco.net/wp-content/uploads/device02-thumb.png" width="162" height="242" /></a> </p>
<p>Gearsからの位置情報をMaps API V3で地図表示。ちゃんと、拡大縮小コントローラーもAndroidなUIになってる。</p>
<p>そして、Maps API V3の逆ジオコーディングを使って、現在住所を取ってくる。</p>
<p>ついでに、GeoPoのエンコードもしてるよ！</p>
<p>一番下のリンクがTwitterにポストするためのリンク。</p>
<h4>３．TwitterにPOST内容を渡す</h4>
<p><a href="http://creco.net/wp-content/uploads/device03.png" rel="lightbox[535]"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="device03" border="0" alt="device03" src="http://creco.net/wp-content/uploads/device03-thumb.png" width="162" height="242" /></a> </p>
<p>http://twitter.com/home/?status=[ポスト内容] で渡すことができるから、単純に URLエンコードしたものを渡してるだけ。</p>
<p>ただ、このようなTwitterのパラメータ渡しは、Twitterの表示モードがモバイルになってると無効になるみたいなので、あらかじめスタンダードに変更しておいてください。</p>
<h3>ブラウザでのGeolocation APIについて</h3>
<p>実は、Google Gearsに対応していれば、ChromeとかFirefox（要アドオン）でも上記のURLで現在地の位置情報が取得できる。</p>
<p>正確にいうと、IPから推測した位置情報なので正しくはないかもしれないけど、JavaScriptだけの実装で簡易的に位置情報が取れるのは素敵ですね。</p>
<p>将来的には、W3CのGeolocation APIが載って、開発者側はハードウェア、ソフトウェアの差異を何も考えなくて位置情報を使ったコンテンツに注力できるっていう世界になってくれると幸せです。</p>
<p>Windows 7 では、OSレベルにGeolocation APIがあるそうなので、そちらも楽しみ… その前にIEをなんとかしてｋ（ｒｙ</p>
]]></content:encoded>
			<wfw:commentRss>http://creco.net/2009/06/11/google_maps_api_v3_with_gears_geolocation_api/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/2009/06/11/google_maps_api_v3_with_gears_geolocation_api/" />
	</item>
		<item>
		<title>ジオポの符号化、復号化をいろんな言語で書いてみる</title>
		<link>http://creco.net/2009/03/05/write_codes_in_variaous_languages/</link>
		<comments>http://creco.net/2009/03/05/write_codes_in_variaous_languages/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 08:55:22 +0000</pubDate>
		<dc:creator>inagaki</dc:creator>
				<category><![CDATA[日記]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[エクセル]]></category>
		<category><![CDATA[ジオポ]]></category>

		<guid isPermaLink="false">http://creco.net/2009/03/05/write_codes_in_variaous_languages/</guid>
		<description><![CDATA[位置情報をいくら短縮して色んなことに応用できるといっても、ユーザーが使ってくれるまでの敷居が高い（今のブラウザ経由の符号化じゃ、ダメってこと）とどうしようもない。
そんな理由で、まずはユーザーが接するアプリケーションの開 [...]]]></description>
			<content:encoded><![CDATA[<p>位置情報をいくら短縮して色んなことに応用できるといっても、ユーザーが使ってくれるまでの敷居が高い（今のブラウザ経由の符号化じゃ、ダメってこと）とどうしようもない。</p>
<p>そんな理由で、まずはユーザーが接するアプリケーションの開発者サイドにジオポ実装を働きかけていきたい。そのためにも、具体的なサンプルコードをプログラミング苦手な僕が書いてみた。</p>
<p>と、その前に&#8230;   <br />ジオポが<a href="http://netafull.net/" target="_blank">ネタフル</a>で紹介されたよ！    <br /><a href="http://netafull.net/tech/029580.html" target="_blank">位置情報を短縮したURLに変換するウェブサービス「ジオポ」</a></p>
<p>スクリーンショット付きで丁寧に紹介していただきありがとうございます。モチベーションあがりました！</p>
<p> <span id="more-129"></span><br />
<h4>実装するアルゴリズム</h4>
<p><a href="http://geopo.at/intl/ja/developer/" target="_blank">ジオポ 開発者向け情報</a>にも書いたんだけど、ジオポの符号化はいろんな方法が考えられる。</p>
<p>その中でも、一番わかりやすいと思われる方法を各サンプルコードで実装することにする。</p>
<blockquote><h6>ジオポの符号化の実装</h6>
<p>ジオポの符号化方法ですが、こちらで紹介する方法以外にもアルゴリズム（8進数化してビット演算など）はあると思います。ここでは、一番わかりやすいアルゴリズムを紹介します。また、文字ではわかりにくいと思いますので、実際にいろいろな言語で実装したコードは、<a href="http://geopo.at/intl/ja/developer/#appendix">付録</a>をご覧ください。</p>
<p>変換する緯度・経度は度数法での度（D）表記での数値です。もし、度分（DM）表記や度分秒（DMS）表記の場合は、前もって度へと変換してください。     <br />また、南緯と西経はそれぞれマイナス値となります。 </p>
<p>緯度・経度からジオポへの符号化を実装するには、まず度数法で与えられる緯度・経度を十進数に変換します。     <br />緯度と経度をそれぞれ90と180を足して正の値とします。それから、それぞれ90と180で割り、0から1までの値になります。最後に、8の10乗をかけます。 </p>
<p>続いて、十進数化した緯度・経度がジオポ符号でのどのエリアにあたるかを算出します。     <br />緯度は、8を9から縮尺を引いた回数だけ乗じた数字で割ってやり、さらに、その数値を8で割ったあまりを取り出します。経度も同様に、8を9から縮尺を引いた回数だけ乗じた数字で割ってやり、さらに、その数値を8で割ったあまりを取り出し、経度には8をかけてやります。その2つの数値を足すと0から63の数値となり、それに対応する文字がジオポ符号ということになります。 </p>
<p>次の符号を上のルーチンを繰り返しますが、8を9から縮尺を引いた回数だけ乗じた数字という部分が変化する点に注意してください。この繰り返す回数により、ジオポコードの縮尺（Scale）を決定することができます。 </p>
<h6>復号化（デコード）</h6>
<p>復号化する方法は符号化の逆をすることで実装できます（ジオポコードは可逆性を持ちます）。 </p>
<p>ただし、ジオポは小縮尺にも対応しているため、小縮尺になるほど符号化した位置情報との誤差が大きくなります。その誤差をできるだけ平均にするため、緯度・経度をエリアの代表緯度・経度（エリアの真ん中の緯度・経度）へと変換する式が含まれています。 </p>
<p>ジオポをクライアントソフト側で独自に復号化して緯度・経度を取り出したい場合は、ジオポURLからジオポコードを抽出する必要があります。     <br />下記の正規表現を用いれば、ジオポコードを抽出することができます。 </p>
</blockquote>
<ul>
<li>四則演算</li>
<li>forループ</li>
<li>べき乗、切り捨て、余り の数学関数</li>
<li>文字列の長さ、指定したサイズでの文字列の切り出し、文字列の中にある文字の位置 の文字列関数</li>
</ul>
<p>キーとなる所はこんだけで、各言語にある関数などを言語間の違いに注意して実装してみる。</p>
<h4>実際に実装</h4>
<h5>JavaScript</h5>
<p>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b44dd511-e4bb-4235-8664-baba02e474ba" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="js">/*
 * GeoPo Encode in JavaScript
 * @author : Shintaro Inagaki
 * @param location (Object)
 * @return geopo (String)
 */
function geopoEncode(location){
	// 64characters (number + big and small letter + hyphen + underscore)
	var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";

	var geopo = new String();
	var lat = parseFloat(location.lat); // Parse as float
	var lng = parseFloat(location.lng); // Parse as float
	var scale = parseInt(location.scale); // Parse as int

	// Change a degree measure to a decimal number
	lat = (lat + 90) / 180 * Math.pow(8, 10);
	lng = (lng + 180) / 360 * Math.pow(8, 10);

	// Compute a GeoPo code from head and concatenate
	for(var i = 0; i &lt; scale; i++) {
		geopo = geopo + chars.substr(Math.floor(lat / Math.pow(8, 9 - i) % 8) + Math.floor(lng / Math.pow(8, 9 - i) % 8) * 8, 1);
	}
	return geopo;
}

/*
 * GeoPo Decode in JavaScript
 * @author : Shintaro Inagaki
 * @param geopo (String)
 * @return location (Object)
 */
function geopoDecode(geopo){
	// 64characters (number + big and small letter + hyphen + underscore)
	var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";

	var location = new Object();
	var lat = 0;
	var lng = 0;
	var scale = geopo.length; // Scale is length of GeoPo code
	var order = 0;

	for (var i = 0; i &lt; scale; i++) {
		// What number of character that equal to a GeoPo code (0-63)
		order = chars.indexOf(geopo.substr(i, 1));
		// Lat/Lng plus geolocation value of scale
		lat = lat + Math.floor(order % 8) * Math.pow(8, 9 - i);
		lng = lng + Math.floor(order / 8) * Math.pow(8, 9 - i);
	}

	// Change a decimal number to a degree measure, and plus revised value that shift center of area
	location.lat = lat * 180 / Math.pow(8, 10) + 180 / Math.pow(8, scale) / 2 - 90;
	location.lng = lng * 360 / Math.pow(8, 10) + 360 / Math.pow(8, scale) / 2 - 180;
	location.scale = scale;

	return location;
}		</pre>
</div>
<p>僕はジオポを最初にJavaScriptで作ったので、いわばこれが原型。</p>
<p>パラメーターがString型でそのまま入ってくるといけないので、最初に<strong>parseFloat()</strong>と<strong>parseInt()</strong>でそれぞれ型を決めてやる。</p>
<p>そして、べき乗には<strong>Math.pow()</strong>、切り捨てには<strong>Math.floor()</strong>という数学関数があるので利用。</p>
<p>文字列。String.<strong>length</strong>は文字の長さ。JavaScriptの文字列の結合は<strong>+</strong>で、String.<strong>substr()</strong>メソッドによって文字列を切り出してやる。文字列の中にある文字の位置を取ってくるのは String.<strong>indexOf()</strong>メソッド。</p>
<p>JavaScriptはTry&amp;Errorがしやすいから、実装の基本にするのに向いてるのかも。amachangさんが言ってたように、ブラウザさえあればどこでもプログラミングできるメリットもあるしね。</p>
<h5>PHP</h5>
<p><div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:6db8bab2-2b9b-497a-8f56-ea95895bede1" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="php">/*
 * GeoPo Encode in PHP
 * @author : Shintaro Inagaki
 * @param $location (Array)
 * @return $geopo (String)
 */
function geopoEncode($location) {
	// 64characters (number + big and small letter + hyphen + underscore)
	$chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";

	$geopo = "";
	$lat = $location['lat'];
	$lng = $location['lng'];
	$scale = $location['scale'];

	// Change a degree measure to a decimal number
	$lat = ($lat + 90) / 180 * pow(8, 10);
	$lng = ($lng + 180) / 360 * pow(8, 10);

	// Compute a GeoPo code from head and concatenate
	for($i = 0; $i &lt; $scale; $i++) {
		$geopo .= substr($chars, floor($lat / pow(8, 9 - $i) % 8) + floor($lng / pow(8, 9 - $i) % 8) * 8, 1);
	}
	return $geopo;
}		

/*
 * GeoPo Decode in PHP
 * @author : Shintaro Inagaki
 * @param $geopo (String)
 * @return $location (Array)
 */
function geopoDecode($geopo) {
	// 64characters (number + big and small letter + hyphen + underscore)
	$chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
	// Array for geolocation
	$location = array ();

	for ($i = 0; $i &lt; strlen($geopo); $i++) {
		// What number of character that equal to a GeoPo code (0-63)
		$order = strpos($chars, substr($geopo, $i, 1));
		// Lat/Lng plus geolocation value of scale
		$location['lat'] = $location['lat'] + floor($order % 8) * pow(8, 9 - $i);
		$location['lng'] = $location['lng'] + floor($order / 8) * pow(8, 9 - $i);
	}

	// Change a decimal number to a degree measure, and plus revised value that shift center of area
	$location['lat'] = $location['lat'] * 180 / pow(8, 10) + 180 / pow(8, strlen($geopo)) / 2 - 90;
	$location['lng'] = $location['lng'] * 360 / pow(8, 10) + 360 / pow(8, strlen($geopo)) / 2 - 180;
	$location['scale'] = strlen($geopo);

	return $location;
}		</pre>
</div>
<p>なんちゃってPerlerからPHPに移行してもう何年も経つけど、やっぱりPHPが好き。未だに知らない関数ばかりだけどね ＞＜</p>
<p>べき乗は<strong>pow()</strong>、切り捨ては<strong>floor()</strong>。文字列の長さは<strong>strlen()</strong>、文字列の切り出しは<strong>substr()</strong>、文字列の中にある文字の位置は<strong>strpos()</strong>。</p>
<p>こういう関数あるかなぁってマニュアル見ると、大抵あるから、CHM形式のマニュアルが手元にあると便利です。</p>
<h5>Objective-C</h5>
<p><div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d88f016a-8581-4dfd-a40a-333a3c108cad" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="c">/*
 * GeoPo Encode in Objective-C
 * @author : Shintaro Inagaki
 * @param geopo, latitude, longitude, scale (pointer)
 */
-(void)encodeGeopo:(id)geopo latitude:(double *)lat longitude:(double *)lng scale:(int *)scale {
	NSString *chars = @"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";

	*lat = (*lat + 90) / 180 * pow(8.0, 10.0);
	*lng = (*lng + 180) / 360 * pow(8.0, 10.0);

	for(int i = 0; i &lt; *scale; i++){
		[geopo appendString:[chars substringWithRange:NSMakeRange(floor(fmod(*lat / pow(8.0, 9.0 - i), 8.0)) + floor(fmod(*lng / pow(8.0, 9.0 - i), 8.0)) * 8, 1)]];
	}
}		

/*
 * GeoPo Decode in Objective-C
 * @author : Shintaro Inagaki
 * @param geopo, latitude, longitude, scale (pointer)
 */
-(void)decodeGeopo:(id)geopo latitude:(double *)lat longitude:(double *)lng scale:(int *)scale {
	NSString *chars = @"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
	int order;

	*scale = [geopo length];

	for (int i = 0; i &lt; *scale; i++) {
		order = NSMaxRange([chars rangeOfString:[geopo substringWithRange:NSMakeRange(i, 1)]]) - 1;
		*lat += (order % 8) * pow(8, 9 - i);
		*lng += floor(order / 8) * pow(8, 9 - i);
	}

	*lat = *lat * 180 / pow(8, 10) + 180 / pow(8, *scale) / 2 - 90;
	*lng = *lng * 360 / pow(8, 10) + 360 / pow(8, *scale) / 2 - 180;
}		</pre>
</div>
<p>iPhone開発者に媚びを売るにはObjective-Cでの実装も必須だよね。でも、素直にCで書いたほうがよかったかもって後から思った。そんな、ダメダメなサンプルコード。つっこみ歓迎。</p>
<p>パラメーターはポインタで渡す。で、未だに理解できてないけど idやdoubleなどのプリミティブなオブジェクトを使うらしい。</p>
<p>整数のintなら<strong>%</strong>が余りとして利用できるんだけど、doubleなど浮動小数点になると<strong>fmod()</strong>を使わなきゃならん。べき乗の<strong>pow()</strong>の中身も小数点付いてますよってことをアピールしてるんだけど、これって意味あったっけ？（c++の場合はこうじゃないと叱られた気がする）<strong> floor()</strong>で切り捨て。</p>
<p>文字列を切り出すには<strong>substringWithRange:</strong> 使うんだけど、これの引数はNSRange型なので中で<strong>NSMakeRange()</strong>使ってNSRange型を作って渡してやる。そして、文字列をくっつけるには<strong>appendString:</strong>。ただし、こうやって可変な文字列を扱うには文字列の型をNSMutableStringにしないとダメ（ここでいうgeopoの宣言）だから注意してね。</p>
<p>こっからが難問ｗ 復号化のほう</p>
<p>文字列の中にある文字の位置を取ってきたいんだけど、一発でできるようなものはなかった＞＜<br />
  <br />仕方がないので、<strong>substringWithRange:</strong>で文字列を切り出してやって、それがどこの位置かを<strong>rangeOfString:</strong>で取り出すという二段構成に。ただ、それだけだとNSRange型が返ってきて、希望するintではないから<strong>NSMaxRange()</strong>で整数値にするという三段構成に。そうすると、先頭からの位置+1になり、帳尻をあわせるために最後に-1。</p>
<p>ひょっとすると、もっと簡単にサクッとできるような関数があるのかもしれない。あったら教えてくださいな。</p>
<p>しっかし、Objective-Cと他の言語を混ぜて考えると関数の形で混乱するわｗ<br />
  <br />iPhoneアプリ作りは、ゆっくりとした休日にやろうと思った。</p>
<h5>エクセル</h5>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:9dcd44c9-7919-4681-97c3-2a1051d16443" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="xml">
ジオポのエンコード方法（エクセル関数）

以下で利用している【】はセルの位置です（A1、B4等）。各自読み替えて利用してください。

緯度を入力するセルの位置を【緯度】とします。
経度を入力するセルの位置を【経度】とします。
符号化に使用する文字列のあるセルを【符号】とし、
「0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_」
を入力します（「」は除いてください）。

ジオポコードの1文字目を出力したいセルに、
「=MID(【符号】,INT(MOD((【緯度】+90)/180*POWER(8,10)/POWER(8,9),8))+INT(MOD((【経度】+180)/360*POWER(8,10)/POWER(8,9),8))*8+1,1)」
とすると、1文字目のジオポコードが得られます。
同様に、
「=MID(【符号】,INT(MOD((【緯度】+90)/180*POWER(8,10)/POWER(8,8),8))+INT(MOD((【経度】+180)/360*POWER(8,10)/POWER(8,8),8))*8+1,1)」
とPOWERの2番目の引数を1引いてやると、2文字目のジオポコードとなり、2文字目以降も同じ繰り返しとなります。

それぞれのジオポコードのセルを&amp;で結合してやれば、ジオポコードの文字列となります。

（例）
A1に緯度、B1に経度、C1に符号化文字列を入力。
A2に「=MID(C1,INT(MOD((A1+90)/180*POWER(8,10)/POWER(8,9),8))+INT(MOD((B1+180)/360*POWER(8,10)/POWER(8,9),8))*8+1,1)」と入力。
B2に「=MID(C1,INT(MOD((A1+90)/180*POWER(8,10)/POWER(8,8),8))+INT(MOD((B1+180)/360*POWER(8,10)/POWER(8,8),8))*8+1,1)」と入力。
C2に「=MID(C1,INT(MOD((A1+90)/180*POWER(8,10)/POWER(8,7),8))+INT(MOD((B1+180)/360*POWER(8,10)/POWER(8,7),8))*8+1,1)」と入力。
D2に「=MID(C1,INT(MOD((A1+90)/180*POWER(8,10)/POWER(8,6),8))+INT(MOD((B1+180)/360*POWER(8,10)/POWER(8,6),8))*8+1,1)」と入力。
E2に「=MID(C1,INT(MOD((A1+90)/180*POWER(8,10)/POWER(8,5),8))+INT(MOD((B1+180)/360*POWER(8,10)/POWER(8,5),8))*8+1,1)」と入力。
F2に「=MID(C1,INT(MOD((A1+90)/180*POWER(8,10)/POWER(8,4),8))+INT(MOD((B1+180)/360*POWER(8,10)/POWER(8,4),8))*8+1,1)」と入力。
A3に「=A2&amp;B2&amp;C2&amp;D2&amp;E2&amp;F2」と入力すれば、A3で6文字のジオポコードが得られます。
		</pre>
</div>
<p>最後にネタ的なエクセル関数を使った実装。</p>
<p>型の宣言しないで計算できるし好き。べき乗は<strong>POWER()</strong>、切り捨ては<strong>INT()</strong>、余りは<strong>MOD()</strong>。</p>
<p>そして、<strong>MID()</strong>は指定した範囲の文字列を取ってこれて、文字を結合するには<strong>&amp;</strong>で繋げるだけ。</p>
<p>無駄が多くて関数が長くなったり、途中計算用のセルが必要になったりするけど、単純なエクセル関数でも実装できるってことが重要。Scale（縮尺）がないけど気にしない。</p>
<h4>まとめ</h4>
<p>簡単に実装できることを実証したかったんだけど、Objective-Cは時間がかかって気づいたら朝になってた&#8230;</p>
<p>いろんな言語に触れてみるのは楽しいね。今度は、C、Perl、Pythonあたりを挑戦してみるつもり。</p>
]]></content:encoded>
			<wfw:commentRss>http://creco.net/2009/03/05/write_codes_in_variaous_languages/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/2009/03/05/write_codes_in_variaous_languages/" />
	</item>
		<item>
		<title>ジオポTrack（仮）を作ったよ</title>
		<link>http://creco.net/2009/02/24/geopo_track_is_live_tracking_service_using_twitter/</link>
		<comments>http://creco.net/2009/02/24/geopo_track_is_live_tracking_service_using_twitter/#comments</comments>
		<pubDate>Tue, 24 Feb 2009 10:40:07 +0000</pubDate>
		<dc:creator>inagaki</dc:creator>
				<category><![CDATA[作ってみた]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[ジオポ]]></category>
		<category><![CDATA[トラッキングサービス]]></category>

		<guid isPermaLink="false">http://creco.net/2009/02/24/geopo_track_is_live_tracking_service_using_twitter/</guid>
		<description><![CDATA[
 まだ、（仮）なので実用に乏しいけど、形だけでも作っておいた。   http://geopo.at/track/index.php?creco_test    注意：URLは仮ですので、リンクしてもなくなっちゃう可能性 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://creco.net/wp-content/uploads/20090224-geopotrack.jpg" rel="lightbox[104]"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="212" alt="20090224_geopotrack" src="http://creco.net/wp-content/uploads/20090224-geopotrack-thumb.jpg" width="404" border="0" /></a></p>
<p> まだ、（仮）なので実用に乏しいけど、形だけでも作っておいた。   <br /><a title="http://geopo.at/track/index.php?creco_test" href="http://geopo.at/track/index.php?creco_test">http://geopo.at/track/index.php?creco_test</a>    <br />注意：URLは仮ですので、リンクしてもなくなっちゃう可能性があります。</p>
<p>どういうサービスかというと、   <br />Twitterにジオポを付加してポストしていくと、それがそのままルートとして地図上に表示してくれるというライブトラッキングサービス。</p>
<p>Ajaxで1分ごとに自動更新され、Twitterのタイムラインを読みにいくので、もし頻繁にジオポをポストするユーザをフォローしてるなら、かなり正確なトラッキングルートができるはず。</p>
<h4>ぶっちゃけ</h4>
<p>全部JavaScriptで動いてるので、サーバは必要なかったりする。ユーザのマシンでタイムライン取りに行ってもらった方が効率いいしね。</p>
]]></content:encoded>
			<wfw:commentRss>http://creco.net/2009/02/24/geopo_track_is_live_tracking_service_using_twitter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/2009/02/24/geopo_track_is_live_tracking_service_using_twitter/" />
	</item>
		<item>
		<title>jQuery Sparklinesはプチ便利</title>
		<link>http://creco.net/2008/08/01/jquery-sparklines/</link>
		<comments>http://creco.net/2008/08/01/jquery-sparklines/#comments</comments>
		<pubDate>Thu, 31 Jul 2008 17:10:01 +0000</pubDate>
		<dc:creator>inagaki</dc:creator>
				<category><![CDATA[レビュー]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://inagaki.co.uk/archives/124</guid>
		<description><![CDATA[ 
jQueryのプラグインで、ちょっとしたグラフを表示したいときに何も考えなくても配列あたえるだけで使えちゃうし、インラインの数値を読み取ってグラフ化もしてくれる。
だけど、軸のあるグラフを作りたいときには向かないね。 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://creco.net/wp-content/uploads/20080801.jpg" rel="lightbox[430]"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="20080801" border="0" alt="20080801" src="http://creco.net/wp-content/uploads/20080801_thumb.jpg" width="424" height="274" /></a> </p>
<p>jQueryのプラグインで、ちょっとしたグラフを表示したいときに何も考えなくても配列あたえるだけで使えちゃうし、インラインの数値を読み取ってグラフ化もしてくれる。</p>
<p>だけど、軸のあるグラフを作りたいときには向かないね。ちょうど、海抜高度の連続をグラフ化しようとしてたんで、これ使ったんだけど、上限下限の幅を配列の最大値、最小値から計算しちゃうんで、相対的な高低しかわからなくなってしまって、ゆるやかな坂も急激な崖も連続して登っているかぎりは同じグラフになってしまう。という問題。</p>
<p>ソース見てrangeで幅を設定していたので、そこらへんをコード中で固定し、あとは最小値を配列の最後の値-rangeという具合にしたら、そこそこうまくいった。</p>
<p>どうせなら、オプションとして採用してもらえると楽なので作者にメールを送っておいた。英文メールを書くのは大学卒業して以来かもしれないｗ</p>
<p>Live GPS Tracking   <br /><a title="http://inagaki.co.uk/misc/gps/" href="http://inagaki.co.uk/misc/gps/">http://inagaki.co.uk/misc/gps/</a></p>
<p>の右上で使ってます。</p>
]]></content:encoded>
			<wfw:commentRss>http://creco.net/2008/08/01/jquery-sparklines/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://creco.net/2008/08/01/jquery-sparklines/" />
	</item>
	</channel>
</rss>
