2011年3月9日水曜日

Illuminations for Devellopers 1.1.5導入

ExtJSでの開発やデバッグの効率を桁違いに高めてくれるかも知れないツールがFireFoxのアドオンとして提供されている。

名前は「Illuminations for Devellopers」で今日現在のバージョンは1.1.5となっている。Senchaのブログに載っていたのでインストールしてみた。

インストールは通常のFirefoxのアドオンと同じ。但し、アドオンFirebugが導入されていることは前提となります。
「ツール」→「アドオン」メニューから、「アドオンを入手」をクリックし、検索のテキストボックスに「Illuminations」と入力し検索すると
Illuminations for Developers for Firebug

作成者: Steven Roussey
が、見つかるのでこれを「Firefoxに追加」する。インストール完了後にFirefoxを再起動し、Firebugを開くと、一番右「接続」の隣に「Illuminations[Trial]」のタブが増えていることがわかる。赤い大きな「Buy or Login」のボタンが少々いやらしいが、まずは無視。

早速、ExtJSを使用しているページを見に行くと、ViewPort以下どのようにBorderLayoutがあり、その中にある入れ子のBorderLayoutがTabPanelでありどんなメニューとプロパティを持っているかなど、階層的に確認していくことができる。


今まで、FireFoxでこれを確認していくことはスクリプトのウォッチの機能でできないことはなかったが、いろいろな情報が頭に入っており、見たいデータを明確にして探さないと見つけることはできなかったし、探したオブジェクトがどんなクラスのオブジェクトかということですら、持っているプロパティやメソッドから推測することしかできなかった。

このアドオンの利用によりかなりデバッグの敷居が下がるかと思う。
まだ、全然見切れていないが、導入後気になったのはこのアドオンがトライアルで、製品版があるらしいということ。どんな機能の違いがあるのだろう。

2011年3月1日火曜日

ExtJSのGridやChartにデータダウンロードの機能を追加する

ExtJSのGridやChartにデータダウンロードの機能を追加した際のメモ

ダウンロードといえば本来サーバ側に実装する機能だが、超短納期で片づけたかったため時間のかからなそうな、javascript側のStoreからダウンロードする方法を検討した。

作成したサンプルは以下の2つ。いずれもExtJSのサンプルに、ダウンロード機能を呼び出すためのボタンを追加したものとなる。

Chartのほうはサーバに無いデータを表示する例なので、よりStoreからのダウンロードに意味が出るかと思う。



ダウンロードはクライアント側だけでは仕組み上実現できないので、ブラウザからPOSTされたデータをそのまま出力する鏡みたいなphpスクリプトを使用することにした。このあたり、javascriptだけでできる方法があるなら、是非コメントでアドバイスいただきたい。

用意したphpスクリプトdownload.phpは以下のようなものだ。
本来、3行で実装できるが、ヘッダの自由度を持たせるためと、最低限のセキュリティとして、リファラが同じサーバかだけのチェックを入れている。

<?php
 if (!isSet($_SERVER['HTTP_REFERER']) 
  || !preg_match('#^http://([^:/]+)#',$_SERVER['HTTP_REFERER'],$mch)
  || $mch[1]!==$_SERVER['SERVER_NAME']
 ) die('Security Error'); // simple security check
 foreach ($_POST as $header=>$val) {
  if ($header==='body') continue;
  header("$header: $val");
 }
 die($_POST['body']);
?>

ChartやGridPanelのスクリプトの変更方法は、ツールバーやツールボタンで、下記のStoreに追加したメソッドExt.data.Store::download(fn)を呼び出すというもの、StoreはGridやChartで使用しているものを、引数fnはダウンロードの際のファイル名を指定すればよい。

Ext.data.Store.prototype.download = function(fn){
    var output=[],o=[],
      fld = this.fields;
    fld.eachKey(function(key){o.push(key)});
    output.push(o.join('\t'));
    this.each(function(rec) {
      var o=[];
      fld.eachKey(function(key){o.push(rec.get(key))});
      output.push(o.join('\t'));
    });
    var form = Ext.DomHelper.append(document.body, {
      tag: 'form',
      style: 'display:none',
      action: 'download.php',
      method: 'post',
      cn:[{
        tag:'textarea',
        name:'body',
        html:output.join('\n')
      },{
        tag:'input',
        name:'Content-Disposition',
        value:'attachment;filename='+'"'+fn+'"'
      },{
        tag:'input',
        name:'Content-Type',
        value:'text/tab-separated-values'
      }]
    });
    form.submit();
    document.body.removeChild(form);
  }


今回の方式はStoreにfilterがかかっていれば、表示されているレコードのみDLされる。
Grid専用にするならば、これを一歩進め、ユーザが画面で操作した列の順番や列の表示/非表示を反映したり、列によってはrendererを指定できるようにすると、ユーザが見たままを手に入れるという意味で完成形になるのではと思う。

今回の例だと出力したLastUpdateの列のDateの出力形式は、欧米人がみればわかりやすいが、日本人向けでなく、Excelでそのまま処理できない等の不満はある。

英語版のフォーラムに投稿してみました
http://www.sencha.com/forum/showthread.php?125611-data-download-function-from-Grid-and-Chart

2011年2月15日火曜日

ExtJS Pivot Gridの拡張

ExtJS3.3のPivotGridは、ヘッダのrendererは無く、セルのrendererのパラメータが値しか受け取れない仕様となっている。今回初めて使用したが、必要に迫られてHackしたのでメモしておく。

それぞれ下記に数行のコードを修正、追加すればよい
・ヘッダのrendererの実装: Ext.grid.PivotAxsisのbuildHeaders()メソッド
   行列のそれぞれ各ディメンジョンごとに指定可能
・セルのrendererの拡張: Ext.grid.GridViewのrenderRows()メソッド
   値以外に、行のカウンタ、列のカウンタ、行ヘッダの情報、列ヘッダの情報、
   グリッドの参照を受け取れるようにした

実装結果はこちら

2011年2月10日木曜日

ExtJS pivotのサンプル

ExtJS pivotのサンプルは下記に紹介されているが、残念なことにリンクが切れている

Ext JS 3.3 Beta 2 がリリース

サンプルは別URLに残っているのでリンクをあげておく

サンプル1
 http://dev.sencha.com/deploy/dev/examples/pivotgrid/simple.html
サンプル2
 http://dev.sencha.com/deploy/dev/examples/pivotgrid/people.html
サンプル3
 http://dev.sencha.com/deploy/dev/examples/pivotgrid/countries.html

ExtJSで折れ線グラフを出したときの線のスタイル

ExtJSのチャート(Ext.chart)は簡単にグラフを表示できるのだが、
マニュアルに何が指定できるのか説明がほとんどない。

デコンパイラでcharts.swfの内部を調べて何ができるのか少し調べてみた。
ほんとは動的にseriesを増減させるメソッドが無いか調べていたのだが
それらしいものは無かった。
代わりにseriesで指定できそうなstyleのプロパティを見つけたのでメモしておく
※visibilityでおおっと思ったがpi chart専用だった

{
 height:350,
 xtype: 'linechart',
 store: store,
 xField: 'date',
 series: [{
  type:'line',
  displayName: 'line1',
  yField: 'val1',
  style: {
   color: 0xFF9999,
   lineSize:2,
   lineAlpha:0.6,
   alpha:0.6
  }
 },{
  type:'line',
  displayName: 'line2',
  yField: 'val2',
  style: {
   color: 0x99FF99,
   lineSize:2,
   lineAlpha:0.6,
   alpha:0.6
  }
 }]
}

「color」はサンプルのコードにあり、意味も明らかだ
「lineSize」は線の太さでデフォルトの太めの線は「3」が設定してあるように思える
「lineAlpha」は線の不透明度でデフォルトは「1(おそらく不透明)」になっている
「alpha」はマーカの不透明度だと思う

他に
images 円グラフのみ
image 折れ線グラフのマーカのイメージ?
mode
colors
borderColor
borderAlpha
fillColor
fillAlPha
size
lineColor 折れ線グラムのみ
lineAlpha 折れ線グラムのみ
showAreaFill
areaFillAlpha
connectPoints 折れ線グラムのみ
connectDistinuousPoints
distinuousDashLength
showLabels
hideOverlappingLabels
font
visibility 円グラフのみ
skin 折れ線グラフのみ

とが、charts.swf > action(3) > Charts > setSeriesStyles() のswitchのcaseラベルにあったが、未調査。

2011年2月8日火曜日

ExtJS の Grid の ヘッダーにスタイルを適用する

ExtJS の Grid の ヘッダーにスタイルを適用にまよったのでメモ

カラムの指定に
{header:'field1', css:'color: green;'},
のように指定すればセルにcssが適用されるが、
ヘッダに適用する為のコンフィグオプションは無くどうするか迷った。

 http://www.sencha.com/forum/showthread.php?94369-Grid-Header-Style&p=447180
をみるとidを指定しスタイルを書けばいいらしい。

スタイルの指定に迷ったが
{header:'field1', id:'field1'}
としたならば、
.x-grid3-hd-field1 {
  color: green;
}

セルも指定したいなら、
.x-grid3-hd-field1,.x-grid3-col-field1 {
  color: green;
}
とかけばいい。

2011年2月2日水曜日

json_encode()代替関数

以前、php5.2未満のサーバのために、json_encode()の代替となる関数を書いた。
いくつかのプログラムで使用してきたが、3年以上たってバグを発見したので、メモしておく。

自作json_encode()は原形をほぼとどめていないが、
phpのマニュアルの中の02-May-2007 01:55のUser Contributed Notesで
Yi-Ren Chen at NCTU CSIEさんが書いたphp_json_encode()を改造して作ったものだ。

json作成のロジックで、数字だったらそのまま使い、文字ならばクォートして使用する
ような部分があるが、ここで数字の判定を
if (is_numeric($val)) return $val;
と記述していたが、これに
$data = array('id'=>'011')
のような入力を食わせると、
{"id":011}
が出力されてしまう。これはブラウザのjavascriptに8進数として処理され
{id:9}
と解釈される。

とりあえず
if (is_int($val)||is_float($val)) return $val;
のように記述し、
{id:"011"}
と受け取られるようになったことを確認したが、過去作ったシステムが、
異常動作しないかひやひやものだ。

Yi-Ren Chenさんのコードを元にjson_encode相当関数を作った世界中の人たちも
大丈夫だったのかなあと心配してみる。

修正済みコード
http://sourceforge.jp/projects/extwiki/svn/view/trunk/plugin/json_encode.php?view=markup&revision=107&root=extwiki

<?php // $Id: json_encode.php 3 2010-10-02 14:56:27Z mashiki $
/**
 * json_encode: use this  for early version(<5.2) of php
 *     which support "multibyte" but doesn't support "json_encode".
 * 
 * Modified by mashiki 2008,2009,2011
 * 
 * Original written by Yi-Ren Chen at NCTU CSIE as php_json_encode()
 *  User Contributed Notes 02-May-2007 01:55 in PHP online manual
 */
function json_encode($val) {
 if (is_int($val)||is_float($val)) return $val;
 if (is_bool($val)) return $val?'true':'false';
 if (is_array($val)) {
  $len = count($val);
  for($ii=0; $ii<$len && isset($val[$ii]); ++$ii) {}
  $temp = array();
  if($len==$ii) {
   for($i=0;$i<$len;$i++) {
    $temp[] = sprintf("%s", json_encode($val[$i]));
   }
   return '['. implode(",",$temp) .']';
  } else {
   foreach($val as $key => $item) {
    $temp[] = sprintf("%s:%s", json_encode($key), json_encode($item));
   }
   return '{'. implode(",", $temp) .'}';
  }
 }
 // else string
 static $from = array('\\',  "\n", "\r", '"');
 static $to   = array('\\\\','\\n','\\r','\\"');
 static $cmap = array(0x80, 0xFFFF, 0, 0xFFFF);
 return '"'. preg_replace_callback(
  '/&#([0-9]+);/',
  create_function('$match','return sprintf("\\u%04x", $match[1]);'),
  mb_encode_numericentity(str_replace($from, $to, $val), $cmap, 'UTF-8')
 ) . '"';
}
?>