Re:ECO

svg circles animation test

by Grzegorz Matyszewski

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.1.1/gsap.min.js"></script>
<article id="re-eco">
    <section class="re-eco-section re-eco-section--yellow"></section>
    <section class="re-eco-section re-eco-section--green" id="re-hu-circles">
        <div class="re-eco-wrap">
            <svg id="re-eco-gfx-01" width="992px" height="484px" viewBox="0 0 992 484">
                <circle cx="250" cy="242" r="241"/>
                <circle cx="260" cy="242" r="241"/>
                <circle cx="270" cy="242" r="241"/>
                <circle cx="280" cy="242" r="241"/>
                <circle cx="290" cy="242" r="241"/>
                <circle cx="300" cy="242" r="241"/>
                <circle cx="310" cy="242" r="241"/>
                <circle cx="320" cy="242" r="241"/>
                <circle cx="330" cy="242" r="241"/>
                <circle cx="340" cy="242" r="241"/>
                <circle cx="350" cy="242" r="241"/>
                <circle cx="360" cy="242" r="241"/>
                <circle cx="370" cy="242" r="241"/>
                <circle cx="380" cy="242" r="241"/>
                <circle cx="390" cy="242" r="241"/>
                <circle cx="400" cy="242" r="241"/>
                <circle cx="410" cy="242" r="241"/>
                <circle cx="420" cy="242" r="241"/>
                <circle cx="430" cy="242" r="241"/>
                <circle cx="440" cy="242" r="241"/>
                <circle cx="450" cy="242" r="241"/>
                <circle cx="460" cy="242" r="241"/>
                <circle cx="470" cy="242" r="241"/>
                <circle cx="480" cy="242" r="241"/>
                <circle cx="490" cy="242" r="241"/>
                <circle cx="500" cy="242" r="241"/>
                <circle cx="510" cy="242" r="241"/>
                <circle cx="520" cy="242" r="241"/>
                <circle cx="530" cy="242" r="241"/>
                <circle cx="540" cy="242" r="241"/>
                <circle cx="550" cy="242" r="241"/>
       ...

CSS

body { margin: 0; }
*:focus { outline: none; }



.re-eco-section {
    color: white;
    font-family: 'Montserrat', sans-serif;
    height: 100vh;
    position: relative;
    width: 100%;
}

.re-eco-section--green { background: linear-gradient(143.54deg, #375725 0%, #608746 100%); }
.re-eco-section--yellow { background: #d0a215; }

.re-eco-wrap {
    align-items: center;
    display: flex;
    height: 100%;
    justify-content: center;
    width: 100%;
}

#re-eco-gfx-01 { overflow: visible; }

#re-eco-gfx-01 circle {
    fill: none;
    stroke-width: 0.25px;
}

JavaScript

function ReHuCircles(view) {
    this.circles = view.querySelectorAll('circle');
    this.amount = this.circles.length;
    this.offset = 0;
    this.visible = false;
    this.timeline = null;
    this.shift = 200;
    this.colors = {
        white: [255,255,255],
        green: [7,52,11],
    }
};


/** build loop animation timeline and hide */
ReHuCircles.prototype.init = function () {

    // build gsap timeline to control offset value:
    this.timeline = new gsap.timeline({
        paused: true,
        onUpdate: this.draw.bind(this),
    }).fromTo(this, { offset: 0 }, {
        offset: this.amount * 2,
        repeat: -1,
        duration: 5,
        ease: 'none'
    });

    // hide circles:
    this.toggle(1, true);
};


/** changing circles' stroke color due to offset value */
ReHuCircles.prototype.draw = function() {
    for (var i = 0; i < this.amount; i++) {
        var alpha = Math.cos((i - this.offset) / this.amount * Math.PI);
        var rgb = this.colors[(alpha > 0 ? 'white' : 'green')].join(',');
        var a = Math.abs(alpha);
        this.circles[i].style.stroke = `rgba(${rgb},${a})`;
    }
};


/** toggle visibility of circles */
ReHuCircles.prototype.toggle = function(state, quick) {
    this.visible = state === 0;
    if(!!this.visible) { this.timeline.play(); }
    gsap.to(this.circles, {
        duration: !quick ? 1 : 0,
        stagger: !quick ? 0.005 : 0,
        y: state * this.shift,
        opacity: 1 - Math.abs(state),
        ease: 'back.out(2)',
        onComplete: function() {
            if (!this.visible) {
                this.timeline.pause();
            }
        }.bind(this),
    });
};




// ============ INIT ============
var circles = new ReHuCircles(document.getElementById('re-hu-circles'));
circles.init();



/**
 * ============ SCROLL ============
 * test scrolling sections with toggling components
 */
var components = {'re-hu-circles': circles};
var onScroll = function(entries, observer) {
   ...