`Zooming and scrolling feature within a masked image`

I'm struggling to achieve a scrolling zoom effect similar to the website mentioned below, but I can't seem to get it to fully zoom.

Additionally, when I try to zoom in on a clipped shape or text while scrolling, the entire div ends up scrolling along with it.

I've set the zoom breakpoint to

document.body.clientWidth / imgElement.clientHeight
, but I'm unable to find an alternative solution.

Any suggestions would be greatly appreciated!
Thank you in advance.

https://i.sstatic.net/ZSBCo.jpg

View Sample Link of the Website

const zoomElement = document.querySelector('.zoom')
const afterZoomElement = document.querySelector('.afterzoom')
const imgElement = document.querySelector('h2')
const WIDTH = document.body.clientWidth
const HEIGHT = zoomElement.clientHeight
const IMAGE_WIDTH = imgElement.clientWidth
const IMAGE_HEIGHT = imgElement.clientHeight
const ZOOM_SPEED = 200 // Lower value for faster speed
const ZOOM_BREAKPOINT = WIDTH / IMAGE_HEIGHT // Point at which zooming should stop
const IMAGE_HEIGHT_MAX = IMAGE_HEIGHT * ZOOM_BREAKPOINT
const ABSOLUTE = ZOOM_BREAKPOINT * ZOOM_SPEED // Absolute position when element reaches maximum size

// Fade --------------------------------------------------------------------------------------
const FADE_SPEED = 400 // Lower value for faster speed
let fade = 1
let prev = 0
// -------------------------------------------------------------------------------------- Fade

function animate() {
    let scroll = window.scrollY
    let temp = scroll / ZOOM_SPEED
    let zoom = temp > 1 ? temp : 1

    if (zoom < ZOOM_BREAKPOINT) {
        imgElement.style.transform = `scale(${zoom})`
        zoomElement.style.top = '0px'
        zoomElement.style.position = 'fixed'
    } else {
        imgElement.style.transform = `scale(${ZOOM_BREAKPOINT})`
        zoomElement.style.position = 'absolute'
        zoomElement.style.top = ABSOLUTE + 'px'
    }

    let dif = prev - scroll

    if (zoom < ZOOM_BREAKPOINT - FADE_SPEED / ZOOM_SPEED) {
        fade = 1
    } else if (zoom > ZOOM_BREAKPOINT) {
        fade = 0
    } else {
        fade += dif / FADE_SPEED
    }

    fadeElement.style.opacity = fade
    prev = scroll
}

if ('scrollRestoration' in history) {
    history.scrollRestoration = 'manual'
}

document.addEventListener('scroll', () => window.requestAnimationFrame(animate))

zoomElement.style.opacity = 1

afterZoomElement.style.top = ABSOLUTE + IMAGE_HEIGHT_MAX / 2 + HEIGHT / 2 + 'px'
body {
    margin: 0;
}

h2 {
  height: 100vh;
  width: 100vw;
  background-color: black;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 5em;
  text-transform: uppercase;
  background: url(https://24.media.tumblr.com/tumblr_m87dri70zh1qzla33o1_500.gif);
  background-size: cover;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.zoom {
  height: 100vh;
  width: 100%;
  display: grid;
  place-items: center;
  position: fixed;
  top: 0;
  left: 0;
}

.afterzoom {
  position: absolute;
  height: 100vh;
  width: 100%;
  background: red;
  overflow-x: auto;
}

h2{
  font-size: 5em;
  text-transform: uppercase;
  background: url(https://24.media.tumblr.com/tumblr_m87dri70zh1qzla33o1_500.gif);
  background-size: cover;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
<div class="zoom">
  <h2>i</h2>
</div>
<div class="afterzoom">
    <p>This content will appear after the above element is fully zoomed.</p>
</div>

Answer №1

Give this a shot. Just an FYI, fadeElement isn't defined in the code you provided so I left that part out. You can adjust the zoom breakpoint depending on how much zoom you want to apply.

function animateZoom() {
        let scrollPos = window.scrollY;
        let tempCalc = scrollPos / ZOOM_SPEED;
        let zoomLevel = tempCalc > 1 ? tempCalc : 1;

        // Updating the scaling for the text or shape based on zoom level
        if (zoomLevel < ZOOM_BREAKPOINT) {
            imgElement.style.transform = `scale(${zoomLevel})`;
            zoomElement.style.position = 'fixed';
        } else {
            imgElement.style.transform = `scale(${ZOOM_BREAKPOINT})`;
            zoomElement.style.position = 'absolute';
            zoomElement.style.top = `${ABSOLUTE}px`;
        }

        // Updating the fade transition effect
        let diff = previousScrollPos - scrollPos;
        let fadeValue = (zoomLevel < ZOOM_BREAKPOINT) ? 1 : 0;
        fadeValue += (zoomLevel >= ZOOM_BREAKPOINT && zoomLevel <= (ZOOM_BREAKPOINT + (FADE_SPEED / ZOOM_SPEED))) ? diff / FADE_SPEED : 0;
        //fadeElement.style.opacity = fadeValue;
        previousScrollPos = scrollPos;

        // Adjusting the position of afterZoomElement
        afterZoomElement.style.top = `${ABSOLUTE + IMAGE_HEIGHT_MAX}px`;
    }
.zoom {
        overflow: hidden;
        /* Other styles */
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble with processing the binding? Use ko.mapping.fromJS to push JSON data into an ObservableArray

Hey everyone, I'm struggling with my code and could really use some help. I'm new to knockout and encountering an issue. Initially, I receive JSON data from the database and it works fine. However, when I click 'Add some', I'm tryi ...

How can we determine which MenuItems to open onClick in a material-ui Appbar with multiple Menus in a React application?

While following the examples provided on the material UI site, I successfully created an AppBar with a menu that works well with one dropdown. However, upon attempting to add a second dropdown menu, I encountered an issue where clicking either icon resulte ...

Tips for passing input fields from a React Function component to a function

How can I retrieve the values from 4 input fields in my react functional component using a function called contactMeButtonPressed? The inputs include name, email, company name, and message when the contact me button is clicked. Do I need to implement stat ...

Setting up a basic testcafe configuration with ES modules

Unique Title When it comes to using ES modules with Testcafe, the documentation may not provide clear instructions on configuring global hooks. There seems to be limited options for configuring Testcafe globally, such as using .json or CommonJS. In my pr ...

Exploring the functionality of textareas within iframes on iPad

There is a known issue where textareas and inputs do not function properly on iPad Safari when placed inside an iframe. For more information, visit: This bug can easily be reproduced on iOS 7, but seems to work fine on iOS 8. Despite this issue, I am in ...

Fill the table with information from a JSON file by selecting options from drop-down menus

I am currently working on a web application project that involves bus timetables. My goal is to display the timetable data in a table using dropdown menus populated with JSON information. While I believe I have tackled the JSON aspect correctly, I am facin ...

What could be causing my React app to consistently reload whenever I save a file in my project?

Hi there, I am currently working on a project using React, GraphQL, Node, and MongoDB. I have been trying to upload images to a folder within my app, but I am facing an issue with the app reloading after saving the file. I attempted to manage a local state ...

Mastering the art of utilizing the LESS preprocessor with React Create-React-APP

Is it possible to implement the LESS preprocessor in my create-react-app project? In my React code, I have the following: ReactDOM.render( <form> <input type="email" data-info="Enter Email" pattern="/\S+@\S+\.\S+/ ...

Minimizing repeated autofocus calls in material-ui's <TextField> component

In the realm of coding with material-ui, when dealing with the <TextField> component, it's important to keep in mind that the solution may actually lie within React itself. Let's paint a scenario where we're crafting a basic login for ...

Press the button to activate the function

<table class="calc" cellpadding=2> <td><input type="button" class="calc" id="screen" value="0" ></td> <td><input type="button" class="calc" id="screen" value="0" ></td> <tr> </ ...

Unusual symbols in HTML code

While working on a website project that utilizes a web font running on Apache, I encountered an issue specifically on Google Chrome for Android. The text displayed weird characters between existing characters, and initially I thought it was related to enco ...

What is the process for defining default prop data in Next.js?

Currently, I am in the process of developing a React/Next app with CRUD functionality. In regards to the update form, I have included the code below which is responsible for fetching existing data and updating it via an API. However, there seems to be a ma ...

Set the mesh position in Three.js to the coordinates 0,0,0

I'm currently working on positioning a basic cube at coordinates 0,0,0. When I try to position the cube at 0,0,0, I end up with this outcome: https://i.sstatic.net/S2zom.png However, this is not the desired result. Here is what I am aiming for: http ...

Deselect an item from a three.js scene by clicking on it

In my three.js scene, I have multiple OBJ models, some already loaded in the scene and others added via a button click. If a user adds an object but later decides to remove it, I am seeking guidance on how to accomplish this effectively. My ideal solutio ...

Having trouble accessing Kotlin JS from JavaScript

I'm currently experiencing an issue where I am unable to call any Kotlin JS function and receiving an error stating that 'something' is not defined. Initially, I attempted compiling the project with Gradle but found success after following ...

Error in finding the element with Selenium webdriver 2.0 was encountered

I can't seem to find the element with the specified class name. Here's a snippet of the HTML code: <a class="j-js-stream-options j-homenav-options jive-icon-med jive-icon-gear" title="Stream options" href="#"></a> I attempted to gen ...

Is a function repeatedly invoked?

I have implemented a Pagination component in NextJS as follows: import Pagination from 'react-bootstrap/Pagination'; import Router from "next/router"; import {useEffect} from "react"; export { Paging } function Paging(props) ...

Leveraging HTML5 Canvas for blending multiple transformations

Is it possible to zoom out an image, rotate it by 30 degrees around its center, and then vertically flip the rotated image while maintaining the rotation? ...

Enhanced Compatibility of HTML5/CSS3 Modal Box with Internet Explorer

I'm experimenting with HTML5/CSS3 for the first time and have implemented a cool little link to display a dialog (modal) on one of my web pages. While this works perfectly in Chrome/Firefox, it unfortunately doesn't function properly in Internet ...

Customize the element of the root node of a MUI component using the styled()

I am trying to implement the "component" prop with a MUI component (such as ListItem) using the styled() API. However, I am facing an issue where it says that "component" is not a valid prop. Can someone guide me on how to correctly achieve this? I have se ...