Vebego Component Library

Counter

<div class="mol-counter">
    <div class="counter-item">
        <div class="number">

            <span class="count-number">86</span>

        </div>
        <div class="text">medewerkers</div>
    </div>
    <span class="atm-slash  " style="width: 1px; height: 30px;"></span>
    <div class="counter-item">
        <div class="number">
            +
            <span class="count-number">245</span>

        </div>
        <div class="text">tevreden klanten</div>
    </div>
    <span class="atm-slash  " style="width: 1px; height: 30px;"></span>
    <div class="counter-item">
        <div class="number">

            <span class="count-number">100</span>
            %
        </div>
        <div class="text">aandacht voor jou</div>
    </div>
    <span class="atm-slash  " style="width: 1px; height: 30px;"></span>
</div>
<div class="mol-counter">
    {{#each items}}
    <div class="counter-item">
        {{#if number}}
        <div class="number">
            {{#if character-before}}{{character-before}}{{/if}}
            <span class="count-number">{{number}}</span>
            {{#if character-after}}{{character-after}}{{/if}}
        </div>
        {{/if}}
        {{#if text}}
        <div class="text">{{text}}</div>
        {{/if}}
    </div>
    {{render '@slash'}}
    {{/each}}
</div>
{
  "items": [
    {
      "text": "medewerkers",
      "number": "86"
    },
    {
      "text": "tevreden klanten",
      "number": "245",
      "character-before": "+"
    },
    {
      "text": "aandacht voor jou",
      "number": "100",
      "character-after": "%"
    }
  ]
}
  • Content:
    .mol-counter {
      @apply flex justify-between items-center;
    
      .counter-item {
        @apply relative;
        @apply text-center;
    
        .number {
          @apply text-h2;
          @apply font-medium;
          @apply text-black;
          @apply whitespace-nowrap;
        }
    
        .text {
          @apply px-4;
        }
      }
    
      .atm-slash {
        @apply block;
      }
    
      .atm-slash:nth-child(4),
      .counter-item:nth-child(5) {
        @apply hidden md:block;
      }
    
      .atm-slash:nth-child(6) {
        @apply hidden;
      }
    }
    
  • URL: /components/raw/counter/counter.css
  • Filesystem Path: src\components\03-molecules\counter\counter.css
  • Size: 506 Bytes
  • Content:
    const COUNTER_ANIMATION_LENGTH = 4000;
    const COUNTER_SELECTOR = ".mol-counter .count-number";
    let counterElements;
    
    window.addEventListener("load", () => {
        const observer = new IntersectionObserver(function (entries) {
            if (entries.some(entry => entry.intersectionRatio >= 0.9 && entry.target.dataset.started === undefined)) {
                entries.forEach(el => {
                    if (el.intersectionRatio >= 0.9 && el.target.dataset.started === undefined) {
                        el.target.dataset.started = true;
                    }
                });
                window.requestAnimationFrame(drawFrame);
            }
        }, { threshold: 0.9 });
    
        counterElements = document.querySelectorAll(COUNTER_SELECTOR);
        counterElements.forEach(el => observer.observe(el));
    }, false);
    
    function drawFrame(timestamp) {
        let runAgain = false;
    
        for (let element of counterElements) {
            if (element.dataset.started === undefined) continue;
    
            let start = element.dataset.start;
            let previousTimeStamp = element.dataset.previousTimeStamp;
    
            if (start === undefined) {
                start = timestamp;
                element.dataset.start = timestamp;
                element.dataset.maxCount = element.innerHTML;
    
                runAgain = true;
            }
    
            let maxCount = parseInt(element.dataset.maxCount);
            const elapsed = timestamp - start;
    
            if (previousTimeStamp !== timestamp) {
                const absoluteProgress = Math.min(elapsed / COUNTER_ANIMATION_LENGTH, 1);
                const easedProgress = easeOutQuint(absoluteProgress);
                element.innerHTML = Math.round(maxCount * easedProgress);
    
                if (elapsed <= COUNTER_ANIMATION_LENGTH) {
                    runAgain = true;
                }
            }
    
            if (elapsed < COUNTER_ANIMATION_LENGTH) {
                element.dataset.previousTimeStamp = timestamp;
            }
        }
    
        if (runAgain) {
            window.requestAnimationFrame(drawFrame);
        }
    }
    
    // https://easings.net
    function easeOutQuint(x) {
        return x === 1 ? 1 : 1 - Math.pow(1 - x, 5);
    }
    
  • URL: /components/raw/counter/counter.js
  • Filesystem Path: src\components\03-molecules\counter\counter.js
  • Size: 2.1 KB

No notes defined.