PageSourceSearch

https://www.newportexperience.com/wp-content/themes/NewportExperience/assets/scripts/lax.js?ver=2.0.3

js newportexperience.com collected 2026-10-04 02:39:50 UTC 17,244 bytes, 616 lines download raw bytes

1(() => {
2  const inOutMap = (y = 30) => {
3    return ["elInY+elHeight", `elCenterY-${y}`, "elCenterY", `elCenterY+${y}`, "elOutY-elHeight"]
4  }
5
6  const laxPresets = {
7    fadeInOut: (y = 30, str = 0) => ({
8      "opacity": [
9        inOutMap(y),
10        [str, 1, 1, 1, str]
11      ],
12    }),
13    fadeIn: (y = 'elCenterY', str = 0) => ({
14      "opacity": [
15        ["elInY+elHeight", y],
16        [str, 1],
17      ],
18    }),
19    fadeOut: (y = 'elCenterY', str = 0) => ({
20      "opacity": [
21        [y, "elOutY-elHeight"],
22        [1, str],
23      ],
24    }),
25    blurInOut: (y = 100, str = 20) => ({
26      "blur": [
27        inOutMap(y),
28        [str, 0, 0, 0, str],
29      ],
30    }),
31    blurIn: (y = 'elCenterY', str = 20) => ({
32      "blur": [
33        ["elInY+elHeight", y],
34        [str, 0],
35      ],
36    }),
37    blurOut: (y = 'elCenterY', str = 20) => ({
38      "opacity": [
39        [y, "elOutY-elHeight"],
40        [0, str],
41      ],
42    }),
43    scaleInOut: (y = 100, str = 0.6) => ({
44      "scale": [
45        inOutMap(y),
46        [str, 1, 1, 1, str],
47      ],
48    }),
49    scaleIn: (y = 'elCenterY', str = 0.6) => ({
50      "scale": [
51        ["elInY+elHeight", y],
52        [str, 1],
53      ],
54    }),
55    scaleOut: (y = 'elCenterY', str = 0.6) => ({
56      "scale": [
57        [y, "elOutY-elHeight"],
58        [1, str],
59      ],
60    }),
61    slideX: (y = 0, str = 500) => ({
62      "translateX": [
63        ['elInY', y],
64        [0, str],
65      ],
66    }),
67    slideY: (y = 0, str = 500) => ({
68      "translateY": [
69        ['elInY', y],
70        [0, str],
71      ],
72    }),
73    spin: (y = 1000, str = 360) => ({
74      "rotate": [
75        [0, y],
76        [0, str],
77        {
78          modValue: y,
79        }
80      ],
81    }),
82    flipX: (y = 1000, str = 360) => ({
83      "rotateX": [
84        [0, y],
85        [0, str],
86        {
87          modValue: y
88        }
89      ],
90    }),
91    flipY: (y = 1000, str = 360) => ({
92      "rotateY": [
93        [0, y],
94        [0, str],
95        {
96          modValue: y
97        }
98      ],
99    }),
100    jiggle: (y = 50, str = 40) => ({
101      "skewX": [
102        [0, y * 1, y * 2, y * 3, y * 4],
103        [0, str, 0, -str, 0],
104        {
105          modValue: y * 4,
106        }
107      ],
108    }),
109    seesaw: (y = 50, str = 40) => ({
110      "skewY": [
111        [0, y * 1, y * 2, y * 3, y * 4],
112        [0, str, 0, -str, 0],
113        {
114          modValue: y * 4,
115        }
116      ],
117    }),
118    zigzag: (y = 100, str = 100) => ({
119      "translateX": [
120        [0, y * 1, y * 2, y * 3, y * 4],
121        [0, str, 0, -str, 0],
122        {
123          modValue: y * 4,
124        }
125      ],
126    }),
127    hueRotate: (y = 600, str = 360) => ({
128      "hue-rotate": [
129        [0, y],
130        [0, str],
131        {
132          modValue: y,
133        }
134      ],
135    }),
136  }
137
138  const laxInstance = (() => {
139    const transformKeys = ["perspective", "scaleX", "scaleY", "scale", "skewX", "skewY", "skew", "rotateX", "rotateY", "rotate"]
140    const filterKeys = ["blur", "hue-rotate", "brightness"]
141    const translate3dKeys = ["translateX", "translateY", "translateZ"]
142
143    const pxUnits = ["perspective", "border-radius", "blur", "translateX", "translateY", "translateZ"]
144    const degUnits = ["hue-rotate", "rotate", "rotateX", "rotateY", "skew", "skewX", "skewY"]
145
146    function getArrayValues(arr, windowWidth) {
147      if (Array.isArray(arr)) return arr
148
149      const keys = Object.keys(arr).map(x => parseInt(x)).sort((a, b) => a > b ? 1 : -1)
150
151      let retKey = keys[keys.length - 1]
152      for (let i = 0; i < keys.length; i++) {
153        const key = keys[i]
154        if (windowWidth < key) {
155          retKey = key
156          break
157        }
158      }
159
160      return arr[retKey]
161    }
162
163    function lerp(start, end, t) {
164      return start * (1 - t) + end * t
165    }
166
167    function invlerp(a, b, v) {
168      return (v - a) / (b - a)
169    }
170
171    function interpolate(arrA, arrB, v, easingFn) {
172      let k = 0
173
174      arrA.forEach((a) => {
175        if (a < v) k++
176      })
177
178      if (k <= 0) {
179        return arrB[0]
180      }
181
182      if (k >= arrA.length) {
183        return arrB[arrA.length - 1]
184      }
185
186      const j = k - 1
187
188      let vector = invlerp(arrA[j], arrA[k], v)
189      if (easingFn) vector = easingFn(vector)
190      const lerpVal = lerp(arrB[j], arrB[k], vector)
191      return lerpVal
192    }
193
194    const easings = {
195      easeInQuad: t => t * t,
196      easeOutQuad: t => t * (2 - t),
197      easeInOutQuad: t => t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
198      easeInCubic: t => t * t * t,
199      easeOutCubic: t => (--t) * t * t + 1,
200      easeInOutCubic: t => t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
201      easeInQuart: t => t * t * t * t,
202      easeOutQuart: t => 1 - (--t) * t * t * t,
203      easeInOutQuart: t => t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t,
204      easeInQuint: t => t * t * t * t * t,
205      easeOutQuint: t => 1 + (--t) * t * t * t * t,
206      easeInOutQuint: t => t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t,
207      easeOutBounce: t => {
208        const n1 = 7.5625
209        const d1 = 2.75
210
211        if (t < 1 / d1) {
212          return n1 * t * t
213        } else if (t < 2 / d1) {
214          return n1 * (t -= 1.5 / d1) * t + 0.75
215        } else if (t < 2.5 / d1) {
216          return n1 * (t -= 2.25 / d1) * t + 0.9375
217        } else {
218          return n1 * (t -= 2.625 / d1) * t + 0.984375
219        }
220      },
221      easeInBounce: t => {
222        return 1 - easings.easeOutBounce(1 - t)
223      },
224      easeOutBack: t => {
225        const c1 = 1.70158
226        const c3 = c1 + 1
227
228        return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2)
229      },
230      easeInBack: t => {
231        const c1 = 1.70158
232        const c3 = c1 + 1
233
234        return c3 * t * t * t - c1 * t * t
235      },
236    }
237
238    function flattenStyles(styles) {
239      const flattenedStyles = {
240        transform: '',
241        filter: ''
242      }
243
244      const translate3dValues = {
245        translateX: 0.00001,
246        translateY: 0.00001,
247        translateZ: 0.00001
248      }
249
250      Object.keys(styles).forEach((key) => {
251        const val = styles[key]
252        const unit = pxUnits.includes(key) ? 'px' : (degUnits.includes(key) ? 'deg' : '')
253
254        if (translate3dKeys.includes(key)) {
255          translate3dValues[key] = val
256        } else if (transformKeys.includes(key)) {
257          flattenedStyles.transform += `${key}(${val}${unit}) `
258        } else if (filterKeys.includes(key)) {
259          flattenedStyles.filter += `${key}(${val}${unit}) `
260        } else {
261          flattenedStyles[key] = `${val}${unit} `
262        }
263      })
264
265      flattenedStyles.transform = `translate3d(${translate3dValues.translateX}px, ${translate3dValues.translateY}px, ${translate3dValues.translateZ}px) ${flattenedStyles.transform}`
266
267      return flattenedStyles
268    }
269
270    // https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollY#Notes
271    function getScrollPosition() {
272      const supportPageOffset = window.pageXOffset !== undefined
273      const isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat')
274
275      const x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft
276      const y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop
277
278      return [y, x]
279    }
280
281    function parseValue(val, { width, height, x, y }, index) {
282      if (typeof val === 'number') {
283        return val
284      }
285
286      const pageHeight = document.body.scrollHeight
287      const pageWidth = document.body.scrollWidth
288      const screenWidth = window.innerWidth
289      const screenHeight = window.innerHeight
290      const [scrollTop, scrollLeft] = getScrollPosition()
291
292      const left = x + scrollLeft
293      const right = left + width
294      const top = y + scrollTop
295      const bottom = top + height
296
297      return Function(`return ${val
298        .replace(/screenWidth/g, screenWidth)
299        .replace(/screenHeight/g, screenHeight)
300        .replace(/pageHeight/g, pageHeight)
301        .replace(/pageWidth/g, pageWidth)
302        .replace(/elWidth/g, width)
303        .replace(/elHeight/g, height)
304        .replace(/elInY/g, top - screenHeight)
305        .replace(/elOutY/g, bottom)
306        .replace(/elCenterY/g, top + (height / 2) - (screenHeight / 2))
307        .replace(/elInX/g, left - screenWidth)
308        .replace(/elOutX/g, right)
309        .replace(/elCenterX/g, left + (width / 2) - (screenWidth / 2))
310        .replace(/index/g, index)
311        }`)()
312    }
313
314    class LaxDriver {
315      getValueFn
316      name = ''
317      lastValue = 0
318      frameStep = 1
319      m1 = 0
320
321      m2 = 0
322      inertia = 0
323      inertiaEnabled = false
324
325
326      constructor(name, getValueFn, options = {}) {
327        this.name = name
328        this.getValueFn = getValueFn
329
330        Object.keys(options).forEach((key) => {
331          this[key] = options[key]
332        })
333
334        this.lastValue = this.getValueFn(0)
335      }
336
337      getValue = (frame) => {
338        let value = this.lastValue
339
340        if (frame % this.frameStep === 0) {
341          value = this.getValueFn(frame)
342        }
343
344        if (this.inertiaEnabled) {
345          const delta = value - this.lastValue
346          const damping = 0.8
347
348          this.m1 = this.m1 * damping + delta * (1 - damping)
349          this.m2 = this.m2 * damping + this.m1 * (1 - damping)
350          this.inertia = Math.round(this.m2 * 5000) / 15000
351        }
352
353        this.lastValue = value
354        return [this.lastValue, this.inertia]
355      }
356    }
357
358    class LaxElement {
359      domElement
360      transformsData
361      styles = {}
362      selector = ''
363
364      groupIndex = 0
365      laxInstance
366
367      onUpdate
368
369      constructor(selector, laxInstance, domElement, transformsData, groupIndex = 0, options = {}) {
370        this.selector = selector
371        this.laxInstance = laxInstance
372        this.domElement = domElement
373        this.transformsData = transformsData
374        this.groupIndex = groupIndex
375
376        const { style = {}, onUpdate } = options
377
378        Object.keys(style).forEach(key => {
379          domElement.style.setProperty(key, style[key])
380        })
381
382        if (onUpdate) this.onUpdate = onUpdate
383
384        this.calculateTransforms()
385      }
386
387      update = (driverValues, frame) => {
388        const { transforms } = this
389
390        const styles = {}
391
392        for (let driverName in transforms) {
393          const styleBindings = transforms[driverName]
394
395          if (!driverValues[driverName]) {
396            console.error("No lax driver with name: ", driverName)
397          }
398
399          const [value, inertiaValue] = driverValues[driverName]
400
401          for (let key in styleBindings) {
402            const [arr1, arr2, options = {}] = styleBindings[key]
403            const { modValue, frameStep = 1, easing, inertia, inertiaMode, cssFn, cssUnit = '' } = options
404
405            const easingFn = easings[easing]
406
407            if (frame % frameStep === 0) {
408              const v = modValue ? value % modValue : value
409
410              let interpolatedValue = interpolate(arr1, arr2, v, easingFn)
411
412              if (inertia) {
413                let inertiaExtra = inertiaValue * inertia
414                if (inertiaMode === 'absolute') inertiaExtra = Math.abs((inertiaExtra))
415                interpolatedValue += inertiaExtra
416              }
417
418              const unit = cssUnit || pxUnits.includes(key) ? 'px' : (degUnits.includes(key) ? 'deg' : '')
419              const dp = unit === 'px' ? 0 : 3
420              const val = interpolatedValue.toFixed(dp)
421              styles[key] = cssFn ? cssFn(val, this.domElement) : val + cssUnit
422            }
423          }
424        }
425
426        this.applyStyles(styles)
427        if (this.onUpdate) this.onUpdate(driverValues, this.domElement)
428      }
429
430      calculateTransforms = () => {
431        this.transforms = {}
432        const windowWidth = this.laxInstance.windowWidth
433
434        for (let driverName in this.transformsData) {
435          let styleBindings = this.transformsData[driverName]
436
437          const parsedStyleBindings = {}
438
439          const { presets = [] } = styleBindings
440
441          presets.forEach((presetString) => {
442
443            const [presetName, y, str] = presetString.split(":")
444
445            const presetFn = window.lax.presets[presetName]
446
447            if (!presetFn) {
448              console.error("Lax preset cannot be found with name: ", presetName)
449            } else {
450              const preset = presetFn(y, str)
451
452              Object.keys(preset).forEach((key) => {
453                styleBindings[key] = preset[key]
454              })
455            }
456          })
457
458          delete styleBindings.presets
459
460          for (let key in styleBindings) {
461            let [arr1 = [-1e9, 1e9], arr2 = [-1e9, 1e9], options = {}] = styleBindings[key]
462
463            const saveTransform = this.domElement.style.transform
464            this.domElement.style.removeProperty("transform")
465            const bounds = this.domElement.getBoundingClientRect()
466            this.domElement.style.transform = saveTransform
467
468            const parsedArr1 = getArrayValues(arr1, windowWidth).map(i => parseValue(i, bounds, this.groupIndex))
469            const parsedArr2 = getArrayValues(arr2, windowWidth).map(i => parseValue(i, bounds, this.groupIndex))
470
471            parsedStyleBindings[key] = [parsedArr1, parsedArr2, options]
472          }
473
474          this.transforms[driverName] = parsedStyleBindings
475        }
476      }
477
478      applyStyles = (styles) => {
479        const mergedStyles = flattenStyles(styles)
480
481        Object.keys(mergedStyles).forEach((key) => {
482          this.domElement.style.setProperty(key, mergedStyles[key])
483        })
484      }
485    }
486
487    class Lax {
488      drivers = []
489      elements = []
490      frame = 0
491
492      debug = false
493
494      windowWidth = 0
495      windowHeight = 0
496      presets = laxPresets
497
498      debugData = {
499        frameLengths: []
500      }
501
502      init = () => {
503        this.findAndAddElements()
504
505        window.requestAnimationFrame(this.onAnimationFrame)
506        this.windowWidth = document.body.clientWidth
507        this.windowHeight = document.body.clientHeight
508
509        window.onresize = this.onWindowResize
510      }
511
512      onWindowResize = () => {
513        const changed = document.body.clientWidth !== this.windowWidth ||
514          document.body.clientHeight !== this.windowHeight
515
516        if (changed) {
517          this.windowWidth = document.body.clientWidth
518          this.windowHeight = document.body.clientHeight
519          this.elements.forEach(el => el.calculateTransforms())
520        }
521      }
522
523      onAnimationFrame = (e) => {
524        if (this.debug) {
525          this.debugData.frameStart = Date.now()
526        }
527
528        const driverValues = {}
529
530        this.drivers.forEach((driver) => {
531          driverValues[driver.name] = driver.getValue(this.frame)
532        })
533
534        this.elements.forEach((element) => {
535          element.update(driverValues, this.frame)
536        })
537
538        if (this.debug) {
539          this.debugData.frameLengths.push(Date.now() - this.debugData.frameStart)
540        }
541
542        if (this.frame % 60 === 0 && this.debug) {
543          const averageFrameTime = Math.ceil((this.debugData.frameLengths.reduce((a, b) => a + b, 0) / 60))
544          console.log(`Average frame calculation time: ${averageFrameTime}ms`)
545          this.debugData.frameLengths = []
546        }
547
548        this.frame++
549
550        window.requestAnimationFrame(this.onAnimationFrame)
551      }
552
553      addDriver = (name, getValueFn, options = {}) => {
554        this.drivers.push(
555          new LaxDriver(name, getValueFn, options)
556        )
557      }
558
559      removeDriver = (name) => {
560        this.drivers = this.drivers.filter(driver => driver.name !== name)
561      }
562
563      findAndAddElements = () => {
564        this.elements = []
565        const elements = document.querySelectorAll(".lax")
566
567        elements.forEach((domElement) => {
568          const driverName = "scrollY"
569          const presets = []
570
571          domElement.classList.forEach((className) => {
572            if (className.includes("lax_preset")) {
573              const preset = className.replace("lax_preset_", "")
574              presets.push(preset)
575            }
576          })
577
578          const transforms = {
579            [driverName]: {
580              presets
581            }
582          }
583
584          this.elements.push(new LaxElement('.lax', this, domElement, transforms, 0, {}))
585        })
586      }
587
588      addElements = (selector, transforms, options = {}) => {
589        const domElements = options.domElements || document.querySelectorAll(selector)
590
591        domElements.forEach((domElement, i) => {
592          this.elements.push(new LaxElement(selector, this, domElement, transforms, i, options))
593        })
594      }
595
596      removeElements = (selector) => {
597        this.elements = this.elements.filter(element => element.selector !== selector)
598      }
599
600      addElement = (domElement, transforms, options) => {
601        this.elements.push(new LaxElement('', this, domElement, transforms, 0, options))
602      }
603
604      removeElement = (domElement) => {
605        this.elements = this.elements.filter(element => element.domElement !== domElement)
606      }
607    }
608
609    return new Lax()
610  })()
611
612  if (typeof module !== 'undefined' && typeof module.exports !== 'undefined')
613    module.exports = laxInstance
614  else
615    window.lax = laxInstance
616})()

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.