プログラミングトピック Ajaxとの連携

「Ajax(エイジャックス)」は、JavaScriptのhttp通信機能を利用してWebページの更新を伴わずにサーバーへアクセスし、ユーザー入力に応じたデータの取得などを実現する技術です。クライアントに手を加えることなく高度なユーザーインタフェースを提供できるため、Webシステム開発の分野で注目を集めています。

JClass ServerChartは、グラフ画像の生成をサーブレットコンテナ上で行います。グラフイメージは、クライアント(ブラウザ)では、単なる画像ファイルとして認識されるため、Ajaxとは一見関係がないように思われます。

しかし、JClass ServerChartで作成したグラフに、Ajaxの自由なプレゼンテーションを組み合わせると、単体では実現が難しい、すぐれたユーザビリティを持ったWebチャートシステムが実現できます。

今回の特集では、JClass ServerChartとAjaxを連携させるサンプルプログラムを作成します。

1. Ajaxと連携するメリット

はじめに述べたように、JClass ServerChartで作成したグラフは、HTMLページ上の静的な画像ファイルとして扱われます。そのため、アプレット上に表示したグラフなどと比べると、ユーザー入力が受け付けられないという問題があります。

入力の問題を解決する方法として、JClass ServerChartには、イメージマップと呼ばれる機能が用意されています。イメージマップは、グラフの各要素に対応したHTMLエリアタグの座標を自動的に生成する機能です。これを利用してユーザー入力をハイパーリンクのクリックとして受け取ることができます。

しかし、イメージマップを利用した場合でも、各リクエストが発生するたびに、ユーザーはサーバーの応答を待たなければなりません。たとえ高性能なサーバーや、十分なネットワーク環境を用意したとしても、ネイティブアプリケーションと同レベルのレスポンスや操作感を得ることは困難です。

このようなWebの仕組みに起因する問題をAjaxの利用によって改善できます。グラフ表示しているWeb画面上でユーザーが行ったアクションに対して、Ajaxを使うことでリアルタイムに応答できるようになります。

2. サンプルプログラムの概要

Ajaxとの連携の例として、グラフ上のマウスカーソルがデータポイントの近辺にある場合に、各データポイントに対応した文字列のポップアップを表示するプログラムを作成してみましょう。

プログラムの実行手順は以下の通りです。

  1. グラフイメージの生成[ChartServlet.java](Servlet)
    HTMLのIMGタグで参照されているChartServletでグラフイメージを作成し、グラフのデータビューをセッション変数に格納します。
  2. XMLHTTPリクエストの実行[schart_ajax.htm](JavaScript)
    ページロードのタイミングで、XMLHTTPリクエストのオブジェクトをブラウザごとに異なる方法で取得し、それを使ってDataPointServletへリクエストを送ります。
  3. XMLオブジェクトの作成[PointDataServlet.java](Servlet)
    セッション変数に格納されていたデータビューを取得し、そこから参照したデータポイントの座標をポップアップに表示する文字列とともにXMLデータとして作成し、ブラウザへ返します。
  4. ポップアップの表示[schart_ajax.htm](JavaScript)
    受け取ったXMLデータを元に、ドキュメント全体のonMouseMoveイベントで、ポップアップの表示/非表示の処理を行います。

※ プログラムのソースファイルは以下からまとめてダウンロードしていただけます。

サンプルファイル

3. プログラムの実装

ここから各処理ごとにどのようなコーディングを行うかを見ていきましょう。

a. グラフイメージの生成

グラフの作成の手順は、通常とまったく同じです。JCServerChartクラスのインスタンスを作成し、グラフ種などのプロパティと、データソースのセットを行います。最後にエンコードメソッドを実行して、グラフイメージを出力します。

通常と異なるのは、イメージを作成した後、作成したグラフのデータビューオブジェクト(ChartDataView)をセッション変数に格納することです。これにより、JavaScriptからXMLHTTPリクエストが送られた時に、同じグラフのデータにアクセスできます。

ChartServlet.java
public void doGet( HttpServletRequest request, HttpServletResponse
response ) throws ServletException, IOException {
 
 (中略)
 
 JCServerChart chart = new JCServerChart(JCChart.PLOT);
 
 (中略)
 
 // グラフイメージを出力
 chart.encodeWithExceptions(JCEncodeComponent.PNG, out);
 
 // データビューをセッション変数へ格納
 session.setAttribute("dataview", chart.getDataView(0));

b. XMLHTTPリクエストの実行

XMLHTTPリクエストを発行するためのオブジェクト作成方法はブラウザごとに異なります。またIEについては、MSXMLのバージョンによっても作成方法が変わります。そのため、ページを開いたタイミングで以下のようなスクリプトを実行します。

schart_ajax.htm
function load() {
 // IEの場合
 try{
  xmlHttpRequest= new ActiveXObject("Msxml2.XMLHTTP");
 } catch (e) {
  try {
   xmlHttpRequest= new ActiveXObject("Microsoft.XMLHTTP");
  } catch (e) {
   xmlHttpRequest= false;
  }
 }
 
 // Mozillaなどの場合
 if (!xmlHttpRequest && typeof xmlHttpRequest!='undefined') {
  xmlHttpRequest = new XMLHttpRequest();
 }

 // XMLHTTPリクエストを行う
 xmlHttpRequest.open('POST', "/ajaxtest/servlet/PointDataServlet", true);
 xmlHttpRequest.onreadystatechange = handleHttpResponse;
 xmlHttpRequest.send(null);

リクエストのレスポンスとして取得したXMLデータは次のスクリプトで変数に格納されます。

schart_ajax.htm
function handleHttpResponse() {

 if ( xmlHttpRequest.readyState == 4 ){

  // サーバーから取得したXMLデータを変数に格納
  xml=xmlHttpRequest.responseXML
  _top = xml.getElementsByTagName("top");
  _left = xml.getElementsByTagName("left");
  _right = xml.getElementsByTagName("right");
  _bottom = xml.getElementsByTagName("bottom");
  _label = xml.getElementsByTagName("label");
  NumData = _top.length;

 }

}

c. XMLオブジェクトの作成

ここからXMLHTTPリクエストを受け取るサーバー側の処理を見てみましょう。

まず、セッション変数にセットしておいたデータビューオブジェクトを取得します。その後、座標データを格納するためのドキュメントオブジェクトを作成します。

PointDataServlet.java
public void doPost(HttpServletRequest request, HttpServletResponse
response)throws ServletException{

 response.setContentType("text/xml; charset=UTF-8");
 HttpSession session = request.getSession(true);

 //セッション変数からデータビューを取得
 ChartDataView dataview = (ChartDataView)session.getAttribute("dataview");

 try{

  // ドキュメントオブジェクトの作成
  DocumentBuilderFactory factory = 
    DocumentBuilderFactory.newInstance();
  DocumentBuilder builder = factory.newDocumentBuilder();
  DOMImplementation domImpl = builder.getDOMImplementation();

  Document document = 
    domImpl.createDocument("","document",null);
  Element root = document.getDocumentElement();

次に、データビューオブジェクトから取得した座標データやポップアップに表示する文字列を、作成したドキュメントオブジェクトに格納していきます。

PointDataServlet.java
//データビューからポイントの座標を取得
for( int i = 0 ; i < dataview.getNumSeries() ; i++ ){
 int LastPoint = dataview.getSeries(i).getLastPoint();
 for( int j = 0 ; j <= LastPoint ; j++ ){

  count++;

  JCDataIndex di = new JCDataIndex(j, dataview.getSeries(i));
  Point p = dataview.dataIndexToCoord(di);

  // XMLデータを作成
  Element data = document.createElement("data" + count);
  Element label = document.createElement("label");
  Element top = document.createElement("top");
  Element left = document.createElement("left");
  Element right = document.createElement("right");
  Element bottom = document.createElement("bottom");

  String labelString = "系列" + (i + 1) + "の" + (j + 1) + "番目のデータです";
  label.appendChild(document.createTextNode(labelString));
  top.appendChild(document.createTextNode(String.valueOf(p.y - pointArea)));
  left.appendChild(document.createTextNode(String.valueOf(p.x - pointArea)));
  right.appendChild(document.createTextNode(String.valueOf(p.x + pointArea)));
  bottom.appendChild(document.createTextNode(String.valueOf
(p.y + pointArea)));

  data.appendChild(label);
  data.appendChild(top);
  data.appendChild(left);
  data.appendChild(right);
  data.appendChild(bottom);

  root.appendChild(data);

 }
}

最後に、作成したXMLデータをHttpServletResponseとしてブラウザに返します。

PointDataServlet.java
// 作成したドキュメントをHttpServletResponseで返す
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(response.getOutputStream());
transformer.transform(source, result);

d. ポップアップの表示

グラフ画像の上でマウスを動かすと、ポップアップ表示用のメソッドがコールされます。

このメソッドでは、マウスカーソルの座標がいずれかのデータポイントの付近にあるかをチェックし、データポイントの近くであれば、XMLドキュメントに格納されている文字列をポップアップで表示します。

schart_ajax.htm
function mousemove(MouseX, MouseY){
 popup = document.getElementById("popup1");
 popup.style.visibility = "hidden";

 for(i=0; i < NumData; i++){ 
  // マウスがデータポイント付近にあるかどうかの判定
  if(MouseX - ChartLeft >= _left[i].childNodes[0].data
  && MouseX - ChartLeft <= _right[i].childNodes[0].data
  && MouseY - ChartTop >= _top[i].childNodes[0].data
  && MouseY - ChartTop <= _bottom[i].childNodes[0].data){
  
  // ポップアップの表示
   popup.innerHTML = _label[i].childNodes[0].data;
   popup.style.left = MouseX+20;
   popup.style.top = MouseY+20;
   popup.style.visibility = "visible";
  }
 }
}

以上でプログラムが完成しました。

作成したプログラムを製品にバンドルされているTomcatなどのアプレット上に配備して実行します。グラフイメージ上のマウスカーソルの動きにあわせて、ポップアップが表示されます。

ポップアップの表示

画像「ポップアップの表示」

まとめ

今回作成したサンプルプログラムは、実装方法の説明を目的としているため、サーバーへのアクセスがページ起動時に一回だけ行われるシンプルなものでした。この動作自体は、Ajaxの形態でなくても実現できます。

しかし、ユーザーの入力に対して、データベースへの問い合わせによって処理を変えたり、サーバーの更新をリアルタイムに監視するような、Ajaxのレスポンスの早さが活かされるシステムでも、このプログラムをそのまま応用できます。

Ajaxは、ナレッジの蓄積や開発者コミュニティの広がりに応じて、利用シーンが増えていくと思われます。今回ご紹介した内容を、JClass ServerChartとAjaxを組み合わせた斬新なシステムの構築にお役立てください。