UNPKG

lightswind

Version:

A collection of beautifully crafted React Components, Blocks & Templates for Modern Developers. Create stunning web applications effortlessly by using our 160+ professional and animated react components.

173 lines 7.84 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const DotGridBackground = ({ cols = 20, dotSize = 12, dotSpacing = 3.6, dotColor, backgroundColor = "transparent", scaleFactor = 6, inertiaDamping = 0.92, inertia = true, minScale = 0.04, className = "", children, }) => { const wrapperRef = (0, react_1.useRef)(null); const canvasRef = (0, react_1.useRef)(null); (0, react_1.useEffect)(() => { const canvas = canvasRef.current; const wrapper = wrapperRef.current; if (!canvas || !wrapper) return; const ctx = canvas.getContext("2d"); if (!ctx) return; const cellSize = dotSize * dotSpacing; // Grid must be at least 3× the container in BOTH axes for full drag range const MULTIPLIER = 3; // Resolve foreground color once per resize to avoid computedStyle overhead in draw loop let resolvedDotColor = dotColor || "#ffffff"; // Compute dots based on measured container size let dots = new Float32Array(0); let gridW = 0; let gridH = 0; const buildGrid = (wW, wH) => { const totalCols = Math.ceil((wW * MULTIPLIER) / cellSize) + 2; const totalRows = Math.ceil((wH * MULTIPLIER) / (cellSize * 0.866)) + 2; gridW = totalCols * cellSize + cellSize; gridH = totalRows * cellSize * 0.866 + cellSize; dots = new Float32Array(totalCols * totalRows * 2); let di = 0; for (let r = 0; r < totalRows; r++) { for (let c = 0; c < totalCols; c++) { dots[di++] = c * cellSize + (r % 2 ? cellSize * 0.5 : 0) + cellSize * 0.5; dots[di++] = r * cellSize * 0.866 + cellSize * 0.5; } } }; // Grid state const gridPos = { x: 0, y: 0 }; const velocity = { x: 0, y: 0 }; let isDragging = false; let dragStart = { mouseX: 0, mouseY: 0, gridX: 0, gridY: 0 }; let lastMouse = { x: 0, y: 0 }; let animId = 0; /** Clamp so the grid always covers the full container in X and Y */ const clamp = (x, y) => { const wW = wrapper.clientWidth; const wH = wrapper.clientHeight; return { x: Math.min(0, Math.max(wW - gridW, x)), y: Math.min(0, Math.max(wH - gridH, y)), }; }; const draw = () => { const { width, height } = canvas; ctx.clearRect(0, 0, width, height); if (backgroundColor && backgroundColor !== "transparent") { ctx.fillStyle = backgroundColor; ctx.fillRect(0, 0, width, height); } const cx = width / 2; const cy = height / 2; const maxDist = Math.hypot(cx, cy) * 1.15; const gx = gridPos.x; const gy = gridPos.y; const halfDot = dotSize * 0.5; const margin = dotSize * 6; ctx.fillStyle = resolvedDotColor; for (let i = 0; i < dots.length; i += 2) { const sx = dots[i] + gx; const sy = dots[i + 1] + gy; if (sx < -margin || sx > width + margin) continue; if (sy < -margin || sy > height + margin) continue; const dx = sx - cx; const dy = sy - cy; const dist = Math.sqrt(dx * dx + dy * dy); const scale = Math.max(minScale, (1.05 - dist / maxDist) ** scaleFactor); if (scale < 0.005) continue; ctx.beginPath(); ctx.arc(sx, sy, halfDot * scale, 0, 6.2832); ctx.fill(); } }; const updateColorAndDraw = () => { if (!dotColor) { resolvedDotColor = getComputedStyle(wrapper).color || "#ffffff"; } else { resolvedDotColor = dotColor; } draw(); }; const resize = () => { const wW = wrapper.clientWidth; const wH = wrapper.clientHeight; canvas.width = wW; canvas.height = wH; buildGrid(wW, wH); const c = clamp((wW - gridW) / 2, (wH - gridH) / 2); gridPos.x = c.x; gridPos.y = c.y; updateColorAndDraw(); }; // Watch for theme changes (dark/light mode toggle on html element) const observer = new MutationObserver(() => updateColorAndDraw()); observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "style"] }); // Inertia loop const tick = () => { if (!isDragging && inertia) { const speed = Math.abs(velocity.x) + Math.abs(velocity.y); if (speed > 0.05) { velocity.x *= inertiaDamping; velocity.y *= inertiaDamping; const c = clamp(gridPos.x + velocity.x, gridPos.y + velocity.y); gridPos.x = c.x; gridPos.y = c.y; draw(); } } animId = requestAnimationFrame(tick); }; animId = requestAnimationFrame(tick); // Pointer handlers const onDown = (e) => { isDragging = true; velocity.x = 0; velocity.y = 0; dragStart = { mouseX: e.clientX, mouseY: e.clientY, gridX: gridPos.x, gridY: gridPos.y }; lastMouse = { x: e.clientX, y: e.clientY }; wrapper.style.cursor = "grabbing"; wrapper.setPointerCapture(e.pointerId); }; const onMove = (e) => { if (!isDragging) return; // Track velocity in BOTH axes for any-angle drag velocity.x = e.clientX - lastMouse.x; velocity.y = e.clientY - lastMouse.y; lastMouse = { x: e.clientX, y: e.clientY }; const c = clamp(dragStart.gridX + e.clientX - dragStart.mouseX, dragStart.gridY + e.clientY - dragStart.mouseY); gridPos.x = c.x; gridPos.y = c.y; draw(); }; const onUp = () => { isDragging = false; wrapper.style.cursor = "grab"; }; wrapper.addEventListener("pointerdown", onDown); wrapper.addEventListener("pointermove", onMove); wrapper.addEventListener("pointerup", onUp); wrapper.addEventListener("pointercancel", onUp); window.addEventListener("resize", resize); resize(); return () => { cancelAnimationFrame(animId); observer.disconnect(); wrapper.removeEventListener("pointerdown", onDown); wrapper.removeEventListener("pointermove", onMove); wrapper.removeEventListener("pointerup", onUp); wrapper.removeEventListener("pointercancel", onUp); window.removeEventListener("resize", resize); }; }, [cols, dotSize, dotSpacing, dotColor, backgroundColor, scaleFactor, inertiaDamping, inertia, minScale]); return ((0, jsx_runtime_1.jsxs)("div", { ref: wrapperRef, className: `relative w-full h-full overflow-hidden cursor-grab select-none ${className}`, children: [(0, jsx_runtime_1.jsx)("canvas", { ref: canvasRef, className: "absolute inset-0 block w-full h-full" }), children && ((0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 z-10 pointer-events-none", children: children }))] })); }; exports.default = DotGridBackground; //# sourceMappingURL=dot-grid-background.js.map