![]() |
<!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 7)</B> <BR><BR> <FORM> <TABLE><TR> <TD VALIGN=TOP> <IMG ID="img" SRC="data:image/bmp;base64,Qk1CAAAAAAAAAD4AAAAoAAAAAQAAAAEAAAABAAEAAAAAAAQAAADEDgAAxA4AAAAAAAAAAAAAAAAAAP///wCAAAAAAAAA" WIDTH=480 HEIGHT=480> </TD> <TD WIDTH=10></TD> <TD VALIGN=TOP NOWRAP> <BR> <IMG SRC="images/spiro.gif" WIDTH=149 HEIGHT=165><BR><BR> r1: <INPUT TYPE=TEXT ID="r1" SIZE=4> (整数)<BR> r2: <INPUT TYPE=TEXT ID="r2" SIZE=4> (整数)<BR> r3: <INPUT TYPE=TEXT ID="r3" SIZE=8><BR> スケール: <INPUT TYPE=TEXT ID="scale" SIZE=8><BR><BR> 色: <SELECT ID="color"> <OPTION SELECTED>黒 <OPTION>赤 <OPTION>ライム <OPTION>青 <OPTION>黄 <OPTION>赤紫 <OPTION>水色 <OPTION>栗色 <OPTION>緑 <OPTION>ネイビー <OPTION>オリーブ <OPTION>紫 <OPTION>青緑 <OPTION>橙 <OPTION>灰 </SELECT><BR><BR> <INPUT TYPE=CHECKBOX ID="quiet">途中経過を表示しない<BR><BR> <INPUT TYPE=BUTTON ID="start" VALUE="描画開始" onClick="start_drawing()"> <INPUT TYPE=BUTTON ID="can" VALUE="描画中止" DISABLED onClick="cancel = true"> <INPUT TYPE=BUTTON ID="undo" VALUE="やり直し" DISABLED onClick="restore_image()"><BR><BR> <INPUT TYPE=BUTTON ID="clear" VALUE="クリア" onClick="clear_image()"><BR><BR> <DIV ID="prog" ALIGN=CENTER STYLE="visibility:hidden"><FONT SIZE="+1">◆ 処理中 ◆</FONT></DIV> </TD> </TR></TABLE> </FORM> </CENTER> <SCRIPT LANGUAGE="JavaScript1.2" TYPE="text/javascript"> <!-- // 整数 キー入力チェック function check_int(e) { return (e.which < 0x20 || e.which >= 0x30 && e.which <= 0x39 || e.ctrlKey || e.metaKey); } // 小数 キー入力チェック function check_float(e) { return (e.which < 0x20 || e.which >= 0x30 && e.which <= 0x39 || e.which == 0x2e || e.ctrlKey || e.metaKey); } // 描画開始 function start_drawing() { // 入力チェック var r1 = elem_r1.value; if(r1.search(/^\s*\d+\s*$/) == -1) r1 = 0; else r1 = parseInt(r1, 10); if((isNaN(r1)) ? true : (r1 == 0 || r1 >= 10000)) { alert("r1 の入力に誤りがあります。"); return; } var r2 = elem_r2.value; if(r2.search(/^\s*\d+\s*$/) == -1) r2 = 0; else r2 = parseInt(r2, 10); if((isNaN(r2)) ? true : (r2 == 0 || r2 >= 10000)) { alert("r2 の入力に誤りがあります。"); return; } if(r2 >= r1) { alert("r2 には r1 より小さい値を入力してください。"); return; } var r3 = elem_r3.value; if(r3.search(/^\s*\d*\.?\d*\s*$/) == -1) r3 = 0; else r3 = parseFloat(r3); if((isNaN(r3)) ? true : (r3 == 0 || r3 >= 10000)) { alert("r3 の入力に誤りがあります。"); return; } var scale = elem_scale.value; if(scale.search(/\S/) == -1) { // 未入力 scale = 0; } else { if(scale.search(/^\s*\d*\.?\d*\s*$/) == -1) scale = 0; else scale = parseFloat(scale); if((isNaN(scale)) ? true : (scale == 0 || scale >= 10000)) { alert("スケールの入力に誤りがあります。"); return; } if(scale < r1 - r2 + r3) { alert("スケールには r1 - r2 + r3 以上の値を入力してください。"); return; } } color = document.getElementById("color").selectedIndex; // 色 quiet = document.getElementById("quiet").checked // 途中経過を表示しない cancel = false; save_data = data; elem_start.disabled = true; elem_undo.disabled = true; elem_clear.disabled = true; if(quiet) elem_prog.style.visibility = "visible"; else elem_can.disabled = false; var rd = r1 - r2; rr = rd / r2; if(!scale) scale = r1 - r2 + r3; rdp = rd * 239.99 / scale; r3p = r3 * 239.99 / scale; // GCD を求める var a, b; for(a = r1, b = r2; ; ) { var w; if(a < b) { w = a; a = b; b = w; } if(!b) break; w = a % b; a = b; b = w; } div_end = NDIV * (r2 / a); prev_x = Math.floor(rdp + r3p) + 240; prev_y = 240; setTimeout(draw, 0, 0); } // 画像復旧 function restore_image() { elem_undo.disabled = true; data = save_data; elem_img.src = data; } // クリア function clear_image() { elem_undo.disabled = true; var d3 = b64.charAt(0x3f); d3 += d3; data = header; for(var i = 76800; i; i--) data += d3; elem_img.src = data; } // 描画 function draw(div) { if(cancel) { elem_can.disabled = true; elem_start.disabled = false; elem_clear.disabled = false; data = save_data; elem_img.src = data; return; } for(var cnt = 10; ; ) { var x, y; if(div == div_end) { x = Math.floor(rdp + r3p) + 240; y = 240; } else { var th1 = PI2DIV * div; var th2 = rr * (th1); x = Math.floor(rdp * Math.cos(th1) + r3p * Math.cos(th2)) + 240; y = Math.floor(rdp * Math.sin(th1) - r3p * Math.sin(th2)) + 240; } if(x != prev_x || y != prev_y) { // 直線補間 var dx = Math.abs(x - prev_x); var dy = Math.abs(y - prev_y); var rem = 0; var xi = (prev_x < x) ? 1 : -1; var yi = (prev_y < y) ? 1 : -1; if(dx >= dy) { for(var d = dx; d; d--) { set_pixel(prev_x, prev_y); if((rem += dy) >= dx) { prev_y += yi; rem -= dx; } prev_x += xi; } } else { for(var d = dy; d; d--) { set_pixel(prev_x, prev_y); if((rem += dx) >= dy) { prev_x += xi; rem -= dy; } prev_y += yi; } } if(!quiet) cnt--; } if(div++ == div_end) { // 終了 elem_can.disabled = true; elem_prog.style.visibility = "hidden"; elem_start.disabled = false; elem_undo.disabled = false; elem_clear.disabled = false; elem_img.src = data; return; } if(!cnt) { elem_img.src = data; setTimeout(draw, 0, div); return; } } } // 1 ピクセル描画 function set_pixel(x, y) { var i = y * 320 + (Math.floor(x / 3) << 1) + header_len; switch(x % 3) { case 0: data = data.substr(0, i) + b64.charAt((color << 2) | b64.indexOf(data.charAt(i)) & 0x3) + data.substr(i + 1); break; case 1: data = data.substr(0, i) + b64.charAt(b64.indexOf(data.charAt(i)) & 0x3c | (color >> 2)) + b64.charAt(((color & 0x3) << 4) | b64.indexOf(data.charAt(i + 1)) & 0xf) + data.substr(i + 2); break; default: data = data.substr(0, i + 1) + b64.charAt(b64.indexOf(data.charAt(i + 1)) & 0x30 | color) + data.substr(i + 2); } } //---------------------------------------------------------- // BMP ヘッダ bmp_header = [ // BITMAPFILEHEADER 0x42, 0x4d, // BM 0x78, 0xc2, 0x01, 0x00, // Size 115320 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, // OffBits 120 // BITMAPINFOHEADER 0x28, 0x00, 0x00, 0x00, // Size 40 0xe0, 0x01, 0x00, 0x00, // Width 480 0xe0, 0x01, 0x00, 0x00, // Height 480 0x01, 0x00, // Planes 1 0x04, 0x00, // BitCount 4 0x00, 0x00, 0x00, 0x00, // Compression 0x00, 0xc2, 0x01, 0x00, // SizeImage 115200 0xc4, 0x0e, 0x00, 0x00, // XPelsPerMeter 3780 0xc4, 0x0e, 0x00, 0x00, // YPelsPerMeter 3780 0x00, 0x00, 0x00, 0x00, // ClrUsed 0x00, 0x00, 0x00, 0x00, // ClrImportant // カラー テーブル(RGBQUAD) 0x00, 0x00, 0x00, 0x00, // 黒 0x00, 0x00, 0xff, 0x00, // 赤 0x00, 0xff, 0x00, 0x00, // ライム 0xff, 0x00, 0x00, 0x00, // 青 0x00, 0xff, 0xff, 0x00, // 黄 0xff, 0x00, 0xff, 0x00, // 赤紫 0xff, 0xff, 0x00, 0x00, // 水色 0x00, 0x00, 0x80, 0x00, // 栗色 0x00, 0x80, 0x00, 0x00, // 緑 0x80, 0x00, 0x00, 0x00, // ネイビー 0x00, 0x80, 0x80, 0x00, // オリーブ 0x80, 0x00, 0x80, 0x00, // 紫 0x80, 0x80, 0x00, 0x00, // 青緑 0x00, 0x80, 0xff, 0x00, // 橙 0x80, 0x80, 0x80, 0x00, // 灰 0xff, 0xff, 0xff, 0x00, // 白 // BASE64 エンコードするのに都合がよくなるよう,ピクセル データのオフセットが // 3 の倍数になるようにパディングを入れておく. 0x00, 0x00 ]; // BASE64 エンコード キャラクタ b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; NDIV = 500; // 2π の分割数 PI2DIV = Math.PI * 2 / NDIV; header = "data:image/bmp;base64,"; for(i = 0; i < bmp_header.length; i += 3) { b3 = (bmp_header[i] << 16) | (bmp_header[i + 1] << 8) | bmp_header[i + 2]; header += b64.charAt(b3 >> 18); header += b64.charAt((b3 >> 12) & 0x3f); header += b64.charAt((b3 >> 6) & 0x3f); header += b64.charAt(b3 & 0x3f); } header_len = header.length; elem_img = document.getElementById("img"); elem_r1 = document.getElementById("r1"); elem_r2 = document.getElementById("r2"); elem_r3 = document.getElementById("r3"); elem_scale = document.getElementById("scale"); elem_start = document.getElementById("start"); elem_can = document.getElementById("can"); elem_undo = document.getElementById("undo"); elem_clear = document.getElementById("clear"); elem_prog = document.getElementById("prog"); elem_r1.onkeypress = check_int; elem_r2.onkeypress = check_int; elem_r3.onkeypress = check_float; elem_scale.onkeypress = check_float; clear_image(); document.forms[0].reset(); // ページを再ロードしたときのため //--> </SCRIPT> </BODY> </HTML> |