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) {
...