lottie-react icon indicating copy to clipboard operation
lottie-react copied to clipboard

Help with playSegments

Open jordanlambrecht opened this issue 3 years ago • 7 comments

I'm trying to have my lottie animation play the first 23 frames, and then skip them when it loops back and restarts and play frames 24-95 indefinitely. I'm dumb and can't seem to figure out how to make this work. Example here of it implemented with react-lottie-player (I'm switching over because you're more active and cool)

Here's my code that isn't working:

function PageHeader_VariableHeight() {
  const playFrames = {
    segments: [
      [0, 23],
      [24, 95],
    ],
    forceFlag: false,
  }
  const LottieAnimation = () => {
    const [animationData, setAnimationData] = useState(undefined)
    useEffect(() => {
      import('@data/Patterns_Peach.json').then(setAnimationData)
    }, [])

    if (!animationData)
      return (<p> Loading</p>)
    return (
      <Lottie
        animationData={animationData}
        loop={true}
        playSegments={playFrames}
        autoplay={true}
        rendererSettings={{ preserveAspectRatio: 'xMidYMid slice' }}
        style={{ height: '100%' }}
      />
    )
  }
  return (
      <LottieAnimation />
  )
}
export default PageHeader_VariableHeight

jordanlambrecht avatar Jul 11 '22 17:07 jordanlambrecht

@Gamote Any ideas?

jordanlambrecht avatar Jul 27 '22 21:07 jordanlambrecht

@michax @mattvague @PatrickDesign Sorry for the pings, but this is pretty mission-critical for me

jordanlambrecht avatar Aug 08 '22 17:08 jordanlambrecht

In what way is it not working?

I'm assuming the fact that you're defining a react component within another react component and using dynamic imports doesn't cause the issue.

PatrickDesign avatar Aug 08 '22 19:08 PatrickDesign

@PatrickDesign Ha, I probably need to separate those components o.O The animation will play just fine. Everything works with no errors. The only issue is the segments part. It simply does not listen to the input and plays the whole animation straight through each loop.

jordanlambrecht avatar Aug 08 '22 19:08 jordanlambrecht

Could you use the onLoopComplete method to update your segment array to be the shortened one after the first loop? And use the initialSegment prop instead of playSegments.

Something like:

// Defined statically outside of any functions (to keep a stable reference https://lottiereact.com/#initialsegment)
const firstLoopSegment = [0, 23]
const secondLoopSegment = [24, 95]

...

const [activeSegment, setActiveSegment] = useState(firstLoopSegment)

const onLoopComplete = () => {
  setActiveSegment(secondLoopSegment)
}

...

<Lottie onLoopComplete={onLoopComplete} initialSegment={activeSegment} ... />

PatrickDesign avatar Aug 08 '22 19:08 PatrickDesign

Like this? Because no dice if so =/

import lottie from 'lottie-web'

interface LottieProps {
  animationData: any
  width: number
  height: number
  onLoopComplete: any
  initialSegment: any
}

const firstLoopSegment = [0, 23]
const secondLoopSegment = [24, 95]

const Lottie = ({ animationData }: LottieProps) => {
  const element = useRef<HTMLDivElement>(null)
  const lottieInstance = useRef<any>()

  useEffect(() => {
    if (element.current) {
      lottieInstance.current?.destroy()
      lottieInstance.current = lottie.loadAnimation({
        container: element.current,
        renderer: 'svg',
        loop: true,
        autoplay: true,

        rendererSettings: {
          preserveAspectRatio: 'xMidYMid slice',
        },
        animationData: animationData,
      })
    }
    return () => {
      lottieInstance.current?.destroy()
      lottieInstance.current = null
    }
  }, [animationData])

  return <div style={{ height: '100%', width: '100%' }} ref={element} />
}

const PageHeader_VariableHeight = ({ animationData }) => {
  const [activeSegment, setActiveSegment] = useState(firstLoopSegment)
  const onLoopComplete = () => {
    setActiveSegment(secondLoopSegment)
  }

  return (
    <Lottie
      animationData={animationData}
      width={100}
      height={100}
      onLoopComplete={onLoopComplete}
      initialSegment={activeSegment}
    />
  )
}
export default PageHeader_VariableHeight

jordanlambrecht avatar Aug 08 '22 21:08 jordanlambrecht

AHA! I got it!

import lottie from 'lottie-web'

interface LottieProps {
  animationData: any
  width: number
  height: number
}

const Lottie = ({ animationData }: LottieProps) => {
  const element = useRef<HTMLDivElement>(null)
  const lottieInstance = useRef<any>()

  useEffect(() => {
    if (element.current) {
      lottieInstance.current?.destroy()
      lottieInstance.current = lottie.loadAnimation({
        container: element.current,
        renderer: 'svg',
        loop: true,
        // autoplay: true,

        rendererSettings: {
          preserveAspectRatio: 'xMidYMid slice',
        },
        animationData: animationData,
      })
    }
    lottieInstance.current.playSegments(
      [
        [0, 23],
        [24, 95],
      ],
      true,
    )
    return () => {
      lottieInstance.current?.destroy()
      lottieInstance.current = null
    }
  }, [animationData])

  return <div style={{ height: '100%', width: '100%' }} ref={element} />
}

const PageHeader_VariableHeight = ({ animationData }) => {
  return <Lottie animationData={animationData} width={100} height={100} />
}
export default PageHeader_VariableHeight

jordanlambrecht avatar Aug 08 '22 21:08 jordanlambrecht