hyunji an
hyunji an

Reputation: 31

how to scale clip-path with svg and container

I’m trying to create a water tank simulation in React. The idea is to use clip-path to restrict an animated wave to the shape of the tank icon (defined as an SVG path).

The SVG path renders correctly, but when I use it as a clip-path, the size of the clip-path doesn’t match the original SVG path. Instead, the wave appears misaligned or not clipped at all.

I tried adding clipPathUnits="objectBoundingBox", but this caused the clip-path to disappear entirely.

enter image description here

Here is my React component:

React Component:

import styles from "./WaterTankSmall.module.css";

const waterLevel = 50;

const WaterTankSmall = () => {
  return (
    <div className={styles.container}>
      {/* SVG */}
      <svg
        className={styles.svgIcon}
        xmlns="http://www.w3.org/2000/svg"
        xmlSpace="preserve"
        viewBox="0 0 66 82.5"
        preserveAspectRatio="xMidYMid meet"
      >
        <defs>
          <clipPath id="waterTankClip">
            <path d="M52.6 47V25H13.4v22.4h39.2V47zM13.5 23h39c-.6-5.5-4.8-9.9-10.1-10.9V3h1.9c.6 0 1-.4 1-1s-.4-1-1-1H21.7c-.6 0-1 .4-1 1s.4 1 1 1h1.7v9.2c-5.2 1.1-9.3 5.4-9.9 10.8zM25.4 3h14.9v9h-6.4V8.3h2.2c.6 0 1-.4 1-1s-.4-1-1-1h-6.5c-.6 0-1 .4-1 1s.4 1 1 1H32V12h-6.6V3zM52.4 49.4H13.6c1 5.1 5.2 9.1 10.4 9.9l-2.5 4.1c-.2.3-.2.7 0 1 .2.3.5.5.9.5h21.2c.4 0 .7-.2.9-.5.2-.3.2-.7 0-1l-2.5-4c5.2-.8 9.3-4.8 10.4-10z" />
          </clipPath>
        </defs>

        <path
          maskContentUnits="objectBoundingBox"
          d="M52.6 47V25H13.4v22.4h39.2V47zM13.5 23h39c-.6-5.5-4.8-9.9-10.1-10.9V3h1.9c.6 0 1-.4 1-1s-.4-1-1-1H21.7c-.6 0-1 .4-1 1s.4 1 1 1h1.7v9.2c-5.2 1.1-9.3 5.4-9.9 10.8zM25.4 3h14.9v9h-6.4V8.3h2.2c.6 0 1-.4 1-1s-.4-1-1-1h-6.5c-.6 0-1 .4-1 1s.4 1 1 1H32V12h-6.6V3zM52.4 49.4H13.6c1 5.1 5.2 9.1 10.4 9.9l-2.5 4.1c-.2.3-.2.7 0 1 .2.3.5.5.9.5h21.2c.4 0 .7-.2.9-.5.2-.3.2-.7 0-1l-2.5-4c5.2-.8 9.3-4.8 10.4-10z"
          className={styles.tankOutline}
        />
      </svg>

      {/* wave container*/}
      <div
        className={styles.waveContainer}
        style={{
          clipPath: "url(#waterTankClip)",
          WebkitClipPath: "url(#waterTankClip)", 
        }}
      >
        {[...Array(4)].map((_, i) => (
          <div
            key={i}
            className={`${styles.wave} ${styles[`wave${i + 1}`]}`}
            style={{
              height: `${waterLevel * 2}%`,
            }}
          ></div>
        ))}
        <div className={styles.waterLevelText}>{`${waterLevel}%`}</div>
      </div>
    </div>
  );
};

export default WaterTankSmall;

module.css below

  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #f0f8ff; 
}

#waterTankClip {
  width: 100px;
  height: 100px;
}

.svgIcon {
  width: 500px;
  height: 500px;
  fill: none;
  stroke-width: 1;
  stroke: #1e90ff;
}

.waveContainer {
  background-color: pink;
  width: 100%;
}


.wave {
  position: absolute;
  bottom: 0;
  /* left: -100%;
  width: 5000px; 
  height: 2500px; 
  background: linear-gradient(to bottom, #87ceeb, #1e90ff);
  clip-path: polygon(
    0% 50%,
    10% 45%,
    20% 50%,
    30% 55%,
    40% 50%,
    50% 45%,
    60% 50%,
    70% 55%,
    80% 50%,
    90% 45%,
    100% 50%,
    100% 100%,
    0% 100%
  );
  z-index: 0;
}

.wave1 {
  background: linear-gradient(to bottom, #87ceeb, #1e90ff);
  opacity: 0.7;
  animation: wave1-animation 6s infinite ease-in-out;
}

.wave2 {
  background: linear-gradient(
    to bottom,
    rgba(135, 206, 235, 0.5),
    rgba(30, 144, 255, 0.5)
  );
  opacity: 0.5;
  animation: wave2-animation 8s infinite ease-in-out;
}

.wave3 {
  background: linear-gradient(
    to bottom,
    rgba(135, 206, 235, 0.4),
    rgba(30, 144, 255, 0.4)
  );
  opacity: 0.3;
  animation: wave3-animation 10s infinite ease-in-out;
}

.wave4 {
  background: linear-gradient(
    to bottom,
    rgba(135, 206, 235, 0.6),
    rgba(30, 144, 255, 0.6)
  );
  opacity: 0.4;
  animation: wave4-animation 12s infinite ease-in-out;
}

/* Wave animation*/
@keyframes wave1-animation {
  0% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(-30%);
  }
  100% {
    transform: translateX(0);
  }
}

@keyframes wave2-animation {
  0% {
    transform: translateX(-25%);
  }
  50% {
    transform: translateX(25%);
  }
  100% {
    transform: translateX(-25%);
  }
}

@keyframes wave3-animation {
  0% {
    transform: translateX(-15%);
  }
  50% {
    transform: translateX(15%);
  }
  100% {
    transform: translateX(-15%);
  }
}

@keyframes wave4-animation {
  0% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(-20%);
  }
  100% {
    transform: translateX(0);
  }
}

What I’ve Tried: Adjusting the viewBox and preserveAspectRatio of the SVG. Adding/removing clipPathUnits="objectBoundingBox" or userSpaceOnUse. Ensuring the SVG dimensions and CSS dimensions match.

Upvotes: 3

Views: 50

Answers (0)

Related Questions