UNPKG

@immutabl3/anime

Version:
410 lines (361 loc) 11.5 kB
<!DOCTYPE html> <html> <head> <title>time control • anime.js</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta property="og:title" content="anime.js"> <meta property="og:url" content="https://animejs.com"> <meta property="og:description" content="Javascript Animation Engine"> <meta property="og:image" content="https://animejs.com/documentation/assets/img/icons/og.png"> <meta name="twitter:card" content="summary"> <meta name="twitter:title" content="anime.js"> <meta name="twitter:site" content="@juliangarnier"> <meta name="twitter:description" content="Javascript Animation Engine"> <meta name="twitter:image" content="https://animejs.com/documentation/assets/img/icons/twitter.png"> <link rel="apple-touch-icon-precomposed" href="../assets/img/social-media-image.png"> <link rel="icon" type="image/png" href="../assets/img/favicon.png" > <link href="../assets/css/animejs.css" rel="stylesheet"> <style> :root { font-size: 24px; } body { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; } .feature-section { position: relative; display: flex; } .feature-section-center { flex-direction: column; align-items: center; text-align: center; } .section-title { font-size: 64px; line-height: 56px; letter-spacing: 0; margin-bottom: 1rem; } .section-title span { display: inline-block; } .section-description { font-size: 24px; line-height: 32px; letter-spacing: 0; margin-bottom: 3rem; } .feature-anim { position: relative; display: flex; flex-wrap: wrap; align-items: center; } .time-control { height: 12rem; } .time-control .ruller { position: absolute; top: 0; display: flex; width: calc(34rem + 4px); padding: 0 1px; } .time-control .line { width: 2px; height: .5rem; background-color: currentColor; } .time-control .line:nth-child(9n+2) { height: 1rem; } .time-control .line:not(:last-child) { margin-right: 4px; } .time-cursor { position: absolute; z-index: 1; top: -1.125rem; left: calc(-1rem + 2px); width: 2rem; height: 2rem; background-color: currentColor; border-radius: 50%; } .time-cursor input { position: relative; z-index: 1; width: 2rem; height: 2rem; color: #FFF; background-color: transparent; border-radius: 50%; text-align: center; font-size: .5rem; } .time-cursor:before { content: ""; position: absolute; top: 0; left: calc(1rem - 1px); display: block; width: 2px; height: 12.125rem; background-color: #F64E4D; } .timeline { position: relative; z-index: 1; overflow: visible; display: flex; width: 100%; height: 8px; font-size: .75rem; } .animation { position: relative; overflow: visible; display: flex; } .animation-band { position: relative; height: 8px; margin: 0 1px; border-radius: 4px; } .animation-delay { background-color: currentColor; width: 48px; } .animation-change { background-color: #F64E4D; width: 156px; } .animation-end-delay { border: 2px solid currentColor; width: 48px; } .info { position: relative; display: flex; flex-direction: column; width: 2px; height: 2rem; margin: 0 1px; } .info + .info { margin-left: -3px; } .info-large { height: 4rem; } .info-top { bottom: 0; justify-content: flex-start; align-items: flex-end; align-self: flex-end; } .info-bottom { top: 0; justify-content: flex-end; } .info-bar { position: absolute; width: 2px; height: 100%; background-color: currentColor; transform-origin: 50% 100%; } .info-top .info-bar { bottom: 0; } .info-bottom .info-bar { top: 0; transform-origin: 50% 0%; } .info-left .info-bar { left: 0; } .info-right .info-bar { right: 0; } .info-label { white-space: nowrap; height: 1rem; padding-left: .5rem; padding-right: .5rem; line-height: 1rem; } .info-top .info-label { margin: -4px 0 0; } .info-bottom .info-label { margin: 0 0 -4px 0; } </style> </head> <body> <section class="feature-section feature-section-center feature-control" style="margin-top: 1000px; margin-bottom: 1000px;"> <h1 class="section-title"> <span>Time</span> <span>control</span> <span>& callbacks</span> </h1> <p class="section-description"> Play, pause, control, reverse and trigger events in sync </p> <div class="time-control feature-anim"> <div class="ruller"> <div class="time-cursor color-red"> <input value="999" /> </div> </div> <div class="timeline"> <div class="info-loop-begin info info-large info-left info-bottom" data-delay="0"> <div class="info-bar"></div> <div class="info-label">loop begin</div> <div class="info-label">animation begin</div> </div> <div class="animation"> <div class="animation-band animation-delay"></div> <div class="info-change-begin info info-left info-bottom" data-delay="100"> <div class="info-bar"></div> <div class="info-label">change begin</div> </div> <div class="animation-band animation-change"></div> <div class="info-change-complete info info-right info-top" data-delay="400"> <div class="info-bar"></div> <div class="info-label">change complete</div> </div> <div class="animation-band animation-end-delay"></div> </div> <div class="info-loop-complete info info-large info-right info-top" data-delay="500"> <div class="info-bar"></div> <div class="info-label">loop complete</div> </div> <div class="info info-large info-left info-bottom" data-delay="500"> <div class="info-bar"></div> <div class="info-label">loop begin</div> <div class="info-label">reverse</div> </div> <div class="animation"> <div class="animation-band animation-delay"></div> <div class="info-change-begin info info-left info-bottom" data-delay="600"> <div class="info-bar"></div> <div class="info-label">change begin</div> </div> <div class="animation-band animation-change"></div> <div class="info-change-complete info info-right info-top" data-delay="900"> <div class="info-bar"></div> <div class="info-label">change complete</div> </div> <div class="animation-band animation-end-delay"></div> </div> <div class="info-loop-complete info info-large info-right info-top" data-delay="1000"> <div class="info-bar"></div> <div class="info-label">loop complete</div> </div> <div class="info info-large info-left info-bottom" data-delay="1000"> <div class="info-bar"></div> <div class="info-label">loop begin</div> <div class="info-label">reverse</div> </div> <div class="animation"> <div class="animation-band animation-delay"></div> <div class="info-change-begin info info-left info-bottom" data-delay="1100"> <div class="info-bar"></div> <div class="info-label">change begin</div> </div> <div class="animation-band animation-change"></div> <div class="info-change-complete info info-right info-top" data-delay="1400"> <div class="info-bar"></div> <div class="info-label">change complete</div> </div> <div class="animation-band animation-end-delay"></div> </div> <div class="info-loop-complete info info-large info-right info-top" data-delay="1500"> <div class="info-bar"></div> <div class="info-label">animation complete</div> <div class="info-label">loop complete</div> </div> </div> </div> </section> </body> <script type="module"> import anime from '../../src/index.js'; const timeControlEl = document.querySelector('.time-control'); const rullerEl = document.querySelector('.ruller'); const timeEl = document.querySelector('.time-cursor input'); const infoEls = document.querySelectorAll('.info'); const fragment = document.createDocumentFragment(); const numberOfElements = 136; function isElementInViewport(el, inCB, outCB) { function handleIntersect(entries, observer) { var entry = entries[0]; if (entry.isIntersecting) { if (inCB) inCB(el, entry); } else { if (outCB) outCB(el, entry); } } var observer = new IntersectionObserver(handleIntersect); observer.observe(el); } for (let i = 0; i < numberOfElements; i++) { const dotEl = document.createElement('div'); dotEl.classList.add('line'); fragment.appendChild(dotEl); } rullerEl.appendChild(fragment); const timeControlAnimation = anime.timeline({ easing: 'linear', autoplay: false }) .add({ targets: '.time-cursor', keyframes: [ { translateY: ['-1rem', 0], duration: 100, easing: 'easeInQuad' }, { translateX: 'calc(34rem - 6px)', duration: 1500 }, { translateY: '-1rem', duration: 100, easing: 'easeOutQuad' } ], duration: 1500, update: function(anim) { timeEl.value = anim.currentTime; } }, -100) .add({ targets: '.ruller .line', translateY: [ {value: '1rem'}, {value: '0rem'} ], duration: 200, delay: anime.stagger([0, 1500]), easing: 'easeInOutSine' }, -100) for (var i = 0; i < infoEls.length; i++) { var infoEl = infoEls[i]; var delay = parseFloat(anime.get(infoEl, 'data-delay')); var direction = infoEl.classList.contains('info-bottom') ? -1 : 1; timeControlAnimation .add({ targets: infoEl.querySelector('.info-bar'), scaleY: [0, 1], duration: 250, easing: 'easeOutCirc' }, delay) .add({ targets: infoEl.querySelectorAll('.info-label'), opacity: [0, 1], translateY: [direction * 10, 0], duration: 150, delay: anime.stagger(50, {start: 10, direction: direction > 0 ? 'reverse' : 'normal'}), easing: 'easeOutSine' }, delay) } var controlAnimationCanMove = false; function moveControlAnimation() { var rect = timeControlEl.getBoundingClientRect(); var top = rect.top; var height = rect.height; var windowHeight = window.innerHeight; var scrolled = (top - windowHeight) * -1; timeControlAnimation.seek((scrolled * 3) - 500); if (controlAnimationCanMove) requestAnimationFrame(moveControlAnimation); } isElementInViewport(timeControlEl, function(el, entry) { controlAnimationCanMove = true; requestAnimationFrame(moveControlAnimation); }, function(el, entry) { controlAnimationCanMove = false; }); </script> </html>