JavaScript
语言:
JaveScriptBabelCoffeeScript
确定
'use strict';
document.addEventListener("DOMContentLoaded", function() {
// Loop over DOM nodes
var forEach = function forEach(array, callback, scope) {
for (var i = 0, arrayLength = array.length; i < arrayLength; i++) {
callback.call(scope, i, array[i]); // passes back stuff we need
}
};
// Return random number between two values
var randomIntFromInterval = function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
};
// Return random float between two values
var randomFloatFromInterval = function randomFloatFromInterval(min, max) {
return (Math.random() * (max - min) + min).toFixed(4);
};
var points = 250; // Number of employees (would be brought in automatically from page)
var bigY = 0; // Placeholder for finding largest Y coordinate so we can make our wave tall enough for mousemove listeners
var $wave = document.querySelector('.Wave');
var bezierCurve = [{
x: 0,
y: 25
}, {
x: 350,
y: 25
}, {
x: 750,
y: 250
}, {
x: 1000,
y: 400
}, {
x: 1400,
y: 400
}];
var docfrag = document.createDocumentFragment();
$wave.timeline = new TimelineMax({
paused: true
});
var easing = Power0.easeNone;
var testEmployee = {
'name': 'Sammy The Shark',
'title': 'Mascot',
'avatar': '/assets/coolgirl.jpg'
};
for (var i = 0; i < points; i++) {
var scale = randomFloatFromInterval(0.35, 0.50);
var randomY;
// Random spread for y values on alternating even/odd "i" count
if (i % 2 === 0) {
randomY = randomIntFromInterval(0, 150);
} else {
randomY = randomIntFromInterval(170, 320);
}
if (randomY > bigY) {
bigY = randomY;
}
var point = document.createElement('div');
point.style.top = randomY + 'px';
point.style.opacity = 0;
point.classList.add('Employee');
point.id = 'Employee-' + i;
point.innerHTML = '
// Setup GSAP Timeline
point.waveTimeline = new TimelineMax({
paused: true
});
TweenMax.set(point.querySelector('.Employee-avatarCircle'), {
scale: scale
});
point.waveTimeline.to(point.querySelector('.Employee-avatarFill'), 0.25, {
opacity: 1
}).to(point.querySelector('.Employee-avatar'), 0.25, {
opacity: 1,
ease: easing
});
point.hoverTimeline = new TimelineMax({
paused: true
});
point.hoverTimeline.to(point.querySelector('.Employee-avatarCircle'), 0.20, {
scale: 1.25,
ease: easing
}, "hover").to(point.querySelector('.Employee-tooltip'), 0.15, {
delay: 0.15,
opacity: 1,
scale: 1,
ease: easing
}, "hover");
$wave.timeline.add(pathTimeline(point, i), 0);
docfrag.appendChild(point);
}
// Bezier path for each point
function pathTimeline(point, i) {
var tl = new TimelineMax({
repeat: -1,
repeatDelay: points * 0.35 - 24
});
tl.delay(i * 0.35).to(point, 1.5, {
opacity: 1,
ease: easing
}, 'path').to(point, 24, {
bezier: {
type: 'soft',
values: bezierCurve
},
ease: easing
}, 'path').to(point, 1.5, {
opacity: 0,
delay: 20,
ease: easing
}, 'path');
return tl;
}
$wave.appendChild(docfrag);
var containerHeight = bigY + 440 + 'px'; // extra `40` is to account for avatar size (CSS)
// Set height of containers
function setContainerHeight() {
// Set `.Wave` to height of tallest coordinate for proper spacing
$wave.parentNode.style.height = containerHeight;
$wave.style.height = containerHeight;
}
// Kick-off animation
function animationSequence() {
// Set timeline to start 20 seconds in so we have a wave shape already
$wave.timeline.time(20);
$wave.timeline.play();
// Set container height
setContainerHeight();
}
animationSequence();
var employees = $wave.querySelectorAll('.Employee');
// Pause timeline on mouseenter
$wave.addEventListener('mouseenter', function() {
TweenMax.to($wave.timeline, 1, {
timeScale: 0
});
}, false);
// Play timeline on mouseleave
$wave.addEventListener('mouseleave', function() {
TweenMax.to($wave.timeline, 1, {
timeScale: 1
});
// Make sure we set each employee tween back to the beginning
forEach(employees, function(index, value) {
value.waveTimeline.tweenTo(0);
});
}, false);
// Hover animation calls
forEach(employees, function(index, value) {
// Add mouseover event listeners for targeted GSAP hover animation
value.addEventListener('mouseenter', function(e) {
e.preventDefault();
value.waveTimeline.pause();
value.hoverTimeline.play();
}, false);
value.addEventListener('mouseleave', function(e) {
e.preventDefault();
value.waveTimeline.resume();
value.hoverTimeline.reverse();
}, false);
});
// Mousemove listener
var currX = -9999;
var lastX = 0;
var employeeHover = false;
$wave.addEventListener('mousemove', function(e) {
e.preventDefault();
currX = e.layerX - 16;
employeeHover = e.target.closest('.Employee') ? true : false;
//console.log(currX);
}, false);
function updateEmployees() {
// Make sure we're inside the wave
if (currX >= 0 && currX <= $wave.offsetWidth && lastX !== currX && !employeeHover) {
// Test each node's coordinates relevant to mouse X position
forEach(employees, function(index, value) {
var offset = value.getBoundingClientRect().left - $wave.getBoundingClientRect().left;
// Determine tweenTo() %
var distance = Math.abs(currX - offset);
// We're burning hot!
if (distance <= 90) {
value.waveTimeline.tweenTo(value.waveTimeline.duration());
}
// We're pretty close
else if (distance <= 180) {
var multiplier = (distance - 90) / 100;
value.waveTimeline.tweenTo(value.waveTimeline.duration() * multiplier);
}
// Nada
else {
value.waveTimeline.tweenTo(0);
}
});
// Update last X coordinate to ensure we don't check needlessly
lastX = currX;
}
requestAnimationFrame(updateEmployees);
}
updateEmployees();
});