/* 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: '-';
}