<!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">
<CENTER>
<B>マンデルブロ アート (Opera 8)</B>
<BR><BR>
<IMG ID="img" SRC="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOwAA"
WIDTH=1 HEIGHT=1 onClick="clicked(event)">
<BR><BR>
現在の表示範囲<BR>
<TABLE><TR><TD VALIGN=TOP NOWRAP>
<SPAN ID="range-f-r-1"> </SPAN><SUP ID="range-f-r-2"> </SUP><SPAN ID="range-f-i-1"> </SPAN><SUP ID="range-f-i-2"> </SUP><SPAN ID="range-f-i-3"> </SPAN>
〜
<SPAN ID="range-t-r-1"> </SPAN><SUP ID="range-t-r-2"> </SUP><SPAN ID="range-t-i-1"> </SPAN><SUP ID="range-t-i-2"> </SUP><SPAN ID="range-t-i-3"> </SPAN>
</TD><TD><BR><BR></TD></TR></TABLE>
<FORM>
パレット
<SELECT ID="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>
<DIV STYLE="position:relative; width:280px">
<BR>
<SPAN STYLE="position:absolute; left:0; top:0">集合</SPAN>
<SPAN STYLE="position:absolute; right:0; top:0">1 回</SPAN>
</DIV>
<DIV STYLE="position:relative; width:258px; height:16px; border:solid black 1px">
<SCRIPT LANGUAGE="JavaScript1.5" TYPE="text/javascript">
<!--
for(var i = 0; i < 256; i++)
document.write("<SPAN ID='p", String(i), "' STYLE='position:absolute; left:",
String(i), "px; top:0; width:1px; height:14px'></SPAN>");
//-->
</SCRIPT>
</DIV>
<BR>
<TABLE>
<TR><TD VALIGN=TOP>倍率</TD><TD NOWRAP>
<INPUT TYPE=RADIO NAME="factor" CHECKED> 変更なし
<BR>
<INPUT TYPE=RADIO NAME="factor"> 1.5 倍
<INPUT TYPE=RADIO NAME="factor"> 2 倍
<INPUT TYPE=RADIO NAME="factor"> 3 倍
<INPUT TYPE=RADIO NAME="factor"> 4 倍
<INPUT TYPE=RADIO NAME="factor"> 8 倍
<INPUT TYPE=RADIO NAME="factor"> 16 倍
<BR>
<INPUT TYPE=RADIO NAME="factor"> 2/3
<INPUT TYPE=RADIO NAME="factor"> 1/2
<INPUT TYPE=RADIO NAME="factor"> 1/3
<INPUT TYPE=RADIO NAME="factor"> 1/4
<INPUT TYPE=RADIO NAME="factor"> 1/8
<INPUT TYPE=RADIO NAME="factor"> 1/16
</TD></TR></TABLE>
<BR>
<INPUT TYPE=BUTTON ID="reset" VALUE="初期位置・倍率" onClick="reset_para()">
<BR><BR>
<TABLE>
<TR><TD ALIGN=CENTER><DIV ID="msg" STYLE="visibility:hidden"> </DIV></TD></TR>
<TR><TD ALIGN=CENTER><DIV ID="prog-back" STYLE="position:relative; height:10px; background-color:white; border:solid black 1px; visibility:hidden">
<SPAN ID="prog" STYLE="position:absolute; left:0; top:0; height:8px; background-color:lime"></SPAN>
</DIV></TD></TR>
<TR><TD ALIGN=CENTER><INPUT TYPE=BUTTON ID="can" VALUE="中止" onClick="cancel = true" STYLE="visibility:hidden"></TD></TR>
</TABLE>
</FORM>
</CENTER>
<SCRIPT LANGUAGE="JavaScript1.5" TYPE="text/javascript">
<!--
SIZE_X = 300;
SIZE_Y = 300;
SIZE_X_H = SIZE_X >> 1;
SIZE_Y_H = SIZE_Y >> 1;
// 画像クリック
function clicked(e) {
if(image_disabled || !cur_image_data.length) // 画像ディスエーブル or イメージ未作成
return;
// 倍率取り込み
for(var i = 0; i < document.forms[0].factor.length; i++) {
if(document.forms[0].factor[i].checked)
break;
}
var w_ratio = ratio;
switch(i) {
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 + (e.offsetX - SIZE_X_H) * ratio;
var w_center_i = center_i + (e.offsetY - 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[0].factor[0].checked = true; // x 1 に戻す
mandelbrot();
}
// 初期位置・倍率
function reset_para() {
center_r = center_i = 0.0;
ratio = 0.01;
document.forms[0].factor[0].checked = true; // x 1 に戻す
mandelbrot();
}
// マンデルブロ集合作成
function mandelbrot() {
image_disabled = true;
elem_pal.disabled = true;
for(var i = 0; i < document.forms[0].factor.length; i++)
document.forms[0].factor[i].disabled = true;
document.getElementById("reset").disabled = true;
elem_msg.firstChild.nodeValue = "計算中...";
elem_msg.style.visibility = "visible";
elem_prog.style.width = "0";
elem_prog_back.style.visibility = "visible";
elem_can.style.visibility = "visible";
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))
elem_prog.style.width = String(y >> 1) + "px";
if(y == SIZE_Y) {
if(cancel) {
end_proc();
return;
}
setTimeout("create_image()", 0);
}
else {
setTimeout("mandelbrot1(" + String(y) + ")", 0);
}
}
function create_image() {
image_data = "";
b64_cnt = 0;
// 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];
elem_msg.firstChild.nodeValue = "画像作成中...";
elem_prog.style.width = "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 != undefined)
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++) {
root_prop[i].chara = undefined;
root_prop[i].prop = undefined;
}
n_code = 258;
code_bits = 9;
max_n = 512;
}
else {
// 辞書に登録
if(prop.chara == undefined) {
prop.chara = cs;
prop.prop = [{code:n_code, chara:undefined, prop:undefined}];
}
else {
prop.chara += cs;
prop.prop.push({code:n_code, chara:undefined, prop:undefined});
}
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))
elem_prog.style.width = String(y >> 1) + "px";
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
// BASE64 バッファ フラッシュ
switch(b64_cnt) {
case 1:
image_data += b64.charAt(b64_buff >> 18);
image_data += b64.charAt((b64_buff >> 12) & 0x3f);
image_data += "==";
break;
case 2:
image_data += b64.charAt(b64_buff >> 18);
image_data += b64.charAt((b64_buff >> 12) & 0x3f);
image_data += b64.charAt((b64_buff >> 6) & 0x3f);
image_data += "=";
break;
}
// イメージ表示
elem_img.src = image_header + image_data;
cur_image_data = image_data;
// 表示範囲
var str;
str = (center_r - SIZE_X_H * ratio).toExponential(4).split("e");
document.getElementById("range-f-r-2").firstChild.nodeValue = "";
switch(Number(str[1])) {
case 0:
break;
default:
document.getElementById("range-f-r-2").firstChild.nodeValue = str[1].replace(/\+/, "");
// fall thru
case 1:
str[0] += "×10";
break;
}
document.getElementById("range-f-r-1").firstChild.nodeValue = str[0];
str = (center_i - SIZE_Y_H * ratio).toExponential(4).split("e");
if(str[0].charAt(0) != "-")
str[0] = "+" + str[0];
document.getElementById("range-f-i-2").firstChild.nodeValue = "";
switch(Number(str[1])) {
case 0:
break;
default:
document.getElementById("range-f-i-2").firstChild.nodeValue = str[1].replace(/\+/, "");
// fall thru
case 1:
str[0] += "×10";
break;
}
document.getElementById("range-f-i-1").firstChild.nodeValue = str[0];
document.getElementById("range-f-i-3").firstChild.nodeValue = "i";
str = (center_r + SIZE_X_H * ratio).toExponential(4).split("e");
document.getElementById("range-t-r-2").firstChild.nodeValue = "";
switch(Number(str[1])) {
case 0:
break;
default:
document.getElementById("range-t-r-2").firstChild.nodeValue = str[1].replace(/\+/, "");
// fall thru
case 1:
str[0] += "×10";
break;
}
document.getElementById("range-t-r-1").firstChild.nodeValue = str[0];
str = (center_i + SIZE_Y_H * ratio).toExponential(4).split("e");
document.getElementById("range-t-i-2").firstChild.nodeValue = "";
if(str[0].charAt(0) != "-")
str[0] = "+" + str[0];
switch(Number(str[1])) {
case 0:
break;
default:
document.getElementById("range-t-i-2").firstChild.nodeValue = str[1].replace(/\+/, "");
// fall thru
case 1:
str[0] += "×10";
break;
}
document.getElementById("range-t-i-1").firstChild.nodeValue = str[0];
document.getElementById("range-t-i-3").firstChild.nodeValue = "i";
// テキストをセットしただけでは何故か表示されない.
// また何故か,ひとつの項目の visibility を再セットしてやると,すべての項目が表示される.
document.getElementById("range-f-r-1").style.visibility = "visible";
end_proc();
}
// 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) {
switch(b64_cnt) {
case 0:
b64_buff = c << 16;
b64_cnt = 1;
break;
case 1:
b64_buff |= c << 8;
b64_cnt = 2;
break;
case 2:
b64_buff |= c;
image_data += b64.charAt(b64_buff >> 18);
image_data += b64.charAt((b64_buff >> 12) & 0x3f);
image_data += b64.charAt((b64_buff >> 6) & 0x3f);
image_data += b64.charAt(b64_buff & 0x3f);
b64_cnt = 0;
break;
}
}
// マンデルブロ集合作成終了
function end_proc() {
var i;
// 辞書ルートを初期状態に戻す
for(i = 0; i < 256; i++) {
root_prop[i].chara = undefined;
root_prop[i].prop = undefined;
}
elem_msg.style.visibility = "hidden";
elem_prog_back.style.visibility = "hidden";
elem_can.style.visibility = "hidden";
image_disabled = false;
elem_pal.disabled = false;
for(i = 0; i < document.forms[0].factor.length; i++)
document.forms[0].factor[i].disabled = false;
document.getElementById("reset").disabled = false;
}
// パレット選択
function sel_palette() {
var i;
var i_pal = elem_pal.selectedIndex;
if(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(i_pal);
if(!cur_image_data.length) // イメージ未作成
return;
// BASE64 エンコードされた GIF イメージのカラー テーブルのみを書き換える.
// 元データの 3 バイト境界で書き換え.カラー テーブルのサイズは 3 バイトの倍数.
// 処理を簡単にするため,header1 は全部書き換えることにする.
image_data = "";
b64_cnt = 0;
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 < 3 - header1.length % 3; i++)
putc(header2[i]);
cur_image_data = image_data + cur_image_data.substr(image_data.length);
elem_img.src = image_header + cur_image_data;
}
// パレット設定
function set_palette(i_pal) {
cur_palette = palette[i_pal];
for(var i = 0; i < 256; i++) {
with(cur_palette[i]) {
document.getElementById("p" + String(i)).style.backgroundColor
= "rgb(" + String(r) + "," + String(g) + "," + String(b) + ")";
}
}
}
//----------------------------------------------------------
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;
}
image_header = "data:image/gif;base64,";
// 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] = {chara:undefined, prop:undefined};
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 イメージ データ
cur_image_data = ""; // 現在の GIF イメージ データ
var b64_buff; // BASE64 バッファ
var b64_cnt; // BASE64 バッファ格納バイト数
// BASE64 エンコード キャラクタ
b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var cancel; // 中止フラグ
image_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};
}
elem_img = document.getElementById("img");
elem_pal = document.getElementById("pal");
elem_msg = document.getElementById("msg");
elem_prog_back = document.getElementById("prog-back");
elem_prog = document.getElementById("prog");
elem_can = document.getElementById("can");
with(elem_img.style) {
width = String(SIZE_X) + "px";
height = String(SIZE_Y) + "px";
}
elem_prog_back.style.width = String(SIZE_Y_H + 2) + "px";
// 初期パレット設定
set_palette(0);
// 初期表示
mandelbrot();
//-->
</SCRIPT>
</BODY>
</HTML>
|