Last active
March 25, 2017 21:12
-
-
Save beemyfriend/c1a649e8c157bb9b5f042cdc797f9330 to your computer and use it in GitHub Desktop.
Fractals With Canvas and D3: Fractal Creater
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <body> | |
| <div style = 'position: absolute; top:0px; left:-500px'><canvas id = 'myCanvas' width = '500' height = '500' ></canvas></div> | |
| <div style = 'position: absolute; top:70px; left:10px'><canvas id = 'otherCanvas' width = '500' height = '500'></canvas></div> | |
| <form name = 'createRule' style = 'position: absolute; top:60px; left:520px'> | |
| <br> | |
| <br> | |
| <h3>Create Fractal Rules</h3> | |
| <label id = 'xslabel'>X-Scale: 0.5</label> | |
| <input id = 'xscale' type = 'range' min = '-1' max = '1' step = '.05' value = '.5' onchange="document.getElementById('xslabel').innerHTML = 'X-Scale: ' + this.value;"/> | |
| <br> | |
| <label id = 'yslabel'>Y-Scale: 0.5</label> | |
| <input id = 'yscale' type = 'range' min = '-1' max = '1' step = '.05' value = '.5' onchange="document.getElementById('yslabel').innerHTML = 'Y-Scale: ' + this.value;"/> | |
| <br> | |
| <label id = 'anglelabel'>Angle: 0 degrees</label> | |
| <input id = 'angle' type = 'range' min = 0 max = '360' step = '5' value = '0' onchange="document.getElementById('anglelabel').innerHTML = 'Angle: ' + this.value + ' degrees';"/> | |
| <br> | |
| <label id = 'xclabel'>X-Coordinate: 0</label> | |
| <input id = 'x' type = 'range' min = '-1' max = '1' step = '.05' value = '0' onchange="document.getElementById('xclabel').innerHTML = 'X-Coordinate: ' + this.value;"/> | |
| <br> | |
| <label id = 'yclabel'>Y-Coordinate: 0</label> | |
| <input id = 'y' type= 'range' min = '-1' max = '1' step = '.05' value = '0' onchange="document.getElementById('yclabel').innerHTML = 'Y-Coordinate: ' + this.value;"/> | |
| <br><br> | |
| <button onclick = 'createNewRule(); update(); return false;'>Add Rule</button> | |
| <br> | |
| <button onclick="draw(myRules, 10); return false;">Build the Fractal!</button> | |
| </form> | |
| <div id = 'showrules' style = 'position:absolute; top: 370; left: 520'></div> | |
| <script src ="https://d3js.org/d3.v4.js"></script> | |
| <script> | |
| var myCanvas = document.getElementById('myCanvas'), | |
| myCtx = myCanvas.getContext('2d'), | |
| otherCtx = document.getElementById('otherCanvas').getContext('2d'), | |
| height = myCanvas.height, | |
| width = myCanvas.width; | |
| //myRules will be populated with rules each time the user pushes the "Add Rule" button | |
| var myRules = []; | |
| var showRules = d3.select('#showrules'); | |
| //Display the rules as the user adds them | |
| //Should be able to delete the rules by pressing a 'delete' button | |
| //Correct rule is deleted, but the <p> object isn't correctly updated | |
| function update(){ | |
| var text = showRules.selectAll('p') | |
| .data(myRules); | |
| text.enter().append('p') | |
| .attr('class', 'enter') | |
| .attr('id', function(d,i){return 'rule'+(i+1);}) | |
| // I think the below .html() cannot be changed without deleting th <p> | |
| .html(function(d, i){return '<b>Fractal Rule #' + (i+1) +'</b><br><b>X-Scale:</b> ' + d[0] + ' <b>Y-Scale:</b> ' + d[1] + ' <b>Angle:</b> ' + d[2] + ' <b>X-Coordinate:</b> ' + d[3] + ' <b>Y-Coordinate:</b> ' + d[4];}); | |
| text.exit().remove(); | |
| var buttons = showRules.selectAll('input') | |
| .data(myRules); | |
| function handleClick(i){ | |
| myRules.splice(i, 1); | |
| update(); | |
| }; | |
| buttons.enter().append('input') | |
| .attr('type', 'button') | |
| .attr('value', function(d, i){return 'delete rule '+ (i+1)}) | |
| .on('click', function(d,i){return handleClick(i)}) | |
| buttons.exit().remove(); | |
| } | |
| //takes user input and pushes the an array of instructions to myRules | |
| function createNewRule(){ | |
| var xscale = document.getElementById('xscale').value; | |
| var yscale = document.getElementById('yscale').value; | |
| var angle = document.getElementById('angle').value; | |
| var x = document.getElementById('x').value; | |
| var y = document.getElementById('y').value; | |
| myRules[myRules.length] = [xscale, yscale, angle, x, y]; | |
| } | |
| //init() creates a rectangle with corners colored different colors | |
| //different colors are meant to act as an aid to identify transformations | |
| function init(){ | |
| console.log('ran init') | |
| myCtx.fillStyle = 'purple'; | |
| myCtx.fillRect(0, 0, width, height); | |
| myCtx.fillStyle = 'yellow'; | |
| myCtx.fillRect(0, 0, width/10 , height/10 ); | |
| myCtx.fillStyle = 'pink'; | |
| myCtx.fillRect(width * 9 / 10, height * 9 / 10, width/10, height/10); | |
| myCtx.fillStyle = 'blue'; | |
| myCtx.fillRect(0, height * 9 /10, width/10, height/10); | |
| myCtx.fillStyle = 'brown'; | |
| myCtx.fillRect(width * 9 / 10, 0, width/10, height/10); | |
| myCtx.strokeStyle = 'red'; | |
| myCtx.rect(0, 0, width, height); | |
| myCtx.stroke(); | |
| } | |
| //Canvas rotations require Radians, not degrees; | |
| function toRads(degree){ | |
| return Math.PI / 180 * degree; | |
| } | |
| //drawFractalRules() draws the rules in an attempt to imitate | |
| //Iterated Fuction Systems (IFS) | |
| //learn more at http://users.math.yale.edu/public_html/People/frame/Fractals/ | |
| function drawFractalRule(scale_x, scale_y, angle, x, y){ | |
| if(scale_x > 0){ | |
| angle = -angle | |
| } | |
| angle = toRads(angle); | |
| var dw = width/scale_x; | |
| var dh = height/scale_y; | |
| var dx = (dw * x) | |
| var dy = dh - (dh * y) - (dh * scale_y); | |
| console.log('dy: ' + dy); | |
| console.log('dh: ' + dh); | |
| otherCtx.save(); | |
| otherCtx.scale(scale_x, scale_y); | |
| otherCtx.translate(0, height) | |
| otherCtx.translate(dx, dy) | |
| otherCtx.rotate(angle); | |
| otherCtx.drawImage(myCanvas, 0, -height); | |
| otherCtx.restore(); | |
| } | |
| function draw(rules, iterations){ | |
| var now = 0; | |
| var animate = setInterval(function(){now < 1 ? start() : update()}, 1000); | |
| function start(){ | |
| console.log('ran start') | |
| init(); | |
| otherCtx.drawImage(myCanvas, 0, 0); | |
| now++ | |
| } | |
| function update(){ | |
| console.log('called update') | |
| if(now >= iterations){ | |
| clearInterval(animate); | |
| } else { | |
| otherCtx.clearRect(0, 0, width, height) | |
| for(var i = 0; i < rules.length; i++){ | |
| drawFractalRules(Number(rules[i][0]), Number(rules[i][1]), Number(rules[i][2]), Number(rules[i][3]), Number(rules[i][4])) | |
| console.log(i + ': ' + rules[i]) | |
| } | |
| myCtx.clearRect(0, 0, width, height); | |
| myCtx.drawImage(otherCanvas, 0, 0); | |
| now++; | |
| } | |
| } | |
| } | |
| </script> | |
| </body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment