Custom Element Interaction with Browser Scroll

Not sure if this will work, you will have to optimize it…

Approach 1: Using getBoundingRect directly in the Custom Element

The example I provided earlier where the custom element calculates its own coordinates using this.getBoundingClientRect() is also a valid approach. Here’s a quick reminder of that:

class ImageSequenceElement extends HTMLElement {
    constructor() {
        super();
        this.images = [];
        this.loadedImages = [];
        this.imageIndex = 0;
        this.canvas = document.createElement('canvas');
        this.ctx = this.canvas.getContext('2d');
        this.appendChild(this.canvas);
    }

    connectedCallback() {
        this.preloadImages(this.images, () => {
            this.canvas.style.height = `100vh`;
            window.addEventListener('wheel', this.onScroll.bind(this));
            this.drawImage(this.loadedImages[0]);
        });
    }

    preloadImages(images, callback) {
        let loadedCount = 0;
        images.forEach((src, index) => {
            const img = new Image();
            img.src = src;
            img.onload = () => {
                this.loadedImages[index] = img;
                loadedCount++;
                if (loadedCount === images.length) {
                    callback();
                }
            };
        });
    }

    onScroll() {
        this.changeImage();
    }

    changeImage() {
        const iCoordinates = this.getBoundingClientRect();
        console.log('Element Coordinates:', iCoordinates);

        if (iCoordinates.top > 200) {
            this.imageIndex = 0;
            this.drawImage(this.loadedImages[0]);
            return;
        } else {
            if (this.imageIndex >= this.images.length) {
                this.imageIndex = this.images.length - 1;
            }
            if (this.imageIndex < this.images.length) {
                this.drawImage(this.loadedImages[this.imageIndex]);
            }
            this.drawImage(this.loadedImages[this.imageIndex++]);
        }
    }

    drawImage(img) {
        const canvasWidth = this.canvas.width = window.innerWidth;
        const canvasHeight = this.canvas.height = window.innerHeight;
        const aspectRatio = img.width / img.height;
        let newWidth, newHeight;

        if (canvasWidth / aspectRatio <= canvasHeight) {
            newWidth = canvasWidth;
            newHeight = canvasWidth / aspectRatio;
        } else {
            newHeight = canvasHeight;
            newWidth = canvasHeight * aspectRatio;
        }

        const x = (canvasWidth - newWidth) / 2;
        const y = (canvasHeight - newHeight) / 2;

        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.drawImage(img, x, y, newWidth, newHeight);
    }
}

// Define the custom element
customElements.define('image-sequence-element', ImageSequenceElement);

Approach-2: Using getBoundingRect() from Wix-Page, sending it to the CE…

class ImageSequenceElement extends HTMLElement {
    constructor() {
        super();
        this.images = []; // Array to hold your images
        this.loadedImages = []; // Array to hold preloaded images
        this.imageIndex = 0; // To track the current image index
        this.canvas = document.createElement('canvas'); // Create a canvas element
        this.ctx = this.canvas.getContext('2d');
        this.appendChild(this.canvas); // Append the canvas to the custom element
    }

    connectedCallback() {
        // Preload images and initialize
        this.preloadImages(this.images, () => {
            this.canvas.style.height = `100vh`;
            window.addEventListener('wheel', this.onScroll.bind(this));
            this.drawImage(this.loadedImages[0]);
        });
    }

    preloadImages(images, callback) {
        // Logic to preload images
        let loadedCount = 0;
        images.forEach((src, index) => {
            const img = new Image();
            img.src = src;
            img.onload = () => {
                this.loadedImages[index] = img;
                loadedCount++;
                if (loadedCount === images.length) {
                    callback();
                }
            };
        });
    }

    onScroll() {
        this.changeImage();
    }

    updateCoordinates(coordinates) {
        this.iCoordinates = coordinates;
        this.changeImage();
    }

    changeImage() {
        if (!this.iCoordinates) return;

        console.log('Element Coordinates:', this.iCoordinates); // Debugging log

        if (this.iCoordinates.top > 200) {
            this.imageIndex = 0;
            this.drawImage(this.loadedImages[0]);
            return;
        } else {
            if (this.imageIndex >= this.images.length) {
                this.imageIndex = this.images.length - 1;
            }
            if (this.imageIndex < this.images.length) {
                this.drawImage(this.loadedImages[this.imageIndex]);
            }
            this.drawImage(this.loadedImages[this.imageIndex++]);
        }
    }

    drawImage(img) {
        const canvasWidth = this.canvas.width = window.innerWidth;
        const canvasHeight = this.canvas.height = window.innerHeight;
        const aspectRatio = img.width / img.height;
        let newWidth, newHeight;

        if (canvasWidth / aspectRatio <= canvasHeight) {
            newWidth = canvasWidth;
            newHeight = canvasWidth / aspectRatio;
        } else {
            newHeight = canvasHeight;
            newWidth = canvasHeight * aspectRatio;
        }

        const x = (canvasWidth - newWidth) / 2;
        const y = (canvasHeight - newHeight) / 2;

        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.drawImage(img, x, y, newWidth, newHeight);
    }
}

// Define the custom element
customElements.define('image-sequence-element', ImageSequenceElement);
1 Like