UNPKG

@arwes/bgs

Version:

Futuristic Sci-Fi UI Web Framework

178 lines (177 loc) 6.47 kB
"use strict"; 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;