@arwes/bgs
Version:
Futuristic Sci-Fi UI Web Framework
178 lines (177 loc) • 6.47 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBackgroundMovingLines = void 0;
const tools_1 = require("@arwes/tools");
const animated_1 = require("@arwes/animated");
const defaultProps = {
lineWidth: 1,
lineColor: '#777',
distance: 30,
sets: 5
};
const random = (min, max) => (max - min) * Math.random();
const minmaxOverflow01 = (value) => Math.min(1, Math.max(0, value === 1 ? 1 : value % 1));
const createLinesSet = (config) => {
const { distance, positionsLength, margin, size } = config;
const linesLength = Math.floor(random(0.1, 0.5) * positionsLength);
const positions = Array(positionsLength)
.fill(0)
.map((_, i) => i);
const positionsRandom = (0, tools_1.randomizeList)(positions);
const positionsSelected = positionsRandom.slice(0, linesLength);
return positionsSelected.map((position) => {
const axis1 = margin / 2 + position * distance;
const axis2Initial = Math.random() * (size / 2);
const length = Math.floor(random(0.1, 0.5) * size);
return { axis1, axis2Initial, length };
});
};
const createBackgroundMovingLines = (props) => {
const { canvas, animator } = props;
const ctx = canvas.getContext('2d');
if (!ctx) {
return { cancel: () => { } };
}
let resizeObserver;
let transitionControl;
let runningControl;
let unsubscribe;
let linesSets = [];
const getSettings = () => ({
...defaultProps,
...props.settingsRef.current
});
const resize = () => {
const dpr = Math.min(window.devicePixelRatio || 2, 2);
const { width, height } = canvas.getBoundingClientRect();
if (canvas.width !== width * dpr || canvas.height !== height * dpr) {
canvas.width = width * dpr;
canvas.height = height * dpr;
}
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.scale(dpr, dpr);
};
const draw = (intervalProgress) => {
const { lineWidth, lineColor, distance, sets: linesSetsLength } = getSettings();
const { width, height } = canvas;
const isResized = canvas.width !== width || canvas.height !== height;
const axis1Size = width;
const axis2Size = height;
const positionsLength = 1 + Math.floor(axis1Size / distance);
const margin = axis1Size % distance;
ctx.clearRect(0, 0, width, height);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = lineColor;
ctx.shadowBlur = lineWidth;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowColor = lineColor;
if (linesSets.length === 0 || isResized) {
linesSets = Array(linesSetsLength)
.fill(null)
.map(() => createLinesSet({ positionsLength, margin, distance, size: axis2Size }));
}
linesSets.forEach((linesSet, linesSetIndex) => {
const linesSetProgressOffset = (1 / linesSetsLength) * linesSetIndex;
const progress = minmaxOverflow01(intervalProgress + linesSetProgressOffset);
const progressEase = animated_1.easing.inOutCubic(progress);
linesSet.forEach((line) => {
const { axis1, axis2Initial, length } = line;
const axis2Move = axis2Size * 2 * progressEase - axis2Size;
ctx.beginPath();
ctx.moveTo(axis1, axis2Size - (axis2Initial + axis2Move));
ctx.lineTo(axis1, axis2Size - (axis2Initial + length + axis2Move));
ctx.stroke();
ctx.closePath();
});
});
};
const run = () => {
if (!animator) {
return;
}
const { duration: { interval = 10 } } = animator.settings;
runningControl?.cancel();
runningControl = (0, animated_1.createAnimation)({
duration: interval,
easing: 'linear',
repeat: Infinity,
onUpdate: draw
});
};
const setup = () => {
if (typeof window !== 'undefined' && !resizeObserver) {
resizeObserver = new window.ResizeObserver(() => {
resize();
if (!animator) {
draw(1);
}
});
resizeObserver.observe(canvas);
resize();
}
};
const stop = () => {
resizeObserver?.disconnect();
resizeObserver = undefined;
transitionControl?.cancel();
transitionControl = undefined;
runningControl?.cancel();
runningControl = undefined;
};
const start = () => {
if (!animator) {
setup();
draw(1);
canvas.style.opacity = '1';
return;
}
unsubscribe = animator.subscribe((node) => {
switch (node.state) {
case 'entering': {
setup();
if (runningControl === undefined) {
run();
}
transitionControl = (0, animated_1.createAnimation)({
duration: node.settings.duration.enter,
onUpdate(progress) {
canvas.style.opacity = String(progress);
}
});
break;
}
case 'entered': {
setup();
if (runningControl === undefined) {
run();
}
canvas.style.opacity = '1';
break;
}
case 'exiting': {
transitionControl = (0, animated_1.createAnimation)({
duration: node.settings.duration.exit,
onUpdate(progress) {
canvas.style.opacity = String(1 - progress);
}
});
break;
}
case 'exited': {
stop();
canvas.style.opacity = '0';
break;
}
}
});
};
const cancel = () => {
unsubscribe?.();
stop();
canvas.style.opacity = '0';
};
start();
return Object.freeze({ cancel });
};
exports.createBackgroundMovingLines = createBackgroundMovingLines;