Global rewriting of the triangle mask script.
It now notably includes more constants, animation properties inside the point structure, and an animation halting mechanism (in case drawing is too slow on the user's device).
This commit is contained in:
parent
2f54b1960e
commit
aecc5172de
1 changed files with 164 additions and 91 deletions
|
@ -1,19 +1,23 @@
|
|||
(function () {
|
||||
/*--------------------------------------------------------*/
|
||||
/* INITIALISATION
|
||||
/*--------------------------------------------------------*/
|
||||
|
||||
const canvas = document.getElementById("main-header-background");
|
||||
const context = canvas.getContext("2d");
|
||||
|
||||
// Get the node dimensions and enforce the canvas width and height
|
||||
const WIDTH = canvas.clientWidth;
|
||||
const HEIGHT = canvas.clientHeight;
|
||||
let WIDTH = canvas.clientWidth;
|
||||
let HEIGHT = canvas.clientHeight;
|
||||
|
||||
canvas.setAttribute("width", WIDTH);
|
||||
canvas.setAttribute("height", HEIGHT);
|
||||
|
||||
// Delay between point positions' updates
|
||||
const POINT_POSITIONS_UPDATE_DELAY = 50; // ms
|
||||
|
||||
// Define some useful constants
|
||||
const POSITIONS_UPDATE_DELAY = 50; // ms
|
||||
|
||||
const NB_POINTS_PER_ROW = 4 + Math.round(WIDTH / 250);
|
||||
// Number of points and initial position parameters
|
||||
const NB_POINTS_PER_ROW = 4 + Math.round(WIDTH / 200);
|
||||
const NB_POINTS_PER_COL = 5;
|
||||
|
||||
const INIT_ROW_SPACING = HEIGHT / (NB_POINTS_PER_COL - 1);
|
||||
|
@ -22,35 +26,76 @@
|
|||
const X_ORIGIN = -INIT_COL_SPACING;
|
||||
const Y_ORIGIN = -100;
|
||||
|
||||
// When creating points
|
||||
const INIT_MAX_X_SHIFT_DISTANCE = INIT_ROW_SPACING / 3;
|
||||
const INIT_MAX_Y_SHIFT_ISTANCE = INIT_COL_SPACING / 4;
|
||||
const INIT_MAX_X_SHIFT = INIT_ROW_SPACING / 3;
|
||||
const INIT_MAX_Y_SHIFT = INIT_COL_SPACING / 4;
|
||||
|
||||
// Movement of the points
|
||||
const POINT_MIN_X_SPEED = 0.15;
|
||||
const POINT_MAX_X_SPEED = 0.3;
|
||||
|
||||
const POINT_MIN_Y_SPEED = 0.15;
|
||||
const POINT_MAX_Y_SPEED = 0.3;
|
||||
|
||||
const POINT_MIN_X_RADIUS = 0.5;
|
||||
const POINT_MAX_X_RADIUS = 2;
|
||||
|
||||
const POINT_MIN_Y_RADIUS = 0.5;
|
||||
const POINT_MAX_Y_RADIUS = 2;
|
||||
|
||||
// Canvas update halting
|
||||
const NB_CANVAS_UPDATES_DELAYS_TO_RECORD = 100;
|
||||
const ANIM_HALT_TIME_THRESHOLD = 100; // ms
|
||||
|
||||
|
||||
// Set the drawing style
|
||||
context.lineWidth = 3;
|
||||
|
||||
|
||||
// Create a grid of points
|
||||
/*--------------------------------------------------------*/
|
||||
/* GRID OF POINTS
|
||||
/*--------------------------------------------------------*/
|
||||
|
||||
const points = [];
|
||||
|
||||
for (let row = 0; row < NB_POINTS_PER_COL; row++) {
|
||||
for (let col = 0; col < NB_POINTS_PER_ROW; col++) {
|
||||
points.push({
|
||||
x: X_ORIGIN + col * INIT_COL_SPACING + ((row % 2 === 1) ? INIT_COL_SPACING : 0),
|
||||
y: Y_ORIGIN + row * INIT_ROW_SPACING
|
||||
});
|
||||
// Create all points
|
||||
// Each point is defined by its position
|
||||
// plus several parameters which control its movement
|
||||
function createAllPoints () {
|
||||
for (let row = 0; row < NB_POINTS_PER_COL; row++) {
|
||||
for (let col = 0; col < NB_POINTS_PER_ROW; col++) {
|
||||
points.push({
|
||||
// Initial position
|
||||
x: X_ORIGIN + col * INIT_COL_SPACING + ((row % 2 === 1) ? INIT_COL_SPACING : 0),
|
||||
y: Y_ORIGIN + row * INIT_ROW_SPACING,
|
||||
|
||||
// Parameters of the movement
|
||||
xDirection: (Math.random() > 0.5 ? 1 : -1),
|
||||
yDirection: (Math.random() > 0.5 ? 1 : -1),
|
||||
|
||||
xSpeed: (Math.random() * (POINT_MAX_X_SPEED - POINT_MIN_X_SPEED)) + POINT_MIN_X_SPEED,
|
||||
ySpeed: (Math.random() * (POINT_MAX_Y_SPEED - POINT_MIN_Y_SPEED)) + POINT_MIN_Y_SPEED,
|
||||
|
||||
xRadius: (Math.random() * (POINT_MAX_X_RADIUS - POINT_MIN_X_RADIUS)) + POINT_MIN_X_RADIUS,
|
||||
yRadius: (Math.random() * (POINT_MAX_Y_RADIUS - POINT_MIN_Y_RADIUS)) + POINT_MIN_Y_RADIUS
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Move each point a little bit
|
||||
// This will make the triangular structure look more random
|
||||
for (let point of points) {
|
||||
point.x += (2 * Math.random() * INIT_MAX_X_SHIFT) - INIT_MAX_X_SHIFT;
|
||||
point.y += (2 * Math.random() * INIT_MAX_Y_SHIFT) - INIT_MAX_Y_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
// Move each point a little bit
|
||||
for (let point of points) {
|
||||
point.x += (2 * Math.random() * INIT_MAX_X_SHIFT_DISTANCE) - INIT_MAX_X_SHIFT_DISTANCE;
|
||||
point.y += (2 * Math.random() * INIT_MAX_Y_SHIFT_ISTANCE) - INIT_MAX_Y_SHIFT_ISTANCE;
|
||||
}
|
||||
createAllPoints();
|
||||
|
||||
|
||||
// Draw lines between points to make triangles
|
||||
|
||||
/*--------------------------------------------------------*/
|
||||
/* TRIANGLE DRAWING
|
||||
/*--------------------------------------------------------*/
|
||||
|
||||
// Draw a line between two points
|
||||
function drawLineBetweenPoints (from, to) {
|
||||
context.beginPath();
|
||||
context.moveTo(from.x, from.y);
|
||||
|
@ -58,7 +103,12 @@
|
|||
context.stroke();
|
||||
}
|
||||
|
||||
function drawLinesBetweenAllPoints () {
|
||||
|
||||
// Draw certain lines between all points to form contours of triangles
|
||||
function drawTriangleContours () {
|
||||
// Width of the contours
|
||||
context.lineWidth = 3;
|
||||
|
||||
for (let row = 0; row < NB_POINTS_PER_COL; row++) {
|
||||
for (let col = 0; col < NB_POINTS_PER_ROW; col++) {
|
||||
// Nothing to do with the last point of each row
|
||||
|
@ -66,10 +116,6 @@
|
|||
continue;
|
||||
}
|
||||
|
||||
//if (Math.abs(col - NB_POINTS_PER_ROW / 2) < (NB_POINTS_PER_ROW / 7)) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
// Get the current index and point
|
||||
const index = row * NB_POINTS_PER_ROW + col;
|
||||
const point = points[index];
|
||||
|
@ -101,9 +147,9 @@
|
|||
}
|
||||
|
||||
|
||||
// Inverse image data alpha channel in order to
|
||||
// make the lines transparent and the triangles visible
|
||||
function invertAlphaChannel () {
|
||||
// Transform the triangle contours into plain white triangles
|
||||
// by iterating over the pixels of the canvas image data
|
||||
function fillTrianglesAndEmptyContours () {
|
||||
const currentImageData = context.getImageData(0, 0, WIDTH, HEIGHT);
|
||||
const currentData = currentImageData.data;
|
||||
|
||||
|
@ -122,82 +168,109 @@
|
|||
}
|
||||
|
||||
|
||||
// Update the point positions
|
||||
|
||||
|
||||
/*--------------------------------------------------------*/
|
||||
/* POINT POSITIONS UPDATE
|
||||
/*--------------------------------------------------------*/
|
||||
|
||||
// N° of the current position update iteration
|
||||
let positionUpdateIter = 0;
|
||||
|
||||
const pointRotationDirections = [];
|
||||
const pointRotationSpeeds = [];
|
||||
const pointRotationRadius = [];
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
pointRotationDirections[i] = {
|
||||
x: Math.random() > 0.5 ? 1 : - 1,
|
||||
y: Math.random() > 0.5 ? 1 : - 1
|
||||
};
|
||||
|
||||
pointRotationSpeeds[i] = {
|
||||
x: (Math.random() * 1) + 1,
|
||||
y: (Math.random() * 1) + 1
|
||||
};
|
||||
|
||||
pointRotationRadius[i] = {
|
||||
x: (Math.random() * 2) + 1,
|
||||
y: (Math.random() * 2) + 1
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function updatePointPositions () {
|
||||
const nbPoints = points.length;
|
||||
|
||||
/*
|
||||
for (let point of points) {
|
||||
point.x += (2 * MAX_X_SHIFT_DISTANCE * Math.random()) - MAX_X_SHIFT_DISTANCE;
|
||||
point.y += (2 * MAX_X_SHIFT_DISTANCE * Math.random()) - MAX_X_SHIFT_DISTANCE;
|
||||
}
|
||||
*/
|
||||
for (let i = 0; i < nbPoints; i++) {
|
||||
const point = points[i];
|
||||
|
||||
/*
|
||||
for (let iter = 0; iter < NB_POINT_POSITIONS_TO_UPDATE; iter++) {
|
||||
const index = Math.floor(points.length * Math.random());
|
||||
const point = points[index];
|
||||
|
||||
point.x += (2 * MAX_X_SHIFT_DISTANCE * Math.random()) - MAX_X_SHIFT_DISTANCE;
|
||||
point.y += (2 * MAX_X_SHIFT_DISTANCE * Math.random()) - MAX_X_SHIFT_DISTANCE;
|
||||
}
|
||||
*/
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
let point = points[i];
|
||||
|
||||
let direction = pointRotationDirections[i];
|
||||
let speed = pointRotationSpeeds[i];
|
||||
let radius = pointRotationRadius[i];
|
||||
|
||||
//console.log(direction, speed, xRadius, yRadius)
|
||||
|
||||
point.x += direction.x * Math.cos(positionUpdateIter * speed.x / 10) * radius.x;
|
||||
//+ (Math.random() * 4) - 2;
|
||||
point.y += direction.y * Math.sin(positionUpdateIter * speed.y / 10) * radius.y;
|
||||
//+ (Math.random() * 4) - 2;
|
||||
point.x += point.xDirection * Math.cos(positionUpdateIter * point.xSpeed) * point.xRadius;
|
||||
point.y += point.yDirection * Math.sin(positionUpdateIter * point.ySpeed) * point.yRadius;
|
||||
}
|
||||
|
||||
positionUpdateIter++;
|
||||
}
|
||||
|
||||
setInterval(updatePointPositions, POSITIONS_UPDATE_DELAY);
|
||||
window.setInterval(updatePointPositions, POINT_POSITIONS_UPDATE_DELAY);
|
||||
|
||||
|
||||
// Update the drawing
|
||||
|
||||
function updateCanvas () {
|
||||
// Clear the canvas
|
||||
|
||||
/*--------------------------------------------------------*/
|
||||
/* CANVAS UPDATE
|
||||
/*--------------------------------------------------------*/
|
||||
|
||||
// Array of times between canvas updates
|
||||
// It is used to compute whether the drawing process should be halted
|
||||
// (if the device is too slow for the animation to look fluid)
|
||||
const canvasUpdateDelays = new Array(NB_CANVAS_UPDATES_DELAYS_TO_RECORD);
|
||||
canvasUpdateDelays.fill(0);
|
||||
|
||||
// Last recorded time (it is set for the first time a bit later)
|
||||
let lastRecordedTime = 0;
|
||||
|
||||
// Flag indicating whether the canvas update has been halted or not
|
||||
let animationHasBeenHalted = false;
|
||||
|
||||
|
||||
function resetHaltingMechanism () {
|
||||
canvasUpdateDelays.fill(0);
|
||||
lastRecordedTime = performance.now();
|
||||
}
|
||||
|
||||
function recordTimeSinceLastCanvasUpdate (time) {
|
||||
canvasUpdateDelays.shift();
|
||||
canvasUpdateDelays.push(time - lastRecordedTime);
|
||||
|
||||
lastRecordedTime = time;
|
||||
}
|
||||
|
||||
|
||||
function animationShouldBeHalted () {
|
||||
let sumOfTimes = canvasUpdateDelays.reduce((sumOfTimes, time) => {
|
||||
return sumOfTimes + time;
|
||||
}, 0);
|
||||
|
||||
// console.log(sumOfTimes / NB_CANVAS_UPDATES_DELAYS_TO_RECORD);
|
||||
return (sumOfTimes / NB_CANVAS_UPDATES_DELAYS_TO_RECORD) > ANIM_HALT_TIME_THRESHOLD;
|
||||
}
|
||||
|
||||
|
||||
function updateCanvas (currentTime) {
|
||||
// Record the time since last update, and halt the animation if required
|
||||
recordTimeSinceLastCanvasUpdate(currentTime);
|
||||
if (animationShouldBeHalted()) {
|
||||
animationHasBeenHalted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the canvas and repeat the drawing process
|
||||
context.clearRect(0, 0, WIDTH, HEIGHT);
|
||||
|
||||
// Repeat the drawing process
|
||||
drawLinesBetweenAllPoints();
|
||||
invertAlphaChannel();
|
||||
drawTriangleContours();
|
||||
fillTrianglesAndEmptyContours();
|
||||
|
||||
window.requestAnimationFrame(updateCanvas);
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(updateCanvas);
|
||||
resetHaltingMechanism();
|
||||
updateCanvas(lastRecordedTime);
|
||||
|
||||
/*
|
||||
* If the page is hidden (e.g. on tab change), the web browser
|
||||
* is likely to stop calling requestAnimationFrame (to save ressources).
|
||||
|
||||
* This may halt the animation when the user displays the page again,
|
||||
* since the time since the last redraw will possibly be very high.
|
||||
*
|
||||
* Therefore, on each visibility change, the halting mechanism must be reset!
|
||||
*/
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
resetHaltingMechanism();
|
||||
|
||||
// In case the animation has been halted before this callback was executed,
|
||||
// the canvas update must be restarted
|
||||
if (animationHasBeenHalted)
|
||||
updateCanvas(lastRecordedTime);
|
||||
}, false);
|
||||
})();
|
Loading…
Reference in a new issue