株価チャート一覧

株価チャートを見るとき、ポートフォリオに入ってるチャートをざーっと見ていくことがある。しかしながら、クリックで順に見て行かねばならず、結構めんどくさい。
そういうわけで、Yahoo!ファイナンスからイメージとデータをとってきて、一覧表示するスクリプトを書いてみた。
perlJavaScriptが合体したようなコード。$がついてるのがperlの変数で、そうじゃないのはJavaScriptだ。
途中でこんがらがりそう。。。
CGIなので、どこかのサーバにおいて、そのURLの後ろに?をつけ、見渡したい銘柄コードをカンマ区切りで渡す。さらに出来るだけぎっしり詰め込むために、チャートは1/3サイズ。さすがにそれでは数字が読めないから、Mac OS XのDockを真似て、カーソルを当てるとぐいっとズームインするようにした。
一日の中での値動きが知りたければ、クリックで日中足に変わる。もう一度クリックすれば日足に戻る。
ぐいっとズームの計算は手抜きなので、ブラウザやウィンドウサイズとかによっては気持ち悪いかもしれない。あとIEだと縮小したイメージがとても汚くなってしまうのでFFやSafariの方が快適だ。(IEでもVMLを使えば綺麗になるが、遅いし面倒くさい…)あんまりリロードしまくると負荷がかかってYahoo!に怒られそうなので注意。

#!/usr/bin/perl
use strict;
use LWP::UserAgent;
my $ua = new LWP::UserAgent;

my $def_w = 512;
my $def_h = 288;
my $scaler = 3;
my $thum_w = $def_w / 3;
my $thum_h = $def_h / 3;
my $ttm_h = $thum_h * 1.5;
my $col_per_row = 4;

my $ids = $ENV{'QUERY_STRING'};
my @ids = split(/,/, $ids);

print <<EOD;
Content-Type: text/html; charset=EUC-JP

<html>
<head>
<title>株価</title>
<style>
td {
	border: solid 1px #ccc;
	margin: 3px;
}
</style>
<script>
function move(e) {
	e = e || event;
	if (navigator.userAgent.match(/Safari/)) {
		isSafari = true;
	} else {
		isSafari = false;
	}
	x = e.clientX + (isSafari ? 0 : document.body.scrollLeft);
	y = e.clientY + (isSafari ? 0 : document.body.scrollTop);
	min_sc = 1;
	window.status = x+", "+y;
	//document.getElementById("msg").innerHTML = "";
	for (i = 0; i <= $#ids; i++) {
		target = document.getElementById("chart"+i);
		tx = (x - lx[i]) / $thum_w * 2;
		ty = (y - ly[i]) / $thum_h * 2;
		sc = Math.sqrt(tx*tx + ty*ty) * 0.5 - 0.25;
		sc = (x < 0) ? 1 : (sc < 0) ? 0 : (sc >= 1) ? 1 : sc;
		min_sc = min_sc > sc ? sc : min_sc;
		//document.getElementById("msg").innerHTML += Math.round(sc * 100) + "%<br>";
		target.width = sc * $thum_w + (1-sc) * $def_w
		target.height = sc * $thum_h + (1-sc) * $def_h;
	}
	document.getElementById("ctbl").style.marginTop = min_sc * $thum_h * 1.5;
}
function getOffset(target)
{
	ret = new Object;
	ret.x = target.offsetLeft;
	ret.y = target.offsetTop;
	do {
		target = target.offsetParent;
		ret.x += target.offsetLeft;
		ret.y += target.offsetTop;
		//document.getElementById('msg').innerHTML += ret.x + "/";
	} while (target.offsetParent && target != target.offsetParent);
	//document.getElementById('msg').innerHTML += "<br>";
	return ret;
}
function init() {
	document.onmousemove = move;
	lx = new Array;
	ly = new Array;
	for (i = 0; i <= $#ids; i++) {
		target = document.getElementById("chart"+i);
		off = getOffset(target);
		lx[i] = off.x + target.offsetWidth / 2;
		ly[i] = off.y + target.offsetHeight / 2;
	}
}
function swImg(img) {
	if (img.m_img) {
		img.src = img.m_img;
		img.m_img = false;
	} else {
		img.m_img = img.src;
		img.src = img.src.replace("tchart","chart").replace("3m","1d");
	}
 }
</script>
</head>
<body onLoad="init()">
<center><table id="ctbl" style="margin-top: ${ttm_h}px;"><tr>
EOD

my $cnt = 0;
foreach my $id (@ids) {
	if ($cnt % $col_per_row == 0) {
		print "?n<tr>?n";
	}
	my ($id, $market) = split(/?./, $id);
	$market = 't' if (!$market);
	my $type = "3m";
	my $id_t = int($id / 1000);
	my $url = "http://quote.yahoo.co.jp/q?s=$id";
	my $imgurl = "http://tchart.yahoo.co.jp/c/$type/$id_t/$id.$market.gif";
	my $data = "??";
	
	my $req = new HTTP::Request GET => $url;
	my $res = $ua->request($req);
	if ($res->is_success) {
		my $ct = $res->content;
		if ($ct =~ m|<tr align=right>?s+<td?s+nowrap?s+align=left><a?s+href="/q??s=$id.$market&d=t">(.*?)</a></td>(.*?)</tr>|) {
			$data = $2;
			my @record = ();
			$data =~ s|<td.*?>(.*?)</td>|push(@record, $1),""|eg;
			$data = "$record[1] $record[3]($record[4])"
		}
	}
	
	my $bgcolor = $cnt/$col_per_row%2 ? "#ffffff" : "#eeeeee";
	print <<EOD;
<td align="center" bgcolor="$bgcolor">$id $data<br>
<img id="chart$cnt" width="$thum_w" height="$thum_h" src="$imgurl" onClick="swImg(this);">
</td>
EOD
	$cnt++;
	if ($cnt > 1 && $cnt % $col_per_row == 0) {
		print "?n</tr>?n";
	}
}
print <<EOD;
</table></centers>
<!--<div id="msg"></div>-->
<br><br><br><br><br><br><br><br><br><br><br><br>
</body>
</html>
EOD