Archive for the 'JavaScript' category

Coding Math Application Series

Feb 10 2014 Published by under General, JavaScript, Technology

Send to Kindle

Last week I kicked off a new series on the Coding Math Channel. It’s the Application series.

I was thinking that it’s nice to present new concepts in each video, but there is a limited amount that I can do with them. I try to make the main episodes be 10-15 minutes long. I can explain a concept, do a few drawings, show some math, write some code, see it in action, and maybe iterate on that once or twice. And then, that’s it for that topic. Hopefully the brief example was good enough, because I’m moving on to something else now.

So my thought was to start another series where I actually build some simple app or game, or at least the barest outline of such. With some real world applications of the principles that are covered in the other videos. Each video will be in the five minute range, adding just one or two small features to the current app or game. Each feature may make use of one or more of the concepts from the other videos.

The first game is something I call Ballistics. It’s just a simple idea where you aim a gun and it shoots a cannonball that you try to hit a target. Like the old QBasic game, Gorillas.

gorilla2

In the first episode, we use a bit of trigonometry, including arctangent, to aim the gun using the mouse. In this week’s upcoming episode, we’ll actually get a cannonball firing, so that will use the particle class, with velocity and gravity, and lots more real world application of trigonometry. But each one is a bite sized piece of an application. We might hit the same concept over and over in different parts of the same app, or in different apps. But that’s the whole idea, to see many different ways you can use these concepts.

So now, we have the main episode each Monday, a Mini episode – shorter 5-minute simple concept – on Wednesday, and these Application episodes on Friday.

I want to thank all of you who have supported me on Patreon.com. It really makes doing these videos more justifiable in terms of the time I spend on them. And if you are a supporter, know that only the main Monday episodes are Patreon sponsored episodes. The Minis and Applications are on the house.

Send to Kindle

No responses yet

JavaScript Audio Synthesis Part 3: Making Music

Oct 01 2013 Published by under JavaScript

Send to Kindle

First of all, I am not a musician by any stretch of the imagination. But that fact will become obvious all too soon. But if you’re going to make sound with code, you wind up either making sound effects or music. So let’s start with music. My goal here was to create a simple “tracker” application. You program in notes, it plays those notes back in progression to form a song. Of sorts.

I’m going to keep the song very simple. Mary Had a Little Lamb. It’s a song that you can play every note with one beat, so you don’t have to mess around with different length notes. Here’s a simple version of the song transcribed into notes and rests:

g f e f
g g g -
f f f -
g b b -
g f e f
g g g g
f f g f
e – - -

A quick search on the ‘net gives you the frequency values for the notes b, e, f and g, the only ones you’ll need for this song. Code that into an object:

scale = {
	g: 392,
	f: 349.23,
	e: 329.63,
	b: 493.88
}

And then you can just code the song as a string.

song = "gfefgg-fff-gbb-gfefggggffgfe---";

Now you can create an AudioContext and an oscillator and set an interval that runs at a certain speed. In the interval callback, get the next note, find its frequency and set the oscillator’s frequency to that value. Like this:

window.onload = function() {

	var audio = new window.webkitAudioContext(),
		osc = audio.createOscillator(),
		position = 0,
		scale = {
			g: 392,
			f: 349.23,
			e: 329.63,
			b: 493.88
		},
		song = "gfefgg-fff-gbb-gfefggggffgfe---";

		osc.connect(audio.destination);
		osc.start(0);

	setInterval(play, 1000 / 4);

	function play() {
		var note = song.charAt(position),
			freq = scale[note];
		position += 1;
		if(position >= song.length) {
			position = 0;
		}
		if(freq) {
			osc.frequency.value = freq;
		}
	}
};

Now this actually works and you should be able to recognize the melody somewhat. But it leaves a lot to be desired. The biggest thing is that there is no separation between notes. You have a single oscillator running and you’re just changing its frequency. This ends up creating a sort of slide between notes rather than distinct notes. And when there’s a rest, well, there is no rest. It just keeps playing the last note.

There are various ways to try to handle this. One would be to call stop() on the oscillator, then change its frequency, then call start() again. But, when you read the documentation, it turns out that start and stop are one time operations on an oscillator. Once you call stop, it’s done. That particular oscillator cannot be restarted. So what to do?

The suggested answer is actually to create a new oscillator for each note. Initially, this sounds like a horrible idea. Create and destroy a new object for every single note in the song??? Well, it turns out that it’s not so bad. There are some frameworks that create a sort of object pool of notes in the background and reuse them. But the downside to that is that every note you create and start continues playing even if you can’t hear it. It’s your choice, and I suppose you could do all sorts of profiling to see which is more performant. But for Mary Had a Little Lamb, I think you’ll be safe to create a new oscillator each time.

To do this, make a new function called createOscillator. This will create an oscillator, specify its frequency and start it. After a given time, it will stop and disconnect that oscillator. You can then get rid of the main osc variable in the code and call the createOscillator function when you want to play a note.

window.onload = function() {

	var audio = new window.webkitAudioContext(),
		position = 0,
		scale = {
			g: 392,
			f: 349.23,
			e: 329.63,
			b: 493.88
		},
		song = "gfefgg-fff-gbb-gfefggggffgfe---";

	setInterval(play, 1000 / 4);

	function createOscillator(freq) {
		var osc = audio.createOscillator();

		osc.frequency.value = freq;
		osc.type = "square";
		osc.connect(audio.destination);
		osc.start(0);
		
		setTimeout(function() {
			osc.stop(0);
			osc.disconnect(audio.destination);
		}, 1000 / 4)
	}


	function play() {
		var note = song.charAt(position),
			freq = scale[note];
		position += 1;
		if(position >= song.length) {
			position = 0;
		}
		if(freq) {
	 		createOscillator(freq);
		}
	}
};

This sounds better already. Each note is distinct, and when there is a rest, no note plays. But you can do even better.

The notes are just flat tones at this point. You can improve this by giving them a quick and dirty sound envelope. In real life, a sound doesn’t usually just start at full volume and cut out to silence when its time is up. The volume usually ramps up a bit first (the attack) and fades out quickly or slowly (the decay). Actually, sound envelopes can be much more complex than this (http://en.wikipedia.org/wiki/ADSR_envelope#ADSR_envelope) but a simple attack and decay to 0 will do fine for now and give the notes a much better sound.

As a sound envelope controls the volume of a sound, you’ll need to create a gain node. Do this inside the createOscillator function:

	function createOscillator(freq) {
		var attack = 10,
			decay = 250,
			gain = audio.createGain(),
			osc = audio.createOscillator();
...

The attack and decay values there are in milliseconds. This means that the sound will ramp up from 0 to full volume in 0.01 seconds and then back down to 0 in .25 seconds.

Next, the gain node will need to go between the oscillator’s output and the destination in order to control the volume of that oscillator.

		gain.connect(audio.destination);
		gain.gain.setValueAtTime(0, audio.currentTime);
		gain.gain.linearRampToValueAtTime(1, audio.currentTime + attack / 1000);
		gain.gain.linearRampToValueAtTime(0, audio.currentTime + decay / 1000);
...

First you set the gain to 0, which in essence sets the volume to 0. You do this with the setValueAtTime method, passing in the current time from the AudioContext object. In other words, set the volume to 0, NOW.

Then you use linearRampToValueAtTime to set the attack and decay. This says go from whatever value you are currently at and interpolate to this new value so that you arrive there at the specified time. Note that the values you pass in here are in seconds, so you’ll need to divide by 1000 when using millisecond values.

Finally, you connect the oscillator to the gain, set the frequency and start it. And of course, when you clean up, you’ll need to disconnect everything as well.

		osc.frequency.value = freq;
		osc.type = "square";
		osc.connect(gain);
		osc.start(0);
		
		setTimeout(function() {
			osc.stop(0);
			osc.disconnect(gain);
			gain.disconnect(audio.destination);
		}, decay)
}

The final code is below:

window.onload = function() {

	var audio = new window.webkitAudioContext(),
		position = 0,
		scale = {
			g: 392,
			f: 349.23,
			e: 329.63,
			b: 493.88
		},
		song = "gfefgg-fff-gbb-gfefggggffgfe---";

	setInterval(play, 1000 / 4);

	function createOscillator(freq) {
		var attack = 10,
			decay = 250,
			gain = audio.createGain(),
			osc = audio.createOscillator();

		gain.connect(audio.destination);
		gain.gain.setValueAtTime(0, audio.currentTime);
		gain.gain.linearRampToValueAtTime(1, audio.currentTime + attack / 1000);
		gain.gain.linearRampToValueAtTime(0, audio.currentTime + decay / 1000);

		osc.frequency.value = freq;
		osc.type = "square";
		osc.connect(gain);
		osc.start(0);
		
		setTimeout(function() {
			osc.stop(0);
			osc.disconnect(gain);
			gain.disconnect(audio.destination);
		}, decay)
	}

	function play() {
		var note = song.charAt(position),
			freq = scale[note];
		position += 1;
		if(position >= song.length) {
			position = 0;
		}
		if(freq) {
	 		createOscillator(freq);
		}
	}
};

Now the notes have a more bell-like sound. It’s not awesome, but it’s a whole lot better. Mess around with trying to create different envelopes to see how that changes the sound. Code in your own song strings too. Don’t forget to add any additional note frequencies that you might use. You might even want to do something with allowing more than one-beat notes, though that starts to get a bit more complex.

Anyway, this is pretty rough and dirty code. A whole lot that could be improved upon here, but it’s good for demonstration purposes and hopefully gives you a better understanding of the underlying fundamentals than a more complex structure would. Have fun with it.

Send to Kindle

3 responses so far

JavaScript Audio Synthesis Part 2: Interactive Sound

Sep 28 2013 Published by under JavaScript

Send to Kindle

In yesterday’s post I covered the bare bones basics of creating audio with the Web Audio API. In this post, I’ll demonstrate one way to start creating some interactivity.

One of the simplest and most dynamic ways to capture interactivity on a computer is by simply reading the mouse position. The strategy for this next experiment is to use the mouse’s y-position to control the frequency of a single oscillator. The code for this is super simple:

window.onload = function() {

	var context = new window.webkitAudioContext(),
		osc = context.createOscillator(),
		h = window.innerHeight;

	osc.connect(context.destination);
	osc.start(0);

	document.addEventListener("mousemove", function(e) {
		osc.frequency.value = e.clientY / h * 1000 + 300;
	});
};
 

Create an AudioContext and an oscillator, get the window dimensions, connect and start the oscillator and listen for mousemove events.

In the mousemove handler, e.clientY / h will be a number from 0 to 1. Multiply this by 1000 and add 300 and you’ll have a frequency from 300 to 1300. This gets assigned to the oscillator’s frequency value. Move your mouse around the screen and get different pitches. Simple.

Remember, the above has only been tested in the latest version of Chrome at the time of this writing. Other configurations may work; some may require some changes.

Now what about they x-axis? Yesterday you had two oscillators going. Let’s try to hook the mouse’s x-position to that second oscillator.

window.onload = function() {

	var context = new window.webkitAudioContext(),
		osc = context.createOscillator(),
		osc2 = context.createOscillator(),
		gain = context.createGain(),
		w = window.innerWidth,
		h = window.innerHeight;

	osc.frequency = 400;

	osc.connect(context.destination);
	osc.start(0);

	gain.gain.value = 100;
	gain.connect(osc.frequency);

	osc2.frequency.value = 5;
	osc2.connect(gain);
	osc2.start(0);

	document.addEventListener("mousemove", function(e) {
		osc.frequency.value = e.clientY / h * 1000 + 200;
		osc2.frequency.value = e.clientX / w * 30 + 5;
	});
};
 

This is much the same as the final code from yesterday, but now you’re using the mouse x- and y-positions to control the frequencies of both oscillators. Move your mouse all over the screen now and you’ll get all kinds of science-fictiony sounds. I picture a 1950′s flying saucer taking off, or maybe an alien ray gun. Mess with the frequency ranges of both oscillators and try changing the oscillator types for both – mix and match square, sawtooth and triangle waves for all kinds of interesting results.

Send to Kindle

No responses yet

Audio Synthesis in JavaScript

Sep 27 2013 Published by under JavaScript

Send to Kindle

This is something I’ve wanted to play with for a long time. So the other day I buckled down and started searching around.

Yes, you can create sound in JavaScript. In some browsers. Supposedly, it works in Chrome 14, Firefox 23, Opera 15 and Safari 6. Not IE. But, I’ve only tested this in Chrome. So for now, consider this something experimental and fun to lay with, not for your super awesome works-in-every-browser game.

I found several sites that had build up complex libraries based on the Web Audio API. These weren’t the greatest things to learn the basics from, but I eventually was able to pare some of the code down to the bare minimum needed to create some sounds in the browser. There’s also the MDN documentation here: https://developer.mozilla.org/en-US/docs/Web_Audio_API, which is a great reference, but not a step-by-step tutorial for creating sounds. There are a few tutorials linked to from there as well, but none really covered what I was interested in.

So, to get down to it, let’s create some noise.

First you need to create an AudioContext object. This is similar in concept to HTML5′s 2D graphics context for canvas. The context is the overarching object that you’ll use to create all the pieces that will create the sound you’re going to make. For Webkit-based browsers, you get an AudioContext like so:


var context = 
    new window.webkitAudioContext();

The AudioContext has a few properties, the most important one being “destination”. The destination is basically the output of the context, where the sound goes. You can think of it as your speakers.

audiocontext

The next thing you need to know about the Web Audio API is that it is a node based system. You use the AudioContext to create various nodes that are used to create and shape sounds. Nodes have inputs and outputs that you can use to hook various nodes together into different configurations.

The most direct way to create a sound is to create an oscillator node. An oscillator node has zero inputs and one output. You can hook that output to the destination of your context. You’ll also need to specify a frequency for the oscillator. 440 hz will create the musical note, A. Here’s the code:

var context = new window.webkitAudioContext();

var osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);
 

And here’s how this looks from a node view:

oscillator

Yeah, it says “frequency: 500″. My goof. Not changing it. Live with it.

You have an oscillator node with a frequency of 440 connected to the destination of the AudioContext. Call start(0) and you should get an annoying sound coming out of your speaker.

The oscillator node has a couple of other properties. One is “type”. This is the type of wave it uses to generate the sound. It defaults to “sine”. But, you can try “square”, “sawtooth” or “triangle” and see how they sound by doing this:

osc.type = "sawtooth";

There’s also a “custom” type, but that involves creating and setting a custom wave table. If you’re into it, go for it.

Anyway, wasn’t that easy? Let’s expand on it and create another oscillator that messes with the first one.

To do this, you’ll create two new nodes, an oscillator node and a gain node. A gain node is usually used to change the volume of a sound, but you’ll be using it here to alter the frequency of the original oscillator node. You’ll also create another, slower oscillator node. This new oscillator node’s output will be connected to the gain node. A gain node has a single input and a single output. As the new oscillator goes up and down at a frequency of 1 hz (once per second), it will affect the output of the gain node. A gain node also has a value property. If you set that to 100, then the gain node’s output will cycle from +100 to -100 as the new oscillator slowly cycles.

Now you need to hook this +/- 100 gain node output to the original oscillator. But remember that oscillator nodes don’t have any inputs, so you can’t connect it directly to the oscillator node. Instead, you connect it directly to the frequency property of the node. Now that gain output will change the original frequency of 440 hz + or – 100 hz as it cycles. A picture is worth several hundred words.

oscillator2

One oscillator is connected to the gain node, which is directly connected to the other oscillator’s frequency. That oscillator is connected to the destination. Here’s the code:

var context = new window.webkitAudioContext();

var osc = context.createOscillator();
osc.frequency.value = 440;
osc.connect(context.destination);
osc.start(0);

var gain = context.createGain();
gain.gain.value = 100;
gain.connect(osc.frequency);

var osc2 = context.createOscillator();
osc2.frequency.value = 1;
osc2.connect(gain);
osc2.start(0);

Run that and you should hear a siren like sound.

You can also change the type of the second oscillator. Try making that a square wave:

osc2.type = "square";

square

Now, instead of cycling smoothly from +100 to -100, the gain’s output will be exactly +100 for half the cycle than jump to exactly -100 for the second half. The result is more like a siren you’d hear in Europe or the UK. It also drives my dog crazy.

Anyway, that’s the bare minimum. Check out the API at the link mentioned previously. There’s a lot more you can do with it from here.

Send to Kindle

No responses yet

Playing With Chaos is Published!

Sep 20 2013 Published by under JavaScript

Send to Kindle

At long last, the book is available for sale. It took a few days to get through all the copy edits and then a few last minute tweaks, then I hit the big old publish button. A few hours later, it was live … except in the US, Japan, India and Canada. I’m not sure if there is just some lag in the system for certain countries. I contacted support, they said they’d look into it and I never heard back, but the book soon went live on the US and Canadian stores. As of this writing it’s still listed as unavailable for purchase in India and Japan. It may resolve itself, but I’ll keep pushing on it anyway.

As mentioned previously, the whole process was a great experience and feels like a big accomplishment to have pulled it off from inception to being in the store, all under my own steam.

Anyway, go get it if this is the kind of thing you’re interested in. I hope you enjoy it. If so, it would be really nice to start seeing some good reviews stacking up there. :)

Send to Kindle

5 responses so far

Playing with Chaos – July Update

Jul 26 2013 Published by under JavaScript, Technology

Send to Kindle

Since my last post, I’ve been focusing almost all of my free time on writing this book. Mostly because I’m having so much fun writing it. I’ve finished a whopping six chapters since I last posted here. So yeah, it’s going pretty well. Here’s the current table of contents:

Chapter 1: Introduction
Chapter 2: What is a Fractal
Chapter 3: Symmetry and Regularity
Chapter 4: Fractal Dimensions
Chapter 5: Order from Chaos
Chapter 6: Diffusion-Limited Aggregation
Chapter 7: The Mandelbrot Set
Chapter 8: The Julia Set and Fatou Dust
Chapter 9: Strange Attractors
Chapter 10: L-Systems
Chapter 11: Cellular Automata
Chapter 12: Fractals in the Real World

I’m through Chapter 8 and heading into Chapter 9 now. Chapters 4 – 8 are first drafts, while 1 – 4 have been worked over a bit and are pretty close to final. I’d like to think I could be done with the writing by the end of August. Then another week or two for personal review and editing. After that I’ll need to have some other people review it and I’m considering how to handle copy editing – whether to hire someone or consider other alternatives.

One stroke of personal brilliance was that the utility library that is used in each example contains a method to pop out a bitmap image of the canvas that can be saved to disk. Built-in screenshots! So all the images for the book are easily created while I’m writing the text and code. Sometimes some cropping is needed, but I’ve got a good flow going for that as well. At this point, I’m up to 155 images. It’s a pretty graphics-heavy for a Kindle book, but I’ve been checking every image on a real Kindle and they all look decent.

If you want to get a feel for what’s coming, I’ve set up a site for the book at http://playingwithchaos.net. It’s got every image in the book, plus a video of the presentation I did at Beyond Tellerand/Play! that sparked my thoughts about writing this book.

Send to Kindle

2 responses so far

Winding Rules in HTML’s Canvas

Feb 01 2013 Published by under JavaScript

Send to Kindle

This is another one that a lot of people should already know, but I’m still betting that a few will find useful. Winding refers to the direction a path is drawn in – clockwise or counterclockwise. In many cases, this makes no difference at all, but there are cases where this is very important and can become a very useful tool.

Just realized that most of the examples I’m showing here could have been done just using a fat stroke instead of fills. My fault for poor examples. I was just trying to show simple shapes. This is still a very valid technique and useful for more complex shapes, such as the last example.

The most common use for this is drawing a shape with a hole in it. Let’s say we wanted to draw a black triangle with an empty hole in the center. We can simply draw a black triangle with a smaller white triangle on top of it.

  context.beginPath();
  context.moveTo(300, 100);
  context.lineTo(500, 400);
  context.lineTo(100, 400);
  context.lineTo(300, 100);
  context.fill();
  
  context.fillStyle = "white";
  context.beginPath();
  context.moveTo(300, 150);
  context.lineTo(450, 370);
  context.lineTo(150, 370);
  context.lineTo(300, 150);
  context.fill();

If the background is also white, this looks just fine.

wind_01

But what if we first draw something in the background, like this red bar?

  context.fillStyle = "red";
  context.fillRect(10, 200, 580, 100);
  context.fillStyle = "black";
  
  context.beginPath();
  context.moveTo(300, 100);
  context.lineTo(500, 400);
  context.lineTo(100, 400);
  context.lineTo(300, 100);
  context.fill();
  
  context.fillStyle = "white";
  context.beginPath();
  context.moveTo(300, 150);
  context.lineTo(450, 370);
  context.lineTo(150, 370);
  context.lineTo(300, 150);
  context.fill();

wind_02

The illusion is shattered. I once tried to change the second fill style from “white” to fully transparent with “rgba(255, 255, 255, 0)” thinking that it would overlay the black with transparency, but no, that does not work. Even if it did, it would also wipe out the red underneath it, so forget that.

The trick is to draw the second triangle within the same beginPath() / fill() section, and draw it in the opposite winding direction. Like so:

  context.fillStyle = "red";
  context.fillRect(10, 200, 580, 100);
  context.fillStyle = "black";
  
  context.beginPath();
  
  // first triangle (clockwise)
  context.moveTo(300, 100);
  context.lineTo(500, 400);
  context.lineTo(100, 400);
  context.lineTo(300, 100);

  // second, smaller triangle (counterclockwise)
  context.moveTo(300, 150);
  context.lineTo(150, 370);
  context.lineTo(450, 370);
  context.lineTo(300, 150);

  context.fill();

Notice that in the second triangle I swapped the first two lineTo statements, so it draws the triangle from the top, to bottom left, bottom right, back to top. This is counterclockwise, while the first triangle is drawn in the opposite direction. Because of this, the second triangle cuts out or subtracts from the first. This gives you the following:

wind_03

This works well for drawing lines with shapes. What about rectangles? Well, it won’t work with fillRect, as fillRect does it’s own internal beginPath() and fill() as part of its operations, so each call to it will draw completely separately, as in the first example. So you have to use the rect method. By default, all rects are drawn with the same winding, but there is a way to reverse the winding – just reverse either the width or height. An example will help:

  context.fillStyle = "red";
  context.fillRect(10, 100, 580, 100);
  context.fillStyle = "black";

  context.beginPath();
  context.rect(50, 50, 200, 200);
  context.rect(75, 225, 150, -150);
  context.fill();

Normally, you’d draw the second rect at an x, y of 75, 75, with a width and height of 150. But this would have the same winding as the first. Reversing either the width or height to become a negative value reverses the winding. Reversing both will send it back to the original. Note that you have to change the position on the axis you reversed the size on. So a position of 75, 75 becomes 75, 225, with a size of 150, -150. This gives you the following:

wind_04

Of course, you might be able to use clearRect, but that would wipe out any background as well.

How about arcs? If you’ve used these, you’ve seen that last boolean parameter and probably just ignore it or use whatever value you’ve gotten used to. I always use false. But if you want to punch a circle from another circle, to make a ring, for example, just draw them with opposite values for that last param:

  context.fillStyle = "red";
  context.fillRect(10, 100, 580, 100);
  context.fillStyle = "black";

  context.beginPath();
  context.arc(150, 150, 100, 0, Math.PI * 2, true);
  context.arc(150, 150, 70, 0, Math.PI * 2, false);
  context.fill();

wind_05

And of course you can mix and match these different shapes, though it might take some trial and error to get the different windings going in the right directions. Here’s a triangle with a punched out circle:

  context.fillStyle = "red";
  context.fillRect(10, 200, 580, 100);
  context.fillStyle = "black";
  
  context.beginPath();
  
  context.moveTo(300, 100);
  context.lineTo(500, 400);
  context.lineTo(100, 400);
  context.lineTo(300, 100);

  context.arc(300, 300, 70, 0, Math.PI * 2, true);

  context.fill(); 

wind_06

Well, that’s the basics on winding. Once you get it down, it can be a pretty powerful way of composing complex shapes.

Send to Kindle

One response so far

Scaling in HTML’s Canvas

Jan 31 2013 Published by under JavaScript

Send to Kindle

I’m probably not dropping any huge knowledge bombs here on many of you, but there are a few neat things about scaling when drawing to an HTML5 Canvas that I didn’t realize until a few months ago. So there are probably one or two of you who might find the info handy too.

Let’s say we’re drawing a circle in a canvas. We do this:

  context.beginPath();
  context.arc(100, 100, 50, 0, Math.PI * 2, false);
  context.stroke();

And we get this:

scale_01

(I’m assuming in all of these examples that you have an HTML document with a canvas element, and you’ve grabbed a reference to its 2d context, stored in a variable named “context”. You laugh, but someone’s bound to paste the above code into a text editor somewhere and complain to me that it doesn’t work.)

You probably also know that you can scale the circle like so:

  context.save();
  context.scale(2, 2);
  context.beginPath();
  context.arc(100, 100, 50, 0, Math.PI * 2, false);
  context.stroke();
  context.restore();

This scales everything by a factor of 2, so we get a circle that’s twice as large:

scale_02

But what might not be immediately obvious is the fact that the size of the shape, and the size of the stroke can be scaled separately. In this case because we set the scale before doing anything and restored the transformation matrix after all was done, everything was doubled, the size, the position, the stroke’s width.

But let’s try moving the restore line up before the stroke:

  context.save();
  context.scale(2, 2);
  context.beginPath();
  context.arc(100, 100, 50, 0, Math.PI * 2, false);
  context.restore();
  context.stroke();

This set up gives us a double sized circle, but because we cancelled the transform before applying the stroke, it stays one pixel thick, the default:

scale_03

We can even do the opposite and draw the circle the normal size, then scale up, stroke it, and restore:

  context.beginPath();
  context.arc(100, 100, 50, 0, Math.PI * 2, false);
  context.save();
  context.scale(4, 4);
  context.stroke();
  context.restore();

scale_04

So how is this useful? At least one great way: drawing ellipses. There is no native way to draw an ellipse in canvas. You can of course use some trig and draw a bunch of line segments, but that can be problematic. How many segments to draw? Too few for a large ellipse and it looks choppy. As the size goes down, you need less segments, and drawing too many is a waste of resources. Another complex and inexact solution involves using bezier curves. The easiest way is to just draw a circle scaled differently on one axis than the other. Of course, if you’re using a stroke on the arc, you can wind up with something weird like this:

  context.save();
  context.scale(10, 2);
  context.beginPath();
  context.arc(20, 20, 10, 0, Math.PI * 2, false);
  context.stroke();
  context.restore();

scale_05

See how the stroke was also scaled more on the x axis than on the y, making it look more like an Oakley logo than anything else. To fix it, just do what we did in the second example, moving the restore to before the stroke:

  context.save();
  context.scale(10, 2);
  context.beginPath();
  context.arc(20, 20, 10, 0, Math.PI * 2, false);
  context.restore();
  context.stroke();

scale_06

With this, we can even make a neat little ellipse function like so:

  function ellipse(x, y, w, h) {
    context.save();
    context.translate(x + w / 2, y + h / 2);
    context.scale(w / 2, h / 2);
    context.beginPath();
    context.arc(0, 0, 1, 0, Math.PI * 2, false);
    context.restore();
    context.stroke();
  }
  
  ellipse(100, 100, 200, 80);

I’ll leave you to work through that on your own. Here’s what calling it gives you:

scale_07

Finally, you can go really funky on it, scaling the shape one way and the stroke the other way, like so:

  context.save();
  context.scale(1, 2);
  context.beginPath();
  context.arc(100, 100, 60, 0, Math.PI * 2, false);
  context.restore();
  
  context.save();
  context.scale(20, 1);
  context.stroke();
  context.restore();

With a bit of experimentation, you can wind up with something that’s a half decent fake perspective:

scale_08

Anyway, old news to some of you, new news to others (I hope). More stuff to play with.

Send to Kindle

No responses yet

Circle Layering

Jan 28 2013 Published by under General, JavaScript

Send to Kindle

If you were wondering where my last post was heading…

growth

growth2

growth3

growth4

Oops, gotta turn off the “capture cursor” on that screenshot program. :)

Anyway, this was an idea I first explored several years ago on my art from code site, but has been in the back of my mind as something I wanted to play with more. (see: http://www.artfromcode.com/?s=cells) In the end I ditched the whole idea of perfection I was going for in the last post, as the fact of the outer circles having some space at the end gives it a more organic feel. In fact, you can see that I even exaggerated the space in some of the examples. Well, just a quick follow up. Carry on.

Send to Kindle

4 responses so far

Working out a Math Problem

Jan 25 2013 Published by under JavaScript

Send to Kindle

So I had this idea the other day for a graphic effect. I thought it might be interesting to walk through how it went from concept to functional code. So here it is. The effect involved placing smaller circles around a larger circle. Here’s about what I was looking to do:

circle

Note that all the outer circles exactly touch the inner circle and all the outer circles exactly touch each other. There are no spaces and no overlapping. When I went about coding it and found there were a few different ways to do such a thing and it wasn’t as straightforward as I thought it’d be.

I first tried specifying the size of the inner circle and the size of the outer circles. You can then go around the perimeter of the inner circle placing as many outer circles as will fit. Rarely will you get an exact fit this way, which means that if you don’t overlap, you’ll have some space. You can either have one big space at the end, or try to precalculate how many circles will fit and space them out evenly. Not what I wanted.

Another option is to specify the size and number of the outer circles. You can then arrange them so they just touch each other, figure out how far from the center they are, which then lets you calculate the size of the inner circle. This was fairly easy, but not my use case. I wanted to draw circles around an existing circle of known size.

The final option was to specify the size of the inner circle and how many outer circles you want. You then just have to figure out how big to make those outer circles so they sit on the edge of the inner circle and just touch each other. This would work, but I didn’t know how to figure out how big to make the outer circles. Time for some math! And some sketchy sketches.

math01

 

I made the above sketches to get a clear idea of what I wanted to do. On the bottom left is the inner circle with a couple of the outer circles shown. I know the angle between them, as it’s just 2 * PI / number of circles. And I know the radius of the inner circle. All I need is the radius of the outer circles.

The drawing on the top right is a close up of the top triangle in the first one. Angle A is one half of the angle between each circle, or PI / number of circles. R is the radius of the inner circle and N is the radius of the outer circle. From this, I could come up with the equation shown:

sin A * (R + N) = N

In other words, the sine of angle, times the radius (R + N) equals the opposite side (N). Basic trig.

Now I just needed to solve for N. My algebra was a bit rusty, but after a few false starts I got it down:

math02

 

Bottom line: N = (sin A * R) / (1 – sin A)

So I put it down in code and amazingly, it worked. Here’s what I came up with. Be it known that this code has been worked over quite a bit. It was originally just the onload function with one long linear mess of statements and vars. Once I saw that it worked, I refactored it into some halfway decent functions and cleaned it up a bit. It could still use work to make it more reusable, but at least it’s readable enough to post now:

window.onload = function() {
  var canvas = document.getElementById("canvas"),
      context = canvas.getContext("2d"),
      width = canvas.width,
      height = canvas.height,
      circles,
      inner,
      count = 20;
  
  // create inner circle and draw it:
  inner = {
    x: width / 2,
    y: height / 2,
    radius: 100
  };
  drawCircle(inner);
  
  // get outer circles and draw them:
  circles = getOuterCircles(inner, count);
  for(var i = 0; i < circles.length; i += 1) {
    drawCircle(circles[i]);
  }
    
  
  
  function getOuterCircles(inner, count) {
    var circles = [],
        angle = Math.PI * 2 / count, // angle between circles
        outerRadius = getOuterRadius(count, inner.radius),
        r = inner.radius + outerRadius,
        currentAngle;
  
    for(var i = 0; i < count; i += 1) {
      currentAngle = i * angle;
      circles.push({
        x: inner.x + Math.cos(currentAngle) * r,
        y: inner.y + Math.sin(currentAngle) * r,
        radius: outerRadius
      });
    }
    return circles;
  }
  
  function getOuterRadius(count, innerRadius) {
    var s = Math.sin(Math.PI / count);
    return (s * innerRadius) / (1 - s);
  }
  
  function drawCircle(c) {
    context.beginPath();
    context.arc(c.x, c.y, c.radius, 0, Math.PI * 2, false);
    context.stroke();
  }
};

As you can see, a circle is just an object with x, y, and radius properties. Create the inner circle and draw it.

The getOuterCircles function creates an array of circle objects that are placed around the inner one. It needs the inner circle and the count of outer circles to create. This function uses the getOuterRadius function to get the size of the smaller circles. The var s represents sin A in the original equation. And (s * innerRadius) / (1 – s) is basically the (sin A * R) / (1 – sin A) that I originally came up with.

The rest should hopefully be pretty obvious.

To see it in action, check it out here: http://jsbin.com/icahul/1/edit

Send to Kindle

12 responses so far

Older posts »