DEV Community

Cover image for how to make dynamic element center horizontally in react js?
Jackson Kasi
Jackson Kasi

Posted on

how to make dynamic element center horizontally in react js?

Hello Devs

I need one help! i am not a master in css. so i did something for my case. but this does not help full. here i try to explain my problem.

any one can help?

Live Code Demo

import "./styles.css";
import React, { useRef, useState, useEffect } from "react";
import styles from "styled-components";

const DotsWrapper = styles.div`
  display: flex;
  justify-content: center;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
`;

const Dot = styles.div`
  width: 50px;
  height: 50px;
  text-align: center;
  padding: 2rem;
  border-radius: 50%;
  background-color: ${({ isActive }) => (isActive ? "#fc916a" : "#436073")};
  transition: transform 0.3s, background-color 0.3s;
  transform: ${({ isActive, index, activeIndex, centerIndex }) => {
    const distanceFromCenter = index - centerIndex;
    const distanceFromActive = index - activeIndex;
    if (isActive) {
      return "scale(1.3)";
    } else if (distanceFromActive === 1) {
      return "translateX(25px)";
    } else if (distanceFromActive === -1) {
      return "translateX(-25px)";
    } else if (distanceFromCenter > 0) {
      return "translateX(50px)";
    } else if (distanceFromCenter < 0) {
      return "translateX(-50px)";
    } else {
      return "scale(1)";
    }
  }};
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
  font-size: 20px;
  margin: 0 10px;
`;

const CenterDot = styles(Dot)`
  transform: scale(1.3);
`;

export default function App() {
  const mobileContent = {
    page_blocks: [
      { info_date: "01-01-2002" },
      { info_date: "01-01-2003" },
      { info_date: "01-01-2004" },
      { info_date: "01-01-2005" },
      { info_date: "01-01-2006" },
      { info_date: "01-01-2007" }
    ]
  };

  const [activeIndex, setActiveIndex] = React.useState(0);
  const activeDot = React.useRef(null);

  const centerIndex = Math.floor(mobileContent.page_blocks.length / 2);
  const windowWidth = window.innerWidth;
  const centerPosition = windowWidth / 2;
  const [activePosition, setActivePosition] = React.useState(0);

  React.useEffect(() => {
    const activeDotPosition = activeDot.current.getBoundingClientRect();
    const activePosition =
      activeDotPosition.x + activeDotPosition.width / 2 - centerPosition;
    setActivePosition(activePosition);
  }, [windowWidth]);

  const result = centerPosition - activePosition;
  const translateX = result > 0 ? `${result}px` : `-${Math.abs(result)}px`;

  return (
    <React.Fragment>
      <div
        className="line"
        style={{
          position: "relative",
          width: "100%",
          overflowX: "hidden",
          height: "350px"
        }}
      >
        <br />
        <br />
        <br />
        windowWidth = {windowWidth}
        <br />
        centerPosition = {centerPosition}
        <br />
        activePosition = {activePosition}
        <br />
        result= {result}
        <br />
        {translateX}
        <br />
        <DotsWrapper style={{ transform: `translateX(${translateX})` }}>
          {mobileContent.page_blocks.map((item, index) =>
            index === activeIndex ? (
              <CenterDot
                key={index}
                isActive
                index={index}
                centerIndex={centerIndex}
                activeIndex={activeIndex}
                ref={activeDot}
              >
                {new Date(item.info_date).getFullYear()}
              </CenterDot>
            ) : (
              <Dot
                key={index}
                isActive={index === activeIndex}
                index={index}
                centerIndex={centerIndex}
                activeIndex={activeIndex}
                onClick={() => setActiveIndex(index)}
              >
                {new Date(item.info_date).getFullYear()}
              </Dot>
            )
          )}
        </DotsWrapper>
      </div>
    </React.Fragment>
  );
}


Enter fullscreen mode Exit fullscreen mode

this pic out put of code

the active circle needs to be always the center of windows horizontally.
and the remaining circles need to be auto align based on the active circle.

how to do this? i hope u will understand. anyone can please help me?

i try to explain here.

in this code above, the active dot circle will be in the center.
so what u need to do is,
current

1) get the total width of widows.
2) get the center of the total width position.
3) get the current position of active dot.

ex diagram.

|-------------------|-------------------|
1000px ( total width )

----active-dot-------------------------
250px

so,

we need to measure. how much space or px u need to move active dot for making it center?

(total width ) - ( center position ) - (active dot position )
ex 1:
result = 1000px - 500px - 500px = 250px

ex 2:
result = 1000px - 500px - 800px = -350px

so now
(active dot position ) + ( result )
ex 1:
250px + 250px = 500px
ex 2:
800px + ( - 300px ) = 500px

so using this calculation make an active dot position center ( use css translateX or any other )

and other not active dots will auto align

Top comments (4)

Collapse
 
longtngo profile image
Long Ngo

Would this work for you? code sandbox

It still has the problem of not staying in the middle when the window resizes.

Collapse
 
jacksonkasi profile image
Jackson Kasi

wow! thanks, man/bro 🙏

how did u fix that. ok i explore the code.

Collapse
 
longtngo profile image
Long Ngo • Edited

You had the right idea of using translate to push the DotContainer using middle calculation. But the main problem was that you are fighting the justify-content: center; which already trying to move the content to center already. So by removing it, the content Dots display locations are deterministic, always show up at 0px from left, and each dot has a size of 114px, and the gap between each dot is 10.

From there, you can calculate how far you want to push the container toward the middle of the screen. The farthest you want to push is window.innerWith / 2. As you increase the activeIndex, since it need to be in the middle, you need to reduce the translation value by its width and its gap 114 * activeIndex.

You should also need to account the bigger width of the active item 114 * 1.3. Hence the final calculation look like this:

const middleX = window.innerWidth / 2 - 114 * activeIndex - 114 * 1.3;

It probably not exact at the dead center of the screen. You might want to fine tune the calc a little bit. But the basic is that.

Hope this help.

Thread Thread
 
jacksonkasi profile image
Jackson Kasi

ohh! i got it thanks!