<!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>
|