SVG Line Glow Animate
October 2023
import React, { useState, useEffect } from "react";const START_GRADIENT_POSITION = -130;const END_GRADIENT_POSITION = 210;const MAX_GRADIENT_Y = 216 - 80;const GRADIENT_MOVE_INTERVAL = 10;const GLOWING_LINE_HEIGHT = 81;const GLOW_COLOR = "#009688";type SVGLineGlowAnimateProps = {movementDelay?: number;id: number;additionalHeight?: number;initialGradientY?: number;};const SVGLineGlowAnimate: React.FC<SVGLineGlowAnimateProps> = ({movementDelay = 0,id,additionalHeight = 0,initialGradientY = 0,}) => {const svgHeight = 228 + additionalHeight;const [gradientPosition, setGradientPosition] = useState({y1: START_GRADIENT_POSITION,y2: END_GRADIENT_POSITION,});const [opacity, setOpacity] = useState(0);useEffect(() => {const totalDistance = svgHeight - GLOWING_LINE_HEIGHT;const halfDistance = totalDistance / 2;const moveGradient = () => {setGradientPosition((prev) => {const newY1 = prev.y1 + 1;const newY2 = prev.y2 + 1;const distanceTravelled = newY1 - START_GRADIENT_POSITION;let newOpacity = 0;if (distanceTravelled <= halfDistance) {newOpacity = distanceTravelled / halfDistance;} else {newOpacity = 1 - (distanceTravelled - halfDistance) / halfDistance;}setOpacity(newOpacity);if (newY1 > MAX_GRADIENT_Y - GLOWING_LINE_HEIGHT) {return {y1: START_GRADIENT_POSITION,y2: END_GRADIENT_POSITION,};}return {y1: newY1,y2: newY2,};});};const startTimeout = setTimeout(() => {const interval = setInterval(moveGradient, GRADIENT_MOVE_INTERVAL);return () => clearInterval(interval);}, movementDelay);return () => {clearTimeout(startTimeout);setOpacity(0);};}, [movementDelay]);return (<svgwidth="12"height={svgHeight}viewBox={`0 0 12 ${svgHeight}`}fill="none"xmlns="http://www.w3.org/2000/svg"><path id={`main-line-${id}`} d={`M6 ${svgHeight} L6 0`}></path><usehref={`#main-line-${id}`}opacity={opacity}stroke={`url(#gradient-glow-${id})`}strokeWidth="6"style={{filter: `blur(2px) drop-shadow(0px 0px 2px ${GLOW_COLOR})`,transition: `opacity ${GRADIENT_MOVE_INTERVAL}ms linear`,}}/><usehref={`#main-line-${id}`}stroke={`url(#gradient-solid-${id})`}strokeWidth="2"/><defs><linearGradientid={`gradient-glow-${id}`}x1="6"y1={gradientPosition.y1}x2="6"y2={gradientPosition.y2}gradientUnits="userSpaceOnUse"><stop offset="0.38" stopColor={GLOW_COLOR} stopOpacity="0"></stop><stop offset="0.5" stopColor={GLOW_COLOR} stopOpacity="0.8"></stop><stop offset="0.62" stopColor={GLOW_COLOR} stopOpacity="0"></stop></linearGradient><linearGradientid={`gradient-solid-${id}`}x1="6"y1={initialGradientY}x2="6"y2={svgHeight}gradientUnits="userSpaceOnUse"><stop stopColor={GLOW_COLOR} stopOpacity="0"></stop><stop offset="0.5" stopColor={GLOW_COLOR}></stop><stop offset="1" stopColor={GLOW_COLOR} stopOpacity="0"></stop></linearGradient></defs></svg>);};export const SVGLineGlowAnimateContainer = () => {return (<div className="flex"><SVGLineGlowAnimate movementDelay={0} id={1} initialGradientY={20} /><SVGLineGlowAnimate movementDelay={3000} id={2} additionalHeight={20} /><SVGLineGlowAnimate movementDelay={6000} id={3} initialGradientY={20} /></div>);};