/* http://www.gameprogrammer.com/fractal.html */ // Also, as expected, shifting is waaay faster than division, even in JS :) http://jsperf.com/division-vs-shift unfortunately it also truncates to the mantissa of floating points var terrain = null; var $canvas = $('canvas'); var canvas = $canvas[0]; var $doc = $(document); var $body = $('body'); var $main = $('#main'); var main = $main[0]; var ctx = canvas.getContext('2d'); // TODO: abs option, obj args, exception reason var calcTerrain = function(conf) { var height = conf.height, swing = conf.swing, h = conf.decay || conf.smooth || conf.smoothness, i = conf.degree, lb = (height-swing < 0) ? conf.lowerBound : null, ub = (swing>height) ? conf.upperBound : null; function CTE(msg) { this.name="CalcTerrainException"; this.message = msg; this.toString = function() { return this.name+": "+this.message; }; }; if(typeof(i) != "number" || i<1) { throw new CTE("degree must be an integer greater than 1"); } if(typeof(swing) != "number" || swing<1) { throw new CTE("swing must be an integer greater than 1"); } if(typeof(height) != "number" || height<0) { throw new CTE("height must be an integer greater than 0"); } if(typeof(h) != "number" || h<0 || h>1) { throw new CTE("smoothness must be a floating point between 0 and 1 non-inclusive"); } var decay = (Math.pow(2,-h)); function gen(start,mid,end,swing,i) { // displace midpoint zero center swing // 0 -> x : -x/2 -> x/2 mid = mid + Math.random()*swing-(swing/2); mid = (lb && mid < lb) ? lb : mid; mid = (ub && mid > ub) ? ub : mid; if(i==1) { i--; return [mid>>0]; } if(i>1) { var midleft = (mid+start)/2; var midright = (end+mid)/2; swing = swing * decay; i--; /* start startright startleft mid | endleft endright | | | . . . . . | | midleft midright */ return gen(start,midleft,mid,swing,i) .concat([mid>>0]) .concat(gen(mid,midright,end,swing,i)); } } return gen(height,height,height,swing,i); }; var render = function(ctx) { canvas.width=canvas.width; var points = calcTerrain({ height: canvas.height/2, swing: canvas.height/1.2, decay: .78, degree: 6, upperBound: canvas.height-1, lowerBound: 1 }); ctx.save(); ctx.strokeStyle = "lime"; ctx.fillStyle = "lime"; ctx.beginPath(); ctx.moveTo(0,canvas.height/2); var stepSize = Math.floor($canvas.width() / points.length), loc = stepSize; for(var i in points) { //console.log("moving to :"+loc+","+points[i]); ctx.lineTo(loc, points[i]); loc = stepSize+loc; } ctx.stroke(); ctx.lineTo(canvas.width, canvas.height); ctx.lineTo(0,canvas.height); ctx.lineTo(0,canvas.height/2); ctx.fill(); ctx.restore(); }; var resizeCanvas = function() { $canvas.height($main.height()); $canvas.width($main.width()); render(ctx); }; $(window).resize(function(e) { resizeCanvas(); }); $(document.body).on('click', function () { resizeCanvas(); }); $doc.ready(function() { resizeCanvas(); render(ctx); });
<!DOCTYPE html> <html> <head> </head> <body> <div id="main"> <canvas></canvas> </div> <div id="controls"> <div class="control"> recalcOnRender <input type="checkbox"/> </div> <div class="control"> decayRate </div> <div class="control"> degree (2^N-1 midpoints) <br/> [slider] OR auto (based on canvas width) </div> <div class="control"> interpolation <span class="label">truncate</span> <span class="label">average</span> </div> </div> </body> </html>
/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain) */ html, body, head, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } /* -- MY STYLES -- */ /* -- cheat cause I don't want to blit the background with fill() */ canvas { background: black; } #main { height: 300px; width: 100%; position: absolute; overflow: hidden; } #controls { display: none; font-family: monospace; color: lime; position: absolute; top:0; left:0; } #controls input { vertical-align: baseline; } .control:before { content: '-'; }