Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS function - Math optimization, off by 1 in some cases

I'm still wet behind the ears with web dev, not the best at math, and have problems moving on when something is still broken. Hopefully you guys can help.

Quick: I'm using Jquery to make some (dynamic in number) divs in my header overlap by 30%, filling the entire width of the container. My current iteration rounds up one too many times, so my last element goes beneath the rest.

I have X elements filling the full width of my header container. Each element overlaps by 30% on either side. In an equation, I can work out the math no problem. Ensuring pixel precision with these numbers has proven more difficult. This is what I'm using to determine the width of each element.

width of element = [container width] / ((.7 * ([# of elements] - 1)) + 1)
left margin of element = [width of element] * .3

I make variables I call extraWidth and extraMargin which are the width and margin % 1 respectively. The default element width I use now is width-(width%1). For every element, I add the extraWidth and extraMargin to running total variables. Any time the total of either of these variables exceeds .5, that particular element has its width or margin set 1 higher than the default.

So I don't run on any longer, here's a JSFiddle with everything necessary to see what I'm dealing with. It runs fine most of the time, but at certain widths I'm 1 pixel too wide.

p.s.

Ran the JSFiddle, didn't work the same way as my live sandbox site, so check that out here. I feel like I included all the necessary bits, but I can't say for sure. On my Chrome, when window size is 575px (among many other widths) it's messed up.

EDIT

It should be noted that I'm making changes to my live site without updating this post. I'm not deleting any functions just yet though, just making new ones/minor alterations to existing ones.

like image 375
Nicholas Avatar asked Aug 07 '26 03:08

Nicholas


1 Answers

Recursion! Recursion was the most elegant answer (which appears to work in ALL cases) I could come up with.

Iterating through my jQuery object one element at a time and calculating the width and margin based on the remaining container width rather than the whole container width makes this much easier to calculate.

function circleWidth(circles, containerWidth) {
    var width = containerWidth / ((.7 * (circles.length - 1)) + 1);
    var pxWidth = Math.round(width);
    var margin = width * .3;
    var pxMargin = Math.round(margin);

    $(circles[0]).css({
        'width': pxWidth + "px",
        'margin-left': "-" + pxMargin + "px"
    });

    containerWidth -= (pxWidth - pxMargin);

    if (circles.length > 1) {
        circleWidth(circles.slice(1), containerWidth);
    }
}

function circleSize(circles, containerWidth) {
    var height = Math.ceil(containerWidth / ((.7 * (circles.length - 1)) + 1));

    circles.each(function() {
        $(this).css({
            'height': height + "px"
        });
    });

    circleWidth(circles, containerWidth);

    $(circles[circles.length]).css({
        'margin-left': $(circles[0]).css('margin-left')
    });

    $(circles[0]).css({
        'margin-left': 0
    });
}

Here's the fiddle with my final result. I'm sure I still have some optimization to do, but at least it's working now.

like image 84
Nicholas Avatar answered Aug 09 '26 16:08

Nicholas