JavaScript修行

TrainNavi2作成にあたり、無印TrainNaviの反省点を挙げておく。
・ソースが単一でメンテナンスが超困難
・クラスの設計が行き当たりばったりで拡張性がない
・せっかくjQueryをインクルードしているのにajax以外でまったく使っていないのでソースが無駄に冗長
一から始めたので仕方ないところもあるが、以上のことからまずJavaScriptとjQueryの勉強をしないとまず開発も不可能であるということがわかった。
ここのところ忙しすぎたことと日曜をほとんど別のアプリケーションの開発に回してしまっていたので本を読めてない。次の目標は
Learning JavaScript Design Patterns
こいつだ!JavaScriptのお作法を学べる上にjQueryの言及もされているので目的に合致しそうだ。なんとweb上で全文公開されてるぞ!太っ腹!しばらく日曜日をこいつの読解に回そう!


時刻表csvその3

下の続き
不具合はあっけなく治ったので、小田急小田原線、休日も含めてcsvが一応できた。未来サーバー・無料PHPサーバーにアップロードした。全部合わせると2.53MBで、そこそこ大きい。
まだ問題点が残っている。
・特急えのしま、特急さがみが分離・併合する場合は、重複区間も含めて実質別の車両にする必要性があるが、現時点の仕様だと新宿〜相模大野間の列車番号が同じなので、一意性がない。えのしまの列車番号に手を加えるしかないか。。?
・伊勢原に臨時停車するロマンスカーがあるらしいのでその取扱い
今日はここまで


時刻表csvその2

時刻表取り込み – diary 六帖の続き
ようやくcsv作成用のプログラムが形になった。が、まだ不具合がある。下りの多摩急行など、3路線以上をまたいだ時の列車番号の切り替えがうまくない。前の路線の列車番号を引き継いだままになってしまっている。今日はcsvを公開できるかと思ったが、まだ駄目なようだ。
[取手〜代々木上原]: 普通
[代々木上原〜唐木田]: 多摩急行
なのに
[取手〜綾瀬]: 2050S
[綾瀬〜代々木上原]: 2051S
[代々木上原〜唐木田]: 3759
と区間の途中で列車番号が変わってしまう場合を考えてなかった。まいった、かなり作り直さなくては。
ちなみに、ローカルのxamppを使用して、小田急小田原線の上り分のcsvファイル(600KBくらい)を吐くのにだいたい4分かかる。大したサイズでもないファイルを出力するのにこれだけマシンパワーを食うんだから、サーバー管理って大変なんだな、と実感する。
また来週。。


グラフができた


9/14の続き。3週間越しでやっとグラフができた。週に2時間くらいしか時間が取れないのでしゃーないが。
上のグラフは、LanguageTrainerの問題の回答状況、復習状況を示したもの。一度問題を解くと「1回解いた」に集計される。翌日に同じ問題が出るので復習すると「1日復習完了」に、さらに1週間後にまた復習すると「1週間復習完了」に、(略)、で、最終的に「1か月復習完了」に集計されたものを、長期記憶に入ったものと考える。完全に自分用。でも、もっと機能を増やしてまともに公開できるようになったら、皆さんにもモチベーション維持のために活用できるのではないかと思う。
PHPでDBを読んでJSONを作り、それを下流のJavaScriptに渡してグラフを描いてもらう、という設計にした。遅いmiraiserverでも3秒程度で表示される。せいぜい150行程度のコードで、キレイなグラフが描けた。flotr2は楽だ。
今回最もつまづいたところ

<head>
<script>
(function bars_stacked(container) {
//グラフをなんやかんや
})(document.getElementById("graph_individual"));
</script>
</head>
<body>
<div id="graph_individual"></div>
</body>

では、動かない。divのオブジェクトを作るよりも先にscriptの中身が動いてしまうらしく、オブジェクトがねぇよ、というエラーになる。

<head>
</head>
<body>
<div id="graph_individual"></div>
<script>
(function bars_stacked(container) {
//グラフをなんやかんや
})(document.getElementById("graph_individual"));
</script>
</body>

とせざるをえない。
PHPからJSONを受け取るには、PHPで変数に

$json_data = json_encode( $info );

のように変数に文字列をしまっておいて、JavaScript側では

var arr = JSON.parse('<?php echo $json_data ?>');

のようにして受け取ると、見事に処理が進む。このとき、必ずphpのタグをシングルクォーテーションで括っておかないと、文字列と認識されずエラーになってしまうので注意。
なお、一番右の「1か月復習完了」に入るまでに最低2か月かかる。気が長い話だが、2か月自分で使ってみて、相当効果があった。特に、伸び悩んで行き詰っていた中・韓国語に光が見えてきた。


MySQL LIMITの開始位置

書いておかなきゃ絶対忘れる!

Be careful with the LIMIT keyword, because offsets start at 0, but the number of rows to return starts at 1.
So LIMIT 1,3 means return three rows starting from the second row.

なんとLIMITキーワードの第1引数で与えたoffsetは1からではなく、0から始まるらしい!覚えておかないと1つずれたことが原因で意味不明のデバッグを強いられる!

SELECT * FROM temp 5,50;
または
SELECT * FROM temp LIMIT 50 OFFSET 5;

なら、5番目のレコードから、ではなく、「5レコード飛ばす」という意味になるということ。


nl2br

nl2brとはPHPで改行コードをBRタグに変換してくれる関数(参考)、
ではない。
公式マニュアルによると「改行文字の前に HTML の改行タグを挿入する」という機能だった。いままで、なぜDB内に大量の改行コードが存在しているのか謎だった。もっと早くマニュアルを見ておけばよかった。なので、実際はBRタグを追加した後改行文字を削除する、次のような実装をしないといけない。

$text = preg_replace('/\n|\r|\r\n/', '', nl2br($text, ENT_QUOTES));

今日は昨日気が付いたミスをカバーすることで時間を使いきってしまった。また来週。


textarea wrap=”hard”

LanguageTrainerの問題入力画面で、textareaタグのwrap属性をhardにしていたため、自動折り返しされた文字列に全部改行が入っていた。。。どうも長い文章の途中に変な場所で改行が入っていると思った。
ああ、これまでに入力した数百の問題の半分くらいの改行をとる作業が待っている。。泣
教訓:wrap属性はsoftにしましょう
参考リンク:http://www.tagindex.com/html_tag/form/textarea_wrap.html


時刻表取り込み

とあるHTMLを1ファイル取り込んで、列車別時刻表のDB用csvファイルを吐き出すPHPプログラムの作成がやっと終了した。500行くらいのそこそこ大きなプログラムになった。以下結果物のサンプル。
列車情報テーブル
路線名,列車番号,平日/休日,列車種類,直通先路線名,直通先列車名

小田急多摩線,3704,1,多摩急行,小田急小田原線,3704
小田急小田原線,3704,1,多摩急行,東京メトロ千代田線,985S
東京メトロ千代田線,985S,1,普通,常磐線各駅停車,985S
常磐線各駅停車,985S,1,普通,,

経路情報テーブル
路線名,列車番号,平日/休日,発駅,着駅,発時刻,着時刻

小田急多摩線,3704,1,唐木田,小田急多摩センター,09:57,09:59
小田急多摩線,3704,1,小田急多摩センター,小田急永山,10:00,10:02
小田急多摩線,3704,1,小田急永山,栗平,10:02,10:06
小田急多摩線,3704,1,栗平,新百合ヶ丘,10:06,10:09
小田急小田原線,3704,1,新百合ヶ丘,登戸,10:10,10:16
小田急小田原線,3704,1,登戸,成城学園前,10:16,10:20
小田急小田原線,3704,1,成城学園前,経堂,10:21,10:24
小田急小田原線,3704,1,経堂,下北沢,10:25,10:28
小田急小田原線,3704,1,下北沢,代々木上原,10:29,10:31
東京メトロ千代田線,985S,1,代々木上原,代々木公園,10:32,10:34
東京メトロ千代田線,985S,1,代々木公園,明治神宮前〈原宿〉,10:34,10:35
東京メトロ千代田線,985S,1,明治神宮前〈原宿〉,表参道,10:36,10:37
東京メトロ千代田線,985S,1,表参道,乃木坂,10:37,10:40
東京メトロ千代田線,985S,1,乃木坂,赤坂,10:40,10:42
東京メトロ千代田線,985S,1,赤坂,国会議事堂前,10:42,10:43
東京メトロ千代田線,985S,1,国会議事堂前,霞ケ関,10:43,10:45
東京メトロ千代田線,985S,1,霞ケ関,日比谷,10:45,10:47
東京メトロ千代田線,985S,1,日比谷,二重橋前,10:47,10:49
東京メトロ千代田線,985S,1,二重橋前,大手町,10:49,10:50
東京メトロ千代田線,985S,1,大手町,新御茶ノ水,10:50,10:53
東京メトロ千代田線,985S,1,新御茶ノ水,湯島,10:53,10:55
東京メトロ千代田線,985S,1,湯島,根津,10:55,10:57
東京メトロ千代田線,985S,1,根津,千駄木,10:57,10:59
東京メトロ千代田線,985S,1,千駄木,西日暮里,10:59,11:00
東京メトロ千代田線,985S,1,西日暮里,町屋,11:01,11:03
東京メトロ千代田線,985S,1,町屋,北千住,11:03,11:06
東京メトロ千代田線,985S,1,北千住,綾瀬,11:07,11:10
常磐線各駅停車,985S,1,綾瀬,亀有,11:11,11:13
常磐線各駅停車,985S,1,亀有,金町,11:13,11:16
常磐線各駅停車,985S,1,金町,松戸,11:16,11:20
常磐線各駅停車,985S,1,松戸,北松戸,11:20,11:23
常磐線各駅停車,985S,1,北松戸,馬橋,11:23,11:25
常磐線各駅停車,985S,1,馬橋,新松戸,11:25,11:27
常磐線各駅停車,985S,1,新松戸,北小金,11:27,11:29
常磐線各駅停車,985S,1,北小金,南柏,11:29,11:32
常磐線各駅停車,985S,1,南柏,柏,11:32,11:35
常磐線各駅停車,985S,1,柏,北柏,11:35,11:37
常磐線各駅停車,985S,1,北柏,我孫子,11:37,11:40

あとはこれをバッチ処理して、2つの大きなファイルにまとめれば下準備は終わりだ。できるだけ汎用的に作ったので、どこの地方の路線でもほぼ動作する、はず。


PHPの配列の参照渡し

また一つつまづいたところを書きます。PHPの配列を関数に渡すと、デフォルトでは参照渡しではなく、なんと値渡しになってしまう。

<?php
$array = array('i', 'have', 'black', 'hair');
SetHage($array);
print_r($array); //Array ( [0] => i [1] => have [2] => black [3] => hair )
function SetHage($array)
{
$array[2] = 'no';
}
?>

ハゲにならない。SetHage関数には、$arrayの内容がまるまるコピーされて、$array[2]を変更しても元の関数に何の影響も与えてない。PHPで配列とはリテラルそのもの、ということなのか?これもC言語使いやJavaScriptからしても不思議な挙動で、ふつう配列はポインタが関数に渡されるものだ、という感覚でコードを書いてしまう。マニュアルによれば、配列の内容を書き換えたかったら明示的に参照渡しを使え、ということだそうだ。でかい配列をたくさん作ったのなら、それを使う関数は参照渡しにしておかないとオーバーヘッドかかってしょうがないことになりそうだ。

<?php
$array = array('i', 'have', 'black', 'hair');
SetHage($array);
print_r($array); //Array ( [0] => i [1] => have [2] => no [3] => hair )
function SetHage(&$array)
{
$array[2] = 'no';
}
?>

これでめでたくハゲになりました。