Progress bar from bottom to top

Hello,

I have a client — a microbrewery — that is planning a fundraising campaign.
Ideally, they would like to display the donation progress using a bottle graphic that fills up as donations come in.

Unfortunately, I haven’t been able to replicate this effect successfully.
I then tried using the “Progress Bar,” but the animation only works from left to right or right to left. However, it would need to animate from bottom to top.

Is there any way to rotate the box via code?

Or do you have any suggestions on how I could recreate this effect using Velo code?
I am working with Wix Studio.

Thank you very much in advance.

Hi, @Kristina_Vogt !!

If you rotate the progress bar itself by -90 degrees or 270 degrees, it could at least give the impression of beer rising from the bottom to the top. :thinking:

There are a lot of possible solutions for your problem.

I will mention2…

  1. You can generate it with the usage of your repeater.
    Let’s say you generate a dATABASE including 1000-items, giving each item an INDEX-ID
    like → 1,2,3,4,5,6,7,8,9,…999,1000. You will call that FIELD → INDEX.
    Now you add a second column, calling it → PICS, where you will put an image of a
    bottle, but not the whole bottle instead you put to index-1 → a pic of 1/1000 of your
    bottle. Into second —> 2/10000, into third → 3/1000.

(So hast du dann jeweils 1 tausendstel deiner Flasche abgebildet.)

Running this trough a REPEATER with a speed of 1 sec per image-switch, you would see how your bottle grows up, or fills up, accordingly to the images you put into the database.

This was the very very easy way for none-coders.

  1. The second way would be → grab the HTML-Component and place it onto your page…
    a) Adding the following code into it…
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Canvas Bottle Fill</title>
  <style>
    body {
      background: #f0f0f0;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }
    canvas {
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <canvas id="bottleCanvas" width="200" height="500"></canvas>

  <script>
    const canvas = document.getElementById("bottleCanvas");
    const ctx = canvas.getContext("2d");

    const width = canvas.width;
    const height = canvas.height;

    let fillLevel = 0; // from 0 to 1

    function drawBottle() {
      ctx.clearRect(0, 0, width, height);

      // Draw bottle shape
      ctx.beginPath();
      ctx.moveTo(80, 50); // neck
      ctx.lineTo(80, 100);
      ctx.quadraticCurveTo(80, 110, 60, 130);
      ctx.lineTo(60, 450);
      ctx.quadraticCurveTo(100, 470, 140, 450);
      ctx.lineTo(140, 130);
      ctx.quadraticCurveTo(120, 110, 120, 100);
      ctx.lineTo(120, 50); // neck
      ctx.closePath();

      // Fill area based on fillLevel
      ctx.save();
      ctx.clip();

      const fillHeight = 450 - (fillLevel * 320); // area to fill
      ctx.fillStyle = "#00aaff";
      ctx.fillRect(60, fillHeight, 80, 500 - fillHeight);

      ctx.restore();

      // Draw bottle outline again
      ctx.beginPath();
      ctx.moveTo(80, 50);
      ctx.lineTo(80, 100);
      ctx.quadraticCurveTo(80, 110, 60, 130);
      ctx.lineTo(60, 450);
      ctx.quadraticCurveTo(100, 470, 140, 450);
      ctx.lineTo(140, 130);
      ctx.quadraticCurveTo(120, 110, 120, 100);
      ctx.lineTo(120, 50);
      ctx.closePath();
      ctx.strokeStyle = "#333";
      ctx.lineWidth = 2;
      ctx.stroke();
    }

    function animateFill() {
      if (fillLevel >= 1) return;
      fillLevel += 0.01;
      drawBottle();
    }

    drawBottle();
    setInterval(animateFill, 1000);
  </script>
</body>
</html>
b) SAVING the HTML-setup.
c) Publishing your website.
d) Open your pubblished website and take a look onto your result.

This is just an EXAMPLE, which will show you the animation. But you want to connect it later maybe to the data inside your database. If your DATABASE will be filled with new ITEMS → your CANVAS-BOTTLE will show the results in a nice VISUALIZATION. Of course you can use also some nice CSS for better design and style of your BOTTLE-ANIMATION. …

ANOTHER-VERSION…

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Stylish Bottle Fill Animation</title>
  <style>
    body {
      background: linear-gradient(to bottom, #e6f2ff, #cce6ff);
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      font-family: sans-serif;
    }

    canvas {
      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
      border-radius: 16px;
      background: #ffffff;
    }
  </style>
</head>
<body>
  <canvas id="bottleCanvas" width="200" height="500"></canvas>

  <script>
    const canvas = document.getElementById("bottleCanvas");
    const ctx = canvas.getContext("2d");
    const width = canvas.width;
    const height = canvas.height;

    let fillPercent = 0; // 0 to 1

    function drawBottle(fillPercent) {
      ctx.clearRect(0, 0, width, height);

      // Draw bottle path
      const path = new Path2D();
      path.moveTo(95, 30); // Neck start
      path.lineTo(95, 90); // Down neck
      path.bezierCurveTo(70, 120, 60, 150, 60, 400); // Left side
      path.bezierCurveTo(60, 440, 140, 440, 140, 400); // Base curve
      path.bezierCurveTo(140, 150, 130, 120, 105, 90); // Right side
      path.lineTo(105, 30); // Up neck
      path.quadraticCurveTo(105, 20, 95, 30); // Cap

      // Liquid fill
      ctx.save();
      ctx.clip(path);
      const liquidHeight = 400 - (fillPercent * 280);
      const grad = ctx.createLinearGradient(0, liquidHeight, 0, 450);
      grad.addColorStop(0, "#00bfff");
      grad.addColorStop(1, "#007acc");
      ctx.fillStyle = grad;
      ctx.fillRect(60, liquidHeight, 80, 450 - liquidHeight);
      ctx.restore();

      // Bottle outline
      ctx.strokeStyle = "#444";
      ctx.lineWidth = 2;
      ctx.stroke(path);

      // Glass highlight
      ctx.beginPath();
      ctx.moveTo(85, 100);
      ctx.bezierCurveTo(75, 180, 75, 320, 85, 390);
      ctx.strokeStyle = "rgba(255, 255, 255, 0.4)";
      ctx.lineWidth = 4;
      ctx.stroke();

      // Inner shadow
      const shadowGrad = ctx.createRadialGradient(100, 250, 10, 100, 250, 100);
      shadowGrad.addColorStop(0, "rgba(0, 0, 0, 0)");
      shadowGrad.addColorStop(1, "rgba(0, 0, 0, 0.2)");
      ctx.fillStyle = shadowGrad;
      ctx.fill(path);
    }

    drawBottle(fillPercent);

    function animateFill() {
      if (fillPercent >= 1) return;
      fillPercent += 0.01;
      drawBottle(fillPercent);
    }

    setInterval(animateFill, 1000);
  </script>
</body>
</html>

So all you have to do now, is to connect your HTML-Component with your Wix-Page or even DATABASE. :upside_down_face:

!!! PROST !!!

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>SVG Beer Mug Fill</title>
  <style>
    body {
      background: #f9f1db;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
    }
    svg {
      width: 200px;
      height: auto;
    }
  </style>
</head>
<body>

<svg viewBox="0 0 100 150" xmlns="http://www.w3.org/2000/svg">
  <!-- Define the clip path for the mug's interior -->
  <defs>
    <clipPath id="beerMask">
      <!-- Adjust this to match the inner fill area of the mug -->
      <rect id="fillRect" x="30" y="40" width="40" height="100" rx="5" />
    </clipPath>
  </defs>

  <!-- Beer fill (masked to mug shape) -->
  <g clip-path="url(#beerMask)">
    <rect id="beer" x="30" y="140" width="40" height="0" fill="#f6c32e" />
  </g>

  <!-- Mug outline -->
  <rect x="30" y="40" width="40" height="100" rx="5" fill="none" stroke="black" stroke-width="2"/>
  <!-- Handle -->
  <path d="M70 50 Q85 75 70 100" fill="none" stroke="black" stroke-width="5" stroke-linecap="round"/>
</svg>

<script>
  const beer = document.getElementById('beer');
  let fillLevel = 0;
  function animate() {
    if (fillLevel <= 100) {
      const height = fillLevel;
      beer.setAttribute('y', 140 - height);
      beer.setAttribute('height', height);
      fillLevel += 0.5;
      requestAnimationFrame(animate);
    }
  }
  animate();
</script>

</body>
</html>