rytm-webflow 1.1.1 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,22 @@
1
1
  # rytm-webflow
2
2
  Rytm webflow pack is used to make websites rendered on the server (using a PHP or other back-end) more dynamic.
3
- A static website can be transformed into something we call a *pseudo single page application* (SPA). The pack includes **ASwap** - a framework programmed by Rytm Digital arround 2016 which uses *AJAX* to first load and then *swap* the page's content in user's browser
3
+ A static website can be transformed into something we call a *pseudo single page application* (SPA). The pack includes **[ASwap](#markdown-header-aswap)** - a framework programmed by Rytm Digital arround 2016 which uses *AJAX* to first load and then *swap* the page's content in user's browser.
4
+ Another future rytm-webflow includes is **[ShowUp](#markdown-header-showup)** - a ScrollMagic.js wrapper which can be integrated with ASwap.
5
+
4
6
 
5
7
  **Install using NPM:**
6
8
  ```
7
9
  $ npm install rytm-webflow --save
8
10
  ```
11
+ ## Dependencies
12
+ - gsap
13
+ - imagesloaded
14
+ - jquery
15
+ - scrollmagic
16
+ - scrollmagic-plugin-gsap
9
17
 
10
- ## Basic usage example
18
+ ## ASwap
19
+ ### Basic usage example
11
20
  In your HTML for each request you neeed a wrapper (default wrapper selector: ```#stage```)
12
21
  Inside a wrapper you can have multiple view instances. Each view uses a name defined in ```data-as-view``` and an unique id defined in ```data-as-id```
13
22
  ```html
@@ -25,12 +34,8 @@ import RytmWebflow from 'rytm-webflow'
25
34
  RytmWebflow.aswap.init()
26
35
  ```
27
36
 
28
- ## Dependencies
29
- - imagesloaded
30
- - jquery
31
-
32
- ## More examples
33
- ### Controllers
37
+ ### More examples
38
+ #### Controllers
34
39
  To programm some interaction within your ASwap views create a controller
35
40
 
36
41
  ```js
@@ -83,7 +88,7 @@ If you are using the ```ControllerImgLoad``` - to hide the view before the show
83
88
  ```
84
89
 
85
90
 
86
- ### Views
91
+ #### Views
87
92
  If you need some fancy animations to show / hide your views you can create view instances.
88
93
  ```js
89
94
  import RytmWebflow from 'rytm-webflow'
@@ -114,7 +119,7 @@ RytmWebflow.aswap.init({
114
119
  })
115
120
  ```
116
121
  Read more about it -> [View class](#markdown-header-view-class)
117
- ### Sample params
122
+ #### Sample params
118
123
  ```js
119
124
  import RytmWebflow from 'rytm-webflow'
120
125
  import { trace } from 'rytm-helpers'
@@ -130,7 +135,7 @@ RytmWebflow.aswap.init({
130
135
  ```
131
136
 
132
137
 
133
- ## Params
138
+ ### Params
134
139
 
135
140
  | param | default | info |
136
141
  |---|---|---|
@@ -149,9 +154,10 @@ RytmWebflow.aswap.init({
149
154
  | ```refreshOnSameUrl``` | ```true``` | When ```true``` each request on same URL will refresh browser's window |
150
155
  | ```routes``` | ```{}``` | The routes object where you can define controllers and views |
151
156
  | ```swapSelector``` | ```'#stage'``` | ASwap wrapper selector |
157
+ | ```defaultDocumentScrollBehavior``` | ```'smooth'``` | Default document scroll behaviour |
152
158
  | ```trace``` | ```(message) => {}``` | A function to log stuff, eg in console |
153
159
 
154
- ## Controller class
160
+ ### Controller class
155
161
 
156
162
  | method | info |
157
163
  |---|---|
@@ -167,7 +173,7 @@ RytmWebflow.aswap.init({
167
173
  | ```onViewShow()``` | read more -> [global events](#markdown-header-global-events) |
168
174
  | ```onViewShown()``` | read more -> [global events](#markdown-header-global-events) |
169
175
 
170
- ## View class
176
+ ### View class
171
177
  | method | parameters | info |
172
178
  |---|---|---|
173
179
  | ```hide()``` | ```container``` | this method is called by the ```Controller``` instance in the ```onViewShow()``` method |
@@ -176,7 +182,7 @@ RytmWebflow.aswap.init({
176
182
  | ```loadImagesStart()``` | ```container``` | this method is called by the ```ControllerImgLoad``` instance on image load start |
177
183
  | ```loadImagesComplete()``` | ```container``` | this method is called by the ```ControllerImgLoad``` instance on image load complete |
178
184
 
179
- ## Global events
185
+ ### Global events
180
186
  You also can pass custom methods to the global ASwap instance events, eg:
181
187
  ```js
182
188
  import RytmWebflow from 'rytm-webflow'
@@ -198,3 +204,154 @@ RytmWebflow.aswap.init(params, {
198
204
  | ```onViewSwapComplete()``` | fired just after the scene's content is being replaced |
199
205
  | ```onViewShow()``` | fired when the new scene is loaded and the show transition is being started |
200
206
  | ```onViewShown()``` | fired within ```animationTimeShow``` ms from show transition start |
207
+
208
+ ### Bootstrap integration ###
209
+ #### Bootstrap v5 ####
210
+ A common situation is to hide all Bootstrap offcanvases or modals when an ASwap page transition is in made. To do so just call the `RytmWebflow.bootsrap5.hideFlyovers()` method. You can also hide offcanvases or modals separatly by calling the `RytmWebflow.bootsrap5.hideOffcanvases()` or `RytmWebflow.bootsrap5.hideModals()` methods.
211
+ A basic usage example:
212
+ ```js
213
+ import RytmWebflow from 'rytm-webflow'
214
+
215
+ RytmWebflow.aswap.init(params, {
216
+ onViewHide: () => {
217
+ RytmWebflow.bootsrap5.hideFlyovers()
218
+ },
219
+ })
220
+ ```
221
+
222
+ ## ShowUp ##
223
+ ShowUp makes creating gsap scroll-triggered-animations much faster. It can be used to show content while user scrolls down the page. It can also be used for parallax like animations. ShowUp comes with the **Webflow syntax** - a minified way to describe an animation, it's duration (time), easing, delay or the trigger. Eg. `y:100,o:0` will animate an element from: `y:100px` and `opacity: 0` to it's current state. Go to [Webflow syntax](#markdown-header-webflow-syntax) for more.
224
+ ### Webflow usage example
225
+ To enable ShowUp call the init method in your JS:
226
+ ```js
227
+ import RytmWebflow from 'rytm-webflow'
228
+
229
+ RytmWebflow.showUp.init()
230
+ ```
231
+ If you are working on a SPA or using ASwap the only thing you need to do is call the rebuild method on each view load. Check out the ASwap example:
232
+ ```js
233
+ import RytmWebflow from 'rytm-webflow'
234
+
235
+ const events = {
236
+ onViewSwapComplete: () => {
237
+ RytmWebflow.showUp.rebuild()
238
+ }
239
+ }
240
+ RytmWebflow.aswap.init({}, events)
241
+ ```
242
+ To implement ShowUp on your HTML add a `data-webflow` or `data-webpara` attribute to DOM elements which will describe the animation
243
+ ```html
244
+ <!-- From opacity: 0 in .4s -->
245
+ <div data-webflow="o:0,t:.4">...</div>
246
+ ```
247
+ Add easing for your animations
248
+ ```html
249
+ <!-- gsap easing -->
250
+ <div data-webflow="x:-10vw,t:.5,e:Expo.easeOut">...</div>
251
+ ```
252
+ Delay animations
253
+ ```html
254
+ <!-- delay by .3s -->
255
+ <div data-webflow="x:-20,t:.5,d:.3">...</div>
256
+ ```
257
+ #### Trigger element
258
+ By default the ScrollMagic.Scene is triggered by the element itself. Also it is triggered once the element becomes visible (at the window bottom).
259
+ You can override these defaults using the `data-webset` attribute.
260
+ To specyfy an offset:
261
+ ```html
262
+ <!-- offset: 100px from bottom up -->
263
+ <div data-webflow="o:0" data-webset="offset:100">...</div>
264
+
265
+ <!-- offset: window center -->
266
+ <div data-webflow="o:0" data-webset="offset:center">...</div>
267
+
268
+ <!-- offset: window top -->
269
+ <div data-webflow="o:0" data-webset="offset:top">...</div>
270
+ ```
271
+ To specyfy a trigger element:
272
+ ```html
273
+ <!-- target -->
274
+ <div data-webflow="o:0" data-webset="trigger:#myTarget">...</div>
275
+ ```
276
+ #### *Hide* animation
277
+ You can specify a *hide* transition (eg. for ASwap View to hide elements)
278
+ Separate *show* and *hide* animation using `;`
279
+ ```html
280
+ <!-- show, hide -->
281
+ <div data-webflow="x:-30,t:.5;x:15,t:.3">...</div>
282
+ ```
283
+ To start the hide animation on each dom element call the `hide()` method
284
+ ```js
285
+ RytmWebflow.showUp.hide()
286
+ ```
287
+ An ASwap example implementing ShowUp along with the *hide* animation:
288
+ ```js
289
+ import RytmWebflow from 'rytm-webflow'
290
+
291
+ const events = {
292
+ onViewSwapComplete: () => {
293
+ RytmWebflow.showUp.rebuild()
294
+ },
295
+ onViewHide: () => {
296
+ RytmWebflow.showUp.hide()
297
+ }
298
+ }
299
+ RytmWebflow.aswap.init({}, events)
300
+ ```
301
+ ### Parallax usage example
302
+ Parallax like animation:
303
+ ```html
304
+ <!-- parallax duration 100% - by container height -->
305
+ <div data-webpara="x:100" data-webset="duration:100%">...</div>
306
+ ```
307
+ Duration can be relative to viewport:
308
+ ```html
309
+ <!-- parallax duration 30vh - by viewport height -->
310
+ <div data-webpara="s:1.2" data-webset="duration:30vh">...</div>
311
+ ```
312
+ When moving elements in the Y axis you can use the `parent` trigger hook:
313
+ ```html
314
+ <!-- parallax triggered by parent Node -->
315
+ <div>
316
+ <div data-webpara="y:-100" data-webset="duration:100%,trigger:parent"></div>
317
+ </div>
318
+ ```
319
+ ### Webflow syntax ##
320
+ | short code | prameter | example |
321
+ |---|---|---|
322
+ | ```d``` | delay | ```"d:.4"``` |
323
+ | ```e``` | ease | ```"e:Bounce:easeOut"``` |
324
+ | ```h``` | height | ```"h:10"``` |
325
+ | ```o``` | opacity | ```"o:0"``` |
326
+ | ```r``` | rotation | ```"r:180"``` |
327
+ | ```s``` | scale | ```"s:.1"``` |
328
+ | ```t``` | time | ```"t:.35"``` |
329
+ | ```w``` | width | ```"w:1200"```| |
330
+
331
+ ### More examples
332
+ Examples:
333
+ ```html
334
+ <h1>Webflow show up</h1>
335
+ <div data-webflow="t:.4,o:0,y:10;t:.4,o:0,y:-30">Webflow Simple ALPHA no delay</div>
336
+ <div data-webflow="t:.4,o:0,s:.4;t:.4,o:0,s:1.5">Webflow Scale</div>
337
+ <div data-webflow="t:1.4,x:-300,e:Expo.easeOut;t:.4,d:0,x:-100,e:Expo.easeIn" data-webset="offset:100">Webflow Offset: 100, Ease EXPO</div>
338
+ <div data-webflow="t:1.4,x:-100vw;t:.4,d:0,x:-250" data-webset="offset:center">Webflow Offset: center</div>
339
+ <div data-webflow="t:1.4,x:-250;t:.4,d:0,x:-250" data-webset="offset:top">Webflow offset: TOP</div>
340
+ <div data-webflow="t:1.4,x:-250,w:10;t:.4,d:0,x:-250" data-webset="trigger:#boom">Webflow Triggered by next BLOCK</div>
341
+ <div id="boom" >Trigger</div>
342
+ <!-- ### Webflow Parallax ### -->
343
+ <h1>Webflow parallax</h1>
344
+ <div data-webpara="x:400" data-webset="duration:100%">Parallax duration 100%</div>
345
+ <div data-webpara="x:400,e:Back.easeOut" data-webset="duration:40vh">Parallax duration 40vh, ease: Back</div>
346
+ <div >parent TRIGGER
347
+ <div data-webpara="y:-500,r:180" data-webset="duration:100%,trigger:parent">Parallax Y</div>
348
+ </div>
349
+ ```
350
+
351
+ You can use the parser functions to implement your own view related methods using the Webflow syntax:
352
+
353
+ | function | descr |
354
+ |---|---|
355
+ | ```RytmWebflow.getWebflowProps(str)``` | converts a webflow syntax string into an webflow parameters object: ```{show: {tween: {}, time: X}, hide: {tween: {}, time: X}``` |
356
+ | ```RytmWebflow.getParallaxProps(str)``` | converts a webflow syntax string into an webflow parameters object: ```{parallax: {tween: {}}}``` |
357
+
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "rytm-webflow",
3
- "version": "1.1.1",
4
- "description": "rytm webflow pack - ASwap+",
3
+ "version": "1.1.5",
4
+ "description": "rytm webflow pack - ASwap, ShowUp",
5
5
  "main": "scripts/index.js",
6
- "scripts": {},
6
+ "scripts": {
7
+ "update": "git pull",
8
+ "push": "git add . && git commit -a -m \"$m\" && git push"
9
+ },
7
10
  "repository": {
8
11
  "type": "git",
9
12
  "url": "git+ssh://git@bitbucket.org/rytm/rytm-webflow.git"
@@ -13,7 +16,10 @@
13
16
  "homepage": "https://bitbucket.org/rytm/rytm-webflow#readme",
14
17
  "devDependencies": {},
15
18
  "dependencies": {
19
+ "gsap": "^3.5.1",
16
20
  "imagesloaded": "^4.1.4",
17
- "jquery": "^3.1.1"
21
+ "jquery": "^3.1.1",
22
+ "scrollmagic": "^2.0.7",
23
+ "scrollmagic-plugin-gsap": "^1.0.4"
18
24
  }
19
25
  }
@@ -25,6 +25,7 @@ class ASwap {
25
25
  refreshOnSameUrl: true, // refresh window if same URL is requested
26
26
  routes: {},
27
27
  swapSelector: '#stage', // swap wrapper selector
28
+ defaultDocumentScrollBehavior: 'smooth',
28
29
  trace: () => {}, // a function to trace progress in console
29
30
  }
30
31
  // public events
@@ -231,8 +231,16 @@ class ASwapDispatcher extends EventDispatcher {
231
231
  * scroll back up
232
232
  **/
233
233
  resetScrollPosition() {
234
- // $("html, body").animate({ scrollTop: "0" }, 300);
235
- $("html, body").scrollTop(0);
234
+ // set scrollBehavior to auto
235
+ document.documentElement.style.scrollBehavior = 'auto';
236
+ // scroll without animation
237
+ setTimeout(() => {
238
+ window.scrollTo(0, 0)
239
+ }, 5)
240
+ // set scrollBehavior to it's default value
241
+ setTimeout(() => {
242
+ document.documentElement.style.scrollBehavior = this.defaultDocumentScrollBehavior ? this.defaultDocumentScrollBehavior : 'smooth';
243
+ }, 5)
236
244
  }
237
245
  /**
238
246
  * Preload URL
@@ -0,0 +1,45 @@
1
+ import { Offcanvas, Modal } from 'bootstrap'
2
+
3
+ /**
4
+ * Bootstrap v5 helpers
5
+ */
6
+ class Bootstrap5 {
7
+ /**
8
+ * @constructor
9
+ **/
10
+ constructor() {
11
+ }
12
+ // # Hide all modals, offcanvases, etc.
13
+ hideFlyovers() {
14
+ this.hideModals()
15
+ this.hideOffcanvases()
16
+ }
17
+ // # Hide all modals #
18
+ hideModals() {
19
+ const list = [...document.querySelectorAll(".modal")]
20
+ list.forEach(this.hdieModal.bind(this))
21
+ }
22
+ // # Hide offcanvas element
23
+ hdieModal(el) {
24
+ const modal = Modal.getInstance(el)
25
+ if (modal) {
26
+ modal.hide()
27
+ }
28
+ }
29
+ // # Hide all offcanvases #
30
+ hideOffcanvases() {
31
+ const list = [...document.querySelectorAll(".offcanvas")]
32
+ list.forEach(this.hdieOffcanvas.bind(this))
33
+ }
34
+ // # Hide offcanvas element
35
+ hdieOffcanvas(el) {
36
+ const offcanvas = Offcanvas.getInstance(el)
37
+ if (offcanvas) {
38
+ offcanvas.hide()
39
+ }
40
+ }
41
+
42
+ }
43
+
44
+ const bootstrap5 = new Bootstrap5();
45
+ export default bootstrap5;
package/scripts/index.js CHANGED
@@ -2,11 +2,26 @@ import aswapInstance from './aswap/ASwap'
2
2
  import Controller from './aswap/Controller'
3
3
  import ControllerImgLoad from './aswap/ControllerImgLoad'
4
4
  import View from './aswap/View'
5
-
5
+ // Bootstrap v5 helper
6
+ import bootsrap5 from './bootstrap/v5/Bootstrap5'
7
+ // showup
8
+ import scrollController from './showup/ScrollController'
9
+ import showUp from './showup/ShowUp'
10
+ import { getWebflowProps, getParallaxProps } from './lib/dataTweenParser'
11
+ import { getScrollMagicSceneProps } from './lib/dataScrollMagicParser'
6
12
 
7
13
  export default {
8
14
  aswap: aswapInstance,
9
15
  Controller,
10
16
  ControllerImgLoad,
11
- View
17
+ View,
18
+ // boottstrap
19
+ bootsrap5,
20
+ // showup
21
+ scrollController,
22
+ showUp,
23
+ // lib
24
+ getWebflowProps,
25
+ getParallaxProps,
26
+ getScrollMagicSceneProps
12
27
  }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * get ScrollMagic.Scene props
3
+ * @param {Object} wfProps
4
+ * @param {Object} setup
5
+ * @return {Object}
6
+ */
7
+ export const getScrollMagicSceneProps = (el, setup) => {
8
+ const triggerElement = getTriggerFromProps(setup, el)
9
+ const duration = getDurationFromProps(setup)
10
+ const offset = getOffsetFromProps(setup)
11
+ return {
12
+ triggerElement,
13
+ duration,
14
+ offset
15
+ }
16
+ }
17
+ const getTriggerFromProps = (setup, el) => {
18
+ let trigger = el
19
+ if (setup.trigger) {
20
+ switch (setup.trigger) {
21
+ case "parent":
22
+ trigger = el.parentNode
23
+ break;
24
+ default:
25
+ trigger = setup.trigger
26
+ break;
27
+ }
28
+ }
29
+ return trigger
30
+ }
31
+ const getDurationFromProps = (setup) => {
32
+ let duration = 0
33
+ if (setup.duration) {
34
+ duration = isNaN(setup.duration) ? translateNonNumericValue("duration", setup.duration) : parseFloat(setup.duration)
35
+ }
36
+ return duration
37
+ }
38
+ const getOffsetFromProps = (setup) => {
39
+ const bottomOffset = setup.offset ? setup.offset : 0
40
+ let offset
41
+ switch (bottomOffset) {
42
+ case "center":
43
+ offset = 0
44
+ break;
45
+ case "top":
46
+ offset = window.innerHeight * .5
47
+ break;
48
+ default:
49
+ offset = bottomOffset - window.innerHeight * .5
50
+ break;
51
+ }
52
+ return offset
53
+ }
54
+
55
+ /**
56
+ * Translate non numeric value strings...
57
+ * @param {string} key
58
+ * @param {string} valStr
59
+ * @return {*}
60
+ */
61
+ const translateNonNumericValue = (key, valStr) => {
62
+ let val
63
+ switch (key) {
64
+ case 'duration':
65
+ // calculate viewport vw & vh
66
+ if (valStr.includes("vw")) {
67
+ val = parseInt(valStr.replace("vw", "")) * .01 * window.innerWidth
68
+ } else if (valStr.includes("vh")) {
69
+ val = parseInt(valStr.replace("vh", "")) * .01 * window.innerHeight
70
+ } else {
71
+ val = valStr
72
+ }
73
+ break;
74
+ default:
75
+ // by default don't change anything (eg. '100%', '50vw')
76
+ val = valStr
77
+ break;
78
+ }
79
+ return val
80
+ }
@@ -0,0 +1,209 @@
1
+ import { Power0, Power1, Power2, Power3, Power4, Back, Bounce, Elastic, Expo, Sine } from 'gsap'
2
+
3
+
4
+ const DEFAULT_ANIMATION_TIME = .4
5
+
6
+ /**
7
+ * Split string into props
8
+ * @param {string} gstr (eg. y:100,o:0)
9
+ * @return {Object}
10
+ */
11
+ export const parseProps = (gstr) => {
12
+ let props = {}
13
+ if (gstr) {
14
+ const arr = gstr.split(',')
15
+ arr.forEach((s, index) => {
16
+ let p = parseWebflowKeyValue(s)
17
+ props = {...props, ...p}
18
+ })
19
+ }
20
+ return props
21
+ }
22
+ /**
23
+ * get Parallax Props
24
+ * @param {String} dataStr
25
+ * @return {Object}
26
+ * {parallax: {tween: {}}}
27
+ */
28
+ export const getParallaxProps = (dataStr) => {
29
+ let params = {}
30
+ if (dataStr) {
31
+ const groups = dataStr.split(';')
32
+ params.parallax = getWebflowAnimationProps(groups[0])
33
+ }
34
+ return params
35
+ }
36
+
37
+ /**
38
+ * get Webflow Props
39
+ * @param {String} dataStr
40
+ * @return {Object}
41
+ * {show: {tween: {}, time: X}, hide: {tween: {}, time: X}
42
+ */
43
+ export const getWebflowProps = (dataStr) => {
44
+ let params = {}
45
+ if (dataStr) {
46
+ const groups = dataStr.split(';')
47
+ params.show = getWebflowAnimationProps(groups[0])
48
+ // hide (optional)
49
+ params.hide = groups.length > 1 ? getWebflowAnimationProps(groups[1]) : false
50
+ }
51
+ return params
52
+ }
53
+ /**
54
+ * group string to JS object
55
+ * @param {string} gstr (eg. y:100,o:0)
56
+ * @return {Object}
57
+ */
58
+ const getWebflowAnimationProps = (gstr) => {
59
+ let propsFromData = parseProps(gstr)
60
+ return getValidWebflowAnimationProps(propsFromData)
61
+ }
62
+
63
+ /**
64
+ * divide properties for TweenMax use: time (int) vs tween (obj)
65
+ * @param {Object} propsFromData
66
+ * @return {Object}
67
+ */
68
+ const getValidWebflowAnimationProps = (propsFromData) => {
69
+ let ap = {
70
+ time: DEFAULT_ANIMATION_TIME,
71
+ tween: {}
72
+ }
73
+ for (let key in propsFromData) {
74
+ switch (key) {
75
+ case 'time':
76
+ ap.time = propsFromData[key]
77
+ break;
78
+ default:
79
+ ap.tween[key] = propsFromData[key]
80
+ break;
81
+ }
82
+ }
83
+ return ap
84
+ }
85
+ /**
86
+ * key:value string to JS object
87
+ * @param {string} s (eg. y:100)
88
+ * @return {*}
89
+ */
90
+ const parseWebflowKeyValue = (s) => {
91
+ let p = {}
92
+ const arr = s.split(':')
93
+ if (arr.length > 1) {
94
+ const key = translateKey(arr[0])
95
+ const val = isNaN(arr[1]) ? translateNonNumericValue(key, arr[1]) : parseFloat(arr[1])
96
+ p[key] = val
97
+ }
98
+ return p
99
+ }
100
+ /**
101
+ * Translate key (eg: 'o' = 'opacity')
102
+ * @param {string} keyStr
103
+ * @return string
104
+ */
105
+ const translateKey = (keyStr) => {
106
+ let key = ''
107
+ switch (keyStr) {
108
+ case 'd':
109
+ key = 'delay'
110
+ break
111
+ case 'e':
112
+ key = 'ease'
113
+ break
114
+ case 'h':
115
+ key = 'height'
116
+ break
117
+ case 'o':
118
+ key = 'opacity'
119
+ break
120
+ case 'r':
121
+ key = 'rotation'
122
+ break
123
+ case 's':
124
+ key = 'scale'
125
+ break
126
+ case 't':
127
+ key = 'time'
128
+ break
129
+ case 'w':
130
+ key = 'width'
131
+ break
132
+ default:
133
+ key = keyStr
134
+ break
135
+ }
136
+ return key
137
+ }
138
+ /**
139
+ * Translate non numeric value strings...
140
+ * @param {string} key
141
+ * @param {string} valStr
142
+ * @return {*}
143
+ */
144
+ const translateNonNumericValue = (key, valStr) => {
145
+ let val
146
+ switch (key) {
147
+ case 'ease':
148
+ val = getWebflowEasing(valStr)
149
+ break;
150
+ default:
151
+ // by default don't change anything (eg. '100%', '50vw')
152
+ val = valStr
153
+ break;
154
+ }
155
+ return val
156
+ }
157
+ /**
158
+ * Get the TweenMax Easing function
159
+ * @param {string} str
160
+ * @return {Ease}
161
+ */
162
+ const getWebflowEasing = (str) => {
163
+ let easing
164
+ let arr = str.split('.')
165
+ if (arr.length == 2) {
166
+ switch (arr[0]) {
167
+ case 'Back':
168
+ easing = Back[arr[1]]
169
+ break;
170
+ case 'Bounce':
171
+ easing = Bounce[arr[1]]
172
+ break;
173
+ case 'Circ':
174
+ easing = Circ[arr[1]]
175
+ break;
176
+ case 'Elastic':
177
+ easing = Elastic[arr[1]]
178
+ break;
179
+ case 'Expo':
180
+ easing = Expo[arr[1]]
181
+ break;
182
+ case 'Power0':
183
+ easing = Power0[arr[1]]
184
+ break;
185
+ case 'Power1':
186
+ easing = Power1[arr[1]]
187
+ break;
188
+ case 'Power2':
189
+ easing = Power2[arr[1]]
190
+ break;
191
+ case 'Power3':
192
+ easing = Power3[arr[1]]
193
+ break;
194
+ case 'Power4':
195
+ easing = Power4[arr[1]]
196
+ break;
197
+ case 'SlowMo':
198
+ easing = SlowMo[arr[1]]
199
+ break;
200
+ case 'Stepped':
201
+ easing = SteppedEase[arr[1]]
202
+ break;
203
+ default:
204
+ easing = Sine[arr[1]]
205
+ break;
206
+ }
207
+ }
208
+ return easing
209
+ }
@@ -0,0 +1,43 @@
1
+ // # configure scroll magic and gsap
2
+ import ScrollMagic from 'scrollmagic'
3
+ import { ScrollMagicPluginGsap } from "scrollmagic-plugin-gsap";
4
+ import { gsap } from 'gsap'
5
+ // GSAP plugins
6
+ ScrollMagicPluginGsap(ScrollMagic, gsap)
7
+
8
+ class ScrollController {
9
+ /**
10
+ * @constructor
11
+ **/
12
+ constructor() {
13
+ this.controller = null
14
+ }
15
+ // Build ScrollMagic Controller
16
+ _build() {
17
+ this.destroy()
18
+ this.controller = new ScrollMagic.Controller({
19
+ loglevel: 0
20
+ })
21
+ }
22
+ get() {
23
+ if (!this.controller) {
24
+ this._build()
25
+ }
26
+ return this.controller
27
+ }
28
+ destroy() {
29
+ if (this.controller) {
30
+ this.controller.destroy()
31
+ this.controller = null
32
+ }
33
+ }
34
+ refresh(immediately = false) {
35
+ if (this.controller) {
36
+ this.controller.update(immediately)
37
+ } else {
38
+ console.warn("Can't refresh ScrollMagic.Controller. Controller was not build")
39
+ }
40
+ }
41
+ }
42
+ const scrollController = new ScrollController();
43
+ export default scrollController;
@@ -0,0 +1,126 @@
1
+ // # configure scroll magic and gsap
2
+ import ScrollMagic from 'scrollmagic'
3
+ import { TweenMax } from 'gsap'
4
+ import scrollController from './ScrollController'
5
+ import { parseProps, getWebflowProps, getParallaxProps } from './../lib/dataTweenParser'
6
+ import { getScrollMagicSceneProps } from './../lib/dataScrollMagicParser'
7
+
8
+ const DATA_ATTR_WEBFLOW = "webflow"
9
+ const DATA_ATTR_SETUP = "webset"
10
+ const DATA_ATTR_PARALLAX = "webpara"
11
+
12
+ class ShowUp {
13
+ /**
14
+ * @constructor
15
+ **/
16
+ constructor() {
17
+ this.scenes = []
18
+ }
19
+ /**
20
+ * Init all scenes
21
+ */
22
+ init() {
23
+ this.buildWebflowScenes()
24
+ this.buildParallaxScenes()
25
+ this.addEventListeners()
26
+ }
27
+ /**
28
+ * Add event listeners
29
+ */
30
+ addEventListeners() {
31
+ $(document).on('DOMContentLoaded load', $.proxy(this.onWindowUpdate, this))
32
+ $(window).on('resize', $.proxy(this.onWindowUpdate, this))
33
+ }
34
+ /**
35
+ * Remove event listeners
36
+ */
37
+ removeEventListeners() {
38
+ $(document).off('DOMContentLoaded load', $.proxy(this.onWindowUpdate, this));
39
+ $(window).off('resize', $.proxy(this.onWindowUpdate, this));
40
+ }
41
+ onWindowUpdate(e) {
42
+ if (this.scenes.length > 0) {
43
+ scrollController.refresh()
44
+ }
45
+ }
46
+ /**
47
+ * Bild scenes for data-webflow elements
48
+ */
49
+ buildWebflowScenes() {
50
+ const list = [...document.querySelectorAll('*[data-' + DATA_ATTR_WEBFLOW + ']')]
51
+ list.forEach(this.buildWebflowScene.bind(this))
52
+ }
53
+ /**
54
+ * Build scene
55
+ * @param {DOM} el
56
+ * @param {Int} index
57
+ */
58
+ buildWebflowScene(el, index) {
59
+ const wfp = getWebflowProps(el.dataset[DATA_ATTR_WEBFLOW])
60
+ const setup = parseProps(el.dataset[DATA_ATTR_SETUP])
61
+ if (wfp.show) {
62
+ const smsp = getScrollMagicSceneProps(el, setup)
63
+ const scene = new ScrollMagic.Scene(smsp)
64
+ scene.setTween(TweenMax.from(el, wfp.show.time, wfp.show.tween))
65
+ scene.addTo(scrollController.get())
66
+ this.scenes.push(scene)
67
+ }
68
+ }
69
+ /**
70
+ * Build Parallax scenes
71
+ */
72
+ buildParallaxScenes() {
73
+ const list = [...document.querySelectorAll('*[data-' + DATA_ATTR_PARALLAX + ']')]
74
+ list.forEach(this.buildParallaxScene.bind(this))
75
+ }
76
+ buildParallaxScene(el, index) {
77
+ const pp = getParallaxProps(el.dataset[DATA_ATTR_PARALLAX])
78
+ const setup = parseProps(el.dataset[DATA_ATTR_SETUP])
79
+ if (pp) {
80
+ const smsp = getScrollMagicSceneProps(el, setup)
81
+ const scene = new ScrollMagic.Scene(smsp)
82
+ scene.setTween(TweenMax.to(el, 1, pp.parallax.tween))
83
+ scene.addTo(scrollController.get())
84
+ this.scenes.push(scene)
85
+ }
86
+ }
87
+ /**
88
+ * Hide webflow elements
89
+ */
90
+ hide() {
91
+ const list = [...document.querySelectorAll('*[data-' + DATA_ATTR_WEBFLOW + ']')]
92
+ list.forEach(this.hideWebflowElement.bind(this))
93
+ }
94
+ /**
95
+ * Hide element
96
+ * @param {DOM} el
97
+ * @param {Int} index
98
+ */
99
+ hideWebflowElement(el, index) {
100
+ const wfp = getWebflowProps(el.dataset[DATA_ATTR_WEBFLOW])
101
+ if (wfp.hide) {
102
+ TweenMax.to(el, wfp.hide.time, wfp.hide.tween)
103
+ }
104
+ }
105
+ /**
106
+ * Destroy all scenes
107
+ */
108
+ destroy() {
109
+ this.removeEventListeners()
110
+ this.scenes.forEach((scene) => {
111
+ scene.destroy()
112
+ scene = null
113
+ })
114
+ this.scenes = []
115
+ }
116
+ /**
117
+ * Rebuild / refresh
118
+ */
119
+ rebuild() {
120
+ this.destroy()
121
+ this.init()
122
+ }
123
+
124
+ }
125
+ const showUp = new ShowUp();
126
+ export default showUp;