Photo: Tweak reveal animations and fix horizontal scroll

- Photo number doesn't jumps anymore (now reveals based on photo not the number)
- Properly reveal title locations lines
- Optimize code
This commit is contained in:
2020-04-06 12:14:48 +02:00
parent bd9b91f480
commit 60fdf02112
4 changed files with 67 additions and 50 deletions

View File

@@ -2,30 +2,40 @@ import anime from 'animejs'
import ScrollOut from 'scroll-out' import ScrollOut from 'scroll-out'
import imagesLoaded from 'imagesloaded' import imagesLoaded from 'imagesloaded'
import { throttle, parallaxAnime } from 'utils/functions' import { throttle, parallaxAnime } from 'utils/functions'
import { animDuration } from 'utils/store'
/* /*
** Transition In ** Transition In
*/ */
export const animateIn = scope => { export const animateIn = scope => {
// Title (reveal on scroll) const tlLocation = anime.timeline({
const titleReveal = ScrollOut({ easing: 'easeOutQuart',
duration: 1000,
autoplay: false
})
// Title
tlLocation.add({
targets: scope.querySelectorAll('.photo__location .line span'),
translateY: ['100%', 0],
delay: anime.stagger(120)
}, 200)
// Description
tlLocation.add({
targets: scope.querySelectorAll('.photo__location p'),
opacity: [0, 1],
duration: animDuration
}, 400)
// Reveal on scroll
const photoReveal = ScrollOut({
once: true, once: true,
targets: scope.querySelector('h2'), targets: scope,
onShown (el) { onShown: () => tlLocation.restart()
// Title reveal
anime({
targets: el.querySelectorAll('span'),
translateY: ['100%', 0],
easing: 'easeOutQuart',
duration: 1000,
delay: anime.stagger(120)
})
}
}) })
// Photo (reveal on scroll) // Image (reveal on scroll)
const photoImage = scope.querySelector('.photo__image') const photoImage = scope.querySelector('.photo__image')
const photoAnim = anime.timeline({ const photoAnim = anime.timeline({
easing: 'easeOutQuart', easing: 'easeOutQuart',
@@ -46,29 +56,30 @@ export const animateIn = scope => {
const photoReveal = ScrollOut({ const photoReveal = ScrollOut({
once: true, once: true,
targets: photoImage, targets: photoImage,
onShown: el => photoAnim.restart() onShown: () => photoAnim.restart()
}) })
}) })
// Number parallax on scroll // Number parallax on scroll
const nbParallaxMedia = window.matchMedia('(min-width: 768px)') const media768 = window.matchMedia('(min-width: 768px)')
const nbParallax = matchMedia => { const number = scope.querySelector('.photo__number')
const numberPallax = anime({
targets: number.querySelector('span'),
translateY: (window.innerWidth <= 768) ? ['0%', '20%'] : ['-20%', '20%'],
duration: 2000,
easing: 'linear',
autoplay: false
})
const numberPallaxScroll = matchMedia => {
if (matchMedia.matches) { if (matchMedia.matches) {
const scroll = ScrollOut({ const scroll = ScrollOut({
targets: scope.querySelector('.photo__number span'), targets: scope,
onShown (el) { onShown: (el) => {
const translate = anime({ window.addEventListener('scroll', throttle(() => parallaxAnime(el, numberPallax), 50))
targets: el, requestAnimationFrame(() => parallaxAnime(el, numberPallax))
translateY: (window.innerWidth <= 768) ? ['0%', '20%'] : ['-15%', '15%'],
duration: 2000,
easing: 'linear',
autoplay: false
})
window.addEventListener('scroll', throttle(() => parallaxAnime(el, translate), 50))
requestAnimationFrame(() => parallaxAnime(el, translate))
}, },
onHidden () { onHidden: () => {
if (parallaxAnime) window.removeEventListener('scroll', parallaxAnime) if (parallaxAnime) window.removeEventListener('scroll', parallaxAnime)
} }
}) })
@@ -76,6 +87,6 @@ export const animateIn = scope => {
} }
// Listen on screen size to run the function // Listen on screen size to run the function
nbParallaxMedia.addListener(nbParallax) media768.addListener(numberPallax)
nbParallax(nbParallaxMedia) numberPallaxScroll(media768)
} }

View File

@@ -37,8 +37,11 @@
<div class="photo__location wrap"> <div class="photo__location wrap">
<div class="wrapper"> <div class="wrapper">
<h2 class="title-location"> <h2 class="title-location">
<span>{name.split(', ')[0]},</span> {#each name.split(', ') as line, i}
<span>{name.split(', ')[1]}</span> <span class="line">
<span>{name.split(', ')[i]},</span>
</span>
{/each}
</h2> </h2>
<p class="style-caps">{location.region}, {location.country.name}</p> <p class="style-caps">{location.region}, {location.country.name}</p>
</div> </div>
@@ -48,20 +51,15 @@
<div class="align"> <div class="align">
<a href="/viewer/{location.country.slug}/{location.slug}/{photo.slug}" sapper-noscroll> <a href="/viewer/{location.country.slug}/{location.slug}/{photo.slug}" sapper-noscroll>
<picture class="photo__picture"> <picture class="photo__picture">
<source media="(min-width: 992px)" data-srcset={getThumbnail(private_hash, 1300)}> <source media="(min-width: 992px)" data-srcset={getThumbnail(private_hash, 1200)}>
<source media="(min-width: 768px)" data-srcset={getThumbnail(private_hash, 992)}> <source media="(min-width: 768px)" data-srcset={getThumbnail(private_hash, 992)}>
<source media="(min-width: 500px)" data-srcset={getThumbnail(private_hash, 650)}> <source media="(min-width: 500px)" data-srcset={getThumbnail(private_hash, 650)}>
<source media="(min-width: 300px)" data-srcset={getThumbnail(private_hash, 400)}> <source media="(min-width: 300px)" data-srcset={getThumbnail(private_hash, 400)}>
{#if layout === 'list'} <img src={layout === 'list' ? 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' : getThumbnail(private_hash, 900)}
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
alt={imgAlt}
width={defaultWidth} height={defaultHeight} width={defaultWidth} height={defaultHeight}
class="lazyload"> alt={imgAlt}
{:else} class:lazyload={layout === 'list'}
<img src="{getThumbnail(private_hash, 900)}" />
alt={imgAlt}
width={defaultWidth} height={defaultHeight}>
{/if}
</picture> </picture>
</a> </a>
<time class="photo__date" datetime={formatDate(date, 'DATETIME')}> <time class="photo__date" datetime={formatDate(date, 'DATETIME')}>

View File

@@ -15,13 +15,18 @@
h2 { h2 {
text-align: left; text-align: left;
overflow: hidden;
@include breakpoint (xs) { @include breakpoint (xs) {
font-size: rem(40px); font-size: rem(40px);
} }
}
.line {
overflow: hidden;
padding-bottom: 3px;
display: block;
span { span {
position: relative;
display: block; display: block;
will-change: transform; will-change: transform;
} }
@@ -29,6 +34,7 @@
p { p {
color: $color-lightgray; color: $color-lightgray;
margin-top: 16px; margin-top: 16px;
will-change: opacity;
} }
} }
@@ -143,6 +149,7 @@
user-select: none; user-select: none;
span { span {
position: relative;
display: block; display: block;
will-change: transform; will-change: transform;
} }

View File

@@ -53,15 +53,10 @@
.photo { .photo {
position: relative; position: relative;
z-index: 4; z-index: 4;
margin-bottom: 88px;
@include breakpoint (sm) {
margin-bottom: 120px;
}
// Last photo doesn't need spacing // Last photo doesn't need spacing
&:last-child { &:last-child {
margin-bottom: 0; padding-bottom: 0;
} }
} }
@@ -79,6 +74,12 @@
// Photo // Photo
.photo { .photo {
padding-bottom: 80px;
@include breakpoint (sm) {
padding-bottom: 120px;
}
// Even photos // Even photos
&:nth-child(even) { &:nth-child(even) {
@include breakpoint (sm) { @include breakpoint (sm) {