Forked from http://rectangleworld.com/
Forked from Max Xiong's Pen Generative Fractal Lines.
Forked from Max Xiong's Pen Generative Fractal Lines.
Forked from http://rectangleworld.com/
Forked from Max Xiong's Pen Generative Fractal Lines.
Forked from Max Xiong's Pen Generative Fractal Lines.
| <div id="container"> | |
| <canvas id="displayCanvas" width="1024px" height="576px"> | |
| Your browser does not support HTML5 canvas. | |
| </canvas> | |
| <form> | |
| <p id="caption"> | |
| <input type="button" ,="" id="btnRegenerate" value="regenerate"> | |
| </p> | |
| </form> | |
| </div> |
| window.addEventListener("load", windowLoadHandler, false); | |
| //for debug messages while testing code | |
| var Debugger = function() { }; | |
| Debugger.log = function(message) { | |
| try { | |
| console.log(message); | |
| } | |
| catch (exception) { | |
| return; | |
| } | |
| }; | |
| function windowLoadHandler() { | |
| canvasApp(); | |
| } | |
| function canvasApp() { | |
| var displayCanvas = document.getElementById("displayCanvas"); | |
| displayCanvas.width = window.innerWidth; | |
| displayCanvas.height = Math.min(window.innerHeight, displayCanvas.height); | |
| var context = displayCanvas.getContext("2d"); | |
| var displayWidth = displayCanvas.width; | |
| var displayHeight = displayCanvas.height; | |
| var btnRegenerate = document.getElementById("btnRegenerate"); | |
| btnRegenerate.addEventListener("click", regeneratePressed, false); | |
| var numCircles; | |
| var maxMaxRad; | |
| var minMaxRad; | |
| var minRadFactor; | |
| var circles; | |
| var iterations; | |
| var numPoints; | |
| var timer; | |
| var drawsPerFrame; | |
| var drawCount; | |
| var bgColor,urlColor; | |
| var lineWidth; | |
| var colorParamArray; | |
| var colorArray; | |
| var dataLists; | |
| var minX, maxX, minY, maxY; | |
| var xSpace, ySpace; | |
| var lineNumber; | |
| var twistAmount; | |
| var fullTurn; | |
| var lineAlpha; | |
| var maxColorValue; | |
| var minColorValue; | |
| init(); | |
| function init() { | |
| numCircles = 15; | |
| maxMaxRad = 200; | |
| minMaxRad = 200; | |
| minRadFactor = 0; | |
| iterations = 11; | |
| numPoints = Math.pow(2,iterations)+1; | |
| drawsPerFrame = 4; | |
| fullTurn = Math.PI*2*numPoints/(1+numPoints); | |
| minX = -maxMaxRad; | |
| maxX = displayWidth + maxMaxRad; | |
| minY = displayHeight/2-50; | |
| maxY = displayHeight/2+50; | |
| twistAmount = 0.67*Math.PI*2; | |
| stepsPerSegment = Math.floor(800/numCircles); | |
| maxColorValue = 100; | |
| minColorValue = 20; | |
| lineAlpha = 0.15; | |
| bgColor = "#000000"; | |
| urlColor = "#333333"; | |
| lineWidth = 1.01; | |
| startGenerate(); | |
| } | |
| function startGenerate() { | |
| drawCount = 0; | |
| context.setTransform(1,0,0,1,0,0); | |
| context.clearRect(0,0,displayWidth,displayHeight); | |
| setCircles(); | |
| colorArray = setColorList(iterations); | |
| lineNumber = 0; | |
| if(timer) {clearInterval(timer);} | |
| timer = setInterval(onTimer,1000/60); | |
| } | |
| function setColorList(iter) { | |
| var r0,g0,b0; | |
| var r1,g1,b1; | |
| var r2,g2,b2; | |
| var param; | |
| var colorArray; | |
| var lastColorObject; | |
| var i, len; | |
| var maxComponentDistance = 32; | |
| var maxComponentFactor = 0.5; | |
| r0 = minColorValue + Math.random()*(maxColorValue-minColorValue); | |
| g0 = minColorValue + Math.random()*(maxColorValue-minColorValue); | |
| b0 = minColorValue + Math.random()*(maxColorValue-minColorValue); | |
| r1 = minColorValue + Math.random()*(maxColorValue-minColorValue); | |
| g1 = minColorValue + Math.random()*(maxColorValue-minColorValue); | |
| b1 = minColorValue + Math.random()*(maxColorValue-minColorValue); | |
| /* | |
| //can also set colors explicitly here if you like. | |
| r1 = 90; | |
| g1 = 60; | |
| b1 = 20; | |
| r0 = 30; | |
| g0 = 77; | |
| b0 = 66; | |
| */ | |
| a = lineAlpha; | |
| var colorParamArray = setLinePoints(iter); | |
| colorArray = []; | |
| len = colorParamArray.length; | |
| for (i = 0; i < len; i++) { | |
| param = colorParamArray[i]; | |
| r = Math.floor(r0 + param*(r1 - r0)); | |
| g = Math.floor(g0 + param*(g1 - g0)); | |
| b = Math.floor(b0 + param*(b1 - b0)); | |
| var newColor = "rgba("+r+","+g+","+b+","+a+")"; | |
| colorArray.push(newColor); | |
| } | |
| return colorArray; | |
| } | |
| function setCircles() { | |
| var i; | |
| var r,g,b,a; | |
| var grad; | |
| circles = []; | |
| for (i = 0; i < numCircles; i++) { | |
| maxR = minMaxRad+Math.random()*(maxMaxRad-minMaxRad); | |
| minR = minRadFactor*maxR; | |
| var newCircle = { | |
| centerX: minX + i/(numCircles-1)*(maxX - minX), | |
| centerY: minY + i/(numCircles-1)*(maxY - minY), | |
| //centerY: minY + Math.random()*(maxY - minY), | |
| maxRad : maxR, | |
| minRad : minR, | |
| phase : i/(numCircles-1)*twistAmount, | |
| pointArray : setLinePoints(iterations) | |
| }; | |
| circles.push(newCircle); | |
| } | |
| } | |
| function onTimer() { | |
| var i; | |
| var cosTheta, sinTheta; | |
| var theta; | |
| var numCircles = circles.length; | |
| var linParam; | |
| var cosParam; | |
| var centerX, centerY; | |
| var xSqueeze = 0.75; | |
| var x0,y0; | |
| var rad, rad0, rad1; | |
| var phase, phase0, phase1; | |
| for (var k = 0; k < drawsPerFrame; k++) { | |
| theta = lineNumber/(numPoints-1)*fullTurn; | |
| context.globalCompositeOperation = "lighter"; | |
| context.lineJoin = "miter"; | |
| context.strokeStyle = colorArray[lineNumber]; | |
| context.lineWidth = lineWidth; | |
| context.beginPath(); | |
| //move to first point | |
| centerX = circles[0].centerX; | |
| centerY = circles[0].centerY; | |
| rad = circles[0].minRad + circles[0].pointArray[lineNumber]*(circles[0].maxRad - circles[0].minRad); | |
| phase = circles[0].phase; | |
| x0 = centerX + xSqueeze*rad*Math.cos(theta + phase); | |
| y0 = centerY + rad*Math.sin(theta + phase); | |
| context.moveTo(x0,y0); | |
| for (i=0; i< numCircles-1; i++) { | |
| //draw between i and i+1 circle | |
| rad0 = circles[i].minRad + circles[i].pointArray[lineNumber]*(circles[i].maxRad - circles[i].minRad); | |
| rad1 = circles[i+1].minRad + circles[i+1].pointArray[lineNumber]*(circles[i+1].maxRad - circles[i+1].minRad); | |
| phase0 = circles[i].phase; | |
| phase1 = circles[i+1].phase; | |
| for (j = 0; j < stepsPerSegment; j++) { | |
| linParam = j/(stepsPerSegment-1); | |
| cosParam = 0.5-0.5*Math.cos(linParam*Math.PI); | |
| //interpolate center | |
| centerX = circles[i].centerX + linParam*(circles[i+1].centerX - circles[i].centerX); | |
| centerY = circles[i].centerY + cosParam*(circles[i+1].centerY - circles[i].centerY); | |
| //interpolate radius | |
| rad = rad0 + cosParam*(rad1 - rad0); | |
| //interpolate phase | |
| phase = phase0 + cosParam*(phase1 - phase0); | |
| x0 = centerX + xSqueeze*rad*Math.cos(theta + phase); | |
| y0 = centerY + rad*Math.sin(theta + phase); | |
| context.lineTo(x0,y0); | |
| } | |
| } | |
| context.stroke(); | |
| lineNumber++; | |
| if (lineNumber > numPoints-1) { | |
| clearInterval(timer); | |
| timer = null; | |
| break; | |
| } | |
| } | |
| } | |
| //Here is the function that defines a noisy (but not wildly varying) data set which we will use to draw the curves. | |
| //We first define the points in a linked list, but then store the values in an array. | |
| function setLinePoints(iterations) { | |
| var pointList = {}; | |
| var pointArray = []; | |
| pointList.first = {x:0, y:1}; | |
| var lastPoint = {x:1, y:1}; | |
| var minY = 1; | |
| var maxY = 1; | |
| var point; | |
| var nextPoint; | |
| var dx, newX, newY; | |
| var ratio; | |
| var minRatio = 0.5; | |
| pointList.first.next = lastPoint; | |
| for (var i = 0; i < iterations; i++) { | |
| point = pointList.first; | |
| while (point.next != null) { | |
| nextPoint = point.next; | |
| dx = nextPoint.x - point.x; | |
| newX = 0.5*(point.x + nextPoint.x); | |
| newY = 0.5*(point.y + nextPoint.y); | |
| newY += dx*(Math.random()*2 - 1); | |
| var newPoint = {x:newX, y:newY}; | |
| //min, max | |
| if (newY < minY) { | |
| minY = newY; | |
| } | |
| else if (newY > maxY) { | |
| maxY = newY; | |
| } | |
| //put between points | |
| newPoint.next = nextPoint; | |
| point.next = newPoint; | |
| point = nextPoint; | |
| } | |
| } | |
| //normalize to values between 0 and 1 | |
| //Also store y values in array here. | |
| if (maxY != minY) { | |
| var normalizeRate = 1/(maxY - minY); | |
| point = pointList.first; | |
| while (point != null) { | |
| point.y = normalizeRate*(point.y - minY); | |
| pointArray.push(point.y); | |
| point = point.next; | |
| } | |
| } | |
| //unlikely that max = min, but could happen if using zero iterations. In this case, set all points equal to 1. | |
| else { | |
| point = pointList.first; | |
| while (point != null) { | |
| point.y = 1; | |
| pointArray.push(point.y); | |
| point = point.next; | |
| } | |
| } | |
| return pointArray; | |
| } | |
| function regeneratePressed(evt) { | |
| startGenerate(); | |
| } | |
| } |
| @import "compass/css3"; | |
| body {background-color:#000000; color:#333333;} | |
| h4 {font-family: sans-serif; color:#333333; font-size:16px;} | |
| h3 {font-family: sans-serif; color:#333333;} | |
| p {font-family: sans-serif; color:#333333; font-size:14px;} | |
| #caption {position:absolute; width:1024px; text-align:center; top:520px; z-index:1} | |
| a {font-family: sans-serif; color:#d15423; text-decoration:none;} | |
| #displayCanvas {position:absolute; top:10px; z-index:0;} |