画面内に自由につぶやける

twitter+αというイメージで作成した、PHP+JavaScriptの作品紹介です。画面内のどこにでも、色を指定して短文をつぶやくことができます。大きさは時系列順になっており、古くなるほど小さく、薄く変化します。パスワードは「1234」となってますので、お試しください。

murmur

murmur.png

JavaScriptによる色空間

ペイントでパレットにない色を作成するとき開く画面がありますよね。カラフルなあれです。カラーピッカーって言うらしいですが...、あれをJavaScriptを使って再現しようと思います。使う知識はHSVとRGBについての知識で、RGBは文字通りRed、Blue、Greenですが、HSVとは何でしょう?僕も初めて知ったのですが、Hue、Saturation、Valueの頭文字で、それぞれ色相、彩度、明度のことらしいです。ペイントで使っているのはHSVとはちょっとばかし違うようですが、まぁ細かいことは気にせずやっていきたいと思います。さてさて問題なのはペイントではHSVで色を表していますが、HTMLではRGB(16進数で例えば#FF0000は赤)でしか表せない点ですね。よってHSVからRGBへと変換しなければなりません。そこでまずはHSVについてお勉強しましょう。
錯体のHSV色空間
図1 錯体のHSV色空間
Wikipedia: HSV色空間より抜粋)


HSVはそれぞれ以下のように定義します。
H: 0~360
S: 0.0~1.0
V: 0.0~1.0
Hについては図を見ての通りぐるっと一周360度です。その他は0~1の範囲にあるパラメータとします。さて、しかしながらこのHが曲者でして...、Hは色相ですのでペイントでやってみると、たとえば左上の点から上に沿って右に進ませていくっていう操作に当たります。このときRGBをじっくり観察してみると、
R ⇒ Y ⇒ G ⇒ C ⇒ B ⇒ M
(Y:Yellow、C:Cyan、M:Magenta)と移り変わります。要は、まずRを255に保ったままGが0から255へ変化、後Gを255に保ったままRが255から0へ変化...(以下略)と動きます。プログラムし辛い...、ヤダヤダ。と思っているところにWikipedia様が登場です。


H_i = \lfloor { H \over 60 } \rfloor mod 6

f = { H \over 60 } - H_i

p = V ( 1 - S ) \,

q = V ( 1 - f S ) \,

t = V ( 1 -  ( 1 - f ) S ) \,

\mbox{if } H_i = 0 \rightarrow R = V, G = t, B = p \,

\mbox{if } H_i = 1 \rightarrow R = q, G = V, B = p \,

\mbox{if } H_i = 2 \rightarrow R = p, G = V, B = t \,

\mbox{if } H_i = 3 \rightarrow R = p, G = q, B = V \,

\mbox{if } H_i = 4 \rightarrow R = t, G = p, B = V \,

\mbox{if } H_i = 5 \rightarrow R = V, G = p, B = q \,

Wikipedia: HSV色空間より抜粋)


なんと!こんな便利な変換式があるんですね。この計算のミソは、はじめにHiを60で割ってあげるところにあります。すると0~6(0/60~360/60)になるのですが、この値をガウス記号(床関数、floor)で切り捨ててあげちゃうんです。つまり、0、1、2、3、4、5のどれかにしちゃうというわけですが...、すると、この数字がそれぞれRYGCBMのどれかに当たることになります!なるほど、これで場合分けをすればいいのか...。ちなみにmod6(6で割ったときの余り)を求めているのは、色相が0~360ではない角度(1000度とか)になった場合を考慮してのものです。さてさて、この数字による場合分けを行ってしまえばめでたくHMKをRGBに変換することができるので、以下にソースを示します。

// HSVtoRGB変換
function HSVtoRGB(H, S, V) {
    var ret = [0, 0, 0];

    // 引数チェック
    if(S < 0 || S > 1 || V < 0 || V > 1) return ret;
    var Hi = Math.floor(H/60) % 6;
    var f  = (H/60) - Hi;

    // RGB
    V = V * 255;
    var p = Math.round(V * (1 - S));
    var q = Math.round(V * (1 - f*S));
    var t = Math.round(V * (1 - (1 - f)*S));

    V = Math.round(V);

    // 色相による場合わけ
    switch(Hi) {
        case 0: ret = [V, t, p]; break;
        case 1: ret = [q, V, p]; break;
        case 2: ret = [p, V, t]; break;
        case 3: ret = [p, q, V]; break;
        case 4: ret = [t, p, V]; break;
        case 5: ret = [V, p, q]; break;
    }
    return ret;
}
こんな感じで配列でRGBを返します。どうせならペイントみたいなインターフェースを作ってしまいましょう。これを頭に#をつけた16進数コードであらわされたRGBの文字列に変換する関数を付け加えます。
function RGBto16(RGB) {
     var R = (RGB[0] < 16) ? "0" + RGB[0].toString(16): RGB[0].toString(16);
    var G = (RGB[1] < 16) ? "0" + RGB[1].toString(16): RGB[1].toString(16);
    var B = (RGB[2] < 16) ? "0" + RGB[2].toString(16): RGB[2].toString(16);
    return ("#" + R + G + B);
}

function getClr(H, S, V) {
    return RGBto16(HSVtoRGB(H,S,V));
}
ここでtoString()を使いましたが、これは与えた引数を基数とした数字を返してくれます。16なので16進数のコードが返ってくるわけです。んー、便利。また、3項演算子を用いて、もし、15=fのように16進数に直した時1文字になってしまうとき、頭に0をつけて2文字にするようにします。この関数とHSVtoRGB()をまとめてやってくれるgetClr()を定義しました。この関数を使って色を設定します。表示部は以下のようになります。

これを書くと下のようになります。
ちなみに、上の例ではペイントに合わせるため、getClrの第3引数を(2+j)/3としました。もし、ここが1だった場合は下はグレーではなく真白になります。
さて、それではペイントライクなカラーピッカーの完成版のソースコードとサンプルを示します。
// パラメータ
di = 6;        // 横の刻み(0~360)
dj = 0.04;    // 縦の刻み(0~1)

// HSVtoRGB変換
function HSVtoRGB(H, S, V) {
    var ret = [0, 0, 0];

    // 引数チェック
    if(S < 0 || S > 1 || V < 0 || V > 1) return ret;
    var Hi = Math.floor(H/60) % 6;
    var f  = (H/60) - Hi;

    // RGB
    V = V * 255;
    var p = Math.round(V * (1 - S));
    var q = Math.round(V * (1 - f*S));
    var t = Math.round(V * (1 - (1 - f)*S));

    V = Math.round(V);

    // 色相による場合わけ
    switch(Hi) {
        case 0: ret = [V, t, p]; break;
        case 1: ret = [q, V, p]; break;
        case 2: ret = [p, V, t]; break;
        case 3: ret = [p, q, V]; break;
        case 4: ret = [t, p, V]; break;
        case 5: ret = [V, p, q]; break;
    }
    return ret;
}

// 16進数変換
function RGBto16(RGB) {
    var R = (RGB[0] < 16) ? "0" + RGB[0].toString(16): RGB[0].toString(16);
    var G = (RGB[1] < 16) ? "0" + RGB[1].toString(16): RGB[1].toString(16);
    var B = (RGB[2] < 16) ? "0" + RGB[2].toString(16): RGB[2].toString(16);
    return ("#" + R + G + B);
}

// まとめ
function getClr(H, S, V) {
    return RGBto16(HSVtoRGB(H,S,V));
}

// カラーコード取得用グローバル変数
_H = 0;
_S = 0;
// VBar変更
function changeVBar(H, S) {
    _H = H; _S = S;
    id=0;
    for(j=1; j>=0; j-=dj) {
        document.getElementById("b_"+ id).bgColor = getClr(H,S,j);
        id++;
    }
}

// カラーコード取得
function setClr(V) {
    with(document.getElementById("gtnClr")) {
        bgColor = getClr(_H, _S, V);
        style.color = getClr(_H, 0, 1 - V);
        innerHTML = getClr(_H, _S, V);
    }
}


<table class="color_table" border="0" cellpadding="0" cellspacing="0"> <script type="text/javascript"> for(j=1; j>=0; j-=dj) { document.write("<tr>"); for(i=0; i<360; i+=di) { document.write('<td onclick="changeVBar(' + i + ',' + j + ')" bgcolor="' + getClr(i,j,1) + '"> </td>'); } document.write("</tr>"); } </script> </table> <table class="color_table VBar" border="0" cellpadding="0" cellspacing="0"> <script type="text/javascript"> id = 0; for(j=1; j>=0; j-=dj) { document.write('<tr>'); document.write('<td id="b_' + id + '" onclick="setClr(' + j + ')" bgcolor="' + getClr(0,1,j) + '"> </td>'); document.write("</tr>"); id++; } </script> </table>
color

sample:
color
①でかい領域のどこかをクリック
②縦長の領域のどこかをクリック

って感じです。個人的には満足です。
しかしながら世の中は広いようで...、ライブラリを使ったりしてちょーすごいカラーピッカーもあります。

球体版(Color Sphere):
http://www.colorjack.com/software/dhtml+color+sphere.html

Saiみたいなやつ(JQuery color picker):
http://acko.net/dev/farbtastic

他にもYahoo!UIとかにもありましたし、フォトショライクなものもありました。ムムム、勉強しないと最先端にはなかなか追いつけませんね。

javascriptによる人間工学シミュレーション

なぞと大層なタイトルをつけてみましたが、やったことはコレです。



prototype.jsによってjavascriptでクラスを実現し、道を歩く人の簡単なAIを作成しました。prototype.jsを用いてクラスを作成するには、
var Human = Class.create();
このように記述します。クラスの定義については、
Human.prototype = {
 initialize: function(obj,x,y,vx,vy) {

 },
 move: function() {

 }
};
こんな感じです。initializeがコンストラクタで、この中にフィールドを入れます。メソッドはprototypeの中に放り込んでやればおkです。他にも記述の仕方はありますが、僕の場合は面倒くさいんでこれで統一しています。ちなみにプログラム自体は、場合分け処理が適当なので見ての通りうまく避けてくれませんw。誰かうまい処理考えてくれないかなー...。以下全ソースです。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html;">
<meta http-equiv="content-script-type" content="text/JavaScript">
<title>人間工学シミュレーション</title>
<meta http-equiv="Content-Type" content="text/html; charset=Shift-JIS">
<style type="text/css"><!--
* {
 margin: 0;
 padding: 0;
}
.street {
 background-color: #ccc;
 position: absolute;
}
.human {
 position: absolute;
 font-size: 16px;
 line-height: 16px;
 margin-left: -8px;
 margin-top: -8px;
}
.human2 {
 color: #f00;
}
#area{
background-color: #000;
}
--></style>
<script type="text/javascript" src="pt.js"></script>
<script type="text/javascript">
// ---------- 初期設定 ----------
// ウインドウサイズと道幅
var WinSizeW = 360, WinSizeH = 360;
var StreetW = WinSizeH/2;
var StreetL = (WinSizeW - StreetW)/2;
var StreetR = StreetL + StreetW;

// 描画間隔(ms)
var t = 10;

// 速度幅
var vy = 5;
var vx = 0;

// 人
var num = 8; // 人数
var size = 8;
var human = Array(num);
var human2 = Array(num);

// ---------- 初期化 ----------
// 初期化関数
function init() {
 createStreet(); // 道の描画
 for(i=0; i<num; i++) {
  var left = StreetL + Math.floor(StreetW * Math.random());
  var vx0 = Math.floor(vx * Math.random());
  var vy0 = Math.floor(1 + vy * Math.random());
  human[i] = new Human($('human_p' + i), left, 0, vx0, vy0);
  human[i].move();

  left = StreetL + Math.floor(StreetW * Math.random());
  vx0 = Math.floor(vx * Math.random());
  vy0 = Math.floor(1 + vy * Math.random());
  human2[i] = new Human($('human_m' + i), left, WinSizeH, vx0, -vy0);
  human2[i].move();
 }

 // タイマーの実行
 Timer();
}

// 道の生成
function createStreet() {
 var vertical = $('vertical');
 Element.setStyle(vertical,
 {
  'left' : StreetL+ "px",
  'top' : 0 + "px",
  'width' : StreetW + "px",
  'height': WinSizeH + "px"
 });
}

// humanクラス
var Human = Class.create();

// クラスの中身
Human.prototype = {
 initialize: function(obj,x,y,vx,vy) { // コンストラクタ(ここでメンバ変数も指定)
  this.obj = obj;
  this.x = x;
  this.y = y;
  this.vx = vx;
  this.vy = vy;
  Element.setStyle(this.obj, // 実際の移動 / 体裁整え
  {
   'left': x + "px",
   'top' : y + "px",
   'font-size': size + "px",
   'line-height': size + "px"
  });
 },
 move: function() { // 移動の記述
  if(this.y > WinSizeH || this.y < 0) { // 下から出たら
   var left = StreetL + Math.floor(StreetW * Math.random()); // 開始位置指定
   var tb = this.vy / Math.abs(this.vy); // 進んでた向き
   var vx0 = Math.floor(vx * Math.random()); // 初速度
   var vy0 = tb * Math.floor(1 + vy * Math.random()); // 初速度
   if(tb>0) this.y = 0; // 上に戻す
   else this.y = WinSizeH; // 下に戻す
   this.x = left; // 初期位置に持っていく
   this.vx = vx0; // 初速度指定
   this.vy = vy0; // 初速度指定
  }
  if(this.x < StreetL) { // 道の外に出たら
   this.vx = -this.vx; // 速度逆
   this.x += size;
  } else if(this.x > StreetR) {
   this.vx = -this.vx;
   this.x -= size;
  }
  this.x += this.vx; // 進む
  this.y += this.vy; // 進む
  this.vx = 0;  // 速度初期化
  Element.setStyle(this.obj, // 実際の移動
  {
   'left': this.x + "px",
   'top' : this.y + "px"
  });
 },
 // --------- ここが衝突判定 ---------
 // this: 自分   obj: 相手
 conflict: function( obj ) {
 // --------- ここから判断の記述 ---------
  var tb = this.vy / Math.abs(this.vy);
  var lx = (obj.x - this.x); // x方向距離
  var ly = tb*(obj.y - this.y); // y方向距離
  var lf = tb*((obj.y + 10*obj.vy) - (this.y + 10*this.vy)); // 10時間後の距離

  if(
   ly > 0 &&   // 後ろにいて
   Math.abs(lx) < 3*size && // かつ3人分の幅の中に入っていて
   lf < 0    // 10時間後抜かしてるとき時
  ) {
   var lr = this.x - obj.x;  // 右か左かの符号用
   if(!lr) lr = 0.5 - Math.random() // 真ん中だったらどっちか
   lr = lr / Math.abs(lr);   // 1か-1にする
   var to = obj.x + lr*3*size;  // 抜かす際の移動幅
   this.vx += Math.floor((to - this.x)/3 + 0.5); // 3時間後に抜かす速度
  }
 // ------------- ここまで -------------
 }
};

// 画面更新関数
function winDraw() {
 for(i=0; i<num; i++) {
  for(j=0; j<num; j++) {
   if(i!=j) human[i].conflict(human[j]);
   if(i!=j) human[i].conflict(human2[j]);
   if(i!=j) human2[i].conflict(human[j]);
   if(i!=j) human2[i].conflict(human2[j]);
  }
 }
 for(i=0; i<num; i++) {
  human[i].move();
  human2[i].move();
 }
}

// タイマー
function Timer() {
 winDraw();
 setTimeout("Timer()", t);
}
--></script>
</head>
<body>
<div id="area">
<div id="vertical" class="street"></div>
<script type="text/javascript">
for(i=0; i<num; i++) {
 document.write('<div id="human_p' + i + '" class="human">●</div>');
 document.write('<div id="human_m' + i + '" class="human human2">●</div>');
}
</script>
</div>
</body>
<script type="text/javascript">init();</script>
</html>

JavaScriptによるあみだくじ

学校がしばらく忙しく、更新できていません...。更新したいと常々思っているのですが...、残念。
今日のバイトの空き時間を使って、あみだくじを作ってみました。

開始を押すとランダムな開始位置よりアミダを辿って下の番号に到達します。ソースは相当汚いですが、動けばいいや的なノリで組みました...、ご助言頂ければありがたいです。

function makeAmida(num, len){
 if(num > 20) alert("20人以下でお願いします。")
 var a = new Array(len);
 for(i=0; i<len; i++) { // 縦
  a[i] = new Array(num);
  for(j=0; j<2*num-1; j++) { // 横
   if (j%2) { // 偶数番目は2通り
    if(a[i][j-1] == "┣") a[i][j] = "━";
    else a[i][j] = " ";
   } else { // 奇数番目は最初、最後を場合分け
    if(a[i][j-1] == "━") a[i][j] = "┫";
    else {
     if(j==2*(num-1)) a[i][j] = "┃";
     else a[i][j] = (Math.floor(Math.random()*2))? "┃" : "┣";
    }
   }
  }
 }
 return a;
}

function writeAmida(matrix) {
 var nums = new Array("①","②","③","④","⑤","⑥","⑦","⑧","⑨","⑩","⑪","⑫","⑬","⑭","⑮","⑯","⑰","⑱","⑲","⑳");
 document.write("<br />");
 for(i=0; i<matrix.length; i++) {
  for(j=0; j<matrix[0].length; j++) {
   document.write('<span class="amida" id="amida' + i + "l" + j + '">');
   document.write(matrix[i][j]);
   document.write('</span>');
  }
  document.write("<br />");
 }
 for(i=0; i<(matrix[0].length+1)/2; i++) {
  document.write('<span class="amida" id="num' + i + '">');
  document.write(nums[i]);
  document.write(' </span>');
 }
}

function traceAmida(matrix,i,i2,j,j2,step) {
 pre_i = i; pre_j = j;
 // n:人数 matrix[0].length: 2n-1 行列から人数を逆算⇒あみだの開始位置は偶数番目
 if(i==0 && j==0 && step==0) {
  pre_i = -1;
  j = 2*Math.floor(Math.random()*(matrix[0].length+1)/2); // 最初は開始位置ランダム
 }
 else {
  if(matrix[i][j] == "━") j += (j - j2);
  else if(matrix[i][j] == "┫") {
   if(i-i2) j--; // 下向きに速度を持っていたら左
   else i++; // 横向きだったら下へ
  }
  else if(matrix[i][j] == "┣") {
   if(i-i2) j++; // 下向きに速度を持っていたら右
   else i++; // 横向きだったら下へ
  }
  else i++; // ┃
 }
 if(!(i==matrix.length)) {
  document.getElementById("amida" + i + "l" + j).style.color = (step)? "f00" : "ff0";
  step++;
  setTimeout(function(){ traceAmida(matrix, i, pre_i, j, pre_j, step) }, 50);
 } else {
  document.getElementById("num" + (j/2)).style.color = "#00f";
 }
}

// numに人数、lenに縦の長さ。これを実行すればOK。

function amida(num, len){
 var a = makeAmida(num, len);
 writeAmida(a);
 traceAmida(a,0,0,0,0,0);
}


といった感じです。参考になれば幸いです。あ、アミダの表示する領域はフォントをMS P ゴシックのようにPのついたものにしないで下さい。これはPのついたフォントが見栄えがいいように文字ごとに横幅を調整しているからです。横幅一定のMS ゴシックのようにPのついてないものを使用すればサンプルのようになります。

[090203] スパムが多いので一時的にコメント不可にします。

PHPにおけるプログレスバーの実現2

再び、競馬の解析のPHP作成を再開しました。前はサイアーラインから色分けした血統表を作成、ってところまで作ったので、とりあえず保留。これからはオッズと着順の関係を条件ごとに検索できるシステムをちょくちょく作っていきたいと思っています。今はURL指定すれば自動で10000件くらいのレースのデータを取って来れるようにはなりました。次は取ってきたデータを解析するところを作っていきます。
話は変わってこのブログで一番アクセスが多いのがPHPのプログレスバー関連の話なので、gdgdだった前回の説明を補足、簡略化する意味で再び解説していきたいと思います。

プログレスバー?
競馬の解析をする際、情報はネットからスクレイピング(必要な部分だけ抽出してくること: はてなダイアリー)していますが、単純にウェブサイトを読み込む時間が必要なので、如何にブロードバンド時代と云えど100ページとか読み込むには相当な時間がかかります。しかもPHP側で特に何もしないと、果たして動いているのか動いていないのか分からないです(もしかしたらエラーが起きているかもしれない…)。そこでWindowsなどでファイルを移動するときに移動状況を表してくれる”アレ”がPHPでも使えたら便利じゃないか!まさにその”アレ”こそ、プログレスバーなのです。

タイムアウトするんだけど?
長い処理をするとタイムアウトしてしまうので、それを防がないとなりません。
set_time_limit(0);
こんな記述を冒頭に入れてあげましょう。


PHPの知識だけでできるの?
PHPの知識を持ってらっしゃる方は、大体HTMLの知識も持っていらっしゃると思います。プログレスバーは、PHP+JavaScriptで実現するのです。つまり、
    PHPでJavaScriptの関数を呼出 ⇒ JavaScriptでプログレスバーを動かす
といったことをやるわけです。それではPHPからどのようにして、JavaScriptを動かせば良いのでしょうか?

JavaScriptの準備
簡単のために、まずはテキストが表示される例を作成してみましょう。HTML側には以下のような記述をしてください。
<span id="msg"></span>
<script type="text/javascript">
function changeMsg(msg) {
    document.getElementById("msg").innerHTML = msg;
}
</script>
このchangeMsg()関数をPHPから呼び出し、<span>タグの中身を書き換えるわけです。

バッファについて
PHP側の記述を紹介する前に、「バッファ」について学んでおきましょう。バッファとはパソコンが処理をする際にそのデータを一時的に蓄えておくところのことです(パソコン用語 - バッファとは)。PHPで意識しなければならないバッファは2種類あります。1つ目はサーバー側のバッファで、PHPで処理しているデータを向こうが処理が完了するまでためている、なんてことがあったら処理が完了するまで途中経過のデータが見れないことになってしまいます。2つ目はブラウザ側のバッファです。読み込みが遅くて画面が真っ白だから、もうや~めた、と思って中止ボタンを押すと、途中まで表示された!なんて例を挙げてみると分かりやすいのではないでしょうか。これらを吐き出させるためにPHPで次の2行を記述しなければなりません。
ob_flush();
flush();
バッファをフラッシュ(水をどっと流す)してあげる記述です。

PHPからJavaScriptを呼び出す!
いよいよここまで来ましたね。さぁ、どうするんだ!といった感じですが、実は至って簡単なのです。
$com = "表示したい内容"
echo '<script type="text/javascript">changeMsg("' . $com . '")</script>';
Quick Lookup:
これだけです。ボブ風にいうと(ボブ知らなかったらすみませんww)、ほら、簡単でしょう?と言った感じですね。そして、お友達も書いてあげましょう、といった感じで、
sleep(1); // 重い処理する場所
$com = $i . "/" . $total; // $i: 処理中のデータ番号 $total: データ総数
echo '<script type="text/javascript">changeMsg("' . $com . '")</script>';
ob_flush();
flush();
こんな風にしちゃえばOKです。いかがでしょうか?思ったよりも簡単ですよね。具体例を挙げると、
$i=1;
foreach($url as $urls) {
    getDataFromURL($url);
    // ($urlのページからデータを取ってくる自分で定義した関数)
    $com = $i . "/" . count($datas);
    echo '<script type="text/javascript">changeMsg("' . $com . '")</script>';
    ob_flush();
    flush();
}

こんな感じです。

プログレスバーに応用したい場合は、JavaScript側で工夫さえすればPHPで何もする必要はありません。PHPにおけるプログレスバーの実現でプログレスバーを動かすサンプルを置いてあるのでぜひそちらも見てみてください。

checkboxのリセット

PHPなどでチェックボックスを配列として受け取るときは、nameの後ろに[]を付ければOKです。しかし、JavaScriptを使ってそんなチェックボックスを全部リセットしたい!もしくは全部チェックしたい!って場面に出くわしたことはないでしょうか。nameが全部同じだからどうやって判別したらいいんだろう・・・?そんな時は、全部の要素を調べてしまうという方法があります。
<form action="./hoge.php" method="POST" name="hoge">
    <input type="checkbox" name="chk[]" value="1" />
    <input type="text" name="text1" value="凸" />
    <input type="checkbox" name="chk[]" value="2" />
    <input type="text" name="text2" value="凹" />
    <input type="checkbox" name="chk[]" value="3" />
</form>

-----------(preview)-----------
こんな風にタグが並んでいるときに、チェックボックスだけ選択してチェックをいれるためには、
document.[form名].elements.length
を使います。これはform内にある要素の数を数えてくれます。上の例でいえば5となります。では、早速すべてのチェックボックスをチェックするスクリプトを書いてみましょう。
<script type="text/javascript">
    function chkAllChkbox() {
        for(i=0;i<document.hoge.elements.length;i++) {
           if(document.hoge.elements[i].name == "chk[]") {
                document.hoge.elements[i].checked = true;
           }
        }
    }
</script>
<input type="button" onClick="chkAllChkbox()" value="check" />

-----------(preview)-----------
いかがでしょうか。なお、checkboxの数を
document.[form名].elements['checkboxの名前'].length
で調べることもできます。覚えておくと便利?これを使ってradioボタンみたいなことを実現してみましょう。checkboxに更にIDを加えます。上とは違ってgetElementByIdを使ってcheckedを調べています。

<script type="text/javascript">
    function unchkOthers(num) {
        for(i=1;i<=document.hoge2.elements['chk[]'].length;i++) {
            document.getElementById('chk' + i).checked = false;
        }
       document.getElementById('chk' + num).checked = true;
    }
</script>

<form action="./hoge.php" method="POST" name="hoge2">
    <input type="checkbox" name="chk[]" value="1" id="chk1" onClick="unchkOthers(1)" />
    <input type="checkbox" name="chk[]" value="2" id="chk2" onClick="unchkOthers(2)" />
    <input type="checkbox" name="chk[]" value="3" id="chk3" onClick="unchkOthers(3)" />
</form>

-----------(preview)-----------
getElementByIdとはその名の通りIDから要素を判別することができます。是非使ってみてくださいね。


Quick Lookup:

PHPにおけるプログレスバーの実現

プログレスバーとは作業の進行状況をバーの長さで表示してくれるアレです。ファイルのコピーとかする時よく見かけますよね。あれをPHPで実現しようと四苦八苦した結果をまとめておきたいと思います。

(別のまとめも作りました:PHPにおけるプログレスバーの実現2

用意するHTMLは、
 
Wait a minute ...
こんなです。ソースは、
<style type="text/css">
#p_bar {background: #565656; font-size: 3mm; width: 0; padding: 0; margin: 0; border-spacing: 0;}
#i_p_bar {color: #ffffff; text-align: right;}
#out_bar {background: #cfcfcf; width: 300px; border: 1px #565656 solid; padding: 0; margin: 0; border-spacing: 0;}
.under_p_bar {color: #565656; font-size: 3mm;}
</style>

<table id="out_bar" width="300">
<tbody><tr><td>

<table id="p_bar">
<tbody><tr><td id="i_p_bar">&nbsp;</td></tr>
</tbody></table>

</td></tr>
</tbody></table>
<span id="msg" class="under_p_bar">Wait a minute ...</span>
<span id="rest" class="under_p_bar"></span>

こんな感じで書けますね。まぁデザイン等はお好みで。次にJavaScript部分は、

// メッセージを変える
function changeMsg(msg) {
    $('msg').innerHTML =msg;
}

// プログレスバーを動かす
function setProgress(i ,all) {
    Element.setStyle($('p_bar'), {'width': ((i/all)*300)+'px'});
    $('i_p_bar').innerHTML = Math.round(100*(i/all))+"%";
    $('rest').innerHTML = i + "/" + all + "件を処理完了";
}

こんなになってます…、あ、ちなみにprototype.js使ってます。まぁ見ての通りchangeMsg()ではidがmsgのspanの中身を変える関数、setProgressではプログレスバーの横幅を変更、処理状況をidがrestのspanに書きだしています。んじゃぁ、この関数をどうやって実行するのか、ですが、これはPHP側で行います。
echo "<script type=\"text/javascript\">changeMsg(\"解析開始...\")</script>\n";
ob_flush();
flush();
こんな感じでです。flush()ってのはバッファをフラッシュしているらしいです。バッファ?フラッシュ?良く分かんないですがwなんか、ob_flush()とflush()を両方コールすることでで向こう側にある処理途中の情報も送信してくれて(普通は処理し終わってから全部こっちに送ってくれるのかな?)ブラウザに表示してくれる、と解釈してます。まぁ動けばよし!ということで…。知ってる人いたら教えてください。そいでもって、プログレスバーを進めるには、
echo "<script type=\"text/javascript\">setProgress(".$i.",".$this->cntData. ")</script>\n";
こんな感じで行います。あ、ちなみに$this->cntDataには解析するデータ総数、$iには解析中のデータの番号を格納しています。こんな感じにすることでプログレスバーが実現できちゃいます。もうちょい詳しく書くと、
$i=0; $all = count($data);
foreach($data) {
    sleep(1); //ここが重い処理をする場所。

    echo "<script type=\"text/javascript\">setProgress(".$i.",".$all. ")</script>\n";
    ob_flush();
    flush();
    $i++;
}
こんな感じですかね。実装すると
 
Wait a minute ...
こんな感じになります。流れとしては、
① 重い処理をする
② 画面にプログレスバーを進めるJavaScriptを書き出す。
③ flushしないと画面に反映されないので、ob_flush()とflush()をする。
という感じです。例が分かりにくかったかもしれませんが参考になれば幸いです。