Efficient jQuery Algorithm for Calculating Image Viewport Sizes Without Scrollbars

I am trying to create an image hover effect, but I am encountering an issue. When I hover over certain images, unwanted scrollbars appear, and I would like to find a way to prevent this from happening. It seems to be related to the viewport and calculations, but I am unsure of the solution.

Check out an example here

View the JSBin code here

Here is the code snippet I am working with:

$('.simplehover').each(function(){
    var $this = $(this);        
    var isrc = $this[0].src, dv = null;
                        
    $this.mouseenter(function(e){
        dv = $('<div />')
            .attr('class', '__shidivbox__')
            .css({
                display: 'none',
                zIndex : 9999,
                position: 'absolute',
                top: e.pageY + 20,
                left: e.pageX + 20
            })
            .html('<img alt="" src="' + isrc + '" />')
            .appendTo(document.body);           
        dv.fadeIn('fast');
    })
    .mouseleave(function(){
        dv.fadeOut('fast');
    });         

});

Can someone please assist me in positioning the hovered image in a way that prevents scrollbars from appearing? (Unless the image size is exceptionally large)

I want to display the original image on zoom without causing scrollbars to show as much as possible.

Please note: I intend to convert this into a jQuery plugin, so I cannot require users of the plugin to set overflow to hidden. The solution should involve properties like viewport, left, top, scroll width, height, window width/height for future incorporation.


Update:

I have made some progress with this solution:

Check it out here

However, it still feels like a hacky fix and not entirely perfect. I am seeking a better algorithm or solution. There are hover plugins that handle this elegantly, but due to my limited expertise, I am struggling. For example, the Hover Zoom Chrome Plugin does an excellent job of positioning hovered images based on their size.

Answer №1

Here's an example:

html{overflow-x:hidden;}
html{overflow-y:hidden;}

To implement this on your website, simply add these CSS definitions and you're good to go.

Update for Resizing: This code handles resizing and positioning images when hovered, both horizontally and vertically. Regardless of where the image appears, it will always be displayed in full without being cut off. If you have more thumbnails than can fit on the page, scrollbars will appear even before the hover images show up.

Final Working Update: While focusing on hiding scrollbars, it's important to consider that if there are more thumbnails than the viewport can display, scrollbars will appear anyway. Therefore, when calculating the position of the hover image, not only the resize but also the scrollTop position must be taken into account! Check out the final JSBin here, where all images are resized and displayed in full regardless of scrollTop and viewport size.

$this.mouseenter(function () {

    // Code for resizing and positioning images

});

Answer №2

To adjust the position of the image, consider the available width: http://example.com/adjust-image

This demonstration considers the space available for positioning the image (such as the window width minus the image width). Additionally, I have enhanced the event order, ensuring the popup div only fades in after the image has fully loaded.

Answer №3

Here is my responsive image adaptation script (JSBin DEMO)

$('.simplehover').each(function(){
        var $this = $(this);

        // Confirm that the element is an image
        if (! $this.is('img')) return false;

        var isrc = $this[0].src, dv = null;

        if (! isrc) return false;

        $this.mouseenter(function(e){
            // Get mouse position
            var initXPos = e.pageX;
            var initYPos = e.pageY+20-$(window).scrollTop();
            var windowWidth = $(window).width();
            var windowHeight = $(window).height();
            // Load the original image
            var $img = $('<img/>');
            $img.on('load',function(eload) {
                var widthImage = this.width;
                var heightImage = this.height;
                // Set inline style to get sizes later
                $(this).css('width',widthImage);
                $(this).css('height',heightImage);
                var ratio = widthImage/heightImage;

                var finalXPos = initXPos+widthImage>windowWidth? windowWidth-widthImage-5 : initXPos;
                var finalYPos = initYPos;

                var img = this;


                // Resize image if bigger than window
                if(finalXPos<0)  {
                    finalXPos = 0;
                    $img.css('width', windowWidth-10);
                    $img.css('height',(windowWidth-10)/ratio);
                }

                // Handle overflow on Y axis

                if(finalYPos+getSize($img,'height')>windowHeight) {

                    // Determine whether to show on top or bottom
                    var showOnTop = (windowHeight-initYPos-10)<windowHeight/2;
                    if(showOnTop) {
                        if(initYPos<getSize($img,'height')) {
                            $img.height(initYPos-30);
                            $img.width(getSize($img,'height')*ratio);
                        }
                        finalYPos = 0;
                        finalXPos = initXPos+getSize($img,'width')>windowWidth? windowWidth-getSize($img,'width')-5 : initXPos;

                    }else {
                        // Show on bottom
                        if(windowHeight-initYPos<getSize($img,'height')) {
                            $img.height(windowHeight-initYPos-10);
                            $img.width(getSize($img,'height')*ratio);

                        }
                        finalXPos = initXPos+getSize($img,'width')>windowWidth? windowWidth-getSize($img,'width')-5 : initXPos;
                    }
                }
                dv = $('<div />')
                .attr('class', '__shidivbox__')
                .css({
                    display: 'none',
                    zIndex : 9999,
                    position: 'absolute',
                    MozBorderRadius : '5px',
                    WebkitBorderRadius : '5px',
                    borderRadius : '5px',
                    top: finalYPos+$(window).scrollTop(),
                    left: finalXPos
                }).append($img)
                .appendTo(document.body);           
            dv.fadeIn('fast');
            });
            // Load the original image
            $img.attr("src",$this.attr("src"));

            function getSize($el,widthOrHeight) {
                return +$el.css(widthOrHeight).replace("px","");
            }
        })
        .mouseleave(function(){
            dv.fadeOut('fast');
        });         

    });

This script adjusts images to fit the window size and position them correctly on the x-axis if necessary.

Answer №4

Hey there! Let's dive into something exciting. Check out my response. I've been observing this for a few days and thought I'd join in too. The following code ensures that the images hover within the viewport. In case the image width exceeds the display space, the image will be resized accordingly (Feel free to disable this feature by commenting out the code section related to resizing).

var $document = $(document);
$('.simplehover').each(function(){
    var $this = $(this);
    // Confirm if the element is actually an image
    if (! $this.is('img')) return false;

    var isrc = $this[0].src, ibox = null;

    if (! isrc) return false;
    ibox = $('<img />')
            .attr('class', 'simpleimagehover__shidivbox__')
            .css({
                display: 'none',
                zIndex : 99,
                MozBoxShadow: '0 0 1em #000', 
                WebkitBoxShadow: '0 0 1em #000',
                boxShadow: '0 0 1em #000',
                position: 'absolute',
                MozBorderRadius : '10px',
                WebkitBorderRadius : '10px',
                borderRadius : '10px'
            })
            .attr('src', isrc)
            .appendTo(document.body);          

    $this.bind('mouseenter mousemove', function(e) {
        $('.simpleimagehover__shidivbox__').hide();

        var left = e.pageX + 5, 
            top = e.pageY + 5,
            ww = window.innerWidth,
            wh = window.innerHeight,
            w = ibox.width(),
            h = ibox.height(),
            overflowedW = 0,
            overflowedH = 0;

        // Calculate to show element without exceeding viewport
        // Code for resizing image if it overflows
        // Other functionality goes here

    }); 

    // More event bindings and functionalities here

});

While my solution isn't flawless, you may discover some helpful insights regarding viewport determination. Additionally, consider optimizing the code for performance. Since this is a plugin under development, ensure it runs efficiently before releasing it to the public. The key is to keep it fast and responsive.

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

Touch interaction operates differently than mouse movement

Imagine three neighboring divs, div1, div2, and div3. When I click on div1 and then move my mouse to div2, the mousemove event is triggered with div2 as the target. However, on mobile devices, if I tap on div1 (touchstart) and slide my finger to div2, the ...

Firefox does not allow contenteditable elements to be edited if they are nested inside a parent element that is draggable

Here is a basic HTML example: <div draggable=true> <div contenteditable=true>can't edit me</div> </div> When testing in Chrome, I noticed that I was able to edit the contents of the contenteditable div, however, this functi ...

CSS slider thumb with visible track behind it

Looking at the images below, or visiting , you can notice that the slider track is visible behind the slider thumb. Check out the images here: Image 1 and Image 2. The CSS for my slider looks like this: input[type=range] { appearance: none; backgro ...

I'm curious about which datatype is best to showcase dates in the Jquery Datatable plugin

For my Jquery Datatable grid, I am trying to bind a date datatype in one of the columns. However, I mistakenly passed it as a string datatype instead of date datatype. Now, I want to sort the records based on this date column. What datatype should I use t ...

What is preventing the 'p:nth-child(1)' from functioning properly in my HTML code?

Even though I used p:nth-child(1){color: white;} in my CSS style tag, it did not produce the expected result. body { background-color: #162b85; } button, p:nth-child(1) { color: white; } <p class="center">Register your account</p&g ...

Unable to implement new ecmascript decorators within typescript version 2.4.2

Check out this example code: function enumerable(value: boolean) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { descriptor.enumerable = value; }; } class A { @enumerable(false) a: number = 1 b: number ...

Blurring a section of a circular image using a combination of CSS and JavaScript

I'm trying to achieve a specific effect with my circular image and overlaying div. I want the overlaying div to only partially shade out the image based on a certain degree value. For example, if I specify 100 degrees, I only want 260 degrees of the c ...

The AJAX request is not executing the xmlhttp.open method for running the script

Currently, I am making adjustments to the tutorial available at this website: http://www.w3schools.com/ajax/ajax_aspphp.asp. My modification involves storing a library of autocomplete names in a database. I have implemented a button that allows users to ...

Personalize the material design datatable checkbox option

Recently, I delved into the world of material-ui design in conjunction with ReactJS. However, I have encountered a roadblock while attempting to customize the style of a checkbox that is being displayed under the <TableRow /> component. (Check out th ...

Utilizing React to pass parent state to a child component becomes more complex when the parent state is derived from external classes and is subsequently modified. In this scenario,

I'm struggling to find the right way to articulate my issue in the title because it's quite specific to my current situation. Basically, I have two external classes structured like this: class Config { public level: number = 1; //this is a s ...

Utilizing jQuery to send data to a PHP script

Actually, I am not very familiar with jQuery. I have a jQuery script that passes variables to a file which displays data in JSON format. However, I am unable to show that data using the code below: $(document).ready(function() { var globalRequest = 0; ...

Customize border color for a single cell in a table using Bootstrap 4

I'm facing an issue where I'm trying to apply a red border color to a specific cell, but it's not appearing on the top and left sides of the cell. It seems like the border color of other cells is taking precedence over the one I'm tryin ...

Ways to position two images in the center

A website has been created by me and now I am looking to center text on the two images in the header. Here is the relevant code snippet: <div class="header"> <img src="css/title578145459.png" class="headerImage left&qu ...

Tips for making a horizontal grid layout with three items in each row

I have a scenario where I need to render a group of Player components using map() loop, and I want them to be displayed horizontally side by side using a Grid component from material-ui. Currently, the components are rendering in a vertical layout: https ...

Minify and group options available for asset managers specifically designed for traditional HTML websites

My primary focus is on working with the CakePHP framework and utilizing a fantastic plugin that minifies and groups selected assets into a single file, reducing the number of HTTP requests needed for the entire site. Currently, I am collaborating with des ...

Create an HTML div element that spans the full width of the

I'm facing an issue on my HTML page where a div containing users from a chat system database is not displaying correctly. The ul li tag within the parent div is not taking up the full width as expected. Here's how it should look: http://prntscr.c ...

Choosing elements in jQuery

Having some trouble with the subnav on my current website project. I think the issue lies in how I am selecting items in my jquery code. It seems like a small fix that needs to be made, but I'm unsure of the correct approach. http://jsfiddle.net/ZDEr ...

Implementing a callback function in Vue js 2 for handling dispatched actions within a component

Is there a method to determine if the action dispatched from a component has completed without utilizing state management? Currently, I have an action called createAddress. In my component, there is a modal where users input their address. Once the user en ...

Removing the column name from a JSON return in C# involves using a variety of techniques

Below is a JSON output I have received : [ { positionCode: "POS1", positionName: "POSITION 1", positionDescription: "", parentPosition: "POS2", }, { positionCode: "POS2", positionName: "POSITION ...

What is the best way to assign a value to the param tag of an applet using JavaScript variables

This is my external javaScript file named myJs.js function search(){ var hint = document.getElementById("sChoice").value; var item = document.getElementById("sKey").value; document.getElementById("c").value=hint; document.getElementById ...