05/29(Fri)

PHPで折れ線グラフをつくるまで[2]

PHPで折れ線グラフをつくるまで[2]

先日、折れ線グラフ作成奴を公開しました。
内部的にはPHPとjavascriptで動いているのですが、その仕組みについての備忘録も兼ねて書いていこうと思います。
前回の続きです。

機能概略【再掲】

  1. パラメータを指定してAjaxで送信する
  2. PHPでパラメータを受け取り画像をつくる
  3. 受け取った画像を表示する

1の後半部分、ページの動的な部分とパラメータを送る前の準備について書いていきます

パラメータを指定してAjaxで送信する

座標[自動]チェックに関する挙動


        // 自動座標切り替え
        $('#linegraph-autoY').click(function(){
          var flag = $(this).prop('checked');
          if (flag){
            $('#linegraph-min').attr('disabled', 'disabled');
            $('#linegraph-max').attr('disabled', 'disabled');
            $('#linegraph-step').attr('disabled', 'disabled');
          }else{
            $('#linegraph-min').removeAttr('disabled');
            $('#linegraph-max').removeAttr('disabled');
            $('#linegraph-step').removeAttr('disabled');
          }
        });
      

みんな大好きjQueryを事前に読み込んでおき、その記法で書きます。
縦軸の自動チェックがクリックされるたびにこの処理が行われます。
3行目で新しいチェック状態を取得して、
真(チェックされた)なら以下の数値入力を無効化します。
偽(チェックが外された)なら以下の数値入力を有効化します。

座標計算


        // Y軸自動目盛り
        function calcAxis(data){
          var val = data.value.split(',');
          var max = Math.max.apply(null, val);
          var min = Math.min(Math.min.apply(null, val), 0);
          
          // 範囲の常用対数をとり、小数で判別
          var log = Math.log(max - min) * Math.LOG10E;
          var a = Math.floor(log);
          var b = log - a;
          
          // 閾値 2-[1.5]-5-[3]-10-[6]-20-
          var thr1 = Math.log(1.5) * Math.LOG10E -0.00001;
          var thr2 = Math.log(3) * Math.LOG10E -0.00001;
          var thr3 = Math.log(6) * Math.LOG10E -0.00001;
          
          // 場合分け
          if      (b < thr1) { var step = 2 * Math.pow(10, a-1);}
          else if (b < thr2) { var step = 5 * Math.pow(10, a-1);}
          else if (b < thr3) { var step = 1 * Math.pow(10, a);}
          else               { var step = 2 * Math.pow(10, a);}
          
          $('#linegraph-max').val(max);
          $('#linegraph-min').val(min);
          $('#linegraph-step').val(step);
          data.max = max;
          data.min = min;
          data.step = step;
        }
      

さっきから何回か登場していた「縦軸の座標を計算する関数」です。
具体的にはグラフの上限、下限、間の目盛線の間隔の3つの数値を決めます。
後述しますが、送信されたパラメータが data オブジェクトに全部入っているので、
この値のデータ(data.value)の最大値と最小値を代入します。
最小値が正の数の場合は0を代入します。

7行目から始まる2つ目のブロックでは、
最大値-最小値で範囲を求め、常用対数を用いて桁数を判別します。
変数aには桁数が、bには上位桁の数字に対応する値が入ります。

12行目から始まる3つ目のブロックでは、
線引間隔を変更する境界の値を設定しています。
上位2桁が15,30,60の時に間隔を変えることにします。

17行目から始まる4つ目のブロックでは、
先ほどの閾値と比較して、実際の線引間隔を設定します。
上位2桁が15,30,60の時に間隔を変えることにします。

23行目から始まる最後のブロックでは、
ページの数値を書き換えて、
ついでにdataにも新しい値を埋め込みます。

データ値の文法チェック


        // 値のチェック
        function validateValue(str){
          
          // 改行文字をカンマに置換
          str = str.replace(/,?[\r\n]+/g, ",");
          // 行末カンマを追加
          str = str.replace(/([^,])$/, "$1,");
            
          // 数字を未検出
          var re1 = new RegExp("[0-9]");
          if (!re1.test(str)){
            return false;
          }
          
          // 数字,カンマ以外を検出
          var check = str.replace(/(\d+(\.\d*)?,)(\d+(\.\d*)?,)+/, '');
          if (check != ''){
            return false;
          }
          
          // 行末カンマを削除
          str = str.replace(/,$/, "");
          
          return str;
        }
      

続いて「入力された値の書式が正しいか確認する関数」です。
引数で入力された文字列を読み込みます。
まずは改行文字をカンマに置換して1行にします。
このときカンマ+改行もうまいことカンマ1つにしておきます。
続く処理の都合がよくなるので、行末にもカンマを補っておきます。

9行目から始まる2つ目のブロックでは、
文字列中に数字が含まれるかどうかを検査しています。
もちろん含まれていなければ、処理を中断します。

15行目から始まる3つ目のブロックでは、
正規表現を使って文法チェックを行います。
「数字(小数含む)+カンマ」のパターンが2回以上出現していれば一時的に消去し、
余計なものが残っていれば処理を中断します。

最後に行末のカンマは要らないので削除して返り値とします。

データラベルの整形


        // ラベルの整形
        function vLabel(str){
          // 改行文字をカンマに置換
          str = str.replace(/,?[\r\n]+/g, ",");
          
          return str;
        }
      

続いて「入力されたラベルを使いやすいよう整形する関数」です。
改行の処理だけを行い返しています。

長くなってしまったのでここらへんで切ります
続きます