Skip to content

Commit

Permalink
Merge pull request #73 from fightforthefuture/parallax
Browse files Browse the repository at this point in the history
parallax element
  • Loading branch information
kenmickles authored Nov 17, 2020
2 parents 694c871 + 3ef9616 commit fa010f6
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 2 deletions.
210 changes: 210 additions & 0 deletions assets/js/parallax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
let listening = false
let targets = []

const defaultOptions = {
speed: 0.3,
grayscale: false,
mobilePx: 400,
startDistance: null,
stopAtEl: null
}

class ParallaxObj {
constructor(target) {
this.mobileDisable = false
this.conditions = []
this.active = true
this.target = target
this.accumulated = 0

if (typeof target === 'string') {
this.target = document.querySelector(`${target}`)
}

if (this.target.dataset.stopAtEl) {
this.stopAtEl = this.target.dataset.stopAtEl
if (typeof this.target.dataset.stopAtEl === 'string') {
this.stopAtEl = document.querySelector(`${this.target.dataset.stopAtEl}`)
}
}

this.speed = this.target.dataset.speed || defaultOptions.speed
this.mobilePx = this.target.dataset.mobilePx || defaultOptions.mobilePx
this.grayscale = this.target.dataset.grayscale || defaultOptions.grayscale
this.startDistance = this.target.dataset.startDistance || defaultOptions.startDistance

resize()
}

// API
stop() {
this.active = false
}

start(reset=false) {
if (this.active) return
if (reset) {
this.accumulated = 0
this.startScroll = this.startAt
}
this.active = true
}

getSpeed() {
return this.speed
}

changeSpeed(newSpeed) {
if (this.inWindow() && newSpeed !== this.speed) {
this.accumulated = this.getTranslation()
this.startScroll = this.scrollY()
}
this.speed = newSpeed
}

when(condition, action) {
this.conditions.push({condition, action})
return this
}

// HELPERS
scrollY() {
return window.scrollY || window.pageYOffset
}

getTranslation() {
const dist = Math.min(this.scrollY(), this.stopAt) - this.startScroll
const translation = (dist * this.speed) + this.accumulated
return translation >= 0 ? translation : 0
}

getGrayscale() {
if (this.scrollY() > this.stopAt) { return 100 }

const val = (this.scrollY() - this.startScroll) / (this.stopAt - this.startScroll) * 100
return Math.min(Math.max(val, 0), 100)
}

getOpacity() {
return 100 - (this.getGrayscale() / 2)
}

getRect() {
this.targetR = this.target.getBoundingClientRect()
return this.targetR
}

inWindow() {
this.getRect()
const top = this.targetR.top
const bottom = this.targetR.bottom

return top < this.winHeight && bottom > 0
}

animate() {
if (this.mobileDisable) return
this.move()

if (this.grayscale) {
this.applyGrayscale()
}
}

move() {
this.target
.style
.transform = `translateY(${this.getTranslation()}px)`
}

applyGrayscale() {
this.target
.style
.filter = `grayscale(${this.getGrayscale()}%) opacity(${this.getOpacity()}%)`
}

setConditions() {
this.winHeight = window.innerHeight
this.getRect()

this.conditions = []
this.startAt = this.startDistance ? this.scrollY() + this.targetR.top - parseInt(this.startDistance) : 0

if (this.target.dataset.stopAtEl) {
// distance to travel before stop
let distance = this.stopAtEl.getBoundingClientRect().top - this.targetR.bottom + (this.targetR.height / 2) + (this.stopAtEl.getBoundingClientRect().height / 2)

// add to start point, and convert based on speed
this.stopAt = this.startAt + (distance / this.speed)

} else {
this.stopAt = this.targetR.height + window.offsetHeight
}

this.startScroll = this.startAt
this.when(
() => this.scrollY() > this.startAt && this.scrollY() < this.stopAt,
() => {
this.start(true)
}
)

this.when(
() => this.scrollY() < this.startAt || this.scrollY() > this.stopAt,
() => this.stop()
)

this.animate()
}
}

const addListener = () => {
window.addEventListener('scroll', event => {
controller(targets)
})

window.addEventListener('resize', event => {
resize()
})
}

const controller = targets => {
requestAnimationFrame(() => {
targets.forEach(obj => {
if (obj.mobileDisable) return
obj.conditions
.forEach(({condition, action}) => {
if (condition()) action()
})

if (obj.active) {
obj.animate()
}
})
})
}

const resize = () => {
const newSize = window.innerWidth

targets.forEach(obj => {
obj.active = false
obj.setConditions()
if (obj.mobilePx >= newSize) {
obj.mobileDisable = true
}
})
}

export default (target, userOptions = {}) => {
const parallax = new ParallaxObj(target, userOptions)
targets.push(parallax)
resize()

if (!listening) {
addListener()
listening = true
}

return parallax
}
49 changes: 49 additions & 0 deletions components/Parallax.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<div class="parallax-element" :data-speed="speed" :data-grayscale="isGrayscale" :data-start-distance="startDistance" :data-stop-at-el="stopAtEl" :data-mobile-px="mobileSize">
<slot />
</div>
</template>



<script>
import parallax from '~/assets/js/parallax'
export default {
props: {
speed: {
type: Number,
required: false,
default: 0.6
},
isGrayscale: {
type: Boolean,
required: false,
default: false
},
mobileSize: {
type: Number,
required: false,
default: null
},
startDistance: {
type: Number,
required: false,
default: null
},
stopAtEl: {
type: String,
required: false,
default: null
}
},
mounted() {
setTimeout(() => {
document.querySelectorAll('.parallax-element:not(.parallaxed)').forEach( (el) => {
parallax(el)
el.classList.add('parallaxed')
})
}, 500)
}
}
</script>
12 changes: 10 additions & 2 deletions pages/test.vue
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@
br
QuoteScroller

section#parallax
.container
parallax(:speed="0.8" is-grayscale stop-at-el="#parallax h2" :start-distance="100")
img(src="~/assets/images/fftf-logo-light.svg")
h2 Parallax
p.mt-5 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vel dapibus tortor. Nam a hendrerit turpis. Aliquam mollis porta lacus, id pellentesque massa tincidunt et. Phasellus facilisis pellentesque justo id egestas. Praesent orci augue, congue id consectetur eget, pharetra at ligula. Donec a augue ornare, vestibulum velit eget, lacinia orci. Aliquam erat volutpat. Donec molestie congue neque, non rutrum lacus maximus a. Proin sed pharetra magna. Fusce est urna, porta et laoreet non, ullamcorper id tellus. Quisque tempor odio sed orci malesuada, quis fringilla urna tristique. Proin at elementum libero.

section
.container
h2 Modals
Expand All @@ -86,18 +93,18 @@
h2 ClickToCopy
br
ClickToCopy(text-to-copy="this is the text to copy")

</template>

<script>
import config from '~/config'
import ActionNetworkForm from '~/components/ActionNetworkForm'
import ClickToCopy from '~/components/ClickToCopy'
import Letter from '~/components/Letter'
import LogoCloud from '~/components/LogoCloud'
import Map from '~/components/Map'
import Parallax from '~/components/Parallax'
import ProgressBar from '~/components/ProgressBar'
import QuoteScroller from '~/components/QuoteScroller'
import ClickToCopy from '~/components/ClickToCopy'
import YoutubeVideo from '~/components/YoutubeVideo'
export default {
Expand All @@ -107,6 +114,7 @@ export default {
Letter,
LogoCloud,
Map,
Parallax,
ProgressBar,
QuoteScroller,
YoutubeVideo
Expand Down

0 comments on commit fa010f6

Please sign in to comment.