$(document).ready(function () { var c = document.getElementById("myCanvas"); var R = 0; var r = 0; var O = 0; var t = 0; var ctx = c.getContext("2d"); $("#spiro").click(function () { var runs = 0; R = Number.parseInt(bigr.value); // I use bigr because Rval would be misinterpreted easily. r = Number.parseInt(rval.value); // Using parseInt ensures the functions read the values as numbers, not strings. O = Number.parseInt(ovalue.value); // Also, it returns NaN for blank and non-numeric responses, aiding validation. if (!Validate(R, "larger circle")) { return; } if (!Validate(r, "smaller circle")) { return; } if (!Validate(O, "pen offset")) { return; } if (!ValidSize(R, r, O)) { return; } ctx.beginPath(); ctx.clear(); ctx.strokeStyle = RandColor(); var interval = setInterval(function(){ runs += 1; if (runs > 350) { clearInterval(interval); } Draw(); }, 20); }) function RandColor() { var hexchars = "0123456789abcdef"; var hex = hexchars.split(""); var hexS = "#"; var rand = Math.floor(Math.random() * 16); for (var i = 0; i < 6; i++) { hexS += hex[rand]; rand = Math.floor(Math.random() * 16); } if (hexS == "#c4ffa7") { //prevents random color from being the background return "#000000"; } else { return hexS; } } function Validate(entry, label) { if (isNaN(entry)) { alert("Please enter the " + label + "'s value and try again."); return false; } else if (entry >= c.width) { alert("The " + label + " is too large! Reduce it and try again."); return false; } else { return true; } } function ValidSize(R, r, O) { // general rules if (R >= c.width/2) { alert("The larger circle doesn't fit on the screen! Make the circle smaller and try again."); return false; } if (r >= R) { alert("The smaller circle is too big! Please reduce the second radius and try again."); return false; } // The pen can go past, but not too far! if (O > (3 * r)) { alert("The pen offset is too far past the smaller circle. Reduce it and try again."); return false; } // As R gets bigger, fewer r values can fit. if (R > 200) { if (r > 50) { alert("The circles are so big that the pen went offscreen!" + " Please reduce the second radius to 50 or less and try again."); return false; } } if (R > 150 && R < 200) { if (r > 100) { alert("The values are so big that the pen went offscreen!" + " Please reduce the second radius to 100 or less and try again."); return false; } } if (r > 100) { if (O > 50) { alert("The values are so big that the pen went offscreen!" + " Please reduce the pen offset to 50 or less and try again."); return false; } } return true; } function Draw() { t += 0.15; var temp = (r + O) * Math.cos(((R + r)/r) * t); var x = ((R + r) * Math.cos(t)) - temp; temp = (r + O) * Math.sin(((R + r)/r) * t); var y = ((R + r) * Math.sin(t)) - temp; // The wiki article on spirographs mathematically describes them centered on the origin, which is // the top left of the canvas. I have to adjust the graph on this line or it stays in the top left corner. ctx.lineTo(x + (c.width/2), y + (c.width/2)); ctx.stroke(); } CanvasRenderingContext2D.prototype.clear = function() { this.clearRect(0, 0, c.width, c.height); return; }})