Nikolay Dyankov
Nikolay Dyankov

Reputation: 7224

Many rectangles in a container - when changing the size of one of them, others must compensate

Let's consider the following example: http://jsfiddle.net/m0gxgu21/

// See the full commented code and a visual example in the JSFiddle
var rects = [
    { x: 0, y: 0, w: 120, h: 120 },
    { x: 120, y: 0, w: 100, h: 40 },
    { x: 220, y: 0, w: 100, h: 120 },
    { x: 120, y: 40, w: 100, h: 80 },
    { x: 0, y: 120, w: 180, h: 60 },
    { x: 180, y: 120, w: 140, h: 60 }
];

function redraw() {
    for (var i=0; i<6; i++) {
        $('#rect-' + i).css({
            left: rects[i].x,
            top: rects[i].y,
            width: rects[i].w,
            height: rects[i].h
        });
    }
}

redraw();

// Now we increase the size of a rectangle
var d = 20;
rects[3].w += d;
rects[3].h += d;

redraw();

We want to resize any one of the given rectangles. Here are the rules:

This is what must NOT happen:

enter image description here

Here is a visual representation of what must happen:

enter image description here

Left is before resizing, right is after.

IT WORKS!!!

Here are two examples and the full code:

http://jsfiddle.net/02s5s5pa/2/ http://jsfiddle.net/9sh4nL46/1/

Upvotes: 3

Views: 132

Answers (1)

If you're going to want the flexibility to shrink the items on the side, you'll need to be able to specify the origin point for the scaling - you've spec'ed center point expansion, but that doesn't account for a rectangle that's scaled from the side.

That said, I'd process x and y separately. This also enables you to expand into a z axis down the road. To do that, I'd change "w" to "xl" (x length). Here's a fiddle: https://jsfiddle.net/mckinleymedia/m0gxgu21/14/

var rects = [
    { x: 0, y: 0, xl: 120, yl: 60 },
    { x: 120, y: 0, xl: 100, yl: 40 },
    { x: 220, y: 0, xl: 100, yl: 120 },
    { x: 120, y: 40, xl: 100, yl: 80 },
    { x: 0, y: 120, xl: 180, yl: 40 },
    { x: 180, y: 120, xl: 140, yl: 60 }
],
    current = 3
    canvas = { x: 320, y: 180 };

function resize(size) {
    size = size || { x: 20, y: 20 };
    var c = {
            x: rects[current].x,
            y: rects[current].y,
            xl: rects[current].xl,
            yl: rects[current].yl
        };
        c.x2 = c.x + c.xl;
        c.y2 = c.y + c.yl;
        c.xm = c.x + c.xl/2;
        c.ym = c.y + c.yl/2;
    for (var i in rects) {
        if (i != current) {
            position( rects[i], c, size, [ 'x', 'y' ] );
            position( rects[i], c, size, [ 'x', 'y' ], true );
        }
    }
    changeSize(size);
    redraw();
}
var position = function( r, c, size, dim, point2 ) {
        var ratio = 1,
            percent = 0;
        for (var index in dim) {
            var d = dim[index],
                point = r[d];
            if (point2) point = point + r[d + 'l'];
            if ( point >= canvas[d] ) {
                point = canvas[d];
            } else {
                if (point <= c[d]) {
                    ratio = (c[d] - size[d]/2) /c[d];
                    point *= ratio;
                } else if (point <= c[d + 'm']) {
                    ratio = (c[d+'l'] + size[d]) /c[d+'l'];
                    point = c[d + 'm'] - ((c[d + 'm'] - point) * ratio);
                } else if (point <= c[d+'2']) {
                    ratio = (c[d+'l'] + size[d]) /c[d+'l'];
                    point = c[d + 'm'] - ((c[d + 'm'] - point) * ratio);
                } else if (point <= canvas[d]) {
                    ratio = ((canvas[d] - c[d+'2']) - size[d]/2) / (canvas[d] - c[d+'2']);
                    point = c[d+'2'] + ratio * ( point - c[d+'2'] );
                }
            }
                if (point2) {
                    if ( point > canvas[d] ) point = canvas[d];
                    r[d + 'l'] = parseInt(point - r[d]);
                } else {
                    r[d] = point > 0 ? parseInt(point):0;
                }
        };
};

function redraw() {
    for (var i in rects) {
        $('#rect-' + i).css({
            left: rects[i].x,
            top: rects[i].y,
            width: rects[i].xl,
            height: rects[i].yl
        });
    }
}

redraw();

var changeSize = function(size) {
    rects[current].x += -size.x/2;
    rects[current].y += -size.y/2;
    rects[current].xl += size.x;
    rects[current].yl += size.y;
};

$('button.smaller').click( function(){ resize({ x:-20, y: -20 }) } );
$('button.bigger').click( function(){ resize() } );

The shapes get a little off if you go back and forth, so it needs some fine-tuning, but I'm out of time and thought this might get you a little further along. It also needs a max-size for the adjusted div, and it should auto-generate the divs from the rects array. You probably also should impose a grid to snap the rectangles.

Hope this helps.

Upvotes: 2

Related Questions