<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2enclosuresfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss version="2.0"><channel><title>blog.yatsu.info</title><link>http://blog.yatsu.info/</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/blogyatsuinfo" /><description></description><language>en</language><managingEditor>noreply@blogger.com (yatsu)</managingEditor><lastBuildDate>Fri, 08 Jul 2011 07:33:54 PDT</lastBuildDate><generator>Blogger http://www.blogger.com</generator><openSearch:totalResults xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">5</openSearch:totalResults><openSearch:startIndex xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">1</openSearch:startIndex><openSearch:itemsPerPage xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">25</openSearch:itemsPerPage><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="blogyatsuinfo" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>iPhoneのUIWebViewではてなキーワードを高速置換</title><link>http://blog.yatsu.info/2010/05/iphoneuiwebview.html</link><category>tx</category><category>objc</category><category>iphone/ipad</category><category>cocoa</category><author>noreply@blogger.com (yatsu)</author><pubDate>Fri, 14 May 2010 00:02:18 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7174491101899985374.post-8581472539846186041</guid><description>&lt;a href="http://blog.yatsu.info/2010/05/cocoatxobjc-tx-objc-wrapper.html"&gt;blog.yatsu.info: CocoaでTxを使うためのObjcラッパー tx-objc-wrapper&lt;/a&gt;&amp;nbsp;で書いた&lt;a href="http://github.com/yatsu/tx-objc-wrapper"&gt;tx-objc-wrapper&lt;/a&gt;にはもうひとつ&lt;a href="http://github.com/yatsu/tx-objc-wrapper/tree/master/HatenaKeywords/"&gt;HatenaKeywords&lt;/a&gt;というサンプルプログラムがあります。&lt;br /&gt;
&lt;br /&gt;
これはiPhone用のシンプルなブラウザアプリで、開いたWebページのすべての&lt;a href="http://d.hatena.ne.jp/keyword/"&gt;はてなキーワード&lt;/a&gt;をリンクに置換するものです。&lt;br /&gt;
&lt;br /&gt;
このアプリをビルドするには、tx-objc-wrapperディレクトリで以下のようにはてなキーワードCSVをダウンロードします。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:shell"&gt;% wget http://d.hatena.ne.jp/images/keyword/keywordlist_furigana.csv
&lt;/pre&gt;&lt;br /&gt;
そして HatenaKeywords/HatenaKeywords.xcodeproj をXcodeでビルドします。&lt;br /&gt;
&lt;br /&gt;
起動するとUIWebViewで&lt;a href="http://ja.wikipedia.org/"&gt;Wikipedia日本語版&lt;/a&gt;を読み込み、以下のようにキーワードを置換します。緑色がはてなキーワードへのリンクです。&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_oJ9ufs4Ajm8/S-zuWJqfxnI/AAAAAAAAACE/PxOPhRB27S8/s1600/tx-hatena.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_oJ9ufs4Ajm8/S-zuWJqfxnI/AAAAAAAAACE/PxOPhRB27S8/s320/tx-hatena.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
iPhone 3G実機で26万語からTxを構築すると90秒くらいかかります。ラッパーのコードがNSStringへの変換などを含んでいて、その分遅いかもしれません。後でチューニングしようと思います。&lt;br /&gt;
&lt;br /&gt;
２回目に起動すると、前回構築したTxを読み込みます。&lt;br /&gt;
&lt;br /&gt;
以下が実装の主な部分です。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
  NSError *error = nil;

  // get the original HTML
  NSString *html = [aWebView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML;"];
  DDXMLDocument *doc =
    [[DDXMLDocument alloc] initWithHTMLString:html
                      options:HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR
                      error:&amp;amp;error];

  // find text nodes that are not included in a link
  NSArray *nodes = [doc nodesForXPath:@"//*[name(.)!='a']/text()"
                  error:&amp;amp;error];
  for (DDXMLNode *node in nodes) {
    [node setStringValue:[txo replace:[node stringValue]]];
  }

  // generate HTML from DDXMLDocument
  html = [[[NSString alloc] initWithData:[doc XMLData]
                  encoding:NSUTF8StringEncoding]
      autorelease];

  // replace '[[[word]]]' with '&lt;a href="http://www.blogger.com/..."&gt;word&lt;/a&gt;'
  NSString *linkStr = [NSString stringWithFormat:@"&lt;a #059028;="" class="\&amp;quot;hatenaKeyword\&amp;quot;" href="http://www.blogger.com/%22http://d.hatena.ne.jp/keyword/$1/%22" text-decoration:="" underline;\"=""&gt;$1&lt;/a&gt;"];
  html = [html stringByReplacingOccurrencesOfRegex:@"\\[\\[\\[([^\\]]*)\\]\\]\\]"
                      withString:linkStr];

  // escape quotation marks
  html = [html stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"];

  // make it one line
  html = [html stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"];

  // execute the JavaScript code
  NSString *js = [NSString stringWithFormat:@"document.body.innerHTML = '%@';", html];
  [aWebView stringByEvaluatingJavaScriptFromString:js];
}
&lt;/pre&gt;&lt;br /&gt;
このメソッドはUIWebViewの読み込みが終わったときに呼び出され、以下を行います。&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;JavaScriptを実行しHTML(&lt;code&gt;document.body.innerHTML&lt;/code&gt;)を取得する&lt;/li&gt;
&lt;li&gt;XPathでリンクの外のテキストノードを取得する&lt;br /&gt;
(&lt;a href="http://d.hatena.ne.jp/cooldaemon/20090911/1252637257"&gt;KissXML+HTML&lt;/a&gt;を使用)&lt;/li&gt;
&lt;li&gt;[Txo replace:] ではてなキーワードを [[[キーワード]]] に置換し、ノードにセット&lt;/li&gt;
&lt;li&gt;DDXMLDocumentからHTMLを生成&lt;/li&gt;
&lt;li&gt;正規表現で [[[キーワード]]] をリンクに置換&lt;br /&gt;
(&lt;a href="http://regexkit.sourceforge.net/RegexKitLite/index.html"&gt;RegexKitLite&lt;/a&gt;を使用)&lt;/li&gt;
&lt;li&gt;HTML文字列のクォーテーションマークをエスケープ&lt;/li&gt;
&lt;li&gt;HTML文字列を１行にまとめる&lt;/li&gt;
&lt;li&gt;JavaScriptでUIWebViewのHTMLを置き換える&lt;/li&gt;
&lt;/ol&gt;&lt;div&gt;いろいろ非効率的なところがあったり、エラー処理がなかったりするので、実際のアプリにするには書き換える必要があります。Webページによってはメモリが足りなくて落ちたり、その他のエラーが出たりすると思うので、ご注意ください。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7174491101899985374-8581472539846186041?l=blog.yatsu.info' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-14T16:02:18.461+09:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_oJ9ufs4Ajm8/S-zuWJqfxnI/AAAAAAAAACE/PxOPhRB27S8/s72-c/tx-hatena.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>CocoaでTxを使うためのObjcラッパー tx-objc-wrapper</title><link>http://blog.yatsu.info/2010/05/cocoatxobjc-tx-objc-wrapper.html</link><category>tx</category><category>objc</category><category>iphone/ipad</category><category>cocoa</category><author>noreply@blogger.com (yatsu)</author><pubDate>Fri, 14 May 2010 00:05:34 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7174491101899985374.post-2822991377863259522</guid><description>Cocoaで&lt;a href="http://www-tsujii.is.s.u-tokyo.ac.jp/~hillbig/tx.htm"&gt;Tx&lt;/a&gt;を使うためのObjective-Cラッパーを作りました。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://github.com/yatsu/tx-objc-wrapper"&gt;tx-objc-wrapper&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
iPhone/iPod touch/iPadで大量の文字列を検出したり置換したりするのに使えます。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;b&gt;使い方&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;ソースをダウンロード&lt;br /&gt;
git clone http://github.com/yatsu/tx-objc-wrapper.git&lt;/li&gt;
&lt;li&gt;Txディレクトリ以下のファイルをXcodeプロジェクトに追加&lt;/li&gt;
&lt;li&gt;"Txo.h"をimport&lt;/li&gt;
&lt;li&gt;Txoのメソッドを呼び出す&lt;/li&gt;
&lt;/ol&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;API&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;構築／読み込み&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;// NSStringが入ったNSSetからTxを構築し、ファイルに保存する
+ (Txo *)build:(NSSet *)wordSet withFileName:(NSString *)fileName;

// Txをファイルから読み込む
+ (Txo *)read:(NSString *)fileName;
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Txの単純なラッパー&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;- (NSUInteger)prefixSearch:(const char *)aString
                    length:(NSInteger)length
              resultLength:(NSInteger *)resultLength;

- (NSUInteger)commonPrefixSearch:(const char *)aString
                          length:(NSInteger)length
                         strings:(NSArray **)strings
                           txIds:(NSArray **)txIds
                           limit:(NSUInteger)limit;

- (NSUInteger)predictiveSearch:(const char *)aString
                        length:(NSInteger)length
                       strings:(NSArray **)strings
                         txIds:(NSArray **)txIds
                         limit:(NSUInteger)limit;

- (NSString *)resultLog;

- (NSString *)errorLog;

- (NSUInteger)keyNum;
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Txo独自メソッド&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
以下のものは&lt;a href="http://gimite.net/en/index.php?tx-ruby"&gt;tx-ruby&lt;/a&gt;をマネして作りました。こちらのメソッドを呼びだすと便利でしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;- (NSInteger)longestPrefix:(NSString *)aString fromPosition:(NSInteger)position;

- (NSInteger)longestPrefix:(NSString *)aString;

- (NSArray *)searchPrefixes:(NSString *)aString forPosition:(NSInteger)position;

- (NSArray *)searchPrefixes:(NSString *)aString;

- (NSArray *)searchExpansions:(NSString *)aString forPosition:(NSInteger)position;

- (NSArray *)searchExpansions:(NSString *)aString;

- (void)scan:(NSString *)aString;

- (NSString *)replace:(NSString *)aString;
&lt;/pre&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;b&gt;サンプルコード&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://gimite.net/en/index.php?tx-ruby"&gt;tx-rubyのサンプルコード&lt;/a&gt;と同じことをしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Tx構築&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *txPath = [NSString stringWithFormat:@"%@/%@", documentsDirectory, @"keywords.tx"];

NSMutableSet *wordSet = [[NSMutableSet alloc] init];
[wordSet addObject:@"foo"];
[wordSet addObject:@"ho"];
[wordSet addObject:@"hog"];
[wordSet addObject:@"hoga"];
[wordSet addObject:@"hoge"];
[wordSet addObject:@"hogeshi"];

Txo *txo = [Txo build:wordSet withFileName:txPath];
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;文字列検索&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;[txo longestPrefix:@"hogeeee"] // =&amp;gt; 4 (which means "hoge" is in the index)

[txo searchPrefixes:@"hoge"] // =&amp;gt; (ho, hog, hoge)

[txo searchExpansions:@"hog"] // =&amp;gt; (hog, hoga, hoge, hogeshi)
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;部分文字列検索(scan)&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
TxoDelegateプロトコルの&lt;code&gt;txo:scannedString:atPosition:&lt;/code&gt;を実装します。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;- (void)txo:(Txo *)aTxo scannedString:(NSString *)aString atPosition:(NSInteger)position {
  // 文字列と位置を含む配列をarrayに追加
  // (arrayはNSMutableArrayとしてクラスに定義しておく)
  [array addObject:[NSArray arrayWithObjects:aString,
                    [NSNumber numberWithInt:position], nil]];
}
&lt;/pre&gt;&lt;br /&gt;
&lt;code&gt;scan&lt;/code&gt;を実行。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;array = [[NSMutableArray alloc] init];
[txo scan:@"hogefugafoo"]; // =&amp;gt; ((hoge, 0), (foo, 8))
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;部分文字列置換(replace)&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
TxoDelegateプロトコルの&lt;code&gt;txo:replace:&lt;/code&gt;を実装します。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;- (NSString *)txo:(Txo *)aTxo replace:(NSString *)aString {
  return [aString uppercaseString]; // 大文字にして返す
}
&lt;/pre&gt;&lt;br /&gt;
&lt;code&gt;replace&lt;/code&gt;を実行。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:objc"&gt;[txo replace:@"hogefugafoo"] // =&amp;gt; HOGEfugaFOO
&lt;/pre&gt;&lt;br /&gt;
以上のサンプルコードは&lt;a href="http://github.com/yatsu/tx-objc-wrapper/tree/master/IPhoneSimpleDemo/"&gt;IPhoneSimpleDemo&lt;/a&gt;というサンプルアプリに実装しているので、Xcodeでビルドしてお試しください。&lt;br /&gt;
実行すると以下のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_oJ9ufs4Ajm8/S-zaDVJDsWI/AAAAAAAAAB8/M09O-5hzpAI/s1600/tx-simpledemo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_oJ9ufs4Ajm8/S-zaDVJDsWI/AAAAAAAAAB8/M09O-5hzpAI/s320/tx-simpledemo.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
C++ライブラリをObjective-Cでラップする方法は、&lt;a href="http://note.sonots.com/Comp/CompLang/objective2D-c.html"&gt;Objective-C Wrappers for C++ Classes&lt;/a&gt;&amp;nbsp;を参考にしました。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;今後の予定&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;NSDictionary互換インターフェース&lt;/li&gt;
&lt;li&gt;テストコードを書く&lt;/li&gt;
&lt;li&gt;UTF8以外の文字コードに対応&lt;/li&gt;
&lt;li&gt;ラッパーコードの効率的でないところを書き直し&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;a name='more'&gt;&lt;/a&gt;もうひとつのサンプルプログラム&lt;a href="http://github.com/yatsu/tx-objc-wrapper/tree/master/HatenaKeywords/"&gt;HatenaKeywords&lt;/a&gt;についてこちらに書きました:&lt;br /&gt;
&lt;a href="http://blog.yatsu.info/2010/05/iphoneuiwebview.html"&gt;blog.yatsu.info: iPhoneのUIWebViewではてなキーワードを高速置換&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7174491101899985374-2822991377863259522?l=blog.yatsu.info' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-14T16:05:34.584+09:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_oJ9ufs4Ajm8/S-zaDVJDsWI/AAAAAAAAAB8/M09O-5hzpAI/s72-c/tx-simpledemo.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>Google Chart ToolsのGeomapで世界地図のドリルダウン</title><link>http://blog.yatsu.info/2010/05/google-chart-toolsgeomap.html</link><category>ruby</category><category>map</category><category>sinatra</category><author>noreply@blogger.com (yatsu)</author><pubDate>Mon, 24 May 2010 01:09:28 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7174491101899985374.post-8634481951952455707</guid><description>&lt;a href="http://code.google.com/intl/ja/apis/charttools/" rel="noreferrer"&gt;Google Chart Tools&lt;/a&gt;の&lt;a href="http://code.google.com/intl/ja/apis/visualization/documentation/gallery/geomap.html" rel="noreferrer"&gt;Geomap&lt;/a&gt;で世界地図のドリルダウンを実装してみました。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://geomapselect.heroku.com/" rel="noreferrer"&gt;サンプルサイト&lt;/a&gt;&amp;nbsp;(&lt;b&gt;2010-05-24 URL更新&lt;/b&gt;)&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_oJ9ufs4Ajm8/S-K72LtabgI/AAAAAAAAABk/2j52jWFM7sc/s320/mapselect_world.png" /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_oJ9ufs4Ajm8/S-K8B4bZYkI/AAAAAAAAABs/B2bfwpOnQTI/s1600/mapselect_japan.png" imageanchor="1" rel="noreferrer" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_oJ9ufs4Ajm8/S-K8B4bZYkI/AAAAAAAAABs/B2bfwpOnQTI/s320/mapselect_japan.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
地図中の領域をクリックしてドリルダウンしていくことができます。上に戻るには左上の「Zoom Out」ボタンをクリックします。&lt;br /&gt;
&lt;br /&gt;
本来は統計データを表示するものですが、地図から住所を入力したり、人やお店を探したりするインターフェースとしても使えそうです。&lt;br /&gt;
&lt;br /&gt;
あまり深くまで行こうとするとエラーになりますので、実際に利用する場合は修正が必要です。&lt;br /&gt;
&lt;br /&gt;
コードは以下のようになっています。&lt;a href="http://www.sinatrarb.com/" rel="noreferrer"&gt;Sinatra&lt;/a&gt;で実装しました。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:ruby"&gt;require 'rubygems'
require 'sinatra'

helpers do
  include Rack::Utils
  alias_method :h, :escape_html

  def render_map(region)
    &amp;lt;&amp;lt;-END
    var data = new google.visualization.DataTable();
    data.addRows(7);
    data.addColumn('string', 'Country');
    data.addColumn('number', 'Number of people');
    data.setValue(0, 0, 'Germany');
    data.setValue(0, 1, 10);
    data.setValue(1, 0, 'United States');
    data.setValue(1, 1, 31);
    data.setValue(2, 0, 'Brazil');
    data.setValue(2, 1, 17);
    data.setValue(3, 0, 'Canada');
    data.setValue(3, 1, 8);
    data.setValue(4, 0, 'France');
    data.setValue(4, 1, 22);
    data.setValue(5, 0, 'RU');
    data.setValue(5, 1, 34);
    data.setValue(6, 0, 'Japan');
    data.setValue(6, 1, 22);
    var options = {};
    options['region'] = '#{h(region)}';
    options['dataMode'] = 'regions';
    options['showZoomOut'] = #{region == 'world' ? 'false' : 'true'};

    var container = document.getElementById('mapCanvas');
    var geomap = new google.visualization.GeoMap(container);
    geomap.draw(data, options);

    google.visualization.events.addListener(geomap, 'regionClick', function(props) {
      var region = props.region;
      new Ajax.Request(region, {
        method: 'get',
        asynchronous: true,
        evalScripts: true
      });
    });

    google.visualization.events.addListener(geomap, 'zoomOut', function() {
      new Ajax.Request('world', {
        method: 'get',
        asynchronous: true,
        evalScripts: true
      });
    });
    END
  end
end

get '/' do
  haml :index
end

get '/:region' do
  content_type('text/javascript')
  render_map(h(params[:region]))
end

__END__

@@ layout
%html
  %head
    %title Map Select
    %script{ :type =&amp;gt; 'text/javascript', :src =&amp;gt; 'http://www.google.com/jsapi' }
    %script{ :type =&amp;gt; 'text/javascript', :src =&amp;gt; 'js/prototype.js' }
    %script{ :type =&amp;gt; 'text/javascript' } google.load('visualization', '1', {'packages': ['geomap']});
  %body
    #mapCanvas
    = yield

@@ index
%script{ :type =&amp;gt; 'text/javascript' }= render_map('world')
&lt;/pre&gt;&lt;br /&gt;
やっていることは、Geomapを表示し、領域がクリックされたときにそのregionをAjaxでサーバーに送り、新しいregionでGeomapを表示しなおしているだけです。&lt;br /&gt;
&lt;br /&gt;
動作させるには、これをmapselect.rbとして保存します。そして保存したディレクトリの下にpublic/jsというディレクトリを作成し、そこに&lt;a href="http://www.prototypejs.org/" rel="noreferrer"&gt;prototype.js&lt;/a&gt;を置きます。起動は&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;ruby mapselect.rb&lt;/pre&gt;とします。&lt;br /&gt;
&lt;br /&gt;
時間があればRailsプラグインか何かにしてみようと思います。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7174491101899985374-8634481951952455707?l=blog.yatsu.info' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-24T17:09:28.597+09:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_oJ9ufs4Ajm8/S-K72LtabgI/AAAAAAAAABk/2j52jWFM7sc/s72-c/mapselect_world.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><title>IME開発者会議@Google食堂</title><link>http://blog.yatsu.info/2010/04/imegoogle.html</link><category>ime</category><author>noreply@blogger.com (yatsu)</author><pubDate>Thu, 13 May 2010 22:12:47 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7174491101899985374.post-3836655150162490379</guid><description>今日はGoogle食堂にIME開発者が集まり、情報交換しました。GoogleIME, Social IME, SKKIME, ChaIME, AquaSKK, uim, MacUIMの開発者など総勢14名(たぶん)が参加し、ライトニングトーク大会になりました。&lt;br /&gt;
&lt;br /&gt;
私の発表資料(余分なもの省略版)&lt;br /&gt;
&lt;div id="__ss_3884824" style="width: 425px;"&gt;&lt;b style="display: block; margin: 12px 0pt 4px;"&gt;&lt;a href="http://www.slideshare.net/yatsu/inputhiliter-shortkey" title="変換文字列をカラフルにする(InputHiliter)"&gt;変換文字列をカラフルにする(InputHiliter)&lt;/a&gt;&lt;/b&gt;&lt;object height="355" id="__sse3884824" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=inputhilitershort-key-100428102847-phpapp02&amp;stripped_title=inputhiliter-shortkey" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse3884824" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=inputhilitershort-key-100428102847-phpapp02&amp;stripped_title=inputhiliter-shortkey" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;div style="padding: 5px 0pt 12px;"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/yatsu"&gt;yatsu&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
InputHiliterについてはこちら。&lt;br /&gt;
&lt;a href="http://inputhiliter.yatsu.info/"&gt;http://inputhiliter.yatsu.info/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
バージョン3.0から色を設定できるようになり、楽しいアプリになりました。&lt;br /&gt;
実用度はわかりませんが。&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3254/4556849341_1a7d30e0ec.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="249" src="http://farm4.static.flickr.com/3254/4556849341_1a7d30e0ec.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3006/4557479054_7dd4cf6e54.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="245" src="http://farm4.static.flickr.com/3006/4557479054_7dd4cf6e54.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div id="FLASH_MESSAGE" style="display: none;"&gt;&lt;/div&gt;&lt;div id="FLASH_MESSAGE" style="display: none;"&gt;&lt;/div&gt;&lt;div id="FLASH_MESSAGE" style="display: none;"&gt;&lt;/div&gt;&lt;div id="FLASH_MESSAGE" style="display: none;"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7174491101899985374-3836655150162490379?l=blog.yatsu.info' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-14T14:12:47.927+09:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm4.static.flickr.com/3254/4556849341_1a7d30e0ec_t.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><enclosure url="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=inputhilitershort-key-100428102847-phpapp02&amp;stripped_title=inputhiliter-shortkey" length="135484" type="application/x-shockwave-flash" /></item><item><title>TreemapKit公開</title><link>http://blog.yatsu.info/2010/04/treemapkit.html</link><category>objc</category><category>visualization</category><category>iphone/ipad</category><category>cocoa</category><author>noreply@blogger.com (yatsu)</author><pubDate>Thu, 13 May 2010 22:14:31 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-7174491101899985374.post-7943590691323323372</guid><description>iPhone/iPod touch/iPadでTreemapを表示するライブラリTreemapKitを公開しました。&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://github.com/yatsu/treemapkit"&gt;http://github.com/yatsu/treemapkit&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" data="http://www.flickr.com/apps/video/stewart.swf?v=71377" height="400" type="application/x-shockwave-flash" width="300"&gt; &lt;param name="flashvars" value="intl_lang=en-us&amp;amp;photo_secret=4c1a37681b&amp;amp;photo_id=4507143423"&gt;&lt;/param&gt;&lt;param name="movie" value="http://www.flickr.com/apps/video/stewart.swf?v=71377"&gt;&lt;/param&gt;&lt;param name="bgcolor" value="#000000"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;embed type="application/x-shockwave-flash" src="http://www.flickr.com/apps/video/stewart.swf?v=71377" bgcolor="#000000" allowfullscreen="true" flashvars="intl_lang=en-us&amp;amp;photo_secret=4c1a37681b&amp;amp;photo_id=4507143423" height="400" width="300"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;br /&gt;
これは&lt;a href="http://www.ovalplan.co.jp/"&gt;Oval Plan&lt;/a&gt;社との共同プロジェクトでの成果の一部をオープンソースとして公開するものです。ライセンスはMITライセンスです。&lt;br /&gt;
ソースを拡張された場合、なるべくGitHub上で公開していただけるとありがたいです。一般的に有用な拡張は取り込んでいきたいと思います。&lt;br /&gt;
&lt;br /&gt;
現時点では、値とラベルの配列を受け取り、内部で値に応じで２分割をネストしていく形になっています。独自のツリー構造を渡すことや、割り当てのアルゴリズムを変更することはできません。それらの機能は今後実装したいと思っています。&lt;br /&gt;
&lt;br /&gt;
表示される四角は画面上では実際にはネストしていません。フラットな四角を並べた構造になっています。これは上のスクリーンキャストのように、データが変更されたときにアニメーションやエフェクトを適用するのに都合がよいからです。&lt;br /&gt;
&lt;div id="FLASH_MESSAGE" style="display: none;"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7174491101899985374-7943590691323323372?l=blog.yatsu.info' alt='' /&gt;&lt;/div&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-05-14T14:14:31.544+09:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><enclosure url="http://www.flickr.com/apps/video/stewart.swf?v=71377" length="67920" type="application/x-shockwave-flash" /></item></channel></rss>

