JavaScript でタイピング速度測定!

JavaScriptでタイピング速度を測定できるスクリプトを書きました。
レイアウトがあまりにもあんまりな感じですが、そこはスルーしてください。



実行ボタンを押すと開始します。

A → Z までの入力速度を計ります。
記録はハイスコアが5つまで保存されるようになっています。


右端にあるテキストエリアに名前を入力して、送信ボタンを押すと、自分のハイスコアをネットランキングに登録できます。

このネットランキングは以前書いた日記(ネットランキングに使う Perl スクリプトを書きました。 - valinstの日記)のPerlスクリプトを使用しています。


ちょっとネタ切れ気味で繋ぎにこんなのを書いてみました。
このブログを立ち上げる前には、勉強したLua言語のまとめを書いていこうって思ってたんですが、今ではLibどうやって作ったっけな?とか言う状況で、今からLuaをまとめるのもなぁという感じになっています……。
Luaとは別の言語でC言語と連携+ゲーム製作に使われるSquirrelというのもあって、こちらの方が導入までの敷居が低い気がするので、次回以降にこちらをまとめてみようかなと思っています。


一応、今回のスクリプトのコードもおいておきます。

var TypeOrder = function() {
    this.alphabet = "abcdefghijklmnopqrstuvwxyz";
    this.index = 0;
    this.startTime = 0;
}

TypeOrder.prototype.getText = function() {
    return ('<div id="TypeChar" style="text-align:center; font-size:70px; color:black">'+this.alphabet.charAt(this.index)+'</div>');
}

// jQuery風
TypeOrder.prototype.getTime = function() {
    return +new Date;
}

TypeOrder.prototype.checkKey = function(key) {
    if(this.alphabet.charAt(this.index) == key.toLowerCase()){
        if(this.index == 0){
            this.startTime = this.getTime();
        }
        if(++this.index > this.alphabet.length-1){
            var score = this.getTime()-this.startTime;
            this.reset();
            return score;
        }
        var element = document.getElementById("TypeChar");
        element.innerHTML = this.alphabet.charAt(this.index);
        element.style.color = "red";
    }
    return 0;
}

TypeOrder.prototype.reset = function() {
    this.index = 0;
    var element = document.getElementById("TypeChar");
    element.innerHTML = this.alphabet.charAt(this.index);
    element.style.color = "black";
}

var Ranking = function() {
    this.ranking = new Array(5);
}

Ranking.prototype.getText = function() {
    return ('\
        <div id="RankingData">\
            '+ this.getRankDataHtml() +'\
        </div>\
    ');
}

Ranking.prototype.getRankDataHtml = function() {
    var ret = "";
    for(var i = 0; i < this.ranking.length; ++i){
        if(typeof this.ranking[i] == 'undefined'){
            ret += (i+1)+ "位 No Score<br>";
            continue;
        }
        ret += (i+1)+ "位 " + this.ranking[i] + " ミリ秒<br>";
    }
    return ret + "</br>";
}

Ranking.prototype.setScore = function(score) {
    for(var i = 0; i < this.ranking.length; ++i){
        if((typeof this.ranking[i] == 'undefined') || (this.ranking[i] > score)){
            this.ranking.splice(i, 0, score);
            this.ranking.pop();
            this.update();
            return i;
        }
    }
    return -1;  
}

Ranking.prototype.update = function() {
    var element = document.getElementById("RankingData");
    element.innerHTML = this.getRankDataHtml();
}

Ranking.prototype.getScore = function(num) {
    return this.ranking[num];
}

var type = new TypeOrder();
var ranking = new Ranking();

var keyDown = function(event) {
    var c = String.fromCharCode(event.keyCode);
    var score = 0;
    if((score = type.checkKey(c)) > 0){
        var num = ranking.setScore(score);
        var message = "";
        if(num != -1){
            message = (num+1) + "位 ";
        }
        message += score + "ミリ秒";
        alert(message);
    }
}


var getTextSpace = function(num) {
    var ret = "";
    for(var i = 0; i < num; ++i){
        ret += "&nbsp;";
    }
    return ret;
}

var check = function(form) {
    if(typeof ranking.getScore(0) == 'undefined'){
        alert("スコアが存在しません。");
        return false;
    }   
    if(window.confirm('1位の記録をランキングに送信してよろしいですか?')){ // 確認ダイアログを表示
        form.score.value = ranking.getScore(0);
        if(form.name.value.length == 0){
            form.name.value = "名無し";
        }
        return true;
    }else{
        return false;
    }
}

var typeReset = function() {
    type.reset();
}

document.write('\
    <table>\
        <tr>\
            <td rowspan="2">\
            '+ type.getText() +'\
            </td>\
            <td rowspan="2">\
            '+ ranking.getText() +'\
            </td>\
        </tr>\
        <tr>\
            <td></td>\
        </tr>\
        <tr>\
            <td>\
                <input type="button" name="ResetButton" value="リセット" onclick="typeReset()">\
            ' + getTextSpace(30) + '\
            </td>\
            <td>\
                ネットランキング登録\
                <form method="post" action="ranking.cgi" onSubmit="return check(this)">\
                    <p><input type="hidden" name="game" value="typegame">名前 <input type="text" name="name" size="10" maxlength="30"><input type="hidden" name="score" value=""><input type="submit" value="送信"></p>\
                </form>\
            </td>\
        </tr>\
    </table>\
');

// Firfox向け
if (document.addEventListener){
    document.addEventListener("keydown", keyDown, true);
// IE向け
} else if (document.attachEvent){
    document.attachEvent("onkeydown", keyDown, true);
}