Jump to content

Making A Spirograph To My HTML


dinasity

Recommended Posts

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

Just curious, did you write this code? If not, what did you use for inspiration?

Edited by niche
Link to comment
Share on other sites

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

You have the right idea: learn as you do.

 

The non web method is learn then do.

Link to comment
Share on other sites

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.

spirograph.png

 

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

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

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

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

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

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

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

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

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...