<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML LANG="ja">
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=Shift_JIS">
<TITLE>マンデルブロ アート</TITLE>
</HEAD>
<BODY BGCOLOR="#CCFFFF" onResize="resize()">
<CENTER>
<B>マンデルブロ アート (Netscape 4)</B>
<BR><BR>
<SCRIPT LANGUAGE="JavaScript1.2" TYPE="text/javascript">
<!--
SIZE_X = 300;
SIZE_Y = 300;
SIZE_X_H = SIZE_X >> 1;
SIZE_Y_H = SIZE_Y >> 1;
// 現在の GIF イメージ データ(初期値は空白)
cur_image_data = "GIF89a\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00"
+ "\xff\xff\xff\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x01\x4c"
+ "\x00\x3b\x00\x00\x00\x00\x00";
//-->
</SCRIPT>
<IMG NAME="img" SRC="javascript:cur_image_data" WIDTH="&{SIZE_X};" HEIGHT="&{SIZE_Y};">
<BR><BR>
現在の表示範囲<BR>
<LAYER NAME="range"></LAYER>
<TABLE CELLPADDING=0><TR><TD><BR><BR></TD></TR></TABLE>
<FORM>
パレット
<SELECT NAME="pal" onChange="sel_palette()">
<OPTION SELECTED>8 色繰り返し
<OPTION>64 色繰り返し 1
<OPTION>64 色繰り返し 2
<OPTION>グレー 256 階調
<OPTION>赤 256 階調
<OPTION>緑 256 階調
<OPTION>青 256 階調
<OPTION>赤 - 緑 - 青
<OPTION>赤 - 青 - 緑
<OPTION>緑 - 青 - 赤
<OPTION>緑 - 赤 - 青
<OPTION>青 - 赤 - 緑
<OPTION>青 - 緑 - 赤
<OPTION>ランダム
</SELECT>
<BR>
</FORM>
<TABLE CELLSPACING=0 CELLPADDING=0>
<TR><TD ALIGN=LEFT><ILAYER NAME="p_l1" LEFT=-12 VISIBILITY="hide">集合</ILAYER></TD>
<TD ALIGN=RIGHT><ILAYER NAME="p_l2" LEFT=12 VISIBILITY="hide">1 回</ILAYER></TD></TR>
<TR><TD COLSPAN=2>
<ILAYER NAME="p_back" WIDTH=258 HEIGHT=16 CLIP="0,0,258,16">
<SCRIPT LANGUAGE="JavaScript1.2" TYPE="text/javascript">
<!--
for(var i = 0; i < 256; i++)
document.write("<LAYER NAME='p", String(i), "' LEFT=", String(1 + i),
" TOP=1 WIDTH=1 HEIGHT=14></LAYER>");
//-->
</SCRIPT>
</ILAYER>
</TD></TR>
</TABLE>
<SCRIPT LANGUAGE="JavaScript1.2" TYPE="text/javascript">
<!--
document.p_l1.visibility = "show";
document.p_l2.visibility = "show";
document.p_back.bgColor = "black";
//-->
</SCRIPT>
<BR>
<FORM>
<TABLE>
<TR><TD VALIGN=TOP>倍率</TD><TD NOWRAP>
<INPUT TYPE=RADIO NAME="factor" CHECKED onClick="sel_factor(0)"> 変更なし
<BR>
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(1)"> 1.5 倍
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(2)"> 2 倍
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(3)"> 3 倍
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(4)"> 4 倍
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(5)"> 8 倍
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(6)"> 16 倍
<BR>
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(7)"> 2/3
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(8)"> 1/2
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(9)"> 1/3
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(10)"> 1/4
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(11)"> 1/8
<INPUT TYPE=RADIO NAME="factor" onClick="sel_factor(12)"> 1/16
</TD></TR></TABLE>
<BR>
<INPUT TYPE=BUTTON NAME="reset" VALUE="初期位置・倍率" onClick="reset_para()">
<BR><BR>
</FORM>
<LAYER NAME="msg1" VISIBILITY="hide"><CENTER>計算中...</CENTER></LAYER>
<LAYER NAME="msg2" VISIBILITY="hide"><CENTER>画像作成中...</CENTER></LAYER>
<BR>
<TABLE CELLSPACING=0 CELLPADDING=0>
<TR><TD></TD></TR>
<TR><TD>
<ILAYER NAME="prog_back" BGCOLOR="black" WIDTH="&{SIZE_Y_H + 2};" HEIGHT=10 CLIP="0,0,&{SIZE_Y_H + 2};,10" VISIBILITY="hide">
<LAYER BGCOLOR="white" LEFT=1 TOP=1 WIDTH="&{SIZE_Y_H};" HEIGHT=8></LAYER>
<LAYER NAME="prog" BGCOLOR="lime" LEFT=1 TOP=1 WIDTH=1 HEIGHT=8></LAYER>
</ILAYER>
</TD></TR>
</TABLE>
<ILAYER NAME="can_base" VISIBILITY="hide">
<FORM>
<INPUT TYPE=BUTTON NAME="can" VALUE="中止" onClick="cancel = true">
<BR>
</FORM>
</ILAYER>
</CENTER>
<SCRIPT LANGUAGE="JavaScript1.2" TYPE="text/javascript">
<!--
// 画像クリック
function clicked(e) {
var x = e.pageX - document.img.x;
var y = e.pageY - document.img.y;
if(x < 0 || x >= SIZE_X || y < 0 || y >= SIZE_Y)
return;
if(input_disabled || !cur_image_data.length) // 入力ディスエーブル or イメージ未作成
return;
var w_ratio = ratio;
switch(cur_i_factor) {
case 1: // x 1.5
w_ratio /= 1.5;
break;
case 2: // x 2
w_ratio /= 2;
break;
case 3: // x 3
w_ratio /= 3;
break;
case 4: // x 4
w_ratio /= 4;
break;
case 5: // x 8
w_ratio /= 8;
break;
case 6: // x 16
w_ratio /= 16;
break;
case 7: // 2/3
w_ratio *= 1.5;
break;
case 8: // 1/2
w_ratio *= 2;
break;
case 9: // 1/3
w_ratio *= 3;
break;
case 10: // 1/4
w_ratio *= 4;
break;
case 11: // 1/8
w_ratio *= 8;
break;
case 12: // 1/16
w_ratio *= 16;
break;
}
if(w_ratio == 0) {
alert("倍率が大きくなりすぎます");
return;
}
if(!isFinite(w_ratio)) {
alert("倍率が小さくなりすぎます");
return;
}
var w_center_r = center_r + (x - SIZE_X_H) * ratio;
var w_center_i = center_i + (y - SIZE_Y_H) * ratio;
if(w_center_r - w_ratio == w_center_r || w_center_i - w_ratio == w_center_i
|| w_center_r + w_ratio == w_center_r || w_center_i + w_ratio == w_center_i // 桁落ち?
|| !isFinite(w_center_r - SIZE_X_H * w_ratio) || !isFinite(w_center_i - SIZE_Y_H * w_ratio)
|| !isFinite(w_center_r + SIZE_X_H * w_ratio) || !isFinite(w_center_i + SIZE_Y_H * w_ratio)) {
alert("計算できません");
return;
}
center_r = w_center_r;
center_i = w_center_i;
ratio = w_ratio;
document.forms[1].factor[0].checked = true; // x 1 に戻す
cur_i_factor = 0;
mandelbrot();
}
function isFinite(num) {
return !(num == Number.POSITIVE_INFINITY || num == Number.NEGATIVE_INFINITY);
}
// 初期位置・倍率
function reset_para() {
if(input_disabled) // 入力ディスエーブル
return;
center_r = center_i = 0.0;
ratio = 0.01;
document.forms[1].factor[0].checked = true; // x 1 に戻す
cur_i_factor = 0;
mandelbrot();
}
// マンデルブロ集合作成
function mandelbrot() {
input_disabled = true;
document.msg1.visibility = "show";
document.prog_back.document.prog.clip.right = 0;
document.prog_back.visibility = "show";
document.can_base.visibility = "show";
cancel = false;
setTimeout("mandelbrot1(0)", 0);
}
function mandelbrot1(y) {
if(cancel) {
end_proc();
return;
}
var b = center_i + (y - SIZE_Y_H) * ratio;
for(var x = 0; x < SIZE_X; x++) {
var a = center_r + (x - SIZE_X_H) * ratio;
var zr, zi;
var zr2, zi2;
zr = zi = zr2 = zi2 = 0.0;
var cnt;
for(cnt = 255; cnt; cnt--) {
zi = 2 * zr * zi + b;
zr = zr2 - zi2 + a;
if((zr2 = zr * zr) + (zi2 = zi * zi) > 4)
break;
}
pixels[y][x] = cnt;
}
y++;
if(!(y & 0x1))
document.prog_back.document.prog.clip.right = y >> 1;
if(y == SIZE_Y) {
if(cancel) {
end_proc();
return;
}
setTimeout("create_image()", 0);
}
else {
setTimeout("mandelbrot1(" + String(y) + ")", 0);
}
}
function create_image() {
image_data = "";
// Header,Logical Screen Descriptor,Global Color Table,Image Descriptor
// と LZW Minimum Code Size
var i;
for(i = 0; i < header1.length; i++)
putc(header1[i]);
for(i = 0; i < 256; i++) {
with(cur_palette[i]) {
putc(r);
putc(g);
putc(b);
}
}
for(i = 0; i < header2.length; i++)
putc(header2[i]);
block_cnt = 0;
pack_buff = 0;
pack_bits = 0;
code_bits = 9;
max_n = 512;
n_code = 258;
put_code(256); // Clear
code = pixels[0][0];
prop = root_prop[code];
document.msg1.visibility = "hide";
document.msg2.visibility = "show";
document.prog_back.document.prog.clip.right = 0;
setTimeout("create_image1(0, 1)", 0);
}
function create_image1(y, x) {
if(cancel) {
end_proc();
return;
}
while(x < SIZE_X) {
// 次の 1 ピクセル
var c = pixels[y][x++];
var cs = String.fromCharCode(c);
// 辞書サーチ
var i = -1;
if(prop.chara)
i = prop.chara.indexOf(cs);
if(i == -1) { // 未登録
put_code(code);
if(n_code == 4095) { // 辞書が一杯(のひとつ前)
// 辞書クリア
put_code(256); // Clear
for(i = 0; i < 256; i++) {
delete root_prop[i].chara;
delete root_prop[i].prop;
}
n_code = 258;
code_bits = 9;
max_n = 512;
}
else {
// 辞書に登録
if(prop.chara) {
prop.chara += cs;
prop.prop.push({code:n_code});
}
else {
prop.chara = cs;
prop.prop = [{code:n_code}];
}
if(n_code++ == max_n) {
code_bits++;
max_n <<= 1;
}
}
code = c;
prop = root_prop[c];
}
else { // 登録済み
code = prop.prop[i].code;
prop = prop.prop[i];
}
}
y++;
if(!(y & 0x1))
document.prog_back.document.prog.clip.right = y >> 1;
if(y == SIZE_Y)
setTimeout("create_image2()", 0);
else
setTimeout("create_image1(" + String(y) + ", 0)", 0);
}
function create_image2() {
put_code(code); // 最後のコード
put_code(257); // End of Information
// コード パック用バッファ フラッシュ
if(pack_bits)
put_code(0);
// ブロック バッファ フラッシュ
if(block_cnt) {
putc(block_cnt);
for(var i = 0; i < block_cnt; i++)
putc(block_buff[i]);
}
putc(0x00); // Block Terminator
putc(0x3b); // Trailer
// イメージ表示
cur_image_data = image_data;
document.img.src = document.img.src; // 表示を更新
// 表示範囲
var str1 = range_num(center_i - SIZE_Y_H * ratio);
if(str1.charAt(0) != "-")
str1 = "+" + str1;
str1 = range_num(center_r - SIZE_X_H * ratio) + str1 + "i";
var str2 = range_num(center_i + SIZE_Y_H * ratio);
if(str2.charAt(0) != "-")
str2 = "+" + str2;
str2 = range_num(center_r + SIZE_X_H * ratio) + str2 + "i";
document.range.document.open();
document.range.document.write(
"<CENTER><TABLE CELLPADDING=0><TR><TD NOWRAP>", str1, "<BR> 〜 ", str2, "<BR></TD></TR></TABLE></CENTER>");
document.range.document.close();
end_proc();
}
// 表示範囲の数値をフォーマット
function range_num(num) {
var str = String(num).split("e");
if(str[0].charAt(0) == ".")
str[0] = "0" + str[0];
else if(str[0].substr(0, 2) == "-.")
str[0] = "-0" + str[0].substr(1);
if(str.length == 1)
return str[0];
return str[0] + "×10<SUP>" + str[1].replace(/\+/, "") + "</SUP>";
}
// LZW コード出力
function put_code(code) {
pack_buff |= code << pack_bits;
pack_bits += code_bits;
while(pack_bits >= 8) {
block_buff[block_cnt++] = pack_buff & 0xff;
if(block_cnt == 255) {
putc(255);
for(var i = 0; i < 255; i++)
putc(block_buff[i]);
block_cnt = 0;
}
pack_buff >>= 8;
pack_bits -= 8;
}
}
// イメージ データに 1 バイト出力
function putc(c) {
image_data += String.fromCharCode(c);
}
// マンデルブロ集合作成終了
function end_proc() {
// 辞書ルートを初期状態に戻す
for(var i = 0; i < 256; i++) {
delete root_prop[i].chara;
delete root_prop[i].prop;
}
document.msg1.visibility = "hide";
document.msg2.visibility = "hide";
document.prog_back.visibility = "hide";
document.can_base.visibility = "hide";
input_disabled = false;
}
// パレット選択
function sel_palette() {
var i;
if(input_disabled) { // 入力ディスエーブル
document.forms[0].pal.selectedIndex = cur_i_pal;
return;
}
cur_i_pal = document.forms[0].pal.selectedIndex;
if(cur_i_pal == 13) { // ランダム
for(i = 0; i < 256; i++) {
var v = Math.floor(Math.random() * 0x1000000);
palette[13][i] = {r:v >> 16, g:(v >> 8) & 0xff, b:v & 0xff};
}
}
set_palette();
if(cur_image_data.length < 256) // イメージ未作成
return;
// GIF イメージのカラー テーブルのみを書き換える.
image_data = "";
for(i = 0; i < 256; i++) {
with(cur_palette[i]) {
putc(r);
putc(g);
putc(b);
}
}
cur_image_data = cur_image_data.substr(0, header1.length) + image_data
+ cur_image_data.substr(header1.length + 256 * 3);
document.img.src = document.img.src; // 表示を更新
}
// パレット設定
function set_palette() {
cur_palette = palette[cur_i_pal];
for(var i = 0; i < 256; i++) {
with(cur_palette[i]) {
document.p_back.document.layers["p" + String(i)].bgColor
= ("0" + r.toString(16)).substr(-2)
+ ("0" + g.toString(16)).substr(-2)
+ ("0" + b.toString(16)).substr(-2);
}
}
}
// 倍率選択
function sel_factor(i_factor) {
if(input_disabled) { // 入力ディスエーブル
document.forms[1].factor[cur_i_factor].checked = true;
return;
}
cur_i_factor = i_factor;
}
function resize() {
// リサイズしたときレイヤー関係の表示が崩れる現象の対策
document.p_back.left = 0
for(var i = 0; i < 256; i++) {
with(cur_palette[i]) {
document.p_back.document.layers["p" + String(i)].bgColor
= ("0" + r.toString(16)).substr(-2)
+ ("0" + g.toString(16)).substr(-2)
+ ("0" + b.toString(16)).substr(-2);
}
}
}
//----------------------------------------------------------
center_r = center_i = 0.0; // 表示中心値
ratio = 0.01; // 1 ピクセルの大きさ
// イメージ配列
pixels = new Array();
pixels.length = SIZE_Y;
for(i = 0; i < SIZE_Y; i++) {
pixels[i] = new Array();
pixels[i].length = SIZE_X;
}
// Header,Logical Screen Descriptor
header1 = [
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, // GIF89a
SIZE_X & 0xff, SIZE_X >> 8,
SIZE_Y & 0xff, SIZE_Y >> 8,
0xf7, // Global Color Table,256色
0x00, // Background Color Index
0x00 // Pixel Aspect Ratio
];
// Image Descriptor と LZW Minimum Code Size
header2 = [
0x2c, // Image Separator
0x00, 0x00, 0x00, 0x00, // 0,0
SIZE_X & 0xff, SIZE_X >> 8,
SIZE_Y & 0xff, SIZE_Y >> 8,
0x00,
8 // 8 ビット
];
// 辞書ルート
root_prop = new Array();
root_prop.length = 256;
for(i = 0; i < 256; i++)
root_prop[i] = {};
var n_code; // コード登録数
var code_bits; // コード ビット数
var max_n; // 最大コード登録数
var code; // コード
var prop; // 辞書情報
var pack_buff; // コード パック用バッファ
var pack_bits; // コード パック用バッファ格納ビット数
block_buff = new Array(); // ブロック バッファ
block_buff.length = 255;
var block_cnt; // ブロック バッファ格納バイト数
var image_data; // GIF イメージ データ
var cancel; // 中止フラグ
input_disabled = true; // 入力ディスエーブル フラグ
// 各種パレット作成
palette = new Array();
palette.length = 14;
for(i = 0; i < 14; i++) {
palette[i] = new Array();
palette[i].length = 256;
}
for(i = 0; i < 256; i++) {
palette[0][i] = {r:(i & 0x1) ? 255 : 0, g:(i & 0x2) ? 255 : 0, b:(i & 0x4) ? 255 : 0};
palette[1][i] = {r:(i & 0x03) * 85, g:((i & 0x0c) >> 2) * 85, b:((i & 0x30) >> 4) * 85};
palette[2][i] = {r:( i & 0x01 | ((i & 0x08) >> 2)) * 85,
g:(((i & 0x02) >> 1) | ((i & 0x10) >> 3)) * 85,
b:(((i & 0x04) >> 2) | ((i & 0x20) >> 4)) * 85};
palette[3][i] = {r:i, g:i, b:i};
palette[4][i] = {r:i, g:0, b:0};
palette[5][i] = {r:0, g:i, b:0};
palette[6][i] = {r:0, g:0, b:i};
}
for(i = 0; i < 64; i++) {
var v = Math.round(i * 255 / 63);
palette[7 ][i ] = {r:255, g:v, b:0};
palette[7 ][127 - i] = {r:v, g:255, b:0};
palette[7 ][128 + i] = {r:0, g:255, b:v};
palette[7 ][255 - i] = {r:0, g:v, b:255};
palette[8 ][i ] = {r:255, g:0, b:v};
palette[8 ][127 - i] = {r:v, g:0, b:255};
palette[8 ][128 + i] = {r:0, g:v, b:255};
palette[8 ][255 - i] = {r:0, g:255, b:v};
palette[9 ][i ] = {r:0, g:255, b:v};
palette[9 ][127 - i] = {r:0, g:v, b:255};
palette[9 ][128 + i] = {r:v, g:0, b:255};
palette[9 ][255 - i] = {r:255, g:0, b:v};
palette[10][i ] = {r:v, g:255, b:0};
palette[10][127 - i] = {r:255, g:v, b:0};
palette[10][128 + i] = {r:255, g:0, b:v};
palette[10][255 - i] = {r:v, g:0, b:255};
palette[11][i ] = {r:v, g:0, b:255};
palette[11][127 - i] = {r:255, g:0, b:v};
palette[11][128 + i] = {r:255, g:v, b:0};
palette[11][255 - i] = {r:v, g:255, b:0};
palette[12][i ] = {r:0, g:v, b:255};
palette[12][127 - i] = {r:0, g:255, b:v};
palette[12][128 + i] = {r:v, g:255, b:0};
palette[12][255 - i] = {r:255, g:v, b:0};
}
// 初期パレット設定
cur_i_pal = 0;
set_palette();
cur_i_factor = 0;
// ページを再ロードしたときコントロールの表示が初期化されない現象の対策
document.forms[0].pal.selectedIndex = 0;
document.forms[1].factor[0].checked = true;
captureEvents(Event.MOUSEDOWN);
onmousedown = clicked;
// 初期表示
mandelbrot();
//-->
</SCRIPT>
</BODY>
</HTML>
|