345 lines
7.3 KiB
JavaScript
345 lines
7.3 KiB
JavaScript
import {Ease} from 'https://assets.codepen.io/3919397/ease.js';
|
|
import {Utils} from 'https://assets.codepen.io/3919397/utilities.js';
|
|
|
|
let gui, canvas, c, width, height, frameSize, id, ease, shapes, size, scale, num, maxDist, hexPoints;
|
|
|
|
const setupGui = () => {
|
|
gui = new dat.GUI();
|
|
|
|
gui.params = {
|
|
timeScale: 0.0005,
|
|
ease: 'easeInOutQuart',
|
|
number: 1,
|
|
scale: 150,
|
|
frame: false,
|
|
start: () => start(),
|
|
stop: () => stop()
|
|
};
|
|
|
|
gui.ctrls = {
|
|
timeScale: gui.add(gui.params, 'timeScale', 0.0001, 0.005, 0.0001),
|
|
ease: gui.add(gui.params, 'ease', Ease.returnEaseType())
|
|
.onChange(() => initialize()),
|
|
number: gui.add(gui.params, 'number', 1, 30, 1)
|
|
.onChange(() => initialize()),
|
|
scale: gui.add(gui.params, 'scale', 1, 500, 1)
|
|
.onChange(() => initialize()),
|
|
frame: gui.add(gui.params, 'frame', false),
|
|
start: gui.add(gui.params, 'start'),
|
|
stop: gui.add(gui.params, 'stop')
|
|
};
|
|
|
|
gui.close();
|
|
};
|
|
|
|
const addFrame = () => {
|
|
c.rect(
|
|
width / 2 - frameSize / 2,
|
|
height / 2 - frameSize / 2,
|
|
frameSize,
|
|
frameSize
|
|
);
|
|
c.clip();
|
|
};
|
|
|
|
const setupCanvas = () => {
|
|
canvas = document.createElement('canvas');
|
|
document.getElementsByTagName('body')[0].appendChild(canvas);
|
|
c = canvas.getContext('2d');
|
|
};
|
|
|
|
const initialize = () => {
|
|
if (id) {
|
|
cancelAnimationFrame(id);
|
|
}
|
|
|
|
width = canvas.width = window.innerWidth;
|
|
height = canvas.height = window.innerHeight;
|
|
|
|
ease = Ease.returnEaseFunc(gui.params.ease);
|
|
|
|
shapes = new Array();
|
|
scale = gui.params.scale;
|
|
num = gui.params.number;
|
|
frameSize = Math.min(width * 0.9, height * 0.9);
|
|
maxDist = 0;
|
|
|
|
hexPoints = getPolygonPoints(360, 4);
|
|
shapes = getSquareGrid(num);
|
|
|
|
draw(0);
|
|
};
|
|
|
|
const getSquareGrid = (num) => {
|
|
const vectors = new Array();
|
|
|
|
for (let x = -num; x <= num; x++) {
|
|
for (let y = -num; y <= num; y++) {
|
|
vectors.push([x, y]);
|
|
}
|
|
}
|
|
|
|
const tmp = new Array();
|
|
|
|
for (let i = 0; i < vectors.length; i++) {
|
|
const params = {};
|
|
const x = vectors[i][0] * scale;
|
|
const y = vectors[i][1] * scale;
|
|
const d = Math.sqrt(x * x + y * y);
|
|
|
|
params.x = x;
|
|
params.y = y;
|
|
params.d = d;
|
|
params.i = i;
|
|
|
|
maxDist = Math.max(d, maxDist);
|
|
|
|
tmp.push(params);
|
|
}
|
|
|
|
size = Math.floor(scale * Math.sqrt(2) / 2);
|
|
//size = scale / 2;
|
|
|
|
return tmp;
|
|
};
|
|
|
|
const getHexGrid = (num) => {
|
|
const vectors = new Array();
|
|
|
|
for (let x = -num; x <= num; x++) {
|
|
for (let y = -num; y <= num; y++) {
|
|
for (let z = -num; z <= num; z++) {
|
|
if (x + y + z === 0) {
|
|
vectors.push([x, y]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const tmp = new Array();
|
|
|
|
for (let i = 0; i < vectors.length; i++) {
|
|
const params = {};
|
|
const x = Math.sqrt(3) * (vectors[i][0] + vectors[i][1] / 2) / 2 * scale;
|
|
const y = 3 / 2 * vectors[i][1] / 2 * scale;
|
|
const d = Math.sqrt(x * x + y * y);
|
|
|
|
params.x = x;
|
|
params.y = y;
|
|
params.d = d;
|
|
|
|
maxDist = Math.max(d, maxDist);
|
|
|
|
tmp.push(params);
|
|
}
|
|
|
|
size = Math.sqrt(3) * (scale / 2) / 2;
|
|
|
|
return tmp;
|
|
};
|
|
|
|
const getSquareGrid2 = (num) => {
|
|
const tmp = new Array();
|
|
const ajust = num * scale / 2 - scale / 2;
|
|
|
|
for (let y = 0; y < num; y++) {
|
|
for (let x = 0; x < num; x++) {
|
|
const params = {};
|
|
const i = y * num + x;
|
|
|
|
let ny = scale * y - ajust;
|
|
let nx = scale * x - ajust;
|
|
|
|
if (y % 2 === 0) {
|
|
nx += scale / 2;
|
|
}
|
|
|
|
const d = Math.sqrt(nx * nx + ny * ny);
|
|
|
|
params.x = nx;
|
|
params.y = ny;
|
|
params.d = d;
|
|
params.i = i;
|
|
params.col = x;
|
|
params.row = y;
|
|
|
|
maxDist = Math.max(dist, maxDist);
|
|
|
|
tmp.push(params);
|
|
}
|
|
}
|
|
|
|
size = scale / 2;
|
|
|
|
return tmp;
|
|
};
|
|
|
|
const getCircleGrid = (num) => {
|
|
const tmp = new Array();
|
|
|
|
for (let k = 1; k <= num; k++) {
|
|
for (let j = 0; j < k * num; j++) {
|
|
const params = {};
|
|
const i = k * k * num + j;
|
|
const x = Math.cos(Math.PI * 2 / (num * k) * j) * k * scale * 0.4;
|
|
const y = Math.sin(Math.PI * 2 / (num * k) * j) * k * scale * 0.4;
|
|
const d = Math.sqrt(x * x + y * y);
|
|
|
|
params.x = x;
|
|
params.y = y;
|
|
params.d = d;
|
|
params.i = i;
|
|
|
|
maxDist = Math.max(d, maxDist);
|
|
|
|
tmp.push(params);
|
|
}
|
|
}
|
|
|
|
size = Math.floor(scale * 0.4 * 2 * Math.PI / num / 2);
|
|
|
|
return tmp;
|
|
};
|
|
|
|
const getPolygonPoints = (number, poly) => {
|
|
const tmp = new Array();
|
|
|
|
for (let j = 0; j < poly; j++) {
|
|
for (let i = 0; i < number / poly; i++) {
|
|
const x = Math.cos(j / poly * Math.PI * 2);
|
|
const y = Math.sin(j / poly * Math.PI * 2);
|
|
|
|
let nx, ny;
|
|
|
|
if (j === poly - 1) {
|
|
nx = Math.cos(0);
|
|
ny = Math.sin(0);
|
|
} else {
|
|
nx = Math.cos((j + 1) / poly * Math.PI * 2);
|
|
ny = Math.sin((j + 1) / poly * Math.PI * 2);
|
|
}
|
|
|
|
const sx = x + (nx - x) * (i / (number / poly));
|
|
const sy = y + (ny - y) * (i / (number / poly));
|
|
|
|
tmp.push([sx, sy]);
|
|
}
|
|
}
|
|
|
|
return tmp;
|
|
};
|
|
|
|
const getNewPoints = (t) => {
|
|
const tmp = new Array();
|
|
|
|
for (let i = 0; i < number; i++) {
|
|
let x, y;
|
|
|
|
tmp.push([x, y]);
|
|
}
|
|
|
|
return tmp;
|
|
};
|
|
|
|
const drawPolygon = (x, y, num, size, fillStyle, strokeStyle) => {
|
|
c.save();
|
|
|
|
c.fillStyle = fillStyle;
|
|
c.strokeStyle = strokeStyle;
|
|
|
|
c.beginPath();
|
|
for (let i = 0; i < num; i++) {
|
|
const nx = Math.cos(i / num * Math.PI * 2) * size + x;
|
|
const ny = Math.sin(i / num * Math.PI * 2) * size + y;
|
|
|
|
if (i === 0) {
|
|
c.moveTo(nx, ny);
|
|
} else {
|
|
c.lineTo(nx, ny);
|
|
}
|
|
}
|
|
c.closePath();
|
|
//c.fill();
|
|
c.stroke();
|
|
|
|
c.restore();
|
|
};
|
|
|
|
const draw = (t) => {
|
|
t *= gui.params.timeScale;
|
|
|
|
c.save();
|
|
c.fillStyle = 'rgba(0, 0, 0, 0.03)';
|
|
c.fillRect(0, 0, width, height);
|
|
//c.clearRect(0, 0, width, height);
|
|
|
|
if (gui.params.frame) addFrame();
|
|
|
|
c.translate(width / 2, height / 2);
|
|
|
|
c.lineCap = 'round';
|
|
c.lineWidth = 30;
|
|
|
|
for (let i = 0; i < shapes.length; i++) {
|
|
let scaledT = (t - (shapes[i].d / maxDist)) % 1;
|
|
scaledT = ease(Math.abs(scaledT));
|
|
|
|
const x = shapes[i].x;
|
|
const y = shapes[i].y;
|
|
|
|
c.save();
|
|
|
|
c.translate(x, y);
|
|
c.rotate(Math.PI / 2);
|
|
c.translate(-x, -y);
|
|
|
|
let index = Math.floor(Utils.map(scaledT, 0, 1, 0, hexPoints.length - 1));
|
|
let endex = Math.ceil(Utils.map(scaledT, 0, 1, index + 1, hexPoints.length - 1));
|
|
|
|
c.strokeStyle = `hsl(${360 * scaledT}, 80%, 60%)`;
|
|
|
|
c.translate(x, y);
|
|
c.beginPath();
|
|
c.moveTo(hexPoints[index][0] * size, hexPoints[index][1] * size);
|
|
for (let i = index; i < endex; i++) {
|
|
if (endex === hexPoints.length - 1) {
|
|
c.lineTo(hexPoints[0][0] * size, hexPoints[0][1] * size);
|
|
} else {
|
|
c.lineTo(hexPoints[i][0] * size, hexPoints[i][1] * size);
|
|
}
|
|
}
|
|
c.stroke();
|
|
|
|
c.restore();
|
|
}
|
|
|
|
c.restore();
|
|
|
|
id = requestAnimationFrame(draw);
|
|
};
|
|
|
|
const start = () => {
|
|
initialize();
|
|
};
|
|
|
|
const stop = () => {
|
|
if (id) {
|
|
cancelAnimationFrame(id);
|
|
id = null;
|
|
}
|
|
};
|
|
|
|
(() => {
|
|
window.addEventListener('DOMContentLoaded', () => {
|
|
console.clear();
|
|
|
|
setupGui();
|
|
setupCanvas();
|
|
|
|
initialize();
|
|
});
|
|
|
|
window.addEventListener('resize', () => {
|
|
initialize();
|
|
});
|
|
})(); |