MSVCネタ(関数コールスタックが表示されないケース)
今日のネタは、MSVC(Microsoft Visual C++)使いには常識かもしれません。 と言うより、自分自身も以前経験したような気もしますが、このタイプのバグはgdbでたいてい見つけてしまうので、すっかり失念していました。
MSVCで落ちた時の関数コールスタックが次のようになることがあります。
アドレスゼロに対して関数呼び出しをした時、こうなります。
(こんなコードを書くことはありえませんが)要は、次のようなことをした時です。
typedef void (*fn_t)(); fn_t fn = NULL; fn();
ESPレジスタ(stack pointer)の値の指すメモリ領域を表示すれば、コールスタック上の関数のアドレスはわかります。しかし、アドレスゼロにジャンプしてスタックを破壊するわけでもないので、関数コールスタックを表示してくれないのは納得できません。
- Category(s)
 - カテゴリなし
 
時間のかかる処理はFirebugでどう観測されるか?
発端は、firebugのNetタブで見ることができるグラフは、ネットワーク待ち時間を含んでいるかという疑問です。調べればどこかに書いてありそう(or JavaScriptコード読んでも分かりそう)ですが、実験した方が早いので、やってみました。
apacheはapache2.2.0です。
まず次のようなCGIスクリプトで、時間のかかる処理をエミュレーションしてみました。
#!/usr/bin/perl sleep 10; print "Content-Type: text/html\n\n"; print "<html><title>t</title><body><img src=\"/img/apache_pb.png\"><img src=\"/img/apache_pb.gif\"></body></html>";
sleepの秒数を変えても、firebugの結果は常に次のような表示になりました。
実際にはネットワーク待ち時間が10秒ありますが、firebugのグラフに10秒は現れません。
次のようにCGIスクリプトを変えてみました。
#!/usr/bin/perl print "Content-Type: text/html\n\n"; $| = 1; # non-buffering print "<html><title>t</title><body><img src=\"/img/apache_pb.png\">"; sleep 10; print "<img src=\"/img/apache_pb.gif\"></body></html>";
この結果は次のようになりました。
10秒のネットワーク待ち時間がグラフに現れました。
この実験で、firebugのNetタグのグラフは、HTTPレスポンスを受け始めてからの時間を表示していることが分かります(リクエストを投げてから、レスポンスを受け始めるまでの待ち時間は含みません)。計測のエンドが、レスポンスを受け終わるまでか、画像であればレンダリングするまでなのか、JavaScriptであれば解釈するまでなのか、の区別は、この実験では判断できません。おそらく、レスポンスを受け終わるまでの時間な気がします(Netタブなので、純粋にデータ転送時間を出すのが自然に思えます)。確証はないので、裏を取りたければ、ほぼ同じサイズのHTMLファイルと(解釈に時間のかかりそうな)JavaScriptファイルで比較すれば判断できるでしょう。
上の実験から、結局、リクエスト開始からレスポンス終了までの時間を知るには、firebugのNetタブは適していないことが分かります。
計測の目的がネットワークの遅延ではなく、サーバ側の処理時間であれば、Apacheのログを見るのが確実です。
LogFormat(http://httpd.apache.org/docs/2.2/en/mod/mod_log_config.html)で%D(マイクロ秒)、%T(秒)のいずれかでログにでます。このふたつ、単位が違うだけで、まったく同じ算出です。
- Category(s)
 - カテゴリなし
 
苦手なこと: 採用活動
最近は、採用活動に取られる時間が増えています。
人が増えた時、ぼくは他人のマネージメントをしたくありません。マネージメントを回避するには、マネージメントの必要が無いぐらい優秀な人間を採ればよいので、採用活動に力をいれるのは理にかなっています。
採用のための募集文を下記のように書きました。どう考えても、ぼくはこういう文章を書くのに向いていません。一番の問題は、ぼく自身、就職なんてしたくない、と常々思っている人間だという点です。他社の募集文を読んでいると、いかに自分たちの会社が楽しいか、いかに自分たちの会社に来れば実力がつくか、と必死にアピールしています。読んでて白々しいので、次のような募集になってしまいました。
後者ふたつ(ネットワーク技術者とドキュメント娘。)はすぐにでも採用したいので、今なら、かなりの売り手市場です(普段より、採用基準が甘くなる可能性が高いです)。興味を感じてくれた人は、是非、応募してください。
1.プログラマ
次のいずれかに当てはまる人は是非応募してください。
- Java、PHP、VBと聞くと、プログラマという括りで一緒にしないで欲しいと言いたい人
 - Javaは悪くない。悪いのは、少しJavaをかじっただけでJava経験者を名乗るヘボJavaプログラマたちだ、と言いたい人
 
状況に応じて、上記ふたつのどちらの立場でも語れる自信のある人は尚可です。
2.ネットワーク技術者
- 仕事内容: Webアプリケーションの導入と技術サポート。
 
面接で次の質問をします。
「Oracle、Websphereで動くWebアプリケーションを導入した顧客企業から、ある朝、突然、アプリケーションの動作が重くなった、と電話がかかってきました。あなたなら、どう対応しますか?」
あなたが、どんな質問をするか、どんなツールを使うか、何をどう分析するか、を問います。 トラブル時には、事実と錯誤が入り乱れます。真実を見極め、現象を切り分け、原因を特定する論理的思考力、およびOracleとWebsphereの経験と知識を備えた人を歓迎します。
- Category(s)
 - カテゴリなし
 
コードの膨張
最近、少しずつJavaScriptを好きになっていた気がしましたが、気のせいだったかもしれません。
次のようなコードを書きました。チェックボックスをON/OFFすると、テキストボックスのパスワードモードを切り替えるだけの簡単なコードです。
<div id="base">
 <input type="text" id="input_foo"/>
 <input type="checkbox" onclick="$('input_foo').setAttribute('type', this.checked ? 'password' : 'text');"/>
</div>
このコード、IEでは動きません(IE6では動きません。IE7は不明です)。
次のページを見ると、type属性を後から変更できないようです。
http://msdn2.microsoft.com/en-us/library/ms534700.aspx
As of Microsoft Internet Explorer 5, the type property is read/write-once, but only when an input element is created with the createElement method and before it is added to the document.
IE5の制限事項と書いてありますが、手元のIE6で上記コードが動きません(エラーが起きます)。
結局、(元はたった1行のコードが)次のような仰々しいコードになってしまいました(最初、cloneNode()を使いましたが、ダメでした)。
function change(v) {
  var e = $('input_foo');
  if (Prototype.Browser.IE) {
    var base = $('base');
    var dup = document.createElement('input');
    dup.setAttribute('type', v ? 'password' : 'text');
    dup.setAttribute('value', e.value);
    dup.setAttribute('id', 'input_foo');
    base.replaceChild(dup, e);
  } else {
    e.setAttribute('type', v ? 'password' : 'text');
  }
}
もっと調べれば、マシな書き方が見つかるかもしれませんが、何を信じてよいのか分かりません。
- Category(s)
 - カテゴリなし
 
GPLなJavaScriptのコードは、非フリーなソフトウェアに使えるのか
Webで探すと次のページがすぐに見つかりました。
結構、自信満々(*)に「使える」と結論づけていますが、そんなに簡単な問いではありません。
(*)字面に現れていない洞察の末の結論かもしれませんが。
ポイントは「派生物(derivative work)」の解釈です。上のサイトからもリンクされているFAQで言えば、次の項目です。
元々、GPLは(主に)C言語を想定している節があり、コンパイルしてひとつの実行ファイルになったら「派生物」ということだけが明確になっています。ライブラリの場合、静的リンクは、この解釈で派生物の判定が容易です。しかし、動的リンクの場合、この解釈だけだと派生物になりません。静的リンクと動的リンクで効力が変わるのは変なので、少し解釈を拡大して、同じ(プロセス)アドレス空間で動くプログラムになるなら「派生物」という解釈で、C言語(などのコンパイル言語)では落ち着いています。しかし、この解釈はスクリプト系言語で困ります。
ちなみに上の説明で、libcどうなんだ、あるいはkernelのコードも結局同じアドレス空間で動くではないか、と思った人は鋭い人です。これらは、GPLの中で例外扱いしています。GPL2では"major components"、GPL3では"System Libraries"と区別して、例外扱いしています。
この辺り、GPL3(draft)で明確化されたのか調べてみましたが、ざっと見る限り変わっていません。
スクリプト系言語の場合、実行系(interpreter)とスクリプト自体に派生関係がないことは次で明言しています。
interpreterから見れば、スクリプトはデータだから、という解釈です。では、スクリプトが別のスクリプトモジュールの関数呼び出しをした場合は派生物なのか?、という疑問があります。上のFAQによれば、派生物、という解釈です("if you choose to use GPL'd Perl modules or Java classes in your program, you must release the program in a GPL-compatible way")。
(スクリプト系言語ではないですが)Javaに関して、次の文書があります(The LGPL and Java)。
あるjarファイルを利用したJavaコードは派生物だと、明確に言っています。ちなみに、継承(inheritance)も派生物、と言い切っています。リンクと同等に解釈しているので、jarファイルのライセンスがLGPLであれば、非フリーなソフトウェアに使えます。
ここまで来ると、GPLなJavaScriptを使うHTMLやJavaScriptは派生物になりそうな気配濃厚ですが、またまた例外事項がありました。
上記から引用します。
As a special exception to GPL, any HTML file which merely makes function calls to this code, and for that purpose includes it by reference shall be deemed a separate work for copyright law purposes.
JavaScriptの関数呼び出し、およびincludes it by reference、要はscriptタグによる読み込みだと思います、は派生物とはしない(=separate work)という例外を認めています。
と話を終わりにしたいところですが、この例外がGPLの一般論として認めた例外なのか、この例外事項を記載することを薦めた主張(記載しないと派生物になる)なのかよく分かっていません。全体のトーンは後者のような気がしないでもありません("it's possible that template+user data+Javascript would be considered one work under copyright law."とか)。
jarファイルとの比較から、JavaScriptファイルの読み込みはリンク相当にはなりそうなので、LGPLのJavaScriptコードは非フリーなソフトウェアで使えそうです。
- Category(s)
 - カテゴリなし
 
時計型カレンダーをcanvasで実装
先日のGoogle Developer DayのGDataのセッションで、Google Calendarの予定を取り込むデバイスの話がありました。 ちらとしか画面に写りませんでしたが、予定を時計状のオブジェクトで表示するようです。1:00から3:00の予定がある場合、円周の右上の円弧が光ります。予定の表示と言えばカレンダー状しか思いつかなかったので、面白い、と思いました。
同じような機能をcanvasで実装してみました。
テキストボックスに 14:00-16:00 のように入力してください。予定のある時刻の円弧が赤くなります。薄い赤色で透過度付きにしているので、予定が重なると、濃い赤になります。 特別なデータ構造やバックエンドに依存していないので、誰でもどこでも使えます。
使い方の例
var cc = new ClockCalendar($("bg_layer").getContext("2d"),
                       $("sched_layer").getContext("2d"),
                       $("clock_layer").getContext("2d"));
cc.add_schedule(new Date(2007,1,1,12,0,0,0), new Date(2007,1,1,13,0,0,0));
canvasを実装したブラウザ(firefox2など)で試すことができます。IEでは見ることができません。
先日、Firefox extensionの勉強会を開催しましたが、他の候補としてcanvasと(JavaScriptの)E4Xがありました。E4Xは個人的にクールだと思います。しかし、いかんせん説明することが無さすぎます。E4Xは何かで10分、DOMとの相互変換で10分、おしまいです。説明することが少ないのは、シンプルで良い技術の証ですが、勉強会のネタとしては物足りません。一方、canvasは存在理由が微妙すぎて見送りました。HTMLの理念からの逸脱も甚だしいですし、IEがサポートしない限り、誰も使えません。
コードの時計部分は http://developer.mozilla.org/en/docs/Canvas_tutorial のぱくりです。AMとPMを分けたり、時計の基盤と針を別のcanvasに分けたり、と少し改変しています。
ちなみに 11:00-15:00 の予定を作ると、次のような表示になります。AM、PMの観点では正しい表示ですが、ビジネスアワー的にはひとつの円弧として表示して欲しい気もします。
- Category(s)
 - カテゴリなし
 
Google Developer Dayレポート
Google Developer Dayに行ってきました。 - http://code.google.com/events/developerday/jp-home.html
午後最初のセッションはGoogle Maps API Introductionでした。講師のChris Atenasioは若い白人で金髪で長身のハンサムガイでした。同時刻の別セッションでは、美人のソフィア(おまけ参照)が講師だったようです。日本人向けのサービスでしょうか。サービスは冗談ですが、講師は全体的に聞き取りやすい英語を話しました。
Chrisの話はGoogle Maps APIの初級の話でした。Google Maps APIのチュートリアルを読んだことがあるので、特に目新しい話題はありませんでした。内容は明瞭でしたが、所々、自分の話したいことを一方的に話す、技術者にありがちなプレゼンでした。例えば、唐突にJavaScriptのクロージャの話を始めました。引数で渡るローカル変数のスコープがうんぬん、とか突然話されても、会場の半分ぐらいはおそらくついていけていないはずです。他にも、サンプルコードから話が脱線して、データをコードから分離して変化に強いコードを書く話とかします。そこを言いたい気持ちは良く分かりますが、セッションの趣旨とはまったく関係ありません。極めつけは、最後に巡回セールスマン問題の例を出したくだりです。Google Mapsで可視化して、人間に解かせる、というオチです。あれは「人間に解かせるのかよ!」とツッコミを入れるべきなんだろうと思っていますが、もちろん誰もそんなことはしません。全般的に、微妙に空回り感のあったプレゼンでした。Chrisは日本人はシャイ、ということを学ぶべきでしょう。
次はKMLの話でした。講師はBruno Bowden。冒頭、日本語で挨拶しました。たどたどしくも一生懸命に日本語で挨拶する姿が会場の多くの日本人の心をつかんだようで、挨拶が終わると拍手まで起きましたが、その程度で、ぼくの心はつかまれません。日本人が英語で挨拶しただけで拍手されますか?、と拍手した日本人に厳しく問い詰めたい気分です。Chrisが言うように(後のAdamも同様の発言を繰り返しますが)、変わりやすい部分をデータに追い出して、コードはデータを入力として読み込んで動く、というアーキテクチャは実に正しい姿です。何も文句はありません。KMLが普及するか、と問われれば、たぶんイエスな気がします。理由は、他のデータフォーマットを使う理由が無いからです。
次はRyan BoydのGDataの話でした。GDataの話は、AirOneでGoogle Calendarのデータを取り込む機能のために調査したので、セッションで話された内容は既に知っていました。GDataはAtomベースの技術です。ぼくは、基本的に、特定の技術の善し悪しをそんなにすぐには判断しません。良いか悪いか判断するためには、まず正しく理解する必要があると思っているからです。好きか嫌いはもっと早く判断を下せます(変わる可能性も高いですが)。現状、Atomに対してぼくは好意的です。少なくとも、SOAPに対する第一印象よりAtomに対する第一印象の方が良いです。もっとも、SOAPもCORBAよりは印象が良かったのですが。
最後はAdam SchuckのGoogle Maps Gadgetsの話でした。個人的には、一番目新しい話でした。もう少し調べてから何か書きます。
おまけ; ソフィアリスト(なぜか微妙な角度ばかり)
- Category(s)
 - カテゴリなし
 
sqliteの反則技(amalgamation )
AirOneで使っているsqliteのパフォーマンスが微妙に気にいらない(*)ので、パフォーマンスチューニングが進んでいるかどうか調べるために、久しぶりにWebサイトをチェックしました。
(*)ノートPCなのでディスクアクセスの遅さが要因かもしれません。
最近のリリース文を見ると、バグを埋め込んでは直し埋め込んでは直し、を繰り返している雰囲気がしないでもありません。それはともかくとして、次のリリース文が目につきました。
2007-Apr-02 - Version 3.3.14
This version focuses on performance improvements. If you recompile the amalgamation using GCC option -O3 (the precompiled binaries use -O2) you may see performance improvements of 35% or more over version 3.3.13 depending on your workload.
35%のパフォーマンス改善とは驚きの数字です(Javaなら驚きませんが。なぜならJavaは最新テクノロジーだからです)。amalgamationとは何かと次のページを見てみると...
全部の.cファイルをひとつのファイルにまとめてからコンパイルするようです。普通のCコンパイラはコンパイル単位(=ひとつのCソースファイル)で最適化を行うので、ひとつのファイルにまとめると速くなりうる、という理屈です。こっちでは、5%から10%の速度改善と書いてあります。
これは反則でしょう。
このテクニック(と呼びたくは無いですが)、そんなに効くものでしょうか。(ソースが分かれていれば)インラインになりえない関数呼び出し部分がインライン化するぐらいはすぐに思いつきますが、それ以外の最適化がどれほど起きるのか不明です。
- Category(s)
 - カテゴリなし
 
ソフトウェア開発プロセスのgiant lock
少し前ですが、以下を読みました。
- http://www.hyuki.com/yukiwiki/wiki.cgi?QualityImprovementInFreeSoftware (翻訳)
 - http://www.cyrius.com/publications/michlmayr-phd.html (論文)
 
Linux(*)のBTSは次のbugzillaです。
今、オープンバグを探すと、たった1546件しかありません。ソフトウェア開発を知らない人は1546件を多いと思うかもしれません。実際には、驚異的に少ない数だと思います。
(*)言うまでも無いですが、GNUをつけないLinuxはカーネルのことです。
論文は、リリースの周期を決めて、そのリリース周期を守れ、と主張します。無計画にリリースがだらだらと延びることを批判しています。長すぎるリリース間隔には悪い点が多いので、短い方が望ましいようです。ただし、リリース間隔を過度に短くすることは主張していません。実際、「7.1.4. Cost Factors Related to Releasing」で、リリースに関わるコストを考察しています。OpenOfficeでは2ヵ月ごとのリリースをやめて、3ヵ月ごとにリリースに延ばしたようです。
リリース間隔を短くするには、ソフトウェアを常にある程度安定した状態に保つ必要があります。「8.2.1 Stability of the Development Tree」に次の4つのプロセスが挙がっています。
- Branches
 - Peer review
 - Testing
 - Reverting and postponing
 
注目したいのがBranchesとReverting and postponingです(Peer reviewとTestingは自明なので省略します)。
branchingは、安定化に時間のかかる開発作業はメイン開発ツリーと別のところで作業を行い、安定してからメインツリーに入れるプロセスです。Reverting and postponingのrevertingは、メインツリーに一度入った機能でも、リリース品質に達しない機能はメインツリーから外すプロセスです。postponingはリリース品質に達しない機能は、(例えリリース予定機能であったとしても)リリースに含めないプロセスです。
branchingとrevertingは、言うほど易しくありません。ソフトウェアが適切にモジュール化できていなければ達成できません。このふたつが可能になれば、大規模ソフトウェア開発としてスケールできます。
個人的な開発体制の理想は、ゴールだけ共有して、後は各人が自分のペースでゴールに向けて走りだすことです。ペース配分はひとりで勝手に決めてもいいですし、数人でまとまっても良いです。リリース間隔の整数倍の周期で作業する人がいても良いと思っています。つまり、リリース周期が1ヵ月の場合、2ヵ月や3ヵ月の周期で作業する人がいても構いません。
現実は理想どおりに行きません。なぜかリリース前になると、全員を動員しなければいけない作業が残って、全員の足並みを揃える羽目になります。締切を決めて作業見積りをさせると、なぜか全員にタスクが割り振られる、という結果になります。人数が変化しても、全員必要、という結果に変化はありません。感覚的には、目に見えないgiant lockがあって、全員の作業が同期してしまうイメージです。スケールするために、この目に見えないgiant lockを取り除きたいのです。
以前からこの現象に気づいて、どうにかしたいと思っていました。先行して作業を進めておけば防げるだろうと考えましたが、考えが甘かったことに気づきました。結局、心理的な問題です。どれだけ前倒ししても、使えるリソース(人と時間)は使い切ってしまうのです。
今考えている手は、強制的に別の周期で動く部隊を作ることです。はじめから使えないリソースとして周知させておけば、巻き込まれないで済みます。
- Category(s)
 - カテゴリなし
 
tempo.elで独自ボキャブラリXMLを書く使い捨てモード
世の中、独自XMLボキャブラリを氾濫させるのは止めようと、誰もが思っているのに、独自XMLボキャブラリは後をたちません。
独自XMLボキャブラリを書くことになったら、使い捨ての自分XMLモードを作って楽をしましょう。tempo.elを使った例を示します。
tempo.el
コードの雛型は次のようになります(メジャーモードの作り方としてはやや変則的な部分がありますが、使い捨てなので許してください)。
(require 'tempo)
(defun my-xml-mode ()
  (interactive)
  (kill-all-local-variables)
  (setq mode-name "my xml")
  (setq major-mode 'my-xml-mode)
  (let ((my-xml-mode-map (make-sparse-keymap)))
    (define-key my-xml-mode-map "\M-\C-f" 'tempo-forward-mark)
    (define-key my-xml-mode-map "\M-\C-b" 'tempo-backward-mark)
    (define-key my-xml-mode-map "\C-c\C-lu" (tempo-define-template "ul" '("<ul>\n<li>" p "</li>\n" p "</ul>\n")))
    (define-key my-xml-mode-map "\C-c\C-li" (tempo-define-template "li" '("<li>" p "</li>\n")))
    ; add more
    (use-local-map my-xml-mode-map)))
add moreの部分に必要なパターンを書き加えます。上の例ではキーアサインをhtml-helper-mode.elに準拠しています。適当に好きなキーアサインにすることも可能です。XMLボキャブラリに応じて、何も考えずに適当に書き加えても動くのが良い点です。
キーアサインとタグの挿入を対応づけているだけです。上のコードだけ見ると、キーボードマクロとたいして変わらないように見えます。良い点は上記のテンプレート内の p の部分にカーソルが移動することと、tempo-forward-mark、tempo-backward-markで p の位置を順々に移動できることです。
上のmy-xml-modeを使って、次のXML断片を書くケースを考えます。
<ul> <li>foo</li> <li>bar</li> <li>baz</li> </ul>
キー入力は次のようになります。
- C-u C-l u
 - foo
 - M-C-f
 - C-u C-l i
 - bar
 - M-C-f
 - C-u C-l i
 - baz
 
コードの重複が悪であるように、キー入力の重複も悪です。3と4のステップの組み合わせは繰り返されているので、気になるなら、無くしてください。キーボードマクロが一番容易でしょう。
- Category(s)
 - カテゴリなし
 
animator.jsの使い方
最近はアリエルの若きJavaScriptマスターの後を追いかけてばかりです。先日、animator.jsを教えてもらいました。他のJavaScriptライブラリより良くできていると思います。
以前、scriptaculousで須崎メソッドを実装しました(http://dev.ariel-networks.com/Members/inoue/suzaki-method)。結局、scriptaculousをAirOneの配布に含めていないので、須崎メソッドは動いていません。今回、animator.jsで再実装しました。今度は、次のメジャーリリースに入ります。
簡単な例を使ってanimator.jsの使い方を説明します。
次のようなbody要素のHTMLを考えます。id="target"の要素を上下に振動させます。
<body onload="init();"> <div style='position:absolute; top:200px'>---200---</div> <div id="target">moving...</div> </body>
magic numberが多いですが、最も簡単なコードは次のようになります。
var t = $('target');
t.style.position = 'absolute';
t.style.top = '200px';
var anim = new Animator({duration: 4000, interval:40, transition: Animator.tx.linear});
anim.addSubject(function (v) { var h = 200 + Math.round(100 * Math.sin(v * 2*Math.PI)); t.style.top = h + 'px';});
anim.play();
最初に、id="target"の要素のpositionスタイルをabsoluteにします。上下に振動させるためにすべきことは、タイマーでt.style.topの値を変更することです。
duration:4000はアニメの長さです(単位はミリ秒)。interval:40はアニメの間隔です(同じく単位はミリ秒)。つまり、上の設定では40msごとのタイマーイベントが100回起きて、4秒すると止まります。
animator.jsの基本は、タイマーのイベントハンドラに、0から1の間の値を取る数値(以下、カウンタ)が渡ることです。transition:Animator.tx.linearの設定で、カウンタが線形に増えます。つまり、イベント回数が100回なので、0.01ずつカウンタが増えます。イベントハンドラは、0,0.01,0.02,0.03,...,0.98,0.99,1のカウンタを受け取ります(後述するイベントハンドラの引数のvの値)。
addSubject()でイベントハンドラを渡します。振動させるためにsin()を使います。1周期の動きをさせるには、0から2πの値を取ればよいので、"v * 2*Math.PI"をsin()に渡します(カウンタvは0から1の間の値)。100は振幅です。高さ200pxを中心に振動させているので200を足して、最後にt.style.topに値をセットします。以下、このコードを改造していきます。
scriptaculousのコードを見ると、prototype.jsのmakePositioned()を使っています。t.style.position = 'absolute';を置き換えられそうなので、次のようにします(以下、この3行は省略)。
var t = $('target');
t.makePositioned();
t.style.top = '200px';
animator.jsのtransitionはいわばカウンタのgeneratorです。上の例のようにAnimator.tx.linearを使ってカウンタを線形にして、イベントハンドラのみを考えるのもひとつの手です。次のように、カウンタそのものの値の範囲を2πの単位で考えることもできます。
var anim = new Animator({duration: 4000, interval:40, transition: function(n){ return n * 2*Math.PI;}});
anim.addSubject(function (v) { var h = 200 + Math.round(100 * Math.sin(v)); t.style.top = h + 'px'; });
anim.play();
以下、Animator.tx.linearに話を戻します。
sin()に渡す数値の範囲を0から8πにすれば4往復します。更に、線形に1から0まで減少する数値をかけると、減衰する振動になります。コードは次のようになります。
var anim = new Animator({duration: 4000, interval:40, transition: Animator.tx.linear});
anim.addSubject(function (v) { var h = 200 + (1-v) * Math.round(100 * Math.sin(v * 8*Math.PI)); t.style.top = h + 'px';});
anim.play();
基本の動きはできました。微妙に気持ち悪いのがイベントハンドラのt(id="target"要素)への依存です。こういう場合、JavaScriptでは、次のようにクロージャを使うのが定石です。
var anim = new Animator({duration: 4000, interval:40, transition: Animator.tx.linear});
var makefn = function(elm, base) { return function(v) { var h = base + (1-v) * Math.round(100 * Math.sin(v * 8*Math.PI)); elm.style.top = h + 'px';} };
anim.addSubject(makefn(t, parseInt(t.style.top)));
anim.play();
makefnは作ってすぐに使うだけなので、こういう場合、名前をつけずに呼ぶ方がJavaScript風です(以下のコード、単にmakefnを無くしただけです)。
var anim = new Animator({duration: 4000, interval:40, transition: Animator.tx.linear});
anim.addSubject((function(elm, base) { return function(v) { var h = base + (1-v) * Math.round(100 * Math.sin(v * 8*Math.PI)); elm.style.top = h + 'px';} })(t, parseInt(t.style.top)));
anim.play();
振幅の100はハードコードのまま残っています。気持ち悪ければこれも引数にできます。
ここまで来ると、実は次のように1行にもできてしまいます。
(new Animator({duration: 4000, interval:40, transition: Animator.tx.linear})).addSubject((function(elm, base) { return function(v) { var h = base + (1-v) * Math.round(100 * Math.sin(v * 8*Math.PI)); elm.style.top = h + 'px';} })(t, parseInt(t.style.top))).play();
もっとも、これはやりすぎでしょう。可読性の観点からお勧めできません。
animator.jsは実はもっとすごいことができます。次のようなコードを書き足すと、背景色が徐々に変化します。
anim.addSubject(new CSSStyleSubject(t, "background-color:#ff0000", "background-color:#0000ff"));
- Category(s)
 - カテゴリなし