yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2018/06 の記事
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
 垂オ訳ございませんが、現在このブログではトラックバックを受け入れていません。

 この記事に対してリンクされる場合には、こちらのURLをご利用ください。
http://void.yamicha.com/blog/blog.cgi?mode=view&number=753
 上記URLをトリプルクリックされますと、簡単にURL全体の選択が行えます。

※以下の記事がトラックバックされます。
谷垣おろし
2010/03/07(Sun)22:47:56
 これだけ混迷の状態にありながら、またも自民党内に新たな問題が浮上してきました。今度の問題は、党内からの不満と谷垣おろしという「人災」です。まず舛添氏が谷垣おろしの可能性に言及したのを皮切りに、大物の与謝野氏も谷垣氏の辞任を求める意見を月刊誌に寄稿するなど、まず党内の体制を整えなければならない中、足並みのそろわない状態となっています。
 まず舛添氏に関しては、「批判のない政党は独裁政党」などとして自己の谷垣批判を正当化していますが、この人は以前に「今の自民党に必要なのは、民主党の小沢氏以上の独裁者」であると主張しており、言い分が完全に破綻していますので、この「谷垣おろし」も自己利益のためのものと考えて間違いなく、私利私欲目的の主張ですから気にする必要はありません。しかし、大物の与謝野氏までそれを言い出しているとなると、党内の結束は相当に崩壊していると考えるのが自然です。
 谷垣氏がここまで人気を落とした原因として、自民党の審議拒否戦術があるのは間違いないでしょう。党内でも実効性に疑問が持たれていながら決行した結果、他の野党の同調は得られず、何の成果もなくむざむざと審議に復帰せざるを得なくなり、しかも国民からはあきれられる始末です。ただでさえ甚大なダメージを受けている自民党を、さらに窮地に追い込んだのは間違いありません。
 その他にも、自党が文民統制違反で処分したはずの田母神氏を候補に立てようとしたり、党名が悪いから嫌われるなどと言い出して「和魂党」に変えようとしたりと、確かに谷垣時代の自民党は意味の分からないことばかりを繰り返しており、党内に怒りが堆積するのも当然です。そのような意味で、ここで総裁を取り替えようとする党内の動きはある意味当然でさえあります。
 しかし、問題は自民党内の反谷垣勢力が、一体どこまで自民党の窮状を正確に認識しているかという点です。審議拒否の失敗に加え、「和魂党」などの冗談とも悪ふざけともつかないやり口に業を煮やしているなら分かりますが、安易に「せっかく民主党が敵失状態にあるのに、そこにつけこめないのは谷垣氏の責任」などと考えているのであれば、これは筋違いであると言わなければなりません。事実、与謝野氏は「(鳩山内閣で)普段なら内閣が倒れるような事件が起きているにもかかわらず、自民党の評価が高まっていないことには、深い反省、思いを抱かないといけない」と発言しており、現状が正しく認識できているのかどうか極めて疑問と言わざるを得ません。
 確かに、民主党の不透明な政治資金の問題を追及するのは大事なことですし、国民の多くも事実が明らかになることを望んでいるでしょう。しかし、民主党の汚点を徹底的に追及したからといって、自民党の株が上がるわけではありません。谷垣氏の放った「平成の脱税王」などの文句は耳ざわりこそ良いですが、これで民主党にダメージを及ぼすことはあっても、自民党の状態は回復しません。
 まして、自民党が民主党の不透明さを攻撃するのは、同時に自分の泣き所をも攻撃するようなものです。小沢氏や鳩山氏は自民党の流れを受け継いだ政治家で、自党も散々なまでに問題を起こしてきたのですから、これらへの攻撃は自分への攻撃にも等しい行為ですし、鳩山氏の金銭感覚を批判するのも結構ですが、それを言うなら麻生内閣も同様の理由で国民に見放されています。したがって、これでは国民に「民主党はダメだ」という印象を与えるどころか、「政治家はダメだ」「世襲は感覚がおかしい」という印象を与えることになり、言うまでもなく自民党の支持が回復するわけもありません。すなわち、敵失につけこんだところで共倒れがオチなのです。
 したがって、自民党が支持を回復したいのであれば、政策などにおいて自分が民主党より優れていることをアピールしなくてはなりません。その意味で、谷垣氏は「和魂党」など意味の分からないことを言い出したり、審議拒否で野党ぶりの堪能さを知らしめるなど、確かに及第点とは言いがたい状態であるため、それができる総裁に取り替えるのであれば意味があります。しかし、与謝野氏は「内閣が倒れるような事件が起きているのに、自民党の評価が高まっていない」などと発言しており、これでは総裁が変わったところで全く同じです。
 また、最近は新党結成の話も出てきているようですが、これもまた状況が読めていないと言わざるを得ません。今の自民党から新党ができたところで、それは自民党のクローンがもう1つ作られるだけに他なりません。ただでさえ存在意義の薄い政党が乱立している中、また同様のものを作成する気なのでしょうか。
 「和魂党」などと言い出したり、田母神氏を立てようとしたり、審議拒否などの戦法を取る総裁の首を取り替えるのも、自民党再生の1つの手段ではあるでしょう。しかし、自民党が「敵失につけこめないから自分の支持が回復しない」と考えている限り、総裁をいくら変えたところで、再生の道は遠いと言わなくてはなりません。

 JSF 2.0ではf:ajaxタグでAjaxが使用できますが、これとは別にJavaScriptからAjaxを呼び出す方法もあるようです。せっかくJSF 2.0を使用するのであれば、できる限りJavaScriptを扱うような泥臭いマネはしたくないものですが、状況によっては必要な場面も出てくるでしょう。JavaScriptは不得手な上、JSFのJavaScriptなど右も左も分からないのですが、ひとまず使用してみる必要がありそうです。
 単純なフォームでは実現できないプログラムということで、最近地図などでよく見かける、「ドラッグで画像が変化する」タイプのJSFを作成してみました。
/WEB-INF
 /classes
  /com
   /yamicha
    /dragajax
     Matrix4.java
     @WebServlet AjaxImage.java
     @ManagedBean DragBean.java
 web.xml
drag.xhtml
 Matrix4.javaは計算用、AjaxImage.javaは画像を生成するServletです。
 web.xmlはいい加減に飽きるほどお決まりの内容です。
<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>

  <display-name>JSF 2.0 Drag Ajax Servlet</display-name>
  <description>JSF 2.0 Drag Ajax Servlet</description>

  <servlet>
    <servlet-name>jsf20dragajax</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>jsf20dragajax</servlet-name>
    <url-pattern>*.jsf</url-pattern>
  </servlet-mapping>
</web-app>
 次は画像生成用のServletですが、色々難しいことをやっているように見えて、実は単に「引数に応じた画像を返している」だけです。したがって、実際には単にドラッグした距離を表示して返すだけでも構わないのですが、それではあまりにも味気ないため、このような面倒な内容となっています。応用次第で地図にでも何にでもできるため、色々な用途に使ってみるのも面白いのではないでしょうか。
 言うまでもありませんが、Matrix4.javaはただのマトリックスであるため、Servlet中で使わないなら用意する必要はありません。
// Matrix4.java
package com.yamicha.dragajax;

// 今回必要な処理のみ実装した、簡易マトリックスクラス
public class Matrix4{
	private double matrix[][];
	private final static int SIZE = 4;

	public final static int X = 0;
	public final static int Y = 1;
	public final static int Z = 2;
	public final static int H = 3;

	public Matrix4(){
		matrix = new double[SIZE][SIZE];
		for(int r = 0; r < SIZE; r++){
			for(int c = 0; c < SIZE; c++){
				matrix[r][c] = 0;
			}
		}
	}
	public Matrix4(double x , double y , double z){
		this();
		set(0 , X , x);
		set(0 , Y , y);
		set(0 , Z , z);
		set(0 , H , 1);
	}
	public double get(int row , int col){
		return matrix[row][col];
	}
	public void set(int row , int col , double value){
		matrix[row][col] = value;
	}

	public Matrix4 multiply(Matrix4 m){
		double n[][] = new double[SIZE][SIZE];

		for(int row = 0; row < SIZE; row++){
			for(int col = 0; col < SIZE; col++){
				double value = 0;
				for(int i = 0; i < SIZE; i++)
					value += get(row , i) *
						m.get(i , col);
				n[row][col] = value;
			}
		}

		matrix = n;
		return this;
	}
	public static Matrix4 rotate(int axis , double rad){
		int c = (axis + 1) % 3;
		int s = (axis + 2) % 3;

		double cos = Math.cos(rad);
		double sin = Math.sin(rad);

		Matrix4 m = new Matrix4();
		m.set(axis , axis , 1);
		m.set(c , c , cos);
		m.set(c , s , sin);
		m.set(s , c , -sin);
		m.set(s , s , cos);
		m.set(H , H , 1);

		return m;
	}
	public static Matrix4 move(double x , double y , double z){
		Matrix4 m = base();

		m.set(H , X , x);
		m.set(H , Y , y);
		m.set(H , Z , z);

		return m;
	}
	public static Matrix4 scale(double x , double y , double z){
		Matrix4 m = new Matrix4();

		m.set(X , X , x);
		m.set(Y , Y , y);
		m.set(Z , Z , z);
		m.set(H , H , 1);

		return m;
	}
	public static Matrix4 base(){
		return scale(1 , 1 , 1);
	}
}

// AjaxImage.java
package com.yamicha.dragajax;

import javax.servlet.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.imageio.*;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.*;

@WebServlet(name="ajaximage" , urlPatterns={"/image"})
  public class AjaxImage extends HttpServlet{
  public void doGet(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    response.setContentType("image/gif");
    OutputStream os = response.getOutputStream();

    try{
      String px = request.getParameter("x");
      String py = request.getParameter("y");
      int x = (px != null && !px.isEmpty()) ? -Integer.parseInt(px) : 0;
      int y = (py != null && !py.isEmpty()) ? -Integer.parseInt(py) : 0;

      // 画像のサイズ
      int width = 200;
      int height = 200;

      // 現在のドラッグ位置から回転度数を生成
      // 画像の幅だけドラッグすると45度
      double dy = ((double)x / width * Math.PI / 4) % (Math.PI * 2);
      double dx = ((double)y / height * Math.PI / 4) % (Math.PI * 2);

      if(dy < 0)
        dy += Math.PI * 2;
      if(dx < 0)
        dx += Math.PI * 2;

      // イメージ作成
      BufferedImage bufimg = new BufferedImage(width , height ,
        BufferedImage.TYPE_INT_ARGB);
      Graphics2D g = bufimg.createGraphics();

      // Graphics2D への描画開始
      g.setColor(Color.black);
      g.fillRect(0 , 0 , width , height);

      Color colors[] = {Color.red , Color.green , Color.blue};

      // 三角形の頂点
      Matrix4 matrixes[] = new Matrix4[3];
      matrixes[0] = new Matrix4(0 , 30 , 0);
      matrixes[1] = new Matrix4(-40 , -40 , 0);
      matrixes[2] = new Matrix4(40 , -40 , 0);

      // 回転
      // ドラッグ分だけ X 及び Y 軸回転し、
      // 最後に Z 方向に100移動
      // (遠近法適用時には物体がある程度離れている必要があるため)
      Matrix4 r = Matrix4.rotate(Matrix4.X , dx).
        multiply(Matrix4.rotate(Matrix4.Y , dy)).
        multiply(Matrix4.move(0 , 0 , 100));

      int points[][] = new int[3][2];

      // 回転を適用し、2D 上の描画位置を算出
      for(int i = 0; i < matrixes.length; i++){
        matrixes[i].multiply(r);

        boolean perspective = "true".equals(request.getParameter("p"));

        if(!perspective){
          // 遠近法を使用しない場合
          points[i][0] = (int)(matrixes[i].get(0 , Matrix4.X) + 0.5);
          points[i][1] = (int)(matrixes[i].get(0 , Matrix4.Y) + 0.5);
        }else{
          // 簡易遠近法
          points[i][0] = (int)(matrixes[i].get(0 , Matrix4.X) *
            ((double)width / 2 / matrixes[i].get(0 , Matrix4.Z)) + 0.5);
          points[i][1] = (int)(matrixes[i].get(0 , Matrix4.Y) * 
            ((double)height / 2 / matrixes[i].get(0 , Matrix4.Z)) + 0.5);
        }

        // 描画を中央にし、Y 座標は反転
        points[i][0] += width / 2;
        points[i][1] = height - (points[i][1] + height / 2);
      }

      // ラインを描画
      for(int i = 0; i < matrixes.length; i++){
        int at = i;
        int next = (i + 1) % 3;

        g.setColor(colors[i]);
        g.drawLine(points[at][0] , points[at][1] ,
          points[next][0] , points[next][1]);
      }

      // 回転度数表示
      g.setColor(Color.white);
      g.drawString("X軸: " + (int)(dx * 180 / Math.PI) +
        " 度" , 10 , height - 30);
      g.drawString("Y軸: " + (int)(dy * 180 / Math.PI) +
        " 度" , 10 , height - 10);

      // 出力
      ImageWriter writer =
        ImageIO.getImageWritersByFormatName("gif").next();

      ImageOutputStream ios = ImageIO.createImageOutputStream(os);
      writer.setOutput(ios);

      writer.write(bufimg);

      ios.close();
      writer.dispose();
    }catch(NumberFormatException e){
    }

    os.close();
  }
}
 地図を作成するのであれば、x及びy引数から必要な地図を生成すると良いでしょう。それ以外にも色々なプログラムが書けそうです。
 ManagedBeanはこれよりかなり単純です。
package com.yamicha.dragajax;

import javax.ejb.*;
import javax.annotation.*;
import javax.faces.bean.*;
import javax.faces.event.*;
import java.util.*;

@ManagedBean @ViewScoped public class DragBean
	implements java.io.Serializable{
	// 累計ドラッグ距離
	private int pos_x;
	private int pos_y;

	// 遠近法の ON/OFF
	private boolean perspective;

	public DragBean(){
		resetPos();
		perspective = true;
	}

	// x 及び y プロパティは drag.xhtml 上で
	// 「差分ドラッグ距離」として使用しているので
	// 取得値は0固定
	public int getX(){
		return 0;
	}
	public int getY(){
		return 0;
	}

	public boolean getPerspective(){
		return perspective;
	}

	// 差分ドラッグ距離を累計分に加算
	public void setX(int x){
		pos_x += x;
	}
	public void setY(int y){
		pos_y += y;
	}

	public void setPerspective(boolean p){
		perspective = p;
	}

	// 累計ドラッグ距離を取得
	public int getPosX(){
		return pos_x;
	}
	public int getPosY(){
		return pos_y;
	}

	// 画像 URL 生成
	// image?x=10&y=10&p=true など
	public String getImageSource(){
		return "image?x=" + getPosX() + "&y=" + getPosY() +
			"&p=" + (getPerspective() ? "true" : "false");
	}

	public void resetPos(){
		pos_x = 0;
		pos_y = 0;
	}
}
 後はXHTMLを残すだけなのですが、これが曲者です。何しろScriptを書くのはここなのですが、何をどうすべきか全く分からないのです。言うまでもなくドキュメントは用意されており、今回使用するのはjsf.ajaxであることまでは大体予想できますが、これを読んで理解できる人は新人類になるべきでしょう。全体的に説明不足で、引数の要求がさっぱり分かりません。
 色々と四苦八苦しつつ、とりあえず以下の点に着目してみました。
<commandButton id="button1" value="submit"
    onclick="jsf.ajax.request(this,event,
      {execute:'button1',render:'status',onevent: handleEvent,
       onerror: handleError});return false;"/>
</commandButton/>
 jsf.ajax.requestの引数は「jsf.ajax.request(source, event, options)」であると説明されています。この場合、thisがsource引数に、eventがevent引数に当たるようです。ちなみに、onclickやondragなどの記述の中でeventと書くと、自分自身のイベントを受け取れます。thisはそのまま自分自身で、jsf.ajax.requestからすれば「イベントのソース」ということになるはずですが、こちらはFirefoxならevent.target、IEならevent.srcElementで取得できます。したがって、引数にeventを取る汎用の関数を書いておいて、ソースはevent.targetやevent.srcElementで取ってjsf.ajax.requestに渡してやれば、割と手軽にプログラムが書けそうです。
 3つ目の引数はオプションですが、これはドキュメントに次のように書かれています。

namevalue
executespace seperated list of client identifiers
renderspace seperated list of client identifiers
oneventfunction to callback for event
onerrorfunction to callback for error
paramsobject containing parameters to include in the request

 executeとrenderはf:ajaxのものと同様として、paramsはリクエストパラメータ、oneventとonerrorはonreadystatechangeの類型と考えるのが妥当でしょう。実際に書いてみたところ、oneventで設定した関数には1つの引数が渡されており、要求が成功するまでに合計3回呼び出されていました。したがって、そのまま処理を書くと複数回実行されてしまいますが、例えば成功の際であれば引数のnameプロパティに"success"が格納されて返ってくるため、それを使って処理を分けられます。
 これ以外の部分は、ほとんど通常のJSFとJavaScriptに準じます。JavaScriptは不得手ですので、コードは何とも見通しが悪いですが、動いてはくれました。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xmlns:ui="http://java.sun.com/jsf/facelets">

<!-- JavaScript ライブラリを読み込ませるための記述 -->
<h:outputScript name="jsf.js" target="head" library="javax.faces" />

<h:head>
  <title>JSF 2.0 Drag Ajax</title>
  <script>
    var start_x = 0;
    var start_y = 0;

    // jsf.ajax.request の onevent コールバック用関数
    // jsf.ajax.request による Ajax リクエストが成功したら
    // 画像の src を dragform:pos:imgsrc のものに変更
    function change(r){
      if(r.name == "success"){
        img = new Image();
        img.src = document.getElementById("dragform:pos:imgsrc").value;
        document.getElementById("imageobj").src = img.src;
      }
    }

    // ドラッグ開始時のマウス位置を設定
    function setFirstPosition(){
      start_x = event.x;
      start_y = event.y;
    }
    // ドラッグ終了時の処理
    function writeDifference(e){
      dif_x = event.x - start_x;
      dif_y = event.y - start_y;

      setFirstPosition();

      document.getElementById("dragform:dif:x").value = dif_x;
      document.getElementById("dragform:dif:y").value = dif_y;

      sendPos(e);
    }
    // 「どれほどの距離をドラッグしたのか」を送信し
    // 「新たな画像の URL」を受信
    // 受信に成功した時点で画像を切り替える
    function sendPos(e){
      jsf.ajax.request(e.target != null ? e.target : e.srcElement , e ,
        {execute:'dragform:dif' , render:'dragform:pos' , onevent:change});

      document.getElementById("dragform:dif:x").value = 0;
      document.getElementById("dragform:dif:y").value = 0;
    }
  </script>
</h:head>

<h:body>
<div align="center">
  <b>JSF 2.0 Drag Ajax</b>
  <br />
  <br />

  <h:form id="dragform">
    <h:panelGroup id="dragimage">
      <img src="#{dragBean.imageSource}" id="imageobj"
        ondragstart="setFirstPosition()"
        ondragend="writeDifference(event)" style="cursor:move" />
    </h:panelGroup>
    <br />

    <h:form id="dif">
      <h:inputHidden id="x" value="#{dragBean.x}" />
      <h:inputHidden id="y" value="#{dragBean.y}" />

      <h:selectBooleanCheckbox value="#{dragBean.perspective}"
        onclick="sendPos(event)" />Perspective
    </h:form>

    <h:form id="pos">
      <h:inputHidden id="imgsrc" value="#{dragBean.imageSource}" />
    </h:form>
  </h:form>

  <h:commandButton action="#{dragBean.resetPos}" value="Reset">
    <f:ajax render="dragform:pos" onevent="change" />
  </h:commandButton>

</div>
</h:body>

</html>
 ドラッグ処理のやり方としては、ondragで次々と処理を行う方法と、ondragendでドラッグ終了時にまとめて処理を行う方法がありますが、ここでは後者を用いています。ondragの場合、ドラッグでマウスが動くたびにイベントが発生し、サーバーに山のようなリクエストが送られるため、Ajaxとしては非常に都合が悪いです。世によくある地図Ajaxなどでも、ondrag中は地図を画面上で動かすなどクライアントサイドの処理にとどめておいて、ondragendなどのタイミングでリクエストを送る場合が多いようです。
 Perspectiveチェックは簡易遠近法の有無、Resetは視点のリセットとなっており、チェックの場合はonclickによって押した時点でsendPosが呼ばれ、画像が更新されます。Resetはf:ajaxを使用しており、JavaScriptを直接呼び出さずに処理しています。


 最初の状態。


 画像を横にドラッグした状態。


 各方向へのドラッグが累積した状態。

 これだけでもかなり様々なことができそうですので、後は応用次第でしょう。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -