Reputation: 7224
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:
Here is a visual representation of what must happen:
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
Reputation: 768
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