dinasity Posted October 4, 2014 Share Posted October 4, 2014 I'm trying to make a "Spirograph" for my website, but I'm not sure what I'm doing wrong... I was able to make a circle, but struggling with the "Spirograph"Here is my code... <!doctype html><html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> <title>Document</title> </head> <body> <button onclick="doDrawing();">Start Drawing</button><button onclick="stopDrawing();">Stop Drawing</button><canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;">Your browser does not support the HTML5 canvas tag.</canvas><script> var t = 0;var c = document.getElementById("myCanvas");var R = c.width/2;var ctx = c.getContext("2d");function doDrawing() { t = 0; // Clear the Canvas ctx.clear(); // Create a random color var timesRun = 0; var color = '#'+Math.floor(Math.random()*16777215).toString(16); // Initial x and y var x = R+R*Math.cos(0); var y = R+R*Math.sin(0); // Start the Drawing ctx.beginPath(); ctx.strokeStyle = color; ctx.moveTo(x,y); //Use the timer to create drawing var interval = setInterval(function(){ timesRun += 1; if(timesRun === 65){ clearInterval(interval); } drawCircle();}, 20); }function drawCircle(){ t += 0.1; x=(R+r)*cos(t)-(r+O)*cos(((R+r)/r)*t); y=(R+r)*sin(t)-(r+O)*sin(((R+r)/r)*t); ctx.lineTo(x,y); ctx.stroke();}CanvasRenderingContext2D.prototype.clear = CanvasRenderingContext2D.prototype.clear || function (preserveTransform) { if (preserveTransform) { this.save(); this.setTransform(1, 0, 0, 1, 0, 0); } this.clearRect(0, 0, this.canvas.width, this.canvas.height); if (preserveTransform) { this.restore(); } };</script> </body></html> Link to comment Share on other sites More sharing options...
niche Posted October 4, 2014 Share Posted October 4, 2014 (edited) Just curious, did you write this code? If not, what did you use for inspiration? Edited October 4, 2014 by niche Link to comment Share on other sites More sharing options...
Ingolme Posted October 4, 2014 Share Posted October 4, 2014 I'm not sure if you got your script from somewhere else, but what's important is understanding how it works. In a spirograph There are two radii, one for the main circle and one for the outside circle. Then there is a ratio of angular velocity between each one (for each degree/radian/cycle on the inner radius how many degrees/radians/cycles does the outer radius do?) Then you have to decide the resolution at which you want to draw the circle, how many segments you're dividing the circle into. The more resolution you give it, the less it will look like a bunch of straight lines put together. Attached is a working example. Here's the explanation: Let's create some input variables:innerRadius = 200 (You could have a user input this value) outerRadius = 100 (You could have a user input this value) ratio = 10 (You could have a user input this value) resolution = 10000 (You probably want this to be very high) This is the amount we move around the circle in each loop iteration: minAngle = 2*PI / resolution Now we need a temporary variable for the current angle: On each iteration innerAngle = i * minAngle; The outer angle is determined by the inner angle and the ratio: outerAngle = innerAngle * ratio We know that in a circle, the X position is given by the cosine of the angle and the Y position is given by the sine of the angle. X = cos(angle) * radius Y = sin(angle) * radius Where to draw The answer to where the "pencil" is in each iteration is given by the X and Y of the inner circle, plus the offsets given by the outer circle innerX = cos(innerAngle) * innerRadius innerY = sin(innerAngle) * innerRadius outerX = cos(outerAngle) * outerRadius outerY = sin(outerAngle) * outerRadius globalX = innerX + outerX globalY = innerY + outerY Offsets Now there's one last thing to do: Our circle is centered on the top left corner of the screen. To fix this will add half the canvas width and half the canvas height to the results: realX = globalX + (0.5* canvas.width) realY = globalY + (0.5* canvas.width) Now draw a line to (canvas lineTo() method) realX and to realY Extra detail: If you use lineTo inside the loop without setting the position first you'll start off with a line from the top left corner of the page to the first point in the spirograph. To prevent this, outside the loop calculate the X and Y for the first point in the spirgraph (inner angle 0, outer angle 0) and use moveTo() to start the cursor there. example.html Link to comment Share on other sites More sharing options...
dinasity Posted October 5, 2014 Author Share Posted October 5, 2014 Thank You For The Explanation Ingolme! "Niche" I'm learning by watching YouTube Videos and Forums... Link to comment Share on other sites More sharing options...
niche Posted October 5, 2014 Share Posted October 5, 2014 You have the right idea: learn as you do. The non web method is learn then do. Link to comment Share on other sites More sharing options...
dinasity Posted October 5, 2014 Author Share Posted October 5, 2014 Just to make sure, dont I have to have this equation in the HTML in order to make a Spirograph? x = (R+r)*cos(t) - (r+O)*cos(((R+r)/r)*t) y = (R+r)*sin(t) - (r+O)*sin(((R+r)/r)*t) Link to comment Share on other sites More sharing options...
Ingolme Posted October 5, 2014 Share Posted October 5, 2014 In programming there's always more than one way to do a job. What they made there looks like a slightly different way to make a spirograph. It probably would work if you gave it the right values, but your code (as presented int he first post) is missing variables "r" and "O" which is why it's not working. Wherever you got the equations from, it would be important that they explained the meaning of R, r and O. Also remember that Javascript uses Math.cos() and Math.sin() rather than cos() and sin() My version of a spirograph is based on something simple to understand. I probably should have included a diagram explaining it. Their script has something mine doesn't: It's animated. This can be achieved by substituting the for() loop for a function that is called using setInterval() and stopped with another function that calls clearInterval. Link to comment Share on other sites More sharing options...
dinasity Posted October 5, 2014 Author Share Posted October 5, 2014 Thank You For The Explanation... Link to comment Share on other sites More sharing options...
dinasity Posted October 6, 2014 Author Share Posted October 6, 2014 I made a couple of changes, I'm on the right path, but I'm not getting the Spirograph Effect... Any tips or suggestions would be greatful... <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><HTML> <HEAD> <TITLE> New Document </TITLE> <META NAME="Generator" CONTENT="EditPlus"> <META NAME="Author" CONTENT=""> <META NAME="Keywords" CONTENT=""> <META NAME="Description" CONTENT=""> </HEAD> <BODY> <button onclick="doDrawing();">Start Drawing</button> <button onclick="stopDrawing();">Stop Drawing</button> <canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;"> </canvas> </BODY> <SCRIPT> var t = 0;var c = document.getElementById("myCanvas");var R = c.width/2;var ctx = c.getContext("2d");r= .9;O= .8;function doDrawing() { t = 0; // Clear the Canvas ctx.clear(); // Create a random color var timesRun = 0; var color = '#'+Math.floor(Math.random()*16777215).toString(16); // Initial x and y var x = R+R*Math.cos(0); var y = R+R*Math.sin(0); // Start the Drawing ctx.beginPath(); ctx.strokeStyle = color; ctx.moveTo(x,y); //Use the timer to create drawing var interval = setInterval(function(){ timesRun += 1; if(timesRun === 65){ clearInterval(interval); } drawCircle();}, 20); }function drawCircle(){ t += 0.1; x = Math.floor((R+r)*Math.cos(t) - (r+O)*Math.cos(((R+r)/r)*t)); y = Math.floor((R+r)*Math.sin(t) - (r+O)*Math.sin(((R+r)/r)*t)); ctx.lineTo(x,y); ctx.stroke();}CanvasRenderingContext2D.prototype.clear = CanvasRenderingContext2D.prototype.clear || function (preserveTransform) { if (preserveTransform) { this.save(); this.setTransform(1, 0, 0, 1, 0, 0); } this.clearRect(0, 0, this.canvas.width, this.canvas.height); if (preserveTransform) { this.restore(); } }; </SCRIPT></HTML> Link to comment Share on other sites More sharing options...
Ingolme Posted October 6, 2014 Share Posted October 6, 2014 Giving random values to "r" and "O" probably won't work, they need to be within a range that will have a noticeable effect. It looks like "r" probably would work best with a value between 10 or 50. The units of measurement are pixels, so 0.9 is a value smaller than one pixel. You need to go back to the place where you found this script and find out what the code authors meant to do with those variables. I'm not sure, but I think "O" is meant the center of the inner circle. The variable "t" is increasing a lot in each step, try increasing t by a smaller amount, such as t += 0.01 and you'll begin to see something happen. The spirograph is centered on the top left corner of the canvas. You will have to move the center by adding a horizontal and vertical offset to the final result of the calculations just before passing them to the lineTo() function. Link to comment Share on other sites More sharing options...
dinasity Posted October 7, 2014 Author Share Posted October 7, 2014 Ok I got a decent Spirograph, but I'm having a problem stopping the spirograph. I really appreciate all the help you have given me "Ingolme"... <!doctype html><html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> <title>Spirograph</title> </head> <body> <center><button onclick="doDrawing();">Start The Spiro</button></center> <center><button onclick="stopDrawing();">Stop The Spiro</button></center> <br></br> <center><canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;"></center> <br></br> <p> When You Click On <strong>"Start The Spirograph"</strong> It Will Make A Clover Leave!!! </p> </canvas> </body> <script> var t = 0;var c = document.getElementById("myCanvas");var R = 100;var ctx = c.getContext("2d");var r= 25;var O= 10;function doDrawing() { t = 0; // Clear the Canvas ctx.clear(); // Create a random color var timesRun = 0; var color = '#'+Math.floor(Math.random()*16777215).toString(16); // Initial x and y var x = (c.width/2) + (R+r)*Math.cos(t) - (r+O)*Math.cos(((R+r)/r)*t); var y = (c.width/2) + (R+r)*Math.sin(t) - (r+O)*Math.sin(((R+r)/r)*t); // Start the Drawing ctx.beginPath(); ctx.strokeStyle = color; ctx.moveTo(x,y); //Use the timer to create drawing var interval = setInterval(function(){ timesRun += 1; if(timesRun === 300){ clearInterval(interval); } drawCircle();}, 55); }function drawCircle(){ t += 0.4; x = Math.floor((c.width/2) + ((R+r)*Math.cos(t) - (r+O)*Math.cos(((R+r)/r)*t))); y = Math.floor((c.width/2) + ((R+r)*Math.sin(t) - (r+O)*Math.sin(((R+r)/r)*t))); ctx.lineTo(x,y); ctx.stroke();}CanvasRenderingContext2D.prototype.clear = CanvasRenderingContext2D.prototype.clear || function (preserveTransform) { if (preserveTransform) { this.save(); this.setTransform(1, 0, 0, 1, 0, 0); } this.clearRect(0, 0, this.canvas.width, this.canvas.height); if (preserveTransform) { this.restore(); } }; </script> </html> Link to comment Share on other sites More sharing options...
Ingolme Posted October 7, 2014 Share Posted October 7, 2014 Remove this part of the code: if(timesRun === 300){clearInterval(interval); } You want the spirograph to stop when the button is clicked. The button is calling the stopDrawing() function, which you haven't created yet. Important: Make the variable interval global. Then you can stop the function using clearInterval in the stopDrawing function: function stopDrawing() { clearInterval(interval);} Link to comment Share on other sites More sharing options...
dinasity Posted October 7, 2014 Author Share Posted October 7, 2014 I've done the change not sure is its correct, but it's not stopping. <!doctype html><html lang="en"> <head> <style> body {background-color:lightgrey} h1 {color:blue} h2 {color:blue} </style> <meta name="Description" content=""> <title>Assignment 7</title> </head> <body> <center><button onclick="doDrawing();">Start The Spiro</button></center> <center><button onclick="stopDrawing();">Stop The Spiro</button></center> <br></br> <center><canvas id="myCanvas" width="400" height="400" style="border:1px solid #0000ff;"></center> <br></br> <p> When You Click On <strong>"Start The Spirograph"</strong> It Will Make A Clover Leave!!! </p> </canvas> </body> <script> var t = 0;var c = document.getElementById("myCanvas");var R = 100;var ctx = c.getContext("2d");var r= 25;var O= 10;function doDrawing() { t = 0; // Clear the Canvas ctx.clear(); // Create a random color var timesRun = 0; var color = '#'+Math.floor(Math.random()*16777215).toString(16); // Initial x and y var x = (c.width/2) + (R+r)*Math.cos(t) - (r+O)*Math.cos(((R+r)/r)*t); var y = (c.width/2) + (R+r)*Math.sin(t) - (r+O)*Math.sin(((R+r)/r)*t); // Start the Drawing ctx.beginPath(); ctx.strokeStyle = color; ctx.moveTo(x,y); //Use the timer to create drawing var interval = setInterval(function(){ timesRun += 1;function stopDrawing() { clearInterval(interval);} drawCircle();}, 55); }function drawCircle(){ t += 0.4; x = Math.floor((c.width/2) + ((R+r)*Math.cos(t) - (r+O)*Math.cos(((R+r)/r)*t))); y = Math.floor((c.width/2) + ((R+r)*Math.sin(t) - (r+O)*Math.sin(((R+r)/r)*t))); ctx.lineTo(x,y); ctx.stroke();}CanvasRenderingContext2D.prototype.clear = CanvasRenderingContext2D.prototype.clear || function (preserveTransform) { if (preserveTransform) { this.save(); this.setTransform(1, 0, 0, 1, 0, 0); } this.clearRect(0, 0, this.canvas.width, this.canvas.height); if (preserveTransform) { this.restore(); } }; </script> </html> Link to comment Share on other sites More sharing options...
Ingolme Posted October 7, 2014 Share Posted October 7, 2014 Like I mentioned, it's important that the variable interval is global, meaning that the statement var interval has to be outside of all the functions and the var keyword can't be used for the variable inside the function, making it simply interval = setInterval( without the var next to it. Link to comment Share on other sites More sharing options...
dinasity Posted October 7, 2014 Author Share Posted October 7, 2014 I'm sorry if I'm not understanding... This is what I have... <!doctype html><html lang="en"> <head> <style> body {background-color:lightgrey} h1 {color:blue} h2 {color:blue} </style> <meta name="Description" content=""> <title>Assignment 7</title> </head> <body> <center><button onclick="doDrawing();">Start The Spiro</button></center> <center><button onclick="stopDrawing();">Stop The Spiro</button></center> <br></br> <center><canvas id="myCanvas" width="400" height="400" style="border:1px solid #0000ff;"></center> <br></br> <p> When You Click On <strong>"Start The Spirograph"</strong> It Will Make A Clover Leave!!! </p> </canvas> </body> <script>var t = 0;var c = document.getElementById("myCanvas");var R = 100;var ctx = c.getContext("2d");var r= 25;var O= 10;function doDrawing() { t = 0; // Clear the Canvas ctx.clear(); // Create a random color var timesRun = 0; var color = '#'+Math.floor(Math.random()*16777215).toString(16); // Initial x and y var x = (c.width/2) + (R+r)*Math.cos(t) - (r+O)*Math.cos(((R+r)/r)*t); var y = (c.width/2) + (R+r)*Math.sin(t) - (r+O)*Math.sin(((R+r)/r)*t); // Start the Drawing ctx.beginPath(); ctx.strokeStyle = color; ctx.moveTo(x,y); //Use the timer to create drawing interval = setInterval(function(){ timesRun += 1;function stopDrawing() { clearInterval(interval);} drawCircle();}, 55); }function drawCircle(){ t += 0.4; x = Math.floor((c.width/2) + ((R+r)*Math.cos(t) - (r+O)*Math.cos(((R+r)/r)*t))); y = Math.floor((c.width/2) + ((R+r)*Math.sin(t) - (r+O)*Math.sin(((R+r)/r)*t))); ctx.lineTo(x,y); ctx.stroke();}CanvasRenderingContext2D.prototype.clear = CanvasRenderingContext2D.prototype.clear || function (preserveTransform) { if (preserveTransform) { this.save(); this.setTransform(1, 0, 0, 1, 0, 0); } this.clearRect(0, 0, this.canvas.width, this.canvas.height); if (preserveTransform) { this.restore(); } }; </script> </html> Link to comment Share on other sites More sharing options...
Ingolme Posted October 7, 2014 Share Posted October 7, 2014 It's not working because you haven't defined stopDrawing() in the right place. It's inside an anonymous function, so it's only accessible inside that anonymous function. Declare the stopDrawing() function outside of all the other functions. Make sure it's not between any pair of braces { }. Link to comment Share on other sites More sharing options...
dinasity Posted October 8, 2014 Author Share Posted October 8, 2014 Thanks For The Help!!! I couldn't get it, but at least go the spiro going... Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now