Skip to content

Instantly share code, notes, and snippets.

@caputomarcos
Created July 10, 2022 04:29
Show Gist options
  • Save caputomarcos/af6d098d3c3cdbb95029930c601a83a8 to your computer and use it in GitHub Desktop.
Save caputomarcos/af6d098d3c3cdbb95029930c601a83a8 to your computer and use it in GitHub Desktop.
hexagon animation
<canvas id="animation" height="300px" width="800px"></canvas>
function start (canvas) {
if (!canvas || !canvas.getContext ) return;
var context = canvas.getContext('2d');
var grid = new Grid(10);
update();
draw();
function update () {
grid.update();
setTimeout(update, 1250);
}
function draw () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.translate(canvas.width / 2, canvas.height / 2);
grid.draw(context);
context.restore();
requestAnimationFrame(draw);
}
}
var YELLOW = [250, 197, 53];
var BULE = [69, 180, 231];
var GREY = [91, 114, 135];
var GREEN = [154, 202, 73];
var COLORS = [YELLOW, BULE, GREY, GREEN];
function Grid (size) {
this.size = size;
this.content = [];
this.access = {};
this.angle = 0;
this.zoom = 1;
this.rotationSpeed = Grid.ROTATION_SPEED;
this.zoomSpeed = Grid.ZOOM_SPEED;
this.init();
}
Grid.ZOOM_MIN = 1;
Grid.ZOOM_MAX = 3;
Grid.ZOOM_SPEED = 0.001;
Grid.ROTATION_SPEED = 0.001;
Grid.ROTATION_PROB = 0.1;
Grid.prototype.init = function () {
for (var i = -this.size; i <= this.size; i++) {
for (var j = -this.size; j <= this.size; j++) {
if (Math.abs(i + j) > this.size) continue;
this.getHex(i, j);
}
}
[[0, 0], [0, 1], [1, 0], [1, 1]].forEach(function (coord, i) {
var hex = this.getHex.apply(this, coord);
hex.on(COLORS[i]);
}, this);
};
Grid.prototype.update = function (context) {
if (Math.random() < Grid.ROTATION_PROB) this.rotationSpeed = -this.rotationSpeed;
this.content.forEach(function (hex) {
hex.update();
});
};
Grid.prototype.updateRotation = function (context) {
this.angle += this.rotationSpeed;
};
Grid.prototype.updateZoom = function (context) {
this.zoom += this.zoomSpeed;
if (this.zoom <= Grid.ZOOM_MIN) this.zoomSpeed = Grid.ZOOM_SPEED;
else if (this.zoom >= Grid.ZOOM_MAX) this.zoomSpeed = -Grid.ZOOM_SPEED;
};
Grid.prototype.draw = function (context) {
this.updateRotation();
this.updateZoom();
context.save();
context.rotate(this.angle);
this.content.forEach(function (hex) {
hex.draw(context);
});
context.restore();
};
Grid.prototype.getHex = function (x, y) {
if (Math.abs(x) > this.size || Math.abs(y) > this.size || Math.abs(x + y) > this.size) return;
if (!(x in this.access)) this.access[x] = {};
if (!(y in this.access[x])) {
var hex = new Hex(this, [x, y]);
this.access[x][y] = hex;
this.content.push(hex);
}
return this.access[x][y];
};
function Hex(grid, coord) {
this.grid = grid;
this.coord = coord;
this.rgb = null;
this.active = 0;
this.opacity = 0;
}
Hex.SIZE = 10;
Hex.FADE_SPEED = 0.01;
Hex.MAX_OPACITY = 0.6;
Hex.prototype.update = function (context) {
var active = this.neighbors().filter(function (hex) {
return hex.active;
});
if (!this.active && (active.length == 2 || active.length == 3)) {
var colors = active.map(function (hex) {
return hex.rgb;
});
colors = COLORS.filter(function (c) {
return !~colors.indexOf(c);
});
this.on(colors[Math.floor(Math.random() * colors.length)]);
}
else if (this.active && active.length != 2 && active.length != 3) {
this.off();
}
};
Hex.prototype.draw = function (context) {
this.fade();
if (!this.opacity) return;
var size = this.size();
context.save();
context.translate.apply(context, this.getCenter());
context.beginPath();
context.moveTo.apply(context, this.corner(0));
for (var i = 1; i <= 6; i ++) {
context.lineTo.apply(context, this.corner(i));
}
context.fillStyle = this.color();
context.shadowColor = this.color(1);
context.shadowBlur = size / 2;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.fill();
context.restore();
};
Hex.prototype.on = function (color) {
setTimeout(function () {
this.rgb = color;
this.active = true;
}.bind(this), 0);
};
Hex.prototype.off = function () {
setTimeout(function () {
this.active = false;
}.bind(this), 0);
};
Hex.prototype.corner = function (i) {
var size = this.size() * 2/3;
var aDeg = 60 * i;
var aRad = aDeg * Math.PI / 180;
return [size * Math.cos(aRad), size * Math.sin(aRad)];
};
Hex.prototype.size = function () {
return Hex.SIZE * this.grid.zoom;
};
Hex.prototype.color = function (opacity) {
opacity = opacity || this.opacity;
return 'rgba('+this.rgb.join(',')+','+this.opacity+')';
};
Hex.prototype.neighbors = function (i) {
var neighbors = [
this.grid.getHex(this.coord[0] + 1, this.coord[1]),
this.grid.getHex(this.coord[0] - 1, this.coord[1]),
this.grid.getHex(this.coord[0] + 1, this.coord[1] - 1),
this.grid.getHex(this.coord[0] - 1, this.coord[1] + 1),
this.grid.getHex(this.coord[0], this.coord[1] + 1),
this.grid.getHex(this.coord[0], this.coord[1] - 1)
];
return neighbors.filter(Boolean);
};
Hex.prototype.fade = function () {
if (this.active) {
this.opacity = Math.min(this.opacity + Hex.FADE_SPEED, Hex.MAX_OPACITY);
}
else {
this.opacity = Math.max(this.opacity - Hex.FADE_SPEED, 0);
}
};
Hex.prototype.getCenter = function () {
var width = Hex.SIZE * 2 * this.grid.zoom;
var height = width * Math.sqrt(3) / 2;
return [this.coord[0] * width * 3/4, (this.coord[1] + this.coord[0]/2) * height];
};
start(document.getElementById('animation'));
body {
text-align:center;
background-color: #181818;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment