in web_ui/src/applications/bistro/view/components/StackedBarChart.php [80:145]
private function computeBarWidths(StackedBarChartData $data) {
// Clear the widths to deal with double-rendering
foreach ($data->bars as $bar) {
$bar->width = null;
}
// The retry logic is needed to both fit in total_width, and not to have
// bars shorter than min_width. I am lazy, so this is quadratic :(
// TODO: faster algorithm
//
// The loop stores the percentage width (or _USE_MIN_WIDTH) in $bar->width
// Both values decrease whenever a bar is below min width
$adjusted_width = $data->totalWidth;
$total_weight = $data->getTotalWeight();
if (!$total_weight) {
return False;
}
$retry = True;
while ($retry) {
$retry = False;
foreach ($data->bars as $bar) {
if ($bar->width === self::_USE_MIN_WIDTH) {
continue;
}
if ($total_weight) {
$bar->width = $bar->weight / $total_weight;
$missing_width = $adjusted_width * $bar->width - $data->minBarWidth;
if ($missing_width < 0) {
$adjusted_width -= $data->minBarWidth;
$total_weight -= $bar->weight;
$bar->width = self::_USE_MIN_WIDTH;
$retry = True;
break;
}
} else {
$bar->width = self::_USE_MIN_WIDTH;
}
}
}
$total_width = 0;
foreach ($data->bars as $bar) {
if ($bar->width === self::_USE_MIN_WIDTH) {
$bar->width = $data->minBarWidth;
} else {
$bar->width *= $adjusted_width;
}
$total_width += $bar->width;
}
// Round to get integers -- important for visually consistent widths
foreach ($data->bars as $bar) {
if ($total_width > $data->totalWidth) {
$rounded = floor($bar->width);
} else {
$rounded = ceil($bar->width);
}
$total_width += $rounded - $bar->width;
$bar->width = $rounded;
}
return True;
}