How to add animate to the alphabets inside a react carousal?

Viewed 266

I'm trying to do a carousal like in this CodePen using React Hooks.

My present result is in this Sandbox: Click..!

The problems I'm facing are:

  1. I don't know how to make that CSS animation effect of the letters coming and forming the text and scattering back as in the CodePen example.
  2. I want to include the description part also which is in the description={data.desc}. Do I have to make the split again or any easy method to split both title and description together. I lag knowledge here.

My code is as below:

import React from "react";

export default function SlideCard(props) {
  const { id, idx, title } = props;

  function mainText() {
    return (
      <div style={{ border: "2px solid gold" }}>
        <h1>{title}</h1>
      </div>
    );
  }
  //console.log(id);
  function scatter() {
    return (
      <div>
        {title.split("").map((item, index) => {
          const style = {
            position: "absolute",
            top: Math.floor(Math.random() * 200) + "px",
            left: Math.floor(Math.random() * 400) + "px",
            zIndex: "initial",
            color: "#AAA",
            overflow: "hidden",
            transition: "left 2s, top 2s, color 2s"
          };

          return (
            <div key={index}>
              <div className="scatter" style={style}>
                {item}
              </div>
            </div>
          );
        })}
      </div>
    );
  }

  return (
    <div>
      <div>{idx === id && mainText()}</div>
      {idx !== id && scatter()}
    </div>
  );
}
2 Answers

He's maintaining two same copies of each page data. One with class .position-data and one with .mutable. .position-data is hidden and only used for getting coordinates to bring back .mutable letters together.
Here is the simplified version of the CodePen example:

$(document).ready(function() {
  assemble();
});

function scatter() {
  for (var i = 0; i < 3; i++) {
    var randLeft = Math.floor(Math.random() * $(window).width());
    var randTop = Math.floor(Math.random() * $(window).height());
    //randomly position .mutable elements
    $(".mutable > span:eq(" + i + ")").animate({
      left: randLeft,
      top: randTop,
      color: "#0005"
    }, 2000, "easeInBack");
  }
}

function assemble() {
  for (var i = 0; i < 3; i++) {
    $(".mutable > span:eq(" + i + ")").animate({
      //get center position from .position data marked elements
      left: $(".position-data > span:eq(" + i + ")").offset().left + "px",
      top: $(".position-data > span:eq(" + i + ")").offset().top + "px",
      color: "#000"
    }, 2000, 'easeOutBounce');
  }
}
span {
  font-size: 30px;
}

.position-data {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  opacity: 0.4;
  color: green;
}

.mutable span {
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="position-data">
  <span>a</span>
  <span>b</span>
  <span>c</span>
</div>
<div class="mutable shadowed">
  <span>a</span>
  <span>b</span>
  <span>c</span>
</div>
<button onclick="scatter()">Scatter</button>
<button onclick="assemble()">Assemble</button>

I want to position the actively displaying Text container to the centre of the carousal.

The actively displaying text container is marked with .mutable class which has following css:

    .mutable {
      position: absolute;
      overflow: hidden;
      display: inline-block;
    
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
    }

So they all have full size of the document body. Using javascript function arrangeCurrentPage() in codepen they are set with coordinates such that they look centered.

I don't know how to make that transition effect of the letters coming and forming the text and scattering back as in the CodePen example.

Refer to above simplified code. Use the buttons to see the effects separately. All letter elements are put in a div with class .mutable. All letters are position: absolute; so they are free to move anywhere. In javascript function scatter() I am simply assigning top and left properties to random coordinates. With animation effect they scatter smoothly. In codepen he is achieving the animation effect using css transition transition: left 2s, top 2s, color 2s;
To bring them back simply us css selector nth-child .position-data > span:eq(n) to get corresponding coordinates of the character. Refer javascript function assemble().

I want to include the description part also which is in the description={data.desc}. Do I have to make the split again or any easy method to split both title and description together. I lag knowledge here.

As title and description will be displayed separately with separate presentation styles. Code will be cleaner if you keep split versions of them separately. You can create utility methods like split(text), scramble(array), arrange(array)and use it for both like cramble(titleArray)and scramble(descArray).




If we use 'position:relative' on letters we don't have to maintain two copies of same data:

<!DOCTYPE html>

<head>
  <title>Document</title>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

  <script>
    $(document).ready(function() {
      assemble();
    });

    function randomX() {
      return Math.floor(Math.random() * $(window).width() * 0.7) - $(window).width() * 0.25;
    }

    function randomY() {
      return Math.floor(Math.random() * $(window).height() * 0.7) - $(window).height() * 0.25;
    }

    function scatter() {
      for (var i = 0; i < 3; i++) {
        $(".mutable > span:eq(" + i + ")").animate({
          left: randomX(),
          top: randomY(),
          color: "#f118"
        }, 2000, "easeInBack");
      }
    }

    function assemble() {
      for (var i = 0; i < 3; i++) {
        $(".mutable > span:eq(" + i + ")").animate({
          left: '0px',
          top: '0px',
          color: "#000"
        }, 2000, 'easeOutBounce');
      }
    }
  </script>
  <style>
    span {
      font-size: 30px;
    }
    
    .mutable {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    .mutable span {
      position: relative;  /* <--- */
    }
  </style>

</head>

<body>
  <div class="mutable">
    <span>a</span>
    <span>b</span>
    <span>c</span>
  </div>
  <button onclick="scatter()">Scatter</button>
  <button onclick="assemble()">Assemble</button>
</body>

</html>

The sandbox demo you want to emulate is using an animation they call Alphabet Soup. After a quick google search, I found an npm package that can help you implement this in your react component: https://github.com/OrigenStudio/react-alphabet-soup.

Why reinvent the wheel?

Related