Javascriptで3次元グラフ

以前、Javaで3次元グラフを描画について日記を書きました。
続・3次元グラフ
3次元グラフ
アクセスログを見てみると「3次元グラフ」で検索してこの日記に辿りつく人が結構いるみたいです。大した内容を書いていないのにありがたいことです。そこで、今回は再度3次元グラフを描画について書きます。

ブラウザに描画!

今回はJavascriptを使います。Javascriptにはもともと描画をするための関数がないので、描画用のライブラリ「wz_jsgraphics.js」を使っています*1


This JavaScript VectorGraphics library provides graphics capabilities for JavaScript: functions to draw circles, ellipses (ovals), oblique lines, polylines and polygons (for instance triangles, rectangles) dynamically into a webpage. Usage of this Vector Graphics library should be easy even if you don't have JavaScript experience. Documentation. Another goal during development of this JavaScript Draw Shapes Vector Graphics Library was to achieve optimized performance and cleanly arranged pixel stair-step patterns (pixel-optimization).

↓日本語の紹介記事もあります。
http://phpspot.org/blog/archives/2007/02/javascriptwz_js.html

実際に描画してみた。

今回も以前の記事と同じグラフを描いています。

【比較用】以前のJavaのグラフ


以前のものと、同じグラフを描けました。

ソースコード

ソースコードも以前のものとほとんど変わりません。Javascript特有の部分以外はほとんど同じです。
このソースでは、以下のwz_jsgraphics.jsのAPIを使用しています。

  • new jsGraphics() … APIを使うためのオブジェクトのコンストラク
  • jg.drawLine() … 線を引くメソッド
  • jg.paint() … 描画を実行するメソッド(これを呼ぶまで描画されない)
<html>
<head>
<title>三次元グラフ</title>
</head>
<body>
<script type="text/javascript" src="wz_jsgraphics.js"></script>
<script type="text/javascript">
<!--

//////////////////////////////////////////////
// 描画アルゴリズム START
//////////////////////////////////////////////

var Xmin = -1;
var Ymin = -1;
var Zmin = -1;
var Xmax = 1;
var Zmax = 1;
var Ymax = 1;

/**
 * 描画アルゴリズムを実行する。
 */
function drawFunction() {
	var x, y, z;
	var i, ix, iz;
	var ok, ok1;
	var lowerhorizon = [];
	var upperhorizon = [];
	
	for ( i = 0; i <= 240; ++i ) {
		lowerhorizon[i] = Number.MAX_VALUE;
		upperhorizon[i] = Number.MIN_VALUE;
	}
	for ( iz = 0; iz <= 20; ++iz ) {
		z = Zmin + ( Zmax - Zmin ) / 20 * iz;
		ok1 = false;
		for ( ix = 0; ix <= 200; ++ix ) {
			x = Xmin + ( Xmax - Xmin ) / 200 * ix;
			i = ix + 2 * ( 20 - iz );
			y = 30 * ( func( x, z ) - Ymin ) / ( Ymax - Ymin ) + 5 * iz;
			
			ok = false;
			if ( y < lowerhorizon[i] ) {
				lowerhorizon[i] = y;
				ok = true;
			}
			if ( y > upperhorizon[i] ) {
				upperhorizon[i] = y;
				ok = true;
			}
			if ( ok && ok1 ) drawLine( i, y );
			else movePen( i, y );
			ok1 = ok;
		}
	}
}
	
//////////////////////////////////////////////
// 描画アルゴリズム END
//////////////////////////////////////////////

//////////////////////////////////////////////
// 描画対象の関数 START
//////////////////////////////////////////////

/**
 * 描画対象の関数
 */
function func( x, z ) {
	var r2 = x * x + z * z;
	return Math.exp( -r2 ) * Math.cos( 10 * Math.sqrt( r2 ) );
}

//////////////////////////////////////////////
// 描画対象の関数 END
//////////////////////////////////////////////

//////////////////////////////////////////////
// ブラウザに描画する関数 START
//////////////////////////////////////////////

// 描画用オブジェクト
var jg = new jsGraphics();
// ペンの座標。
var pen_x, pen_y;


/**
 * 実数のX座標値を補正し、整数にする。
 * @param x 補正前のX座標値
 * @return 補正後のX座標値
 */
function adjustX( x ) {
	return Math.floor( x * 2.0 );
}

/**
 * 実数のY座標値を補正し、整数にする。
 * @param y 補正前のY座標値
 * @return 補正後のY座標値
 */
function adjustY( y ) {
	return 300 - Math.floor( y * 2.0 );
}

/*
 * 線分を描く。
 * @param x X座標
 * @param y Y座標
 */
function drawLine( x, y ) {
	// ペンの座標から指定した座標までの線分を描く。
	jg.drawLine( adjustX( pen_x ), adjustY( pen_y ), adjustX( x ), adjustY( y ) );
	// ペンの座標を指定した座標に変更する。
	pen_x = x;
	pen_y = y;
}

/*
 * ペンを移動する。
 * @param x X座標
 * @param y Y座標
 */
function movePen( x, y ) {
	// ペンの座標を指定した座標に変更する。
	pen_x = x;
	pen_y = y;
}

//////////////////////////////////////////////
// ブラウザに描画する関数 END
//////////////////////////////////////////////


// 描画アルゴリズムを実行する。
drawFunction();
// 描画を実行する。
jg.paint();

//-->
</script> 
</body>
</html>

せっかくなので色など変えてみた

wz_jsgraphics.jsのsetColor()というメソッドを使うと、描画する色を変えることができます。
このメソッドを使って、線の色を変えてみました。

こんな感じ


なんだか気持ち悪い色です。

ソースの変更箇所

二点だけ変更しました。一点目は、色に関するグローバル変数の追加です。

// 色の一覧
var colorList = [
	"#004444",
	"#ffff00"
];

// 色のインデックス
var colorIndex = 0;

二点目は、drawLine関数への色の設定の処理の追加です。

/*
 * 線分を描く。
 * @param x X座標
 * @param y Y座標
 */
function drawLine( x, y ) {
	// 色を設定する。
	jg.setColor( colorList[colorIndex] );
	// ペンの座標から指定した座標までの線分を描く。
	jg.drawLine( adjustX( pen_x ), adjustY( pen_y ), adjustX( x ), adjustY( y ) );
	// ペンの座標を指定した座標に変更する。
	pen_x = x;
	pen_y = y;
	// 色のインデックスを変更する。
	colorIndex = ( colorIndex + 1 ) % colorList.length;
}
おわりに

Java(Swing)で描いた三次元グラフが、Javascriptでも問題なく描画できました。

ついでに、wz_jsgraphics.jsが簡単に使えることもわかりました。Swingの描画メソッドと作りがほぼ同じでわかりやすかったので、とても簡単でした。ただし、描画速度が遅いので、あまり大量の描画には向いてないと思います。
速度に関する欠点はあるものの、Javascript描画ができること自体が素敵なので、使いどころがあればまた使ってみたいです。

*1:最近はCanvasというHTML要素で描画できるそうですが、よく知りません。