diff --git a/website/assets/js/components/parallax-city.component.js b/website/assets/js/components/parallax-city.component.js index b96cb58435..f023d03fff 100644 --- a/website/assets/js/components/parallax-city.component.js +++ b/website/assets/js/components/parallax-city.component.js @@ -13,19 +13,19 @@ parasails.registerComponent('parallaxCity', { // ╔═╗╦═╗╔═╗╔═╗╔═╗ // ╠═╝╠╦╝║ ║╠═╝╚═╗ // ╩ ╩╚═╚═╝╩ ╚═╝ - props: ['isMobile'], + props: [], // ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗ // ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣ // ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝ data: function (){ return { - parallaxCityElement: undefined, - elementBottomPosition: undefined, - elementHeight: undefined, - distanceFromTopOfPage: undefined, - distanceFromBottomOfPage: undefined, - isAnimating: false, + parallaxCityElement: undefined,// For storing a jquery reference to the paralax-city-container div. + parallaxLayers: [],// Stores an array of dictionaries, each containing a reference to a parallax-layer element, and the scroll-amount attribute + elementBottomPosition: undefined,// For keeping track of the bottom position of the parllax image. + elementHeight: undefined,// For keeping track of how large the parallax image element's height + distanceFromTopOfPage: undefined, // Used to check if the image is within the user's viewport. + distanceFromBottomOfPage: undefined, // Used to track the amount of distance between the bottom of the image, and the bottom of the page. }; }, @@ -54,73 +54,54 @@ parasails.registerComponent('parallaxCity', { }, mounted: async function(){ - if(!this.isMobile){ - this.parallaxCityElement = document.querySelector('[purpose="parallax-city-container"]'); - this.elementHeight = this.parallaxCityElement.clientHeight; - this.distanceFromTopOfPage = this.parallaxCityElement.offsetTop; - this.distanceFromBottomOfPage = document.body.scrollHeight - this.distanceFromTopOfPage - (this.elementHeight * .5); - this.elementBottomPosition = this.elementHeight + this.distanceFromTopOfPage; - let parallaxCityElementPosition = this.parallaxCityElement.getBoundingClientRect(); - if(parallaxCityElementPosition.bottom > this.distanceFromTopOfPage) { - this.handleParallaxScroll(); + if(!bowser.isMobile){ + // Store a reference to the parent container, we'll use this to determine the elements position relative to the user's viewport. + this.parallaxCityElement = $('div[purpose="parallax-city-container"]')[0]; + // Build an array of parallax layers, and set the initial bottom position of each layer to be negative the layer's scroll amount. + for(let layer of $('div.parallax-layer')) { + let scrollAmount = Number($(layer).attr('scroll-amount')); + $(layer).css('bottom', `-${scrollAmount}px`); + this.parallaxLayers.push({element: layer, scrollAmount}); } - - this.parallaxCityElement.querySelectorAll('div.parallax-layer').forEach((layer)=>{ - let initialPosition = layer.getAttribute('scroll-amount'); - layer.style.bottom = `-${Number(initialPosition) + 4}px`; - }); - - window.addEventListener('scroll', this.onScroll); - window.addEventListener('resize', this.updateElementPositions); - window.addEventListener('orientationchange', this.updateElementPositions); + // Determine the parallax image's position on the page/user's viewport. + this.getElementPositions(); + // If the bottom of the element is within the user's viewport, update the positions of the layers. + if(this.parallaxCityElement.getBoundingClientRect().bottom > this.parallaxCityElement.offsetTop) { + this.scrollParallaxLayers(); + } + // Add a scroll event listener + $(window).scroll(this.scrollParallaxLayers); + // Add a resize event listener. + $(window).resize(this.getElementPositions); } }, beforeDestroy: function() { - if(!this.isMobile){ - window.removeEventListener('scroll', this.onScroll); - window.removeEventListener('resize', this.updateElementPositions); - window.removeEventListener('orientationchange', this.updateElementPositions); - } + }, // ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ // ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗ // ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝ methods: { - updateElementPositions: function() { + getElementPositions: function() { this.elementHeight = this.parallaxCityElement.clientHeight; this.distanceFromTopOfPage = this.parallaxCityElement.offsetTop; + this.distanceFromBottomOfPage = document.body.scrollHeight - this.distanceFromTopOfPage - (this.elementHeight * .5); this.elementBottomPosition = this.elementHeight + this.distanceFromTopOfPage; }, - onScroll: function() { - if(!this.isAnimating){ - this.isAnimating = true; - window.requestAnimationFrame(this.handleParallaxScroll); - } - return; - }, - handleParallaxScroll: function() { - let viewportBottom = window.scrollY + window.innerHeight; - let percentageScrolled; - if (this.parallaxCityElement.offsetTop < viewportBottom) { - let visibleHeight = viewportBottom - Math.max(this.distanceFromTopOfPage, window.scrollY); - percentageScrolled = visibleHeight / (this.distanceFromBottomOfPage + (this.elementHeight / 2 )); - } else { - percentageScrolled = 0; - } - if(percentageScrolled > 1){ - percentageScrolled = 1; - } - percentageScrolled = percentageScrolled.toFixed(4); - if(percentageScrolled > .25){// When the element has been scrolled down 25%, start adjusting the position of layers. + scrollParallaxLayers: function() { + // Calculate how much of the parallax image is visible. + let visibleHeight = (window.scrollY + window.innerHeight) - Math.max(this.distanceFromTopOfPage, window.scrollY); + let percentageScrolled = visibleHeight / (this.distanceFromBottomOfPage + (this.elementHeight / 2 )); + // When the element has been scrolled down 25%, iterate through the layers and update their positions. + if(percentageScrolled > .25 ){ let adjustedPercentage = (percentageScrolled - .25) * 4/3; - this.parallaxCityElement.querySelectorAll('div.parallax-layer').forEach((layer) => { - let scrollAmount = layer.getAttribute('scroll-amount'); - let movement = adjustedPercentage * scrollAmount; - layer.style.transform = 'translateY(-' + movement + 'px)'; - }); + for(let layer of this.parallaxLayers) { + let movement = Math.min(adjustedPercentage * layer.scrollAmount, layer.scrollAmount); + // Update the position of each layer. + $(layer.element).css('transform', 'translate3D(0, -' + movement + 'px, 0)'); + } } - this.isAnimating = false; }, } }); diff --git a/website/assets/styles/components/parallax-city.component.less b/website/assets/styles/components/parallax-city.component.less index b9ed8f2366..8becc971ca 100644 --- a/website/assets/styles/components/parallax-city.component.less +++ b/website/assets/styles/components/parallax-city.component.less @@ -28,7 +28,6 @@ } [purpose='foreground-cloud-1'] { background-image: url('/images/parallax-cloud-city/1-cloud-7050x600@2x.png'); - background-position: center bottom; background-repeat: no-repeat; z-index: 100; diff --git a/website/views/pages/device-management.ejs b/website/views/pages/device-management.ejs index f1b27f1441..84bef812c6 100644 --- a/website/views/pages/device-management.ejs +++ b/website/views/pages/device-management.ejs @@ -211,6 +211,6 @@ <%/* Cloud city banner */%> - + <%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %> diff --git a/website/views/pages/endpoint-ops.ejs b/website/views/pages/endpoint-ops.ejs index bf4758fd48..fb63338124 100644 --- a/website/views/pages/endpoint-ops.ejs +++ b/website/views/pages/endpoint-ops.ejs @@ -192,7 +192,7 @@ <%/* Cloud city banner */%> - + diff --git a/website/views/pages/homepage.ejs b/website/views/pages/homepage.ejs index e7008e3082..9a4f1cfb8e 100644 --- a/website/views/pages/homepage.ejs +++ b/website/views/pages/homepage.ejs @@ -322,7 +322,7 @@ <%/* Cloud city banner */%> - + diff --git a/website/views/pages/vulnerability-management.ejs b/website/views/pages/vulnerability-management.ejs index c3323fcde9..04aadf0c57 100644 --- a/website/views/pages/vulnerability-management.ejs +++ b/website/views/pages/vulnerability-management.ejs @@ -151,7 +151,7 @@ <%/* Cloud city banner */%> - +