![]() |
<!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>スパイログラフ(Canvas 版)</TITLE> </HEAD> <BODY BGCOLOR="#CCFFFF"> <CENTER> <B>スパイログラフ(Canvas 版)</B> <BR><BR> <FORM> <TABLE><TR> <TD VALIGN=TOP><CANVAS ID="img" WIDTH=480 HEIGHT=480></CANVAS></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; } } quiet = document.getElementById("quiet").checked // 途中経過を表示しない if(!elem_undo.disabled) // 直前に描いた図形あり ctx_comp.drawImage(elem_cur, 0, 0); // 重ね描き cancel = false; elem_start.disabled = true; elem_undo.disabled = true; elem_clear.disabled = true; if(!scale) scale = r1 - r2 + r3; ctx_cur.clearRect(0, 0, 480, 480); ctx_cur.fillStyle = color[document.getElementById("color").selectedIndex]; // 色 if(quiet) { elem_prog.style.visibility = "visible"; } else { ctx_work.drawImage(elem_comp, 0, 0); // 外円 var r1p = r1 * 239.99 / scale; if(r1p > 0.5) { ctx_work.beginPath(); ctx_work.moveTo(240 + r1p - 0.5, 240); // Opera で必要 ctx_work.arc(240, 240, r1p - 0.5, 0, Math.PI * 2, false); ctx_work.stroke(); } r2p = r2 * 239.99 / scale; elem_can.disabled = false; } var rd = r1 - r2; rr = rd / r2; 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; ctx_img.drawImage(elem_comp, 0, 0); } // クリア function clear_image() { elem_undo.disabled = true; ctx_img.fillRect(0, 0, 480, 480); ctx_comp.fillRect(0, 0, 480, 480); } // 描画 function draw(div) { if(cancel) { elem_can.disabled = true; elem_start.disabled = false; elem_clear.disabled = false; ctx_img.drawImage(elem_comp, 0, 0); return; } for(var cnt = 10; ; ) { var x, y; var x1, y1; if(div == div_end) { x = Math.floor(rdp + r3p) + 240; y = 240; } else { var th1 = PI2DIV * div; var th2 = rr * (th1); x = Math.floor((x1 = rdp * Math.cos(th1)) + r3p * Math.cos(th2)) + 240; y = Math.floor((y1 = - 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--) { ctx_cur.fillRect(prev_x, prev_y, 1, 1); if((rem += dy) >= dx) { prev_y += yi; rem -= dx; } prev_x += xi; } } else { for(var d = dy; d; d--) { ctx_cur.fillRect(prev_x, prev_y, 1, 1); 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; ctx_img.drawImage(elem_comp, 0, 0); ctx_img.drawImage(elem_cur, 0, 0); return; } if(!cnt) { ctx_img.drawImage(elem_work, 0, 0); // 内円 if(r2p > 0.5) { ctx_img.beginPath(); ctx_img.moveTo(x1 + 240 + r2p - 0.5, y1 + 240); // Opera で必要 ctx_img.arc(x1 + 240, y1 + 240, r2p - 0.5, 0, Math.PI * 2, false); ctx_img.stroke(); } ctx_img.drawImage(elem_cur, 0, 0); setTimeout(draw, 0, div); return; } } } //---------------------------------------------------------- // 色 color = [ "#000000", // 黒 "#ff0000", // 赤 "#00ff00", // ライム "#0000ff", // 青 "#ffff00", // 黄 "#ff00ff", // 赤紫 "#00ffff", // 水色 "#800000", // 栗色 "#008000", // 緑 "#000080", // ネイビー "#808000", // オリーブ "#800080", // 紫 "#008080", // 青緑 "#ff8000", // 橙 "#808080" // 灰 ]; NDIV = 500; // 2π の分割数 PI2DIV = Math.PI * 2 / NDIV; 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"); ctx_img = elem_img.getContext("2d"); ctx_img.fillStyle = "white"; ctx_img.strokeStyle = "#a0a0a0"; // 作業用 Canvas // 重ね描き用 elem_comp = document.createElement("CANVAS"); elem_comp.width = 480; elem_comp.height = 480; ctx_comp = elem_comp.getContext("2d"); ctx_comp.fillStyle = "white"; // 現在の図形 elem_cur = document.createElement("CANVAS"); elem_cur.width = 480; elem_cur.height = 480; ctx_cur = elem_cur.getContext("2d"); // 経過表示用 elem_work = document.createElement("CANVAS"); elem_work.width = 480; elem_work.height = 480; ctx_work = elem_work.getContext("2d"); ctx_work.strokeStyle = "#a0a0a0"; 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> |