Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way to position two rectangles

I have a rectangle (called the target) and want to place another rectangle (called the satellite) alongside. The satellite has a position (top, bottom, left, right) that determines the placement edge relative to the target. It also has an alignment that (left, center, right for top and bottom position, top, middle and bottom for left and right position).

Example:

+----------+----------------------------+
|          |                            |
|  Target  | Satellite, Position=RIGHT, |
|          | Align=TOP                  |
|          |                            |
|          |----------------------------+
|          |
+----------+

I know the top left coordinates of the target and also its width and height. I also know the width and height of the satellite and want to calculate the top left coordinates of it. I could do that as a series of 12 if clauses, but maybe there is a more elegant, mathematical or algorithmic way to do it. Is there an alternative way to this:

# s = satellite, t = target
if pos == "top" && align == "left"
  s.x = t.x
  s.y = t.y - s.height
else if pos == "top" && align == "center"
  s.x = t.x + t.width / 2 - s.width / 2
  s.y = t.y - s.height
# etc, etc

Any good solutions in Ruby or JavaScript?

like image 966
chiborg Avatar asked Apr 15 '11 20:04

chiborg


1 Answers

I like the other answer, but here's how to do it without having to store anything. All math and logic using the trick that in javascript true evaluates to 1 and false evaluates to 0 when arithmetic operators are applied:

p.s. (check out the working jsfiddle: http://jsfiddle.net/vQqSe/52/)

var t = {
    jq: $('#target'),
    width: parseInt($('#target').css('width')),
    height: parseInt($('#target').css('height')),
    top: parseInt($('#target').css('top')),
    left: parseInt($('#target').css('left'))
};
var s = {
    jq: $('#satellite'),
    width: parseInt($('#satellite').css('width')),
    height: parseInt($('#satellite').css('height'))
};

// start with it top left and add using javascript tricks
s.jq.css('top', t.top - s.height +
    s.height * (a == 'top') +
    (t.height/2 + s.height/2) * (a == 'middle') +
    t.height * (a == 'bottom') +
    (t.height + s.height) * (p == 'bottom')
);        

s.jq.css('left', t.left - s.width +
    t.width * (a == 'left') +
    s.width * (a == 'right') +
    (s.width/2 + t.width/2) * (a == 'center') +
    (s.width + t.width) * (p == 'right')
);
like image 187
Milimetric Avatar answered Oct 11 '22 13:10

Milimetric