Make Magic object, and /magic page
This commit is contained in:
parent
3c16648f09
commit
5dff1b2fd7
9
_data/magic.yml
Normal file
9
_data/magic.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
counting: false
|
||||||
|
waitTime: 20
|
||||||
|
step: 0.4
|
||||||
|
prune_to: 15
|
||||||
|
maxDuration: 600
|
||||||
|
minDuration: 50
|
||||||
|
splineLength: 15
|
||||||
|
maxAngleChange: 180
|
||||||
|
minAngleChange: 90
|
@ -30,8 +30,8 @@
|
|||||||
<link rel="shortcut icon" href="/favicon.png" />
|
<link rel="shortcut icon" href="/favicon.png" />
|
||||||
|
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script src="js/AnimationFrame.min.js"></script>
|
<script src="/js/AnimationFrame.min.js"></script>
|
||||||
<script async src="js/magic.js"></script>
|
<script async src="/js/magic.js"></script>
|
||||||
|
|
||||||
<!-- Google Analytics -->
|
<!-- Google Analytics -->
|
||||||
<script>
|
<script>
|
||||||
|
@ -3,6 +3,11 @@ layout: home
|
|||||||
title: Tyler Hallada
|
title: Tyler Hallada
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
new Magic().draw();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<div id="home">
|
<div id="home">
|
||||||
<div class="card profile-card">
|
<div class="card profile-card">
|
||||||
<div class="row clearfix">
|
<div class="row clearfix">
|
||||||
|
178
js/magic.js
178
js/magic.js
@ -1,29 +1,46 @@
|
|||||||
window.onload = function () {
|
var Magic = function (options) {
|
||||||
|
options = options || {}
|
||||||
// Array to hold all active spells being drawn
|
// Array to hold all active spells being drawn
|
||||||
var spells = [];
|
this.spells = [];
|
||||||
|
|
||||||
// When on, wait a certain amount of time before casting (for initial
|
// When on, wait a certain amount of time before casting (for initial
|
||||||
// load-up)
|
// load-up)
|
||||||
var counting = true;
|
this.counting = options.counting || true;
|
||||||
|
|
||||||
// The amount of time to wait (in number of animate() calls)
|
// The amount of time to wait (in number of animate() calls)
|
||||||
var waitTime = 20;
|
this.waitTime = options.waitTime || 20;
|
||||||
|
|
||||||
// How fast to draw the spells
|
// How fast to draw the spells
|
||||||
var step = 0.2;
|
this.step = options.step || 0.2;
|
||||||
|
|
||||||
// Limit of branches per spell at any time
|
// Limit of branches per spell at any time
|
||||||
var prune_to = 20;
|
this.prune_to = options.prune_to || 20;
|
||||||
|
|
||||||
|
// Max duration possible (in steps) of a spell
|
||||||
|
this.maxDuration = options.maxDuration || 600;
|
||||||
|
|
||||||
|
// Min duration possible (in steps) of a spell
|
||||||
|
this.minDuration = options.minDuration || 50;
|
||||||
|
|
||||||
|
// Max angle deviation during branch split
|
||||||
|
this.maxAngleChange = options.maxAngleChange || 180;
|
||||||
|
|
||||||
|
// Min angle deviation during branch split
|
||||||
|
this.minAngleChange = options.minAngleChange || 90;
|
||||||
|
|
||||||
|
// Average length of new spline (branch)
|
||||||
|
this.splineLength = options.splineLength || 15;
|
||||||
|
|
||||||
// Save this query here now that the page is loaded
|
// Save this query here now that the page is loaded
|
||||||
var canvas = document.getElementById("magic");
|
this.canvas = document.getElementById("magic");
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the height and width of full document. To avoid browser
|
|
||||||
|
/* Get the height and width of full document. To avoid browser
|
||||||
* incompatibility issues, choose the maximum of all height/width values.
|
* incompatibility issues, choose the maximum of all height/width values.
|
||||||
*
|
*
|
||||||
* Method from http://stackoverflow.com/a/1147768 */
|
* Method from http://stackoverflow.com/a/1147768 */
|
||||||
function getDocumentDimensions() {
|
Magic.prototype.getDocumentDimensions = function () {
|
||||||
var body = document.body,
|
var body = document.body,
|
||||||
html = document.documentElement;
|
html = document.documentElement;
|
||||||
|
|
||||||
@ -36,11 +53,11 @@ window.onload = function () {
|
|||||||
html.offsetWidth);
|
html.offsetWidth);
|
||||||
|
|
||||||
return {"height": height, "width": width};
|
return {"height": height, "width": width};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Specifies what will be added to the red, green, and blue values of the
|
/* Specifies what will be added to the red, green, and blue values of the
|
||||||
* color at each interval. */
|
* color at each interval. */
|
||||||
function pickGradient() {
|
Magic.prototype.pickGradient = function () {
|
||||||
var directions = [-1, 0, 1];
|
var directions = [-1, 0, 1];
|
||||||
var magnitudes = [1, 2, 3];
|
var magnitudes = [1, 2, 3];
|
||||||
|
|
||||||
@ -50,9 +67,9 @@ window.onload = function () {
|
|||||||
magnitudes[Math.floor(Math.random() * 3)],
|
magnitudes[Math.floor(Math.random() * 3)],
|
||||||
"b": directions[Math.floor(Math.random() * 3)] *
|
"b": directions[Math.floor(Math.random() * 3)] *
|
||||||
magnitudes[Math.floor(Math.random() * 3)]};
|
magnitudes[Math.floor(Math.random() * 3)]};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Alters the given color by the given gradient and returns both.
|
/* Alters the given color by the given gradient and returns both.
|
||||||
|
|
||||||
If the red, green, or blue value of the color is at 0 or 255 and the
|
If the red, green, or blue value of the color is at 0 or 255 and the
|
||||||
gradient for that value is not zero, then the gradient for that value
|
gradient for that value is not zero, then the gradient for that value
|
||||||
@ -60,7 +77,7 @@ window.onload = function () {
|
|||||||
|
|
||||||
Unused for now. It turns out that changing the canvas stroke color is a
|
Unused for now. It turns out that changing the canvas stroke color is a
|
||||||
costly operation and slows things down a lot. */
|
costly operation and slows things down a lot. */
|
||||||
function nextColor(color, gradient) {
|
Magic.prototype.nextColor = function(color, gradient) {
|
||||||
var values = ["r", "g", "b"];
|
var values = ["r", "g", "b"];
|
||||||
|
|
||||||
// Check if color at end of range and reverse gradient direction if so
|
// Check if color at end of range and reverse gradient direction if so
|
||||||
@ -79,16 +96,16 @@ window.onload = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {"color": color, "gradient": gradient};
|
return {"color": color, "gradient": gradient};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Choose a random RGB color to begin the color gradient with */
|
/* Choose a random RGB color to begin the color gradient with */
|
||||||
function pickRandomColor() {
|
Magic.prototype.pickRandomColor = function() {
|
||||||
return {"r": Math.floor(Math.random() * (255 + 1)),
|
return {"r": Math.floor(Math.random() * (255 + 1)),
|
||||||
"g": Math.floor(Math.random() * (255 + 1)),
|
"g": Math.floor(Math.random() * (255 + 1)),
|
||||||
"b": Math.floor(Math.random() * (255 + 1))};
|
"b": Math.floor(Math.random() * (255 + 1))};
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawSplineSegment(branch, context) {
|
Magic.prototype.drawSplineSegment = function(branch, context) {
|
||||||
var ax = (-branch.points[0].x + 3*branch.points[1].x - 3*branch.points[2].x + branch.points[3].x) / 6;
|
var ax = (-branch.points[0].x + 3*branch.points[1].x - 3*branch.points[2].x + branch.points[3].x) / 6;
|
||||||
var ay = (-branch.points[0].y + 3*branch.points[1].y - 3*branch.points[2].y + branch.points[3].y) / 6;
|
var ay = (-branch.points[0].y + 3*branch.points[1].y - 3*branch.points[2].y + branch.points[3].y) / 6;
|
||||||
var bx = (branch.points[0].x - 2*branch.points[1].x + branch.points[2].x) / 2;
|
var bx = (branch.points[0].x - 2*branch.points[1].x + branch.points[2].x) / 2;
|
||||||
@ -102,22 +119,22 @@ window.onload = function () {
|
|||||||
ay*Math.pow(branch.t, 3) + by*Math.pow(branch.t, 2) + cy*branch.t + dy
|
ay*Math.pow(branch.t, 3) + by*Math.pow(branch.t, 2) + cy*branch.t + dy
|
||||||
);
|
);
|
||||||
context.lineTo(
|
context.lineTo(
|
||||||
ax*Math.pow(branch.t+step, 3) + bx*Math.pow(branch.t+step, 2) + cx*(branch.t+step) + dx,
|
ax*Math.pow(branch.t+this.step, 3) + bx*Math.pow(branch.t+this.step, 2) + cx*(branch.t+this.step) + dx,
|
||||||
ay*Math.pow(branch.t+step, 3) + by*Math.pow(branch.t+step, 2) + cy*(branch.t+step) + dy
|
ay*Math.pow(branch.t+this.step, 3) + by*Math.pow(branch.t+this.step, 2) + cy*(branch.t+this.step) + dy
|
||||||
);
|
);
|
||||||
branch.t += step;
|
branch.t += this.step;
|
||||||
}
|
}
|
||||||
|
|
||||||
function splitBranch(branch) {
|
Magic.prototype.splitBranch = function(branch) {
|
||||||
var newBranches = [];
|
var newBranches = [];
|
||||||
// Replace with 2 new branches
|
// Replace with 2 new branches
|
||||||
for (var k = 0; k < 2; k++) {
|
for (var k = 0; k < 2; k++) {
|
||||||
|
|
||||||
// Generate random deviation from previous angle
|
// Generate random deviation from previous angle
|
||||||
var angle = branch.angle - (Math.random() * 180 - 90);
|
var angle = branch.angle - (Math.random() * this.maxAngleChange - this.minAngleChange);
|
||||||
|
|
||||||
// Generate random length
|
// Generate random length
|
||||||
var length = Math.random() * 15 + 4;
|
var length = Math.random() * this.splineLength + 4;
|
||||||
|
|
||||||
// Calculate new point
|
// Calculate new point
|
||||||
var x2 = branch.points[3].x + Math.sin(Math.PI * angle / 180) * length;
|
var x2 = branch.points[3].x + Math.sin(Math.PI * angle / 180) * length;
|
||||||
@ -137,39 +154,39 @@ window.onload = function () {
|
|||||||
|
|
||||||
}
|
}
|
||||||
return newBranches;
|
return newBranches;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cast(x, y, angle, chain) {
|
Magic.prototype.cast = function(x, y, angle, chain) {
|
||||||
// Find random position if not defined
|
// Find random position if not defined
|
||||||
if (x === undefined) {
|
if (x === undefined) {
|
||||||
x = Math.floor(Math.random() * (canvas.width + 1));
|
x = Math.floor(Math.random() * (this.canvas.width + 1));
|
||||||
}
|
}
|
||||||
if (y === undefined) {
|
if (y === undefined) {
|
||||||
y = Math.floor(Math.random() * (canvas.height + 1));
|
y = Math.floor(Math.random() * (this.canvas.height + 1));
|
||||||
}
|
}
|
||||||
if (angle === undefined) {
|
if (angle === undefined) {
|
||||||
angle = Math.random() * 360;
|
angle = Math.random() * 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
var color = pickRandomColor();
|
var color = this.pickRandomColor();
|
||||||
var colorString = "rgb(" + color.r + "," + color.g + "," + color.b + ")";
|
var colorString = "rgb(" + color.r + "," + color.g + "," + color.b + ")";
|
||||||
|
|
||||||
// Create new spell (branch)
|
// Create new spell (branch)
|
||||||
spells.push({
|
this.spells.push({
|
||||||
branches:new Array({
|
branches:new Array({
|
||||||
points:new Array({x:x, y:y}, {x:x, y:y}, {x:x, y:y}, {x:x, y:y}),
|
points:new Array({x:x, y:y}, {x:x, y:y}, {x:x, y:y}, {x:x, y:y}),
|
||||||
angle:angle,
|
angle:angle,
|
||||||
t:0,
|
t:0,
|
||||||
}),
|
}),
|
||||||
color:colorString,
|
color:colorString,
|
||||||
duration:Math.floor(Math.random() * (600 - 50 + 1)) + 50,
|
duration:Math.floor(Math.random() * (this.maxDuration - this.minDuration + 1)) + 50,
|
||||||
chain:chain,
|
chain:chain,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Most of this funtion is provided by Maissan Inc. in their tutorial:
|
/* Most of this funtion is provided by Maissan Inc. in their tutorial:
|
||||||
http://www.maissan.net/articles/simulating-vines */
|
http://www.maissan.net/articles/simulating-vines */
|
||||||
function drawSpells(context, sort, prune, chain) {
|
Magic.prototype.drawSpells = function(context, sort, prune, chain) {
|
||||||
var AnimationFrame = window.AnimationFrame;
|
var AnimationFrame = window.AnimationFrame;
|
||||||
AnimationFrame.shim();
|
AnimationFrame.shim();
|
||||||
var animationFrame = new AnimationFrame(30),
|
var animationFrame = new AnimationFrame(30),
|
||||||
@ -178,51 +195,52 @@ window.onload = function () {
|
|||||||
gradient;
|
gradient;
|
||||||
context.lineWidth = 0.5;
|
context.lineWidth = 0.5;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
function animate(time) {
|
function animate(time) {
|
||||||
// resize canvas if document size changed
|
// resize canvas if document size changed
|
||||||
dimensions = getDocumentDimensions();
|
dimensions = self.getDocumentDimensions();
|
||||||
if ((dimensions.height !== canvas.height) ||
|
if ((dimensions.height !== self.canvas.height) ||
|
||||||
(dimensions.width !== canvas.width)) {
|
(dimensions.width !== self.canvas.width)) {
|
||||||
canvas.height = dimensions.height;
|
self.canvas.height = dimensions.height;
|
||||||
canvas.width = dimensions.width;
|
self.canvas.width = dimensions.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if enough time has passed, cast another spell to draw
|
// if enough time has passed, cast another spell to draw
|
||||||
if (timeCounter >= waitTime && counting) {
|
if (timeCounter >= self.waitTime && self.counting) {
|
||||||
cast(undefined, undefined, undefined, chain); // start position
|
self.cast(undefined, undefined, undefined, chain); // start position
|
||||||
counting = false;
|
self.counting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw branches
|
// Draw branches
|
||||||
for (var i in spells) {
|
for (var i in self.spells) {
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.strokeStyle = spells[i].color;
|
context.strokeStyle = self.spells[i].color;
|
||||||
|
|
||||||
if (spells[i].duration > 0) {
|
if (self.spells[i].duration > 0) {
|
||||||
for (var j in spells[i].branches) {
|
for (var j in self.spells[i].branches) {
|
||||||
drawSplineSegment(spells[i].branches[j], context);
|
self.drawSplineSegment(self.spells[i].branches[j], context);
|
||||||
|
|
||||||
// When finished drawing splines, create a new set of branches
|
// When finished drawing splines, create a new set of branches
|
||||||
if (spells[i].branches[j].t >= 1) {
|
if (self.spells[i].branches[j].t >= 1) {
|
||||||
|
|
||||||
var newBranches = splitBranch(spells[i].branches[j]);
|
var newBranches = self.splitBranch(self.spells[i].branches[j]);
|
||||||
|
|
||||||
// Replace old branch with two new branches
|
// Replace old branch with two new branches
|
||||||
spells[i].branches.splice(j, 1);
|
self.spells[i].branches.splice(j, 1);
|
||||||
spells[i].branches = spells[i].branches.concat(newBranches);
|
self.spells[i].branches = self.spells[i].branches.concat(newBranches);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If over 10 branches, prune the branches
|
// If over 10 branches, prune the branches
|
||||||
if (prune) {
|
if (prune) {
|
||||||
if (sort) {
|
if (sort) {
|
||||||
while (spells[i].branches.length > prune_to) {
|
while (self.spells[i].branches.length > self.prune_to) {
|
||||||
spells[i].branches.pop();
|
self.spells[i].branches.pop();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (spells[i].branches.length > prune_to) {
|
while (self.spells[i].branches.length > self.prune_to) {
|
||||||
spells[i].branches.splice(
|
self.spells[i].branches.splice(
|
||||||
Math.floor(Math.random() * spells[i].branches.length),
|
Math.floor(Math.random() * self.spells[i].branches.length),
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,18 +248,18 @@ window.onload = function () {
|
|||||||
|
|
||||||
context.stroke();
|
context.stroke();
|
||||||
context.closePath();
|
context.closePath();
|
||||||
spells[i].duration--;
|
self.spells[i].duration--;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// cast a new spell at random position
|
// cast a new spell at random position
|
||||||
if (spells[i].chain) {
|
if (self.spells[i].chain) {
|
||||||
cast(undefined, undefined, undefined, true);
|
self.cast(undefined, undefined, undefined, true);
|
||||||
}
|
}
|
||||||
spells.splice(i, 1); // spell is done now
|
self.spells.splice(i, 1); // spell is done now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counting) {
|
if (self.counting) {
|
||||||
timeCounter++;
|
timeCounter++;
|
||||||
}
|
}
|
||||||
frameId = animationFrame.request(animate);
|
frameId = animationFrame.request(animate);
|
||||||
@ -250,33 +268,31 @@ window.onload = function () {
|
|||||||
// Drawing interval
|
// Drawing interval
|
||||||
var frameId = animationFrame.request(animate);
|
var frameId = animationFrame.request(animate);
|
||||||
return frameId;
|
return frameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function canvasClickHandler(event) {
|
Magic.prototype.canvasClickHandler = function(event) {
|
||||||
var x = event.pageX;
|
var x = event.pageX;
|
||||||
var y = event.pageY;
|
var y = event.pageY;
|
||||||
|
|
||||||
cast(x, y, undefined, false);
|
this.cast(x, y, undefined, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
Magic.prototype.draw = function() {
|
||||||
var interval_time = 2000;
|
var interval_time = 2000;
|
||||||
|
|
||||||
// Initialize canvas
|
// Initialize canvas
|
||||||
var dimensions = getDocumentDimensions();
|
var dimensions = this.getDocumentDimensions();
|
||||||
canvas.height = dimensions.height;
|
this.canvas.height = dimensions.height;
|
||||||
canvas.width = dimensions.width;
|
this.canvas.width = dimensions.width;
|
||||||
|
|
||||||
// Check for canvas support, bind click event, and get context
|
// Check for canvas support, bind click event, and get context
|
||||||
if (canvas.getContext){
|
if (this.canvas.getContext){
|
||||||
canvas.addEventListener("click", canvasClickHandler);
|
var self = this;
|
||||||
|
this.canvas.addEventListener("click", function () { self.canvasClickHandler.apply(self, arguments); });
|
||||||
|
|
||||||
var context = canvas.getContext("2d");
|
var context = this.canvas.getContext("2d");
|
||||||
|
|
||||||
// Cast magic spells
|
// Cast magic spells
|
||||||
var frameId = drawSpells(context, false, true, true);
|
var frameId = this.drawSpells(context, false, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw();
|
|
||||||
};
|
|
||||||
|
10
magic/index.html
Normal file
10
magic/index.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
layout: home
|
||||||
|
title: Tyler Hallada
|
||||||
|
---
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.onload = function () {
|
||||||
|
new Magic({{ site.data.magic | jsonify }}).draw();
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue
Block a user