「CoffeeScript でシダを描画する」をしました。。。これって、半年くらい前にブームだったんですね。
既にブームは去っているようですが、気にせず投稿。
※ブラウザ: Chromium バージョン 39.0.2171.65 Ubuntu 14.04 (64-bit)
JavaScript は CoffeeScript で記述。jQuery を使用。Canvas に描画。
myscript.coffee
$ ->
# 乱数
rand = (max = 0xff, min = 0) -> min + Math.random() * (max - min + 1) | 0
#
# ---- Canvas ---------------------------------------------
#
plotter = (color = (() -> [0, 0xff, 0, 0xff]), canvas = $('canvas')[0]) ->
ctx = canvas.getContext '2d'
img = ctx.createImageData canvas.width, canvas.height
put_pixel = (x, y, rgba) ->
offset = (x * 4) + (y * canvas.width * 4)
rgba.forEach (c, i) -> img.data[offset + i] = c
put: (xy, rgba = color()) ->
x = xy[0] * (+1) * (canvas.width - 10) + (canvas.width / 2) |0
y = xy[1] * (-1) * (canvas.height - 10) + (canvas.height ) |0
put_pixel x, y, rgba
this
plot: (g) ->
g.apply null, [this.put].concat([].slice.call arguments, 1)
this
clear: (rgba = [0,0,0,0]) ->
[0...canvas.width].forEach (x) ->
[0...canvas.height].forEach (y) -> put_pixel x, y, rgba
this
show: () ->
ctx.putImageData img, 0, 0
this
#
# ---- 「シダ」のアルゴリズム ----------------------------
#
fern = (callback = (() ->), k = 20) ->
w1x = (x, y) -> 0.836 * x + 0.044 * y
w1y = (x, y) -> -0.044 * x + 0.836 * y + 0.169
w2x = (x, y) -> -0.141 * x + 0.302 * y
w2y = (x, y) -> 0.302 * x + 0.141 * y + 0.127
w3x = (x, y) -> 0.141 * x - 0.302 * y
w3y = (x, y) -> 0.302 * x + 0.141 * y + 0.169
w4x = (x, y) -> 0.0
w4y = (x, y) -> 0.175337 * y
f = (k, x, y) ->
if 0 < k
f(k - 1, w1x(x, y), w1y(x, y))
f(k - 1, w2x(x, y), w2y(x, y)) if Math.random() < 0.3
f(k - 1, w3x(x, y), w3y(x, y)) if Math.random() < 0.3
f(k - 1, w4x(x, y), w4y(x, y)) if Math.random() < 0.3
else
callback [x, y]
f(k, 0, 0)
#
# ---- 描画の実行 -----------------------------------------
#
console.log '描画開始'
color = () -> [rand()/4, rand(), rand()/2, 0xff - rand()/8]
plotter color # ここを plotter() にすると緑単色(デフォルト)になる
.clear()
.plot fern
.show()
console.log '描画終了'
HTML は Haml で記述。
sample.haml
!!!
%meta(charset="UTF-8")
%title #{@title="CoffeeScript でシダを描画する"}
%h1 #{@title}
%canvas(width="500" height="500" style="background-color: #000000;")
このブラウザは HTML5 Canvas に対応していません。
%script(src="//code.jquery.com/jquery-1.11.1.min.js")
%script(src="myscript.js")
Haml -> HTML、CoffeeScript -> JavaScript への変換。
$ haml -q sample.haml sample.html # 'sample.html' が生成される
$ coffee -c myscript.coffee # 'myscript.js' が生成される
変換後の HTML と JavaScript
sample.html
<!DOCTYPE html>
<meta charset="UTF-8">
<title>CoffeeScript でシダを描画する</title>
<h1>CoffeeScript でシダを描画する</h1>
<canvas height="500" style="background-color: #000000;" width="500">
このブラウザは HTML5 Canvas に対応していません。
</canvas>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="myscript.js"></script>
myscript.js
// Generated by CoffeeScript 1.8.0
$(function() {
var color, fern, plotter, rand;
rand = function(max, min) {
if (max == null) {
max = 0xff;
}
if (min == null) {
min = 0;
}
return min + Math.random() * (max - min + 1) | 0;
};
plotter = function(color, canvas) {
var ctx, img, put_pixel;
if (color == null) {
color = (function() {
return [0, 0xff, 0, 0xff];
});
}
if (canvas == null) {
canvas = $('canvas')[0];
}
ctx = canvas.getContext('2d');
img = ctx.createImageData(canvas.width, canvas.height);
put_pixel = function(x, y, rgba) {
var offset;
offset = (x * 4) + (y * canvas.width * 4);
return rgba.forEach(function(c, i) {
return img.data[offset + i] = c;
});
};
return {
put: function(xy, rgba) {
var x, y;
if (rgba == null) {
rgba = color();
}
x = xy[0] * (+1) * (canvas.width - 10) + (canvas.width / 2) | 0;
y = xy[1] * (-1) * (canvas.height - 10) + canvas.height | 0;
put_pixel(x, y, rgba);
return this;
},
plot: function(g) {
g.apply(null, [this.put].concat([].slice.call(arguments, 1)));
return this;
},
clear: function(rgba) {
var _i, _ref, _results;
if (rgba == null) {
rgba = [0, 0, 0, 0];
}
(function() {
_results = [];
for (var _i = 0, _ref = canvas.width; 0 <= _ref ? _i < _ref : _i > _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }
return _results;
}).apply(this).forEach(function(x) {
var _i, _ref, _results;
return (function() {
_results = [];
for (var _i = 0, _ref = canvas.height; 0 <= _ref ? _i < _ref : _i > _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }
return _results;
}).apply(this).forEach(function(y) {
return put_pixel(x, y, rgba);
});
});
return this;
},
show: function() {
ctx.putImageData(img, 0, 0);
return this;
}
};
};
fern = function(callback, k) {
var f, w1x, w1y, w2x, w2y, w3x, w3y, w4x, w4y;
if (callback == null) {
callback = (function() {});
}
if (k == null) {
k = 20;
}
w1x = function(x, y) {
return 0.836 * x + 0.044 * y;
};
w1y = function(x, y) {
return -0.044 * x + 0.836 * y + 0.169;
};
w2x = function(x, y) {
return -0.141 * x + 0.302 * y;
};
w2y = function(x, y) {
return 0.302 * x + 0.141 * y + 0.127;
};
w3x = function(x, y) {
return 0.141 * x - 0.302 * y;
};
w3y = function(x, y) {
return 0.302 * x + 0.141 * y + 0.169;
};
w4x = function(x, y) {
return 0.0;
};
w4y = function(x, y) {
return 0.175337 * y;
};
f = function(k, x, y) {
if (0 < k) {
f(k - 1, w1x(x, y), w1y(x, y));
if (Math.random() < 0.3) {
f(k - 1, w2x(x, y), w2y(x, y));
}
if (Math.random() < 0.3) {
f(k - 1, w3x(x, y), w3y(x, y));
}
if (Math.random() < 0.3) {
return f(k - 1, w4x(x, y), w4y(x, y));
}
} else {
return callback([x, y]);
}
};
return f(k, 0, 0);
};
console.log('描画開始');
color = function() {
return [rand() / 4, rand(), rand() / 2, 0xff - rand() / 8];
};
plotter(color).clear().plot(fern).show();
return console.log('描画終了');
});
確認したブラウザ
- Chromium バージョン 39.0.2171.65 Ubuntu 14.04 (64-bit) [Ubuntu Linux 14.04]
- Firefox 34.0 Mozilla Firefox for Ubuntu canonical - 1.0 [Ubuntu Linux 14.04]
- Google Chrome バージョン 39.0.2171.95 (64-bit) [Mac OS X 10.10.1 Yosemite]
- Safari バージョン 8.0.2 (10600.2.5) [Mac OS X 10.10.1 Yosemite]
- Safari [iOS 8.1.2]