Layout: avoid floating point numbers

The previous approach involved calculating the width of each element
independently, and deriving the `x` coordinate of each element by
summing the previous widths. However, if the widths are rounded, summing
them leads to accumulated rounding errors.

This change effectively takes the alternate approach of calculating the
`x` coordinate of each element independently, and then deriving the
widths from the differences between adjacent values of `x`.

As a bonus, this change corrects a couple issues in the
`padding_with_fill` test.
pull/829/head
Ben Whittaker 2021-09-28 22:16:34 -04:00
parent 48bb819be7
commit 3622895f09
3 changed files with 26 additions and 18 deletions

View File

@ -239,29 +239,37 @@ Layout.prototype.layout = function (l) {
// exw,exh = extra width/height available
switch (l.type) {
case "h": {
var x = l.x + (0|l.pad);
var acc_w = l.x + (0|l.pad);
var accfillx = 0;
var fillx = l.c && l.c.reduce((a,l)=>a+(0|l.fillx),0);
if (!fillx) { x += (l.w-l._w)/2; }
if (!fillx) { acc_w += (l.w-l._w)>>1; }
var x = acc_w;
l.c.forEach(c => {
c.w = c._w + ((0|c.fillx)*(l.w-l._w)/(fillx||1));
c.h = c.filly ? l.h - (l.pad<<1) : c._h;
c.x = x;
c.y = l.y + (0|l.pad) + (1+(0|c.valign))*(l.h-(l.pad<<1)-c.h)/2;
x += c.w;
c.x = 0|x;
acc_w += c._w;
accfillx += 0|c.fillx;
x = acc_w + Math.floor(accfillx*(l.w-l._w)/(fillx||1));
c.w = 0|(x - c.x);
c.h = 0|(c.filly ? l.h - (l.pad<<1) : c._h);
c.y = 0|(l.y + (0|l.pad) + ((1+(0|c.valign))*(l.h-(l.pad<<1)-c.h)>>1));
if (c.c) this.layout(c);
});
break;
}
case "v": {
var y = l.y + (0|l.pad);;
var acc_h = l.y + (0|l.pad);
var accfilly = 0;
var filly = l.c && l.c.reduce((a,l)=>a+(0|l.filly),0);
if (!filly) { y += (l.h-l._h)/2 }
if (!filly) { acc_h += (l.h-l._h)>>1; }
var y = acc_h;
l.c.forEach(c => {
c.w = c.fillx ? l.w - (l.pad<<1) : c._w;
c.h = c._h + ((0|c.filly)*(l.h-l._h)/(filly||1));
c.y = y;
c.x = l.x + (0|l.pad) + (1+(0|c.halign))*(l.w-(l.pad<<1)-c.w)/2;
y += c.h;
c.y = 0|y;
acc_h += c._h;
accfilly += 0|c.filly;
y = acc_h + Math.floor(accfilly*(l.h-l._h)/(filly||1));
c.h = 0|(y - c.y);
c.w = 0|(c.fillx ? l.w - (l.pad<<1) : c._w);
c.x = 0|(l.x + (0|l.pad) + ((1+(0|c.halign))*(l.w-(l.pad<<1)-c.w)>>1));
if (c.c) this.layout(c);
});
break;
@ -288,8 +296,8 @@ Layout.prototype.update = function() {
if (l.r&1) { // rotation
var t = l._w;l._w=l._h;l._h=t;
}
l._w = Math.max(l._w + (l.pad<<1), 0|l.width);
l._h = Math.max(l._h + (l.pad<<1), 0|l.height);
l._w = 0|Math.max(l._w + (l.pad<<1), 0|l.width);
l._h = 0|Math.max(l._h + (l.pad<<1), 0|l.height);
}
var cb = {
"txt" : function(l) {
@ -349,8 +357,8 @@ Layout.prototype.update = function() {
} else {
l.w = l._w;
l.h = l._h;
l.x = (w-l.w)/2;
l.y = y+(h-l.h)/2;
l.x = (w-l.w)>>1;
l.y = y+((h-l.h)>>1);
}
// layout children
this.layout(l);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB