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 () {
|
(function () {
|
||||||
|
/*--------------------------------------------------------*/
|
||||||
|
/* INITIALISATION
|
||||||
|
/*--------------------------------------------------------*/
|
||||||
|
|
||||||
const canvas = document.getElementById("main-header-background");
|
const canvas = document.getElementById("main-header-background");
|
||||||
const context = canvas.getContext("2d");
|
const context = canvas.getContext("2d");
|
||||||
|
|
||||||
// Get the node dimensions and enforce the canvas width and height
|
// Get the node dimensions and enforce the canvas width and height
|
||||||
const WIDTH = canvas.clientWidth;
|
let WIDTH = canvas.clientWidth;
|
||||||
const HEIGHT = canvas.clientHeight;
|
let HEIGHT = canvas.clientHeight;
|
||||||
|
|
||||||
canvas.setAttribute("width", WIDTH);
|
canvas.setAttribute("width", WIDTH);
|
||||||
canvas.setAttribute("height", HEIGHT);
|
canvas.setAttribute("height", HEIGHT);
|
||||||
|
|
||||||
|
// Delay between point positions' updates
|
||||||
|
const POINT_POSITIONS_UPDATE_DELAY = 50; // ms
|
||||||
|
|
||||||
// Define some useful constants
|
// Number of points and initial position parameters
|
||||||
const POSITIONS_UPDATE_DELAY = 50; // ms
|
const NB_POINTS_PER_ROW = 4 + Math.round(WIDTH / 200);
|
||||||
|
|
||||||
const NB_POINTS_PER_ROW = 4 + Math.round(WIDTH / 250);
|
|
||||||
const NB_POINTS_PER_COL = 5;
|
const NB_POINTS_PER_COL = 5;
|
||||||
|
|
||||||
const INIT_ROW_SPACING = HEIGHT / (NB_POINTS_PER_COL - 1);
|
const INIT_ROW_SPACING = HEIGHT / (NB_POINTS_PER_COL - 1);
|
||||||
|
@ -22,35 +26,76 @@
|
||||||
const X_ORIGIN = -INIT_COL_SPACING;
|
const X_ORIGIN = -INIT_COL_SPACING;
|
||||||
const Y_ORIGIN = -100;
|
const Y_ORIGIN = -100;
|
||||||
|
|
||||||
// When creating points
|
const INIT_MAX_X_SHIFT = INIT_ROW_SPACING / 3;
|
||||||
const INIT_MAX_X_SHIFT_DISTANCE = INIT_ROW_SPACING / 3;
|
const INIT_MAX_Y_SHIFT = INIT_COL_SPACING / 4;
|
||||||
const INIT_MAX_Y_SHIFT_ISTANCE = 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 = [];
|
const points = [];
|
||||||
|
|
||||||
for (let row = 0; row < NB_POINTS_PER_COL; row++) {
|
// Create all points
|
||||||
for (let col = 0; col < NB_POINTS_PER_ROW; col++) {
|
// Each point is defined by its position
|
||||||
points.push({
|
// plus several parameters which control its movement
|
||||||
x: X_ORIGIN + col * INIT_COL_SPACING + ((row % 2 === 1) ? INIT_COL_SPACING : 0),
|
function createAllPoints () {
|
||||||
y: Y_ORIGIN + row * INIT_ROW_SPACING
|
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
|
createAllPoints();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Draw lines between points to make triangles
|
|
||||||
|
/*--------------------------------------------------------*/
|
||||||
|
/* TRIANGLE DRAWING
|
||||||
|
/*--------------------------------------------------------*/
|
||||||
|
|
||||||
|
// Draw a line between two points
|
||||||
function drawLineBetweenPoints (from, to) {
|
function drawLineBetweenPoints (from, to) {
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.moveTo(from.x, from.y);
|
context.moveTo(from.x, from.y);
|
||||||
|
@ -58,7 +103,12 @@
|
||||||
context.stroke();
|
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 row = 0; row < NB_POINTS_PER_COL; row++) {
|
||||||
for (let col = 0; col < NB_POINTS_PER_ROW; col++) {
|
for (let col = 0; col < NB_POINTS_PER_ROW; col++) {
|
||||||
// Nothing to do with the last point of each row
|
// Nothing to do with the last point of each row
|
||||||
|
@ -66,10 +116,6 @@
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (Math.abs(col - NB_POINTS_PER_ROW / 2) < (NB_POINTS_PER_ROW / 7)) {
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Get the current index and point
|
// Get the current index and point
|
||||||
const index = row * NB_POINTS_PER_ROW + col;
|
const index = row * NB_POINTS_PER_ROW + col;
|
||||||
const point = points[index];
|
const point = points[index];
|
||||||
|
@ -101,9 +147,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Inverse image data alpha channel in order to
|
// Transform the triangle contours into plain white triangles
|
||||||
// make the lines transparent and the triangles visible
|
// by iterating over the pixels of the canvas image data
|
||||||
function invertAlphaChannel () {
|
function fillTrianglesAndEmptyContours () {
|
||||||
const currentImageData = context.getImageData(0, 0, WIDTH, HEIGHT);
|
const currentImageData = context.getImageData(0, 0, WIDTH, HEIGHT);
|
||||||
const currentData = currentImageData.data;
|
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;
|
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 () {
|
function updatePointPositions () {
|
||||||
|
const nbPoints = points.length;
|
||||||
|
|
||||||
/*
|
for (let i = 0; i < nbPoints; i++) {
|
||||||
for (let point of points) {
|
const point = points[i];
|
||||||
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;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
point.x += point.xDirection * Math.cos(positionUpdateIter * point.xSpeed) * point.xRadius;
|
||||||
for (let iter = 0; iter < NB_POINT_POSITIONS_TO_UPDATE; iter++) {
|
point.y += point.yDirection * Math.sin(positionUpdateIter * point.ySpeed) * point.yRadius;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
positionUpdateIter++;
|
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);
|
context.clearRect(0, 0, WIDTH, HEIGHT);
|
||||||
|
|
||||||
// Repeat the drawing process
|
drawTriangleContours();
|
||||||
drawLinesBetweenAllPoints();
|
fillTrianglesAndEmptyContours();
|
||||||
invertAlphaChannel();
|
|
||||||
|
|
||||||
window.requestAnimationFrame(updateCanvas);
|
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…
Add table
Add a link
Reference in a new issue