ユーザーから動画が見れなくなったという問い合わせが来たので確認すると、自分達の環境では普通に見れる。原因がよくわからない。
詳しく聞いてみるとどうやらIE7 ProというIE 7のAdd-onを入れてから見れなくなったらしい。ということでそれを入れてみたところ見事に動画が再生されなくなった。
さらに詳しく調べていくと、IE7 ProのFlash広告をブロックする機能が、プレイヤーが取得しようとする動画を広告とみなしてブロックしてしまい、動画を取得できないため再生できないことがわかった。
ブロックされていた動画のURLがこれ。
http://www.flipclip.net/ads/logo_animation_a.flv
この広告ブロック、広告かどうかの判定をURLにテキストマッチをかける形で行っていて、「/ads/」という部分が判定にひっかかていたみたい。
原因がわかれば対応は簡単!
動画のURLを変更することで無事問題解決しました。
めでたしめでたし。
2008年1月25日金曜日
2006年10月4日水曜日
巨大なFLVを再生中に他のリンクをクリックしてもなかなか移動できない現象を回避する方法
FlipClipでクリップを見ていると、再生の途中で画面内のリンクをクリックして他のページに移動しようとしても、なかなか移動できなくてイライラすることがあったので、これを回避する方法がないものかと考えていたのですが、今日試した方法が有効だったので紹介します。
この現象は、再生している動画のサイズが大きい場合によく起こる現象で、リンクをクリックしてもブラウザはこの大きな動画の再生に忙しいのか、なかなか画面を切り替えてくれません。
そこで考えたのが、クリックした時に、再生している動画をけしてしまうという方法です。
試した方法は簡単で、リンクなどをクリックしてページが切り替わるタイミングで、再生中のフレームを含むdiv要素のinnnerHTMLを空にしてしまうというものです。
コードのイメージはこんな感じです。
>
最初はbeforeunloadではなくunloadで試してみましたが、タイミングが遅いらしく、効果がありませんでした。
beforeunloadはブラウザによっては動かないといった情報をどこかで見たような気がしたのですが、IE, FireFox, Safariでうまく動いたので、互換性に問題なしと判断し、FlipClipでもこの方法を早速採用しました。
画面の移動がスムースになって、いい感じです。
この現象は、再生している動画のサイズが大きい場合によく起こる現象で、リンクをクリックしてもブラウザはこの大きな動画の再生に忙しいのか、なかなか画面を切り替えてくれません。
そこで考えたのが、クリックした時に、再生している動画をけしてしまうという方法です。
試した方法は簡単で、リンクなどをクリックしてページが切り替わるタイミングで、再生中のフレームを含むdiv要素のinnnerHTMLを空にしてしまうというものです。
コードのイメージはこんな感じです。
>
<
<script type="text/javascript"><:!--
Event.observe(window, 'beforeunload', function(){
$('clipPlayer').innerHTML='';
});
--></script>
最初はbeforeunloadではなくunloadで試してみましたが、タイミングが遅いらしく、効果がありませんでした。
beforeunloadはブラウザによっては動かないといった情報をどこかで見たような気がしたのですが、IE, FireFox, Safariでうまく動いたので、互換性に問題なしと判断し、FlipClipでもこの方法を早速採用しました。
画面の移動がスムースになって、いい感じです。
2006年7月31日月曜日
コネクションプーリング都市伝説は正しそう
またちょっと古いねたですが、WEB+DB PRESS vol.33でnipotanさんが書いてたコネクションプーリング都市伝説を読んだ時、ほんとのところどっちが速いのかってのをabでベンチマークをとってみました。
ベンチマークとったときにエントリを書こうと思ってたんですが、モチベーションがあがらず今になっちゃいました。。
以下がベンチマークの結果です。
>
>
これ以外にもいくつかパスを替えてベンチマークをとったところ、いずれも若干ですがプーリングしないほうが早かったので、現在はプーリングしないほうで運用しています。
ベンチマークとったときにエントリを書こうと思ってたんですが、モチベーションがあがらず今になっちゃいました。。
以下がベンチマークの結果です。
プーリングを有効にした場合
>
<
Server Hostname: rakuda.localhost
Server Port: 80
Document Path: /
Document Length: 12323 bytes
Concurrency Level: 20
Time taken for tests: 107.840 seconds
Complete requests: 1000
Failed requests: 0
Broken pipe errors: 0
Total transferred: 12579000 bytes
HTML transferred: 12323000 bytes
Requests per second: 9.27 [#/sec] (mean)
Time per request: 2156.80 [ms] (mean)
Time per request: 107.84 [ms] (mean, across all concurrent requests)
Transfer rate: 116.65 [Kbytes/sec] received
Connnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 1
Processing: 640 2140 486.9 1999 4674
Waiting: 639 2139 486.9 1999 4673
Total: 640 2140 486.9 1999 4674
ERROR: The median and mean for the initial connection time are more than twice the standard
deviation apart. These results are NOT reliable.
Percentage of the requests served within a certain time (ms)
50% 1999
66% 2066
75% 2141
80% 2267
90% 2650
95% 3388
98% 3774
99% 3941
100% 4674 (last request)
コネクションプーリングを無効にした場合
>
<
Server Hostname: rakuda.localhost
Server Port: 80
Document Path: /
Document Length: 12323 bytes
Concurrency Level: 20
Time taken for tests: 104.939 seconds
Complete requests: 1000
Failed requests: 0
Broken pipe errors: 0
Total transferred: 12579000 bytes
HTML transferred: 12323000 bytes
Requests per second: 9.53 [#/sec] (mean)
Time per request: 2098.78 [ms] (mean)
Time per request: 104.94 [ms] (mean, across all concurrent requests)
Transfer rate: 119.87 [Kbytes/sec] received
Connnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 3
Processing: 353 2081 502.0 1969 5219
Waiting: 351 2081 502.0 1969 5219
Total: 353 2081 502.0 1969 5219
Percentage of the requests served within a certain time (ms)
50% 1969
66% 2033
75% 2117
80% 2192
90% 2503
95% 3011
98% 4032
99% 4571
100% 5219 (last request)
これ以外にもいくつかパスを替えてベンチマークをとったところ、いずれも若干ですがプーリングしないほうが早かったので、現在はプーリングしないほうで運用しています。
Sledgeのセッション用テーブルはMyISAMにしています。
naoyaさんのエントリーnaoyaのはてなダイアリー - MyISAM vs InnoDBに反応して、久々にエントリを書いてみます。
FlipClipは、すべてMyISAMで運用しているんですが、理由はあんまりなくて、デフォルトでMyISAMだからってのが大きいのと、スナップショットを取るのにmysqlsnapshotに手を加えたものを使っているので、InnoDBにするとそれを使えなくなるというのが主な理由です。それにまだDBがボトルネックだうはーってな状態になったことがないってのもあります。
それでも少し前にサーバのチューニングをそろそろ考えたほうがいいかなーということを考えたことがありまして、
その時にチューニングの候補に考えたものの一つが、Sledgeのセッション用のテーブルをMyISAMからInnoDBに替えてみるということでした。
セッションテーブルはスナップショットを取る必要ないですし、InnoDBにして早くなったらラッキーってのと、Sledgeのセッション用のテーブルは1リクエストで必ず1回書き込みが行われるので、読み込みと書き込みが同程度発生するので、更新系が多い場合はInnoDBがよいというのにあてはまるかなと思ったからです。
そこで実際にSledgeで作ったアプリケーションを使ってセッションテーブルをInnoDBにした場合と、MyISAMにした場合でどれほど性能に差がでるかabを使って簡単にベンチマークしてみました。
以下がabを使って同時10リクエストで合計1000リクエスト実行した際の結果です。
>
>
結果としてMyISAMもInnoDBも速度的にはほとんど変わらなかった(ちょっとMyISAMのほうが速かった)ので、今まで通りMyISAMでいいかという結論に達しました。
FlipClipは、すべてMyISAMで運用しているんですが、理由はあんまりなくて、デフォルトでMyISAMだからってのが大きいのと、スナップショットを取るのにmysqlsnapshotに手を加えたものを使っているので、InnoDBにするとそれを使えなくなるというのが主な理由です。それにまだDBがボトルネックだうはーってな状態になったことがないってのもあります。
それでも少し前にサーバのチューニングをそろそろ考えたほうがいいかなーということを考えたことがありまして、
その時にチューニングの候補に考えたものの一つが、Sledgeのセッション用のテーブルをMyISAMからInnoDBに替えてみるということでした。
セッションテーブルはスナップショットを取る必要ないですし、InnoDBにして早くなったらラッキーってのと、Sledgeのセッション用のテーブルは1リクエストで必ず1回書き込みが行われるので、読み込みと書き込みが同程度発生するので、更新系が多い場合はInnoDBがよいというのにあてはまるかなと思ったからです。
そこで実際にSledgeで作ったアプリケーションを使ってセッションテーブルをInnoDBにした場合と、MyISAMにした場合でどれほど性能に差がでるかabを使って簡単にベンチマークしてみました。
以下がabを使って同時10リクエストで合計1000リクエスト実行した際の結果です。
MyISAMの場合
>
<
Benchmarking rakuda.localhost (be patient)
Server Software: Apache/1.3.36
Server Hostname: rakuda.localhost
Server Port: 80
Document Path: /
Document Length: 14911 bytes
Concurrency Level: 10
Time taken for tests: 110.009 seconds
Complete requests: 1000
Failed requests: 0
Broken pipe errors: 0
Total transferred: 15167000 bytes
HTML transferred: 14911000 bytes
Requests per second: 9.09 [#/sec] (mean)
Time per request: 1100.09 [ms] (mean)
Time per request: 110.01 [ms] (mean, across all concurrent requests)
Transfer rate: 137.87 [Kbytes/sec] received
Connnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 1
Processing: 292 1096 223.5 1031 1976
Waiting: 291 1096 223.5 1031 1976
Total: 292 1096 223.5 1031 1976
ERROR: The median and mean for the initial connection time are more than twice the standard
deviation apart. These results are NOT reliable.
Percentage of the requests served within a certain time (ms)
50% 1031
66% 1071
75% 1109
80% 1145
90% 1338
95% 1753
98% 1832
99% 1888
100% 1976 (last request)
InnoDBの場合
>
<
Benchmarking rakuda.localhost (be patient)
Server Software: Apache/1.3.36
Server Hostname: rakuda.localhost
Server Port: 80
Document Path: /
Document Length: 14911 bytes
Concurrency Level: 10
Time taken for tests: 110.730 seconds
Complete requests: 1000
Failed requests: 0
Broken pipe errors: 0
Total transferred: 15167000 bytes
HTML transferred: 14911000 bytes
Requests per second: 9.03 [#/sec] (mean)
Time per request: 1107.30 [ms] (mean)
Time per request: 110.73 [ms] (mean, across all concurrent requests)
Transfer rate: 136.97 [Kbytes/sec] received
Connnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 765 1102 273.9 1010 2476
Waiting: 765 1102 273.9 1010 2476
Total: 765 1102 273.9 1010 2476
Percentage of the requests served within a certain time (ms)
50% 1010
66% 1059
75% 1120
80% 1180
90% 1466
95% 1787
98% 1973
99% 2198
100% 2476 (last request)
結果としてMyISAMもInnoDBも速度的にはほとんど変わらなかった(ちょっとMyISAMのほうが速かった)ので、今まで通りMyISAMでいいかという結論に達しました。
2006年5月23日火曜日
JSON::Syckで改行を含むデータをダンプすると改行の後にスペースが2個入る
Ajaxる時のサーバとのデータ交換フォーマットとして、JSONを使う時、perlでサーバ側を実装する際にはJSONとかJSON::Syckというモジュールを使うとperlのデータ構造をJSONフォーマットに変換してくれるので便利です。
昨日これを使って、サーバからデータを取得し、textareaに取得したデータを入れるということをしたところ、改行を含んだテキストだと、改行の後にスペースが2個入ってしまうという現象に遭遇しました。
要はこうなってほしいところが、
><
こうなってしまうんです。
><
調べてみると、クライアントで受け取ったJSONデータをevalした段階ですでにスペースを含んでいたので、サーバ側でJSONデータを作成するところに問題がありそうだということがわかりました。
そこで以下のようなスクリプトを書いて、JSON,JSON::SyckがどんなJSONデータを吐き出すか見てみました。
>
結果は以下のとおり。
>
どうやらJSON::Syckを使ってダンプしたデータは、整形のため、改行の後に、スペースが2個入っているようです。それでこれをJavaScriptでevalするとこのスペースもデータとして含まれてしまうため、上記のような現象が起きたみたいです。
そもそも改行後にスペースが入ってしまうのが問題なのか、スペースが入るのは問題なくて、クライアント側のJavaScriptでのパースに問題があるのかわかってませんが、試した限りだと、IEとFirefoxでスペースつきのデータの扱い方が異なるようで、挙動が変わってしまい、困りました。
とりあえず、サーバ側で改行コードを[BR]とかに変換しておいて、クライアント側でそれを改行コードとか、<br />に変換するという風にして対処しましたが、ちょっと付け焼刃的ですかねー。
昨日これを使って、サーバからデータを取得し、textareaに取得したデータを入れるということをしたところ、改行を含んだテキストだと、改行の後にスペースが2個入ってしまうという現象に遭遇しました。
要はこうなってほしいところが、
><
こうなってしまうんです。
><
調べてみると、クライアントで受け取ったJSONデータをevalした段階ですでにスペースを含んでいたので、サーバ側でJSONデータを作成するところに問題がありそうだということがわかりました。
そこで以下のようなスクリプトを書いて、JSON,JSON::SyckがどんなJSONデータを吐き出すか見てみました。
>
<
#!/usr/bin/env perl
use strict;
use JSON::Syck;
use JSON;
my $data = {
key => "foo\nbar\nbaz\n"
};
print "# Dumped by JSON::Syck $JSON::Syck::VERSION:\n";
print JSON::Syck::Dump($data), "\n";
print "# Dumped by JSON $JSON::VERSION:\n";
print objToJson($data), "\n";
結果は以下のとおり。
>
<
# Dumped by JSON::Syck 0.12:
{"key":"foo\n\
bar\n\
baz\n"}
# Dumped by JSON 1.05:
{"key":"foo\nbar\nbaz\n"}
どうやらJSON::Syckを使ってダンプしたデータは、整形のため、改行の後に、スペースが2個入っているようです。それでこれをJavaScriptでevalするとこのスペースもデータとして含まれてしまうため、上記のような現象が起きたみたいです。
そもそも改行後にスペースが入ってしまうのが問題なのか、スペースが入るのは問題なくて、クライアント側のJavaScriptでのパースに問題があるのかわかってませんが、試した限りだと、IEとFirefoxでスペースつきのデータの扱い方が異なるようで、挙動が変わってしまい、困りました。
とりあえず、サーバ側で改行コードを[BR]とかに変換しておいて、クライアント側でそれを改行コードとか、<br />に変換するという風にして対処しましたが、ちょっと付け焼刃的ですかねー。
2006年5月21日日曜日
OOなJavaScriptの勉強がてら、ボタンの2度押し禁止機能を簡単に実現するライブラリを作ってみました
ちょっと時代に乗り遅れている気もしますが、最近prototype.jsをつかったOOなJavaScriptを書くのにはまっています。
今日はbindとbindAsEbentListenerの勉強がてら、これまたかなり昔話題になった「2度押し禁止ボタン」を実現するコードを書いてみました。
input.js
使い方はこんな感じです。
>
ボタンのテキストを変えたい場合は2番目の引数に代替テキストを渡します。
画像の場合は代替画像のURLを渡します。
>
一定時間経過後にボタンを再度有効にしたい場合は、3番目の引数に有効にするまでの時間をミリ秒単位で渡します。
>
サンプルページにサンプルがあります。
また、input.jsの中身はこんな感じです。画像ボタンの扱いはもっといい方法があるのかなーとも思うんですが、おかしなところがあったら突っ込んでください。
>
今日はbindとbindAsEbentListenerの勉強がてら、これまたかなり昔話題になった「2度押し禁止ボタン」を実現するコードを書いてみました。
input.js
使い方はこんな感じです。
>
<
// prototype.jsとinput.jsをロードします。
<script type="text/javascript" src="/path/to/prototype.js"></script>
<script type="text/javascript" src="/path/to/input.js"></script>
<script type="text/javascript"><!--
// windoのロード時に2度押し禁止機能を有効にします。
Event.observe(window, 'load', function(){
// ボタンのIDか要素のオブジェクトを渡せばクリックすると押せなくなります。
new Input.DisableAfterClick('myButton');
}, false);
--></script>
ボタンのテキストを変えたい場合は2番目の引数に代替テキストを渡します。
画像の場合は代替画像のURLを渡します。
>
<
new Input.DisableAfterClick('mySubmitButton2', '送信中です');
new Input.DisableAfterClick('myImageButton2', '/path/to/image2.gif');
一定時間経過後にボタンを再度有効にしたい場合は、3番目の引数に有効にするまでの時間をミリ秒単位で渡します。
>
<
new Input.DisableAfterClick('myButton', '1秒後にまた有効になります', 1000);
サンプルページにサンプルがあります。
また、input.jsの中身はこんな感じです。画像ボタンの扱いはもっといい方法があるのかなーとも思うんですが、おかしなところがあったら突っ込んでください。
>
<
var Input = new Object();
Input.DisableAfterClick = Class.create();
Input.DisableAfterClick.prototype = {
initialize : function(input, alt, timer){
this.input = $(input);
this.alt = alt;
this.timer = timer;
this.org = this.input.type == 'image'
? this.input.src
this.stopEvent = this._stopEvent.bindAsEventListener(this);
Event.observe(this.input, 'click', this.disable.bind(this));
},
disable : function() {
this.input.blur();
if (this.input.type == 'image'){
if ( this.alt )
this.input.src = this.alt;
Event.observe(this.input, 'click', this.stopEvent);
} else {
if ( this.alt )
this.input.value = this.alt;
this.input.disabled = true;
}
if (this.timer)
setTimeout(this.enable.bind(this), this.timer);
},
enable : function() {
if (this.input.type == 'image'){
if ( this.alt )
this.input.src = this.org;
Event.stopObserving(this.input, 'click', this.stopEvent);
} else {
if ( this.alt )
this.input.value = this.org;
this.input.disabled = '';
}
},
_stopEvent : function (evt) {
evt.stop();
return false;
}
};
2006年3月15日水曜日
_blankを使わないで別ウィンドウを開くにはrel="external"を使うのが美しいと思う。
はてなブックマークをみていたら、気になるエントリーを発見。
[戯] target="_blank" を使わないで新しいウィンドウでリンクを開く方法
target="_blank"という書き方がXHTML 1.1 や XHTML Basicに準拠していないので、これらに準拠するようにしつつ、別ウィンドウで開くにはどうすればよいかという話です。
別ウィンドウで開くにはJavaScriptを使えってのが推奨される方法なんですが、onclickを使って定義するのはめんどうということで、この記事では、aタグにclass="popup"という属性を与えておけば、JavaScriptで別ウィンドウを開くということをしています。
この件については友人のHTML、CSSマスターなkawachi君と話したことがあって、そのときは、下のエントリで紹介されているrel="external"という方法を使うのがいいんじゃないかという結論に達しました。
Opening a link in a new window - the valid way
僕は上のエントリを参考に以下のようなjsファイルを用意して使っています。
>
使い方は簡単でこのjsファイルをインクルードするだけです。
>
load時にこのファンクションを実行するためにprototype.jsのEvent.observeを使っているため、
prototype.jsもインクルードしています。ここはwindow.onload=externalLinks;に書き換えれば、
prototype.jsは必要ありません。
このファイルをインクルードすると、rel="external"と指定したaタグをクリックすると別ウィンドウで開くようになります。
>
rel="external"というこのリンク先は外部のサイトだよという関連性を示す記述に対して、JavaScriptで別ウィンドウで開くんだよと定義してあげるというアプローチが美しいなと思っています。
[戯] target="_blank" を使わないで新しいウィンドウでリンクを開く方法
target="_blank"という書き方がXHTML 1.1 や XHTML Basicに準拠していないので、これらに準拠するようにしつつ、別ウィンドウで開くにはどうすればよいかという話です。
別ウィンドウで開くにはJavaScriptを使えってのが推奨される方法なんですが、onclickを使って定義するのはめんどうということで、この記事では、aタグにclass="popup"という属性を与えておけば、JavaScriptで別ウィンドウを開くということをしています。
この件については友人のHTML、CSSマスターなkawachi君と話したことがあって、そのときは、下のエントリで紹介されているrel="external"という方法を使うのがいいんじゃないかという結論に達しました。
Opening a link in a new window - the valid way
僕は上のエントリを参考に以下のようなjsファイルを用意して使っています。
>
<
//external.js
function externalLinks() {
if (!document.getElementsByTagName) return;
var anchors = document.getElementsByTagName("a");
for (var i=0; i<anchors.length; i++) {
var anchor = anchors[i];
if (anchor.getAttribute("href") &&
anchor.getAttribute("rel") == "external")
anchor.target = "_blank";
}
}
Event.observe(window,'load', externalLinks, false);
使い方は簡単でこのjsファイルをインクルードするだけです。
>
<
<script type="text/javascript" src="/path/to/prototype.js"></script<
<script type="text/javascript" src="/path/to/external.js"></script>
load時にこのファンクションを実行するためにprototype.jsのEvent.observeを使っているため、
prototype.jsもインクルードしています。ここはwindow.onload=externalLinks;に書き換えれば、
prototype.jsは必要ありません。
このファイルをインクルードすると、rel="external"と指定したaタグをクリックすると別ウィンドウで開くようになります。
>
<
<a rel="external" href="http://www.google.com/">別ウィンドウで開きます。</a>
rel="external"というこのリンク先は外部のサイトだよという関連性を示す記述に対して、JavaScriptで別ウィンドウで開くんだよと定義してあげるというアプローチが美しいなと思っています。
2005年9月30日金曜日
続・onload時に複数のfunctionを実行するJavaScript
ちょっと前に書いたonload時に複数のfunctionを実行するJavascriptというエントリーへのkoさんのコメントでaddEventListenerというのを初めて知りました。
これは何なんだろうということで、調べてみると、W3C DOM Level2 のイベントモデルでイベントハンドリングを行う際に使う関数だということがわかりました。
もう少し調べてみると、このDOM Level2、FirefoxなどMozilla系のブラウザには実装されているようなのですが、IEには実装されていないため、addEventListenerが使えず、そのかわりに同等の機能をもったattachEventという関数が定義されているそうです。
将来的にはIEもDOM Level2をサポートして、addEventListenerが使えるようになると思いますが、現状では、ブラウザを判定してaddEventListenerを使うか、attachEventを使うかを切り替える必要がありそうです。うーん、めんどくさい。。
なので、ブラウザに依存しない前回書いた方法もまんざら無駄骨ということもなかったかな、と思っていたんですが、昨日友人にイベントの登録はprototype使えば簡単にできるよといわれ、無駄骨だったことが確定しましたw
prototype.jsを使ったonload時に実行するfunctionの登録はこんな感じです。
>
prototype.jsで定義されているEvent.observeを使って関数を登録します。引数は最初に対象となるオブジェクトを渡すところ以外はaddEventListenerと同じです。IE6とFirefox1.0.7で動作することを確認しました。
IEと、Firefoxでは関数の実行順が逆になってましたが、DOM Level2でもイベントの実行順は定義されてないことと、そもそも実行順に結果が依存するような関数はひとつにまとめておくべきだと思うので、これは問題にならなそうです。
prototypeにはこれ以外にもまだまだ知らない便利な関数、クラスがたくさんありそうです。prototype恐るべし。
これは何なんだろうということで、調べてみると、W3C DOM Level2 のイベントモデルでイベントハンドリングを行う際に使う関数だということがわかりました。
もう少し調べてみると、このDOM Level2、FirefoxなどMozilla系のブラウザには実装されているようなのですが、IEには実装されていないため、addEventListenerが使えず、そのかわりに同等の機能をもったattachEventという関数が定義されているそうです。
将来的にはIEもDOM Level2をサポートして、addEventListenerが使えるようになると思いますが、現状では、ブラウザを判定してaddEventListenerを使うか、attachEventを使うかを切り替える必要がありそうです。うーん、めんどくさい。。
なので、ブラウザに依存しない前回書いた方法もまんざら無駄骨ということもなかったかな、と思っていたんですが、昨日友人にイベントの登録はprototype使えば簡単にできるよといわれ、無駄骨だったことが確定しましたw
prototype.jsを使ったonload時に実行するfunctionの登録はこんな感じです。
>
<
<!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>Event observe sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
<script type="text/javascript" src="/js/prototype-1.3.1.js"></script>
<script type="text/javascript">
function foo() {alert('foo')}
function bar() {alert('bar')}
function baz() {alert('baz')}
Event.observe(window, 'load', foo, false);
Event.observe(window, 'load', bar, false);
Event.observe(window, 'load', baz, false);
</script>
</head>
<body></body>
</html>
prototype.jsで定義されているEvent.observeを使って関数を登録します。引数は最初に対象となるオブジェクトを渡すところ以外はaddEventListenerと同じです。IE6とFirefox1.0.7で動作することを確認しました。
IEと、Firefoxでは関数の実行順が逆になってましたが、DOM Level2でもイベントの実行順は定義されてないことと、そもそも実行順に結果が依存するような関数はひとつにまとめておくべきだと思うので、これは問題にならなそうです。
prototypeにはこれ以外にもまだまだ知らない便利な関数、クラスがたくさんありそうです。prototype恐るべし。
2005年9月19日月曜日
onload時に複数のfunctionを実行するJavaScript
昨日に引き続きJavaScriptねたです。
ページを表示した時点でJavaScriptを実行したい場合、
>
のようにwindowオブジェクトのonloadイベントに実行したいfunctionをセットしてやればいいのですが、これだと、オンロード時にひとつのfunctionしか実行できません。
そこで、オンロード時に複数のfunctionを実行できるようなスクリプトを書いてみました。今回のコードはnaoyaさんのprototype.js でデザインパターン - IteratorのエントリにあるIteratorパターンのコードをそのまま借りたリスペクト指向プログラミングになってますw
>
使用方法はこんな感じです。
動作させるにはprototype.jsが必要なので最初にインクルードしています。
>
まず、multiple_onload.jsをインクルードしておきます。そして、定義したfunctionをappendFunctionメソッドを使ってセットしておきます。
これでfoo,bar,bazがオンロード時に順番に実行されます。
ページを表示した時点でJavaScriptを実行したい場合、
>
<
window.onload=function(){ alert('called when window is loaded.'); }
のようにwindowオブジェクトのonloadイベントに実行したいfunctionをセットしてやればいいのですが、これだと、オンロード時にひとつのfunctionしか実行できません。
そこで、オンロード時に複数のfunctionを実行できるようなスクリプトを書いてみました。今回のコードはnaoyaさんのprototype.js でデザインパターン - IteratorのエントリにあるIteratorパターンのコードをそのまま借りたリスペクト指向プログラミングになってますw
>
<
//multiple_onload.js
var OnloadFunction = Class.create();
OnloadFunction.prototype = {
initialize : function(func) {
this.func = func;
},
getFunc : function() {
return this.func;
}
};
var OnloadFunctions = Class.create();
OnloadFunctions.prototype = {
initialize : function() {
this.last = 0;
this.functions = new Array();
},
getFunctionAt : function(index) {
return this.functions[index];
},
appendFunction : function(func) {
this.functions[this.last] = func;
this.last++;
},
getLength : function() {
return this.last;
},
iterator : function() {
return new OnloadFunctionIterator(this);
}
}
var OnloadFunctionIterator = Class.create();
OnloadFunctionIterator.prototype = {
initialize : function(functions) {
this.functions = functions;
this.index = 0;
},
hasNext : function () {
return this.index < this.functions.getLength();
},
next : function() {
return this.functions.getFunctionAt(this.index++);
}
}
var onloadFunctions = new OnloadFunctions();
function multipleOnload () {
var it = onloadFunctions.iterator();
while (it.hasNext()){
var func = it.next();
func.func();
}
}
window.onload = multipleOnload;
使用方法はこんな感じです。
動作させるにはprototype.jsが必要なので最初にインクルードしています。
>
<
<html>
<head>
<script type="text/javascript" src="/js/prototype-1.3.1.js" ></script>
<script type="text/javascript" src="/js/multiple_onload.js" ></script>
<script type="text/javascript">
functon foo() {alert('foo');}
functon bar() {alert('bar');}
functon baz() {alert('baz');}
onloadFunctions.appendFunction(new OnloadFunction(foo) );
onloadFunctions.appendFunction(new OnloadFunction(bar) );
onloadFunctions.appendFunction(new OnloadFunction(baz) );
</script>
</head>
<body>
...
</body>
</html>
まず、multiple_onload.jsをインクルードしておきます。そして、定義したfunctionをappendFunctionメソッドを使ってセットしておきます。
これでfoo,bar,bazがオンロード時に順番に実行されます。
2005年9月18日日曜日
画像のスワップをクラス名で制御するJavaScript(プリロード付き)
ちょっとJavaScriptをまじめに勉強しようかと思い始めました。
というわけで、手始めにマウスオーバーすると別画像に切り替わるスクリプトを書いてみました。
マウスオーバーで画像が切り替わるなんて、Dreamweaver使えばJavaScriptを知らなくてもできてしまうんですが、Dreameweaverが吐き出すコードはHTMLタグの中にonload="xxxxxxxx"とか、onmouseover="xxxxx"をやたらと追加して、非常に見づらいのです。
これだとテキストエディタでちょろっとHTMLを編集したい時に大変ですし、きっとGoogleさんもクロールしにくいでしょうから、imgタグに予めスワップ用に設定しておいたクラス名を記述しておけば、マウスオーバー、マウスアウトで画像が切り替わるようにしてみました。
作成したスクリプトはこんな感じです。クラス名から要素を取得するところはprototype.jsから借りてきました。
>
実際の使用例はこんな感じです。クラス名により画像のスワップを制御するようにすることで、HTMLがすっきりしました。さらにhead要素内のscriptタグを削除してもValidなHTMLのままってところもいいですよね。
>
というわけで、手始めにマウスオーバーすると別画像に切り替わるスクリプトを書いてみました。
マウスオーバーで画像が切り替わるなんて、Dreamweaver使えばJavaScriptを知らなくてもできてしまうんですが、Dreameweaverが吐き出すコードはHTMLタグの中にonload="xxxxxxxx"とか、onmouseover="xxxxx"をやたらと追加して、非常に見づらいのです。
これだとテキストエディタでちょろっとHTMLを編集したい時に大変ですし、きっとGoogleさんもクロールしにくいでしょうから、imgタグに予めスワップ用に設定しておいたクラス名を記述しておけば、マウスオーバー、マウスアウトで画像が切り替わるようにしてみました。
作成したスクリプトはこんな感じです。クラス名から要素を取得するところはprototype.jsから借りてきました。
>
<
// swap_image.js
var imagesNormal = new Object();
var imagesHilite = new Object();
function SwapImage (name,normalSrc,hiliteSrc) {
this.name = name;
this.normalSrc = normalSrc;
this.hiliteSrc = hiliteSrc;
}
function setupSwapImages(swapImages) {
preloadSwapImages(swapImages);
setupSwapEvent(swapImages);
}
function preloadSwapImages (a) {
for (var i=0; i < a.length; i++){
imagesNormal[a[i].name] = new Image();
imagesNormal[a[i].name].src = a[i].normalSrc;
imagesHilite[a[i].name] = new Image();
imagesHilite[a[i].name].src = a[i].hiliteSrc;
}
}
function setupSwapEvent (a) {
for (var i=0; i<a.length; i++){
var images = getElementsByClassName(a[i].name);
for (var j=0; j<images.length; j++){
var image = images[j];
if (image.getAttribute("src")){
image.onmouseover = function () {swapImage( this, "hilite" );}
image.onmouseout = function () {swapImage( this, "normal" );}
}
}
}
}
// 2006-05-15追記
function swapImage(image,type){
if (type=="hilite") {
image.src = imagesHilite[image.className].src;
} else if (type=="normal") {
image.src = imagesNormal[image.className].src;
}
}
// 追記ここまで(こぴぺしわすれ・・。)
// copied from prototype.js v1.3.1
// http://prototype.conio.net/
function getElementsByClassName (className) {
var children = document.getElementsByTagName('*') || document.all;
var elements = new Array();
for (var i = 0; i < children.length; i++) {
var child = children[i];
var classNames = child.className.split(' ');
for (var j = 0; j < classNames.length; j++) {
if (classNames[j] == className) {
elements.push(child);
break;
}
}
}
return elements;
}
実際の使用例はこんな感じです。クラス名により画像のスワップを制御するようにすることで、HTMLがすっきりしました。さらにhead要素内のscriptタグを削除してもValidなHTMLのままってところもいいですよね。
>
<
<html>
<head>
<script type="text/javascript" src="/js/swap_image.js" ></script>
<script type="text/javascript">
var swapImages = [
new SwapImage('class01','/images/foo.gif', '/images/foo_onmouse.gif'),
new SwapImage('class02','/images/bar.gif', '/images/bar_onmouse.gif'),
new SwapImage('class03','/images/baz.gif', '/images/baz_onmouse.gif')
];
window.onload = function () {setupSwapImages(swapImages);};
</script>
</head>
<body>
<img src="/images/foo.gif" class="class01" />
<img src="/images/bar.gif" class="class02" />
<img src="/images/baz.gif" class="class03" />
</body>
</html>
2005年8月23日火曜日
クリックするとすべて選択されるテキストエリア
GoogleAdsenseのテキストエリア
created by horiuchi.
GoogleAdsenseのAdsenseコードを表示するテキストエリアがちょっと便利。クリックすると、テキストエリア内のコードがすべて選択された状態になるので、あとは右クリックしてコピーするだけでOK。ちょっとした気遣いだけど、これだけですごく使い勝手がよくなっている気がします。
実際どうやって実現しているのかなとコードを覗いてみると、こんな感じ。
>
<
<textarea readonly rows="12" cols="65" onclick="this.focus();this.select()" id="code">
標準関数のfocus()とselect()を使うだけでできてしまうので、非常に簡単ですね。早速まねしよう。
2005年5月30日月曜日
SEPY ActionScript Editor - オープンソースなActionScriptエディタ
SEPY ActionScript Editor: Epic->yoshimax
もうひとつyoshimaxさんのより。
オープンソースなActionScriptエディタSEPY ActionScript Editor というのがyoshimaxさんの周りではやっているらしい。
もうひとつyoshimaxさんのより。
オープンソースなActionScriptエディタSEPY ActionScript Editor というのがyoshimaxさんの周りではやっているらしい。
Live Journalのバックエンド
qootas.org/blogさんのBlog Hackers Conference 2005のエントリで取り上げられていたInside LiveJournal's Backend
という資料が興味深いです。
前のエントリで書いた画像とか動画のような大きなファイルを扱うにはどうしたらいいかという疑問にたいする解答もこの中からつかめるかも。
perlベースのリバースプロキシロードバランサー兼WebサーバPerlbalは負荷分散に使えるだけでなく、mod_perlと組み合わせてファイル閲覧の認証とかもできるようなので、もう少し詳しく調べてみようかと思います。
という資料が興味深いです。
前のエントリで書いた画像とか動画のような大きなファイルを扱うにはどうしたらいいかという疑問にたいする解答もこの中からつかめるかも。
perlベースのリバースプロキシロードバランサー兼WebサーバPerlbalは負荷分散に使えるだけでなく、mod_perlと組み合わせてファイル閲覧の認証とかもできるようなので、もう少し詳しく調べてみようかと思います。
2005年5月27日金曜日
Seleniumすごい
Selenium: blog.bulknews.netより
Javascriptを利用したWebアプリケーションのテストツールSeleniumというのが熱いらしいので、ちょっと試してみました。
これちょっとすごいですね。
一番驚いたのが、テストケースの作成が簡単にできること。HTMLのテーブル内にテストの手順を書いていけばそれがそのまま実行可能なテストケースになってしまいます。
このHTML見た目はちょっとしたテスト仕様書なので、そのまま成果物として出すことも可能かもしれません。ただ、内容が英語になるので、ちょっと読みにくくはありますが。。
テストケースを日本語で書けたらほんとそのままテスト仕様書になるなぁと思ってみました。
Javascriptを利用したWebアプリケーションのテストツールSeleniumというのが熱いらしいので、ちょっと試してみました。
これちょっとすごいですね。
一番驚いたのが、テストケースの作成が簡単にできること。HTMLのテーブル内にテストの手順を書いていけばそれがそのまま実行可能なテストケースになってしまいます。
このHTML見た目はちょっとしたテスト仕様書なので、そのまま成果物として出すことも可能かもしれません。ただ、内容が英語になるので、ちょっと読みにくくはありますが。。
テストケースを日本語で書けたらほんとそのままテスト仕様書になるなぁと思ってみました。
2005年5月24日火曜日
Prototype.jsのEffectサンプル
オブジェクト指向JavaScriptライブラリPrototypeを試すために作ったページがそのままサンプルになりそうだったので、公開してみます。
Prototype.js - Effectサンプル
イベントを定義するだけでここまでのことが出来るのにちょっと感動しました。
Prototypeいい感じです。
ちょっと気になった点
-Effect.Fade()とEffect.AppearはFirefoxでみるといい感じだけどIEだとしょぼい
-Effect.Scaleは動きがもっさりしているような。。
-sleipnirでEffect.Puff()中にブラウザごと落ちることがしばしば。
Prototype.js - Effectサンプル
イベントを定義するだけでここまでのことが出来るのにちょっと感動しました。
Prototypeいい感じです。
ちょっと気になった点
-Effect.Fade()とEffect.AppearはFirefoxでみるといい感じだけどIEだとしょぼい
-Effect.Scaleは動きがもっさりしているような。。
-sleipnirでEffect.Puff()中にブラウザごと落ちることがしばしば。
2005年4月26日火曜日
郵便番号変換でXMLRPCサーバのベンチ
XML-RPCを使って、郵便番号から住所引っ張ってくるサービスを作る際に、perlとPHPどちらの方がパフォーマンスがでるのか気になったので、ちょっと実験してみました。
perlの方はnaoyaさんのApache::XMLRPC::Lite を使った mod_perl ハンドラによる XML-RPC サーバのエントリを参考にApache::XMLRPC::LiteとClass::DBIを使って実装し、PHPの方はXMLRPCの実装にXML-RPC for PHPにあるライブラリを使い、DBとの連携は組み込みのmysql_connectとかを使って実装してみました。ちなみにPHPはまともに動くコードを初めて書きましたが、意外と書けるものですねw
ベンチマークにはabを使い、同時接続数が1,5,10,20の場合をそれぞれ測定してみました。
>
以下結果です。
-Apache::XMLRPC::Lite
-Apache::XMLRPC::Lite(レスポンスを強制的にbase64にした場合)
-PHP
-CGI ( perl )
レスポンスを強制的にbase64にした場合を測定したのはSOAP::Liteのドキュメントにそうするとパフォーマンスをあがるというようなことが書かれていたので試してみました。
ですが、結果としてはそれほどパフォーマンスはあがってません。逆に同時アクセス数を大きくするとパフォーマンスが落ちてしまいました。
また、PerlとPHPではそれほどパフォーマンスに違いがないようです。
PHPだと劇的に早いという結果になったらPHPにしようかとも思ったのですが、結局どちらにしても違いはそれほどなさそうなので、得意のPerlで行くことにしました。
perlの方はnaoyaさんのApache::XMLRPC::Lite を使った mod_perl ハンドラによる XML-RPC サーバのエントリを参考にApache::XMLRPC::LiteとClass::DBIを使って実装し、PHPの方はXMLRPCの実装にXML-RPC for PHPにあるライブラリを使い、DBとの連携は組み込みのmysql_connectとかを使って実装してみました。ちなみにPHPはまともに動くコードを初めて書きましたが、意外と書けるものですねw
ベンチマークにはabを使い、同時接続数が1,5,10,20の場合をそれぞれ測定してみました。
>
<
ab -n 100 -c 1 -T text/xml -p post.txt -w http://horiuchi.vcube.net/zipconv/xmlrpc > result.html
以下結果です。
-Apache::XMLRPC::Lite
-Apache::XMLRPC::Lite(レスポンスを強制的にbase64にした場合)
-PHP
-CGI ( perl )
レスポンスを強制的にbase64にした場合を測定したのはSOAP::Liteのドキュメントにそうするとパフォーマンスをあがるというようなことが書かれていたので試してみました。
ですが、結果としてはそれほどパフォーマンスはあがってません。逆に同時アクセス数を大きくするとパフォーマンスが落ちてしまいました。
また、PerlとPHPではそれほどパフォーマンスに違いがないようです。
PHPだと劇的に早いという結果になったらPHPにしようかとも思ったのですが、結局どちらにしても違いはそれほどなさそうなので、得意のPerlで行くことにしました。
2005年3月20日日曜日
2005年2月28日月曜日
2004年11月25日木曜日
iモード向けサイトでリダイレクト使う際は最後の/に注意
今日iモード向けのコンテンツで、QVGA端末かQQVGA端末かを判別して各端末用のページにリダイレクトするというスクリプトを書いたんですが、リダイレクトする際に必ず「ページが移動しました」のようなメッセージがでてしまうという現象に出くわしました。
今まで同じようなスクリプトを書いたときにはこんな現象が起きたことがなかったので、一瞬とまどいましたが、原因はなんてことなく、Locationで指定した飛び先のURLの最後に/(スラッシュ)がついていなかったからでした。
たとえば、http://hori-uchi.com/qvga/index.htmlにリダイレクトさせたくて、
>
と記述すると、携帯のブラウザではまずhori-uchi.comの/qvgaというファイルを見に来るのですが、そのファイルがないので(ディレクトリなので)、次に/qvga/index.htmlを取得しようと試みます。どうやらこのファイルがないので・・・のあたりで、「ページが移動しました」のようなメッセージを表示するようです。/があるとないとで大違いなんですね。
今まで同じようなスクリプトを書いたときにはこんな現象が起きたことがなかったので、一瞬とまどいましたが、原因はなんてことなく、Locationで指定した飛び先のURLの最後に/(スラッシュ)がついていなかったからでした。
たとえば、http://hori-uchi.com/qvga/index.htmlにリダイレクトさせたくて、
>
print "Location: http://hori-uchi.com/qvga";<
print "\n\n";
と記述すると、携帯のブラウザではまずhori-uchi.comの/qvgaというファイルを見に来るのですが、そのファイルがないので(ディレクトリなので)、次に/qvga/index.htmlを取得しようと試みます。どうやらこのファイルがないので・・・のあたりで、「ページが移動しました」のようなメッセージを表示するようです。/があるとないとで大違いなんですね。
登録:
投稿 (Atom)

