Reworked Sierpinski Triangle JavaScript

I’m just about done reworking the recursive function to plot the mid points of a triangle and create nested triangles within it. I still have to tweak it a bit because I want the middle triangle to be the color of the canvas. Not entirely sure how to do that yet but I’ll update this post when I figure it out.

Also this was a pretty good read:
http://sixrevisions.com/html/canvas-element/

// Global variables
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var MAX_DEPTH = 3;

window.onload = init();

function init(){
	sierpinski( MAX_DEPTH, {x: 20, y: 20}, {x:20, y:80}, {x:80, y:20}, false, false, false );
}

/* Draws a triangle from three given points */
function draw( pointA, pointB, pointC, fillStyle, strokeStyle, lineWidth ){
	// Setting start point
	context.moveTo( pointA.x, pointA.y );

	// Connecting the points
	context.lineTo( pointB.x, pointB.y );
	context.lineTo( pointC.x, pointC.y );
	context.lineTo( pointA.x, pointA.y );

	// Line style variables may be false
	if( fillStyle != false ){
		context.fillStyle = fillStyle;
		context.fill();
	}

	if( strokeStyle != false )
		context.strokeStyle = strokeStyle;

	if( lineWidth != false )
		context.lineWidth = lineWidth;

	// Draws the line
	context.stroke();
}

function sierpinski( depth, pointA, pointB, pointC ){
	// Non fixed points
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	// Midpoint of A - B; { x: ( ( A.x + B.x ) / 2 ), y: ( ( A.y + B.y ) / 2 ) }
	// Midpoint of B - C; { x: ( ( B.x + C.x ) / 2 ), y: ( ( B.y + C.y ) / 2 ) }
	// Midpoint of C - A; { x: ( ( C.x + A.x ) / 2 ), y: ( ( C.y + A.y ) / 2 ) }
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

	// Nested triangle around point A.
	draw( pointA,
		{ x: ( ( pointA.x + pointB.x ) / 2 ), y: ( ( pointA.y + pointB.y ) / 2 ) },
		{ x: ( ( pointA.x + pointC.x ) / 2 ), y: ( ( pointA.y + pointC.y ) / 2 ) },
		'gold', false, false
	);

	// Nested triangle around point B.
	draw( pointB,
		{ x: ( ( pointB.x + pointA.x ) / 2 ), y: ( ( pointB.y + pointA.y ) / 2 ) },
		{ x: ( ( pointB.x + pointC.x ) / 2 ), y: ( ( pointB.y + pointC.y ) / 2 ) },
		'gold', false, false
	);

	// Nested triangle around point C.
	draw( pointC,
		{ x: ( ( pointC.x + pointA.x ) / 2 ), y: ( ( pointC.y + pointA.y ) / 2 ) },
		{ x: ( ( pointC.x + pointB.x ) / 2 ), y: ( ( pointC.y + pointB.y ) / 2 ) },
		'gold', false, false
	);

	if( depth > 1 ){
		// First pass
		sierpinski(
			(depth - 1 ),
			pointA,
			{ x: ( ( pointA.x + pointB.x ) / 2 ), y: ( ( pointA.y + pointB.y ) / 2 ) },
			{ x: ( ( pointA.x + pointC.x ) / 2 ), y: ( ( pointA.y + pointC.y ) / 2 ) }
		);

		// Second pass
		sierpinski(
			(depth - 1 ),
			pointB,
			{ x: ( ( pointB.x + pointA.x ) / 2 ), y: ( ( pointB.y + pointA.y ) / 2 ) },
			{ x: ( ( pointB.x + pointC.x ) / 2 ), y: ( ( pointB.y + pointC.y ) / 2 ) }
		);

		// Third pass
		sierpinski(
			(depth - 1 ),
			pointC,
			{ x: ( ( pointC.x + pointA.x ) / 2 ), y: ( ( pointC.y + pointA.y ) / 2 ) },
			{ x: ( ( pointC.x + pointB.x ) / 2 ), y: ( ( pointC.y + pointB.y ) / 2 ) }
		);
	}
}

Update: I been tearing up this code and here is what I’ve gotten done so far.
1. Now able to dynamically create an equatorial triangle from the canvas dimensions.
2. Change the draw function so that draws line segments.
3. Change the Sierpinski function to work with the new draw function

This is still a work in progress but I’m not sure when I get back to it. I’m probably going to put the code to draw the initial base triangle back into a draw function that takes in three points and then just make a tenary on liner for the code inside init(). I’ll try at some to explain at least how my code finds the points to make an equatorial triangle that best fits a canvas. There are few other methods this could be rewritten that might be easier to code or understand but this just what I did under an hour so I just went with what I knew what would work.

// Global Variables
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var canvasBuffer = 20; // Hard coded hack. Extra pixel space.

window.onload = init();

function init(){

	if( canvas.width > canvas.height ) {
		// Draws a line segment between A - B
		draw(
			{ x:( canvas.height / 2 ), y:( canvasBuffer ) },
			{ x:( canvas.height - canvasBuffer ), y:( ( ( canvas.height - canvasBuffer ) + ( canvas.height - canvasBuffer ) ) / 2 ) }
		);

		// Draws a line segment between A - C
		draw(
			{ x:( canvas.height / 2 ), y:( canvasBuffer ) },
			{ x:( canvas.height - ( canvas.height - canvasBuffer) ), y:( ( ( canvas.height - canvasBuffer ) + ( canvas.height - canvasBuffer ) ) / 2 ) }
		);

		// Draws a line segment between B - C
		draw(
			{ x:( canvas.height - canvasBuffer ), y:( ( ( canvas.height - canvasBuffer ) + ( canvas.height - canvasBuffer ) ) / 2 ) },
			{ x:( canvas.height - ( canvas.height - canvasBuffer) ), y:( ( ( canvas.height - canvasBuffer ) + ( canvas.height - canvasBuffer ) ) / 2 ) }
		);

		// sierpinski() finds and draws mid-points between the triangle.
		sierpinski(
			1,
			{ x:( canvas.height / 2 ), y:( canvasBuffer ) },
			{ x:( canvas.height - canvasBuffer ), y:( ( ( canvas.height - canvasBuffer ) + ( canvas.height - canvasBuffer ) ) / 2 ) },
			{ x:( canvas.height - ( canvas.height - canvasBuffer) ), y:( ( ( canvas.height - canvasBuffer ) + ( canvas.height - canvasBuffer ) ) / 2 ) }
		);
	}

	else{
		// Draws a line segment between A - B
		draw(
			{ x:( canvas.width / 2 ), y:( canvasBuffer ) },
			{ x:( canvas.width - canvasBuffer ), y:( ( ( canvas.width - canvasBuffer ) + ( canvas.width - canvasBuffer ) ) / 2 ) }
		);

		// Draws a line segment between A - C
		draw(
			{ x:( canvas.width / 2 ), y:( canvasBuffer ) },
			{ x:( canvas.width - ( canvas.width - canvasBuffer) ), y:( ( ( canvas.width - canvasBuffer ) + ( canvas.width - canvasBuffer ) ) / 2 ) }
		);

		// Draws a line segment between B - C
		draw(
			{ x:( canvas.width - canvasBuffer ), y:( ( ( canvas.width - canvasBuffer ) + ( canvas.width - canvasBuffer ) ) / 2 ) },
			{ x:( canvas.width - ( canvas.width - canvasBuffer) ), y:( ( ( canvas.width - canvasBuffer ) + ( canvas.width - canvasBuffer ) ) / 2 ) }
		);

		// sierpinski() finds and draws mid-points between the triangle.
		sierpinski(
			1,
			{ x:( canvas.width / 2 ), y:( canvasBuffer ) },
			{ x:( canvas.width - canvasBuffer ), y:( ( ( canvas.width - canvasBuffer ) + ( canvas.width - canvasBuffer ) ) / 2 ) },
			{ x:( canvas.width - ( canvas.width - canvasBuffer) ), y:( ( ( canvas.width - canvasBuffer ) + ( canvas.width - canvasBuffer ) ) / 2 ) }
		);
	}
}

/* Draws a line segment */
function draw( pointA, pointB ){
	context.moveTo( pointA.x, pointA.y );
	context.lineTo( pointB.x, pointB.y );
	context.stroke();
}

function sierpinski( level, pointA, pointB, pointC ){
	// Non fixed points
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	// Midpoint of A - B; { x: ( ( A.x + B.x ) / 2 ), y: ( ( A.y + B.y ) / 2 ) }
	// Midpoint of B - C; { x: ( ( B.x + C.x ) / 2 ), y: ( ( B.y + C.y ) / 2 ) }
	// Midpoint of C - A; { x: ( ( C.x + A.x ) / 2 ), y: ( ( C.y + A.y ) / 2 ) }
	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

	// Draws line segment between midpoint A - B and midpoint A - C.
	draw(
		{ x: ( ( pointA.x + pointB.x ) / 2 ), y: ( ( pointA.y + pointB.y ) / 2 ) },
		{ x: ( ( pointA.x + pointC.x ) / 2 ), y: ( ( pointA.y + pointC.y ) / 2 ) }
	);

	// Draws line segment between midpoint B - A and midpoint B - C.
	draw(
		{ x: ( ( pointB.x + pointA.x ) / 2 ), y: ( ( pointB.y + pointA.y ) / 2 ) },
		{ x: ( ( pointB.x + pointC.x ) / 2 ), y: ( ( pointB.y + pointC.y ) / 2 ) }
	);

	// Draws line segment between midpoint C - A and midpoint C - B.
	draw(
		{ x: ( ( pointC.x + pointA.x ) / 2 ), y: ( ( pointC.y + pointA.y ) / 2 ) },
		{ x: ( ( pointC.x + pointB.x ) / 2 ), y: ( ( pointC.y + pointB.y ) / 2 ) }
	);

	if( level > 0 ){
		// First pass
		sierpinski(
			(level - 1 ),
			pointA,
			{ x: ( ( pointA.x + pointB.x ) / 2 ), y: ( ( pointA.y + pointB.y ) / 2 ) },
			{ x: ( ( pointA.x + pointC.x ) / 2 ), y: ( ( pointA.y + pointC.y ) / 2 ) }
			);

		// Second pass
		sierpinski(
			(level - 1 ),
			pointB,
			{ x: ( ( pointB.x + pointA.x ) / 2 ), y: ( ( pointB.y + pointA.y ) / 2 ) },
			{ x: ( ( pointB.x + pointC.x ) / 2 ), y: ( ( pointB.y + pointC.y ) / 2 ) }
		);

		// Third pass
		sierpinski(
			(level - 1 ),
			pointC,
			{ x: ( ( pointC.x + pointA.x ) / 2 ), y: ( ( pointC.y + pointA.y ) / 2 ) },
			{ x: ( ( pointC.x + pointB.x ) / 2 ), y: ( ( pointC.y + pointB.y ) / 2 ) }
		);
	}
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s