Note: この記事は、3年以上前に書かれています。Webの進化は速い!情報の正確性は自己責任で判断してください。
Note: Chart APIは現在ではGoogle Chartとして整理されており、この記事で利用されているImage Chart APIは旧仕様として削除対象になっています。実際に削除はされていないので今のところ利用できていますが、2015年中には消えてしまいそうです。(2015-08-31)
CGI側でデータを用意してやって、JavaScriptでうにうにするみたいな。値は吐けるんだからTTとか使ってれば直接埋め込んでも良いような気がしますが、JS挟んだほうがメンテしやすいので!
とはいえ未完成(IEのみ)。ここまでで1時間弱。70%くらい? まあ原因ははっきりしているのでこのままでも使えはしますが。う~ん(ーー; 一緒に悩んで、暇な人!
IE対応しました~。
HTML
<p id="IMG1">※グラフを表示するためには、JavaScriptを有効にしてください。</p>
HTML側はこれだけ。グラフの挿入先になるタグです。JS無効時のアラートも兼ねたお手軽設計。ホントはこれも生成しちゃっても良いんだけど、まあそこまで拘るひつこともないか、とかとか。
JavaScript
var chd = [[% IF enq1_1 != '' %][% data.q1_1 || 0 %],[% END %][% IF enq1_2 != '' %][% data.q1_2 || 0 %],[% END %][% IF enq1_3 != '' %][% data.q1_3 || 0 %],[% END %][% IF enq1_4 != '' %][% data.q1_4 || 0 %],[% END %][% IF enq1_5 != '' %][% data.q1_5 || 0 %],[% END %][% IF enq1_6 != '' %][% data.q1_6 || 0 %],[% END %][% IF enq1_7 != '' %][% data.q1_7 || 0 %],[% END %][% IF enq1_8 != '' %][% data.q1_8 || 0 %],[% END %][% IF enq1_9 != '' %][% data.q1_9 || 0 %],[% END %][% IF enq1_10 != '' %][% data.q1_10 || 0 %],[% END %]];var chl = [[% IF enq1_1 != '' %]1,[% END %][% IF enq1_2 != '' %]2,[% END %][% IF enq1_3 != '' %]3,[% END %][% IF enq1_4 != '' %]4,[% END %][% IF enq1_5 != '' %]5,[% END %][% IF enq1_6 != '' %]6,[% END %][% IF enq1_7 != '' %]7,[% END %][% IF enq1_8 != '' %]8,[% END %][% IF enq1_9 != '' %]9,[% END %][% IF enq1_10 != '' %]10,[% END %]];function createImg(chd,chl){var max_value = Math.max.apply(null,chd);(apply()はIE未実装?)var max_value = 2;for(var i=0;i<chd.length;i++){if(max_value < chd[i]){max_value = chd[i]}}//IEの空配列を削除for(var i=0;i<chd.length;i++){if(isNaN(chd[i])){ chd.splice(i,1); }}var max_value = Math.max.apply(null,chd);var mid_value = Math.round(max_value / 2);if(max_value < 2) max_vlue = 2;//値をchart用に百分率化for(var i=0;i<chd.length;i++){chd[i] = Math.round(chd[i] / max_value * 100);if(isNaN(chd[i])){ chd.splice(i,1); }}//値をsrc用に連結var str_chd = chd.join(',');var str_chl = chl.join('|');// 棒グラフvar graph1 = new Image();graph1.src = 'http://chart.apis.google.com/chart?cht=bvs';graph1.src += '&chs=240x125';graph1.src += '&chxt=x,y';graph1.src += '&chxl=0:|' + str_chl + '|1:|0|' + mid_value + '|' + max_value;graph1.src += '&chco=FFC266';graph1.src += '&chd=t:' + str_chd;// 円グラフvar graph2 = new Image();graph2.src = 'http://chart.apis.google.com/chart?cht=p';graph2.src += '&chs=240x125';graph2.src += '&chl=' + str_chl;graph2.src += '&chd=t:' + str_chd;$('IMG1').removeChild($('IMG1').firstChild);$('IMG1').appendChild(graph1);$('IMG1').appendChild(graph2);}createImg(chd,chl);
データを用意し、最大値と中央値を算出し、データをグラフ用の百分率にして、Imageオブジェクト作ってsrc属性をうにうに追記しつつ、挿入先のテキスト消してからインサート!
24行目までがデータ部分。普通に配列。[% %]みたいなのは元コードのTemplate Toolkitの名残ですが、JSON吐けるならそれでも良いでしょう。
34/43行目はIE対策です。書き方てきとーだからってのもありますが、データ作るときに後ろにカンマ付けてるので、IEだと空の配列が1個できちゃいます。なのでNaNを検出して配列から消してる感じ。
あとは特に言うことはないかな。66~68行目の$()関数は自前です。組み込みじゃありませんよ!
function $(id){return document.getElementById(id);}
document.getElementById('IMG1') と同じ。getElement~といちいち書くのも面倒なので。IEだと高速化も見込めたような? てかprototype.js以降たびたび見かけますね。
課題
問題なのは27行目。Math.max()に配列つっこんで最大値を取ってるわけですが、IEはapply()未実装!
まあ適当な数を入れるなり直接書くなりすれば動きはするんですけどね。値が百分率なんでMaxずれると微妙だよなあ ...てなところです。ここさえどうにかできればcreateImg()を外部JSに移せるんだけども。なんか良い案はないものか?
解法その1
コメント欄より、chihiroさん案。オリジナルはArrayオブジェクト拡張だったけど、わかりやすくcreateImg()内で直接回しても良し。
var max_value = 2;for(var i=0;i<chd.length;i++){if(max_value < chd[i]){max_value = chd[i]}}var mid_value = Math.round(max_value / 2);
解法その2
IEでapply()使えたよ! エラーチェックすべきだったという話(汗) しかし記事にして良かったー。chihiroさん度々ありがとう!
Note: スパム対策が面倒なので、コメント投稿を廃止しました。以前のコメントは残します。
ご意見・ご要望はtwitter@sigwygかはてブコメントにて。
6 Comments
配列に数字以外が入ると動かなくなりますが…
Array.prototype.max = function(){
max = this[0];
for(i=0;i<this.length;i++){
if(max < this[i]){max = this[i]}
}
return max;
}
上記宣言後、27行目は以下に置換。
var max_value = chd.max(); 2008–10–10 07:50
なるほどprototype拡張か。JavaScriptっぽい!
エラー回避はtypeofとかisNaNとか使えばいけるかな。
今回だけならfor文だけ抜いてもいけますが、max()よく使うなら検討の価値アリですね。
とっても参考になりました。ありがとう! 2008–10–10 16:23
IEで Math.max.apply は実装されているようです(IE7のみ検証)。
for(var i=0;i<chd.length;i++){
if(isNaN(chd[i])){ chd.splice(i,1); }
}
をMath.max.applyよりも先に実行するとIEでも動きますね。
最後の,から来る空要素が問題のようです。 2008–10–10 16:54
ありがとー!
IE5.5まで動作を確認しました。
どおりで情報が少ない筈だ^^;
しかし未実装って記述も多いんですよね。これはどこから来てるんだろう。
なんか実装方法が違うとか(prototype周りで)いう話をどっかで拾った気がする... この辺はもうちょい調べてみよう。
いやーブログ書いて良かった。これで今日の仕事も安泰です(ぇ 2008–10–10 17:45
ちょっと別の問題に気がついたのでしつこく追記します…。
現在のコードではIsNan要素の削除時にインデックスがずれてしまい、
連続したIsNan要素([1,2,,5]のようなデータ)に対処できないようです。
for(var i=0;i<chd.length;i++){
if(isNaN(chd[i])){
chd.splice(i,1);
i--;
}
}
上記コードはこの問題に対してインデックスを調整した場合。
下記コードは数値のみの新配列を生成し、置き換える方法。
こちらは続くコードを変更することで元配列も残すことができます。
var numChd = new Array();
for(var i=0;i<chd.length;i++){
if(isNaN(chd[i])==false){ numChd.push(chd[i]); }
}
chd = numChd; 2008–10–11 18:22
ふむふむ、チェック済みの値のみの新配列を作るわけですね。元コードでは出力する段階で既にチェックしているので、そういうケースは考えにくいですが、使いまわしを考慮するなら必要な措置かもです。
度々ありがとうございまっす^^b 2008–10–14 06:15