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?
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')
);
If you used a series of objects it will do the trick:
var positions = { top: {left:{x:t.x, y:y.y-s.height}, center:{x:tx.x + t.width/2- s.width/2, y:t.y-s.height}} //etc.... } //then to get the position you can simply var pos = positions[pos][align])
def vector pos, align, hash
case hash[pos]
when -1; [0.0, -1.0]
when 1; [1.0, 0.0]
else
case hash[align]
when -1; [0.0, 0.0]
when 1; [1.0, -1.0]
else [0.5, -0.5]
end
end
end
y_t, y_s = vector(pos, align, "top" => -1, "bottom" => 1)
x_t, x_s = vector(pos, align, "left" => -1, "right" => 1)
s.y = t.y + y_t*t.height + y_s*s.height
s.x = t.x + x_t*t.width + x_s*s.width
or
def vector pos, align, head, tail
case pos
when head; [0.0, -1.0]
when tail; [1.0, 0.0]
else
case align
when head; [0.0, 0.0]
when tail; [1.0, -1.0]
else [0.5, -0.5]
end
end
end
y_t, y_s = vector(pos, align, "top", "bottom")
x_t, x_s = vector(pos, align, "left", "right")
s.y = t.y + y_t*t.height + y_s*s.height
s.x = t.x + x_t*t.width + x_s*s.width
精彩评论