![]() |
<!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>マンデルブロ アート (Netscape 6)</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><TR><TD HEIGHT=5></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:256px; height:14px; 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:8px; 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.layerX - elem_img.offsetLeft - SIZE_X_H) * ratio; var w_center_i = center_i + (e.layerY - elem_img.offsetTop - 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"; 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) + "px"; // 初期パレット設定 set_palette(0); // ページを再ロードしたときコントロールの表示が初期化されない現象の対策 elem_pal.style.visibility = "hidden"; setTimeout("elem_pal.selectedIndex = 0; elem_pal.style.visibility = 'visible'", 0); document.forms[0].factor[0].checked = true; // 初期表示 mandelbrot(); //--> </SCRIPT> </BODY> </HTML> |