05/29(Fri)

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

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

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

機能概略【再掲】

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

1の後半部分、Ajaxで通信クエリを投げます

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

設定を送信 -> プレビュー


        // 設定を送信 -> プレビュー
        $('#linegraph-form').submit(function(){
          // いろいろ処理を記述
        }
      

formタグにsubmitイベントを関連付けます。
submitボタンが押されるとここの動作が実行されます。
以下、ここの中身を組んでいきます。

パラメータをオブジェクトに格納


        // 送信するパラメータを取得
        var data = {
          'autoY'   : $('#linegraph-autoY').prop('checked'),
          'width'   : $('#linegraph-width').val() -0,
          'height'  : $('#linegraph-height').val() -0,
          'max'     : $('#linegraph-max').val() -0,
          'min'     : $('#linegraph-min').val() -0,
          'step'    : $('#linegraph-step').val() -0,
          'label'   : $('#linegraph-label').val(),
          'value'   : $('#linegraph-value').val(),
          'fsize'   : $('#linegraph-fsize').val() -0,
          'margin0' : $('#linegraph-margin-0').val() -0,
          'margin1' : $('#linegraph-margin-1').val() -0,
          'margin2' : $('#linegraph-margin-2').val() -0,
          'margin3' : $('#linegraph-margin-3').val() -0,
          'BG_COLOR'   : $('#linegraph-color-bg').val(),
          'AXIS_COLOR' : $('#linegraph-color-axis').val(),
          'GRID_COLOR' : $('#linegraph-color-grid').val(),
          'LINE_COLOR' : $('#linegraph-color-line').val(),
          'TEXT_COLOR' : $('#linegraph-color-text').val()
        };
      

パラメータをdataオブジェクトに全て突っ込みます。
チェックボックスはpropメソッドで取得します。
0を引いているのは整数型にキャストするためです。
投げる先が(データ型をあまり気にしない)PHPなので意味はないかもしれませんが。
この時点でlabelとvalueに入るのは文字列です。

パラメータの微調整


        // データ値構文チェック
        var v_value = validateValue(data.value);
        if (!v_value){
          alert('データの構造が正しくありません');
          return false;
        }else{
          data.value = v_value;
        }
        
        // ラベルの整形
        data.label = vLabel(data.label);
        
        // 縦軸自動計算
        if (data.autoY) {
          calcAxis(data);
        }
      

前回準備した3つの関数を使っていきます。
構文チェックがfalseを返してきたら構文が間違っているので処理を中断します。
それ以外はパラメータを上書きしています。

XMLHttpRequestを投げる


        // XMLHttpRequestを投げる(プレビュー用)
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'line_preview.php', true);
        xhr.responseType = 'arraybuffer'
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")

        xhr.onload = function(e){
          if(this.status == 200){
            view = new Uint8Array(this.response)
            blob = new Blob([view], { "type" : "image/png" })
            URL = window.URL || window.webkitURL
            
            blob_url = URL.createObjectURL(blob)
            
            // 画像URLを書き換える
            var image = document.getElementById('linegraph-image')
            image.src = blob_url
          }
        }
        xhr.send(EncodeHTMLForm( data ))
        
        // XMLHttpRequestを投げる(フルサイズ用)
        var xhr2 = new XMLHttpRequest();
        xhr2.open('POST', 'line.php', true);
        xhr2.responseType = 'arraybuffer'
        xhr2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")

        xhr2.onload = function(e){
          if(this.status == 200){
            view = new Uint8Array(this.response)
            blob = new Blob([view], { "type" : "image/png" })
            URL = window.URL || window.webkitURL
            
            blob_url = URL.createObjectURL(blob)
            
            // リンクURLを書き換える
            var link = document.getElementById('linegraph-download')
            link.href = blob_url
          }
        }
        xhr2.send(EncodeHTMLForm( data ))
        
        // リンクを表示する
        $('#linegraph-download').show();
        return false;
      

プレビュー画像とフルサイズ画像の2つが必要なので、同じような処理を2回行っています。
$.ajax()ではバイナリデータを扱いづらいようなので、こちらのサイトをほぼ丸パクリしました。
行末のセミコロンの有無とか、正直よくわかってない部分が多いです。

3行目の送信先URL、9行目のmimeタイプ、14-16行目のコールバック処理を書き換えています。
変数blob_urlには生成したグラフ画像のURLが入っています。
19行目で送信するデータを指定していますが詳しくは後述します。
21行目からのブロックもほぼ同じで、コールバック処理が多少違います。
処理の最後にfalseを返して、フォーム送信時のデフォルト動作をキャンセルしておきます。

送信するデータの整形


        function EncodeHTMLForm( data )
        {
            var params = [];

            for( var name in data )
            {
                var value = data[ name ];
                var param = encodeURIComponent( name ) + '=' + encodeURIComponent( value );

                params.push( param );
            }

            return params.join( '&' ).replace( /%20/g, '+' );
        }
      

先述した、データの整形を行う関数です。
こちらのサイトのコードそのままです。
オブジェクト形式からURLエンコードされた文字列に変換してるっぽいですね。

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