forked from jlmakes/scrollreveal
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsequence.js
More file actions
121 lines (106 loc) · 2.88 KB
/
sequence.js
File metadata and controls
121 lines (106 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import animate from './animate'
import each from '../../utils/each'
import nextUniqueId from '../../utils/next-unique-id'
export default function sequence(element, pristine = this.pristine) {
/**
* We first check if the element should reset.
*/
if (!element.visible && element.revealed && element.config.reset) {
return animate.call(this, element, { reset: true })
}
const seq = this.store.sequences[element.sequence.id]
const i = element.sequence.index
if (seq) {
const visible = new SequenceModel(seq, 'visible', this.store)
const revealed = new SequenceModel(seq, 'revealed', this.store)
seq.models = { visible, revealed }
/**
* If the sequence has no revealed members,
* then we reveal the first visible element
* within that sequence.
*
* The sequence then cues a recursive call
* in both directions.
*/
if (!revealed.body.length) {
const nextId = seq.members[visible.body[0]]
const nextElement = this.store.elements[nextId]
if (nextElement) {
cue.call(this, seq, visible.body[0], -1, pristine)
cue.call(this, seq, visible.body[0], +1, pristine)
return animate.call(this, nextElement, { reveal: true, pristine })
}
}
/**
* If our element isn’t resetting, we check the
* element sequence index against the head, and
* then the foot of the sequence.
*/
if (
!seq.blocked.head &&
i === [...revealed.head].pop() &&
i >= [...visible.body].shift()
) {
cue.call(this, seq, i, -1, pristine)
return animate.call(this, element, { reveal: true, pristine })
}
if (
!seq.blocked.foot &&
i === [...revealed.foot].shift() &&
i <= [...visible.body].pop()
) {
cue.call(this, seq, i, +1, pristine)
return animate.call(this, element, { reveal: true, pristine })
}
}
}
export function Sequence(interval) {
const i = Math.abs(interval)
if (!isNaN(i)) {
this.id = nextUniqueId()
this.interval = Math.max(i, 16)
this.members = []
this.models = {}
this.blocked = {
head: false,
foot: false
}
} else {
throw new RangeError('Invalid sequence interval.')
}
}
function SequenceModel(seq, prop, store) {
this.head = []
this.body = []
this.foot = []
each(seq.members, (id, index) => {
const element = store.elements[id]
if (element && element[prop]) {
this.body.push(index)
}
})
if (this.body.length) {
each(seq.members, (id, index) => {
const element = store.elements[id]
if (element && !element[prop]) {
if (index < this.body[0]) {
this.head.push(index)
} else {
this.foot.push(index)
}
}
})
}
}
function cue(seq, i, direction, pristine) {
const blocked = ['head', null, 'foot'][1 + direction]
const nextId = seq.members[i + direction]
const nextElement = this.store.elements[nextId]
seq.blocked[blocked] = true
setTimeout(() => {
seq.blocked[blocked] = false
if (nextElement) {
sequence.call(this, nextElement, pristine)
}
}, seq.interval)
}