cristi2050 cristi2050 - 5 months ago 7
CSS Question

How to change a div's position according to data from database

So I use an api connection to fetch some data. The information I get represents a barlike div with a:

$target = number_format((float)$data->data[2][32][3], 2, '.', '');


And an average of an array:

public static function try($data)
{

$array = [];
$sum = 0;
$path = $data->data[2];
foreach($path as $key => $item){
if($key > 1 && isset($item[5])){
$array[] = (int)$item[5];
$sum += (int)$item[5];
}
}
$avg = ($sum / count($array));
return json_encode(number_format((float)$avg, 2, '.', ''));
}


So the target is: 9.33% and the average is 14.77%
I tried to make a function to fill a div (.outer) using another div (.inner) and the target is a third div shaped like a bar (.target). What I try to do is make the .iner div complete a percentage of the .outer div according to the result(in this case 14.77). The problem occurs when the average (.iner div) is higher than the target (which right now is the .outer div width). Right now the .target div is not dynamic, it is placed in the right of the .outer div, the .outer div representing the target. This doesn't work when the average is higher than the target. When this happens I want to make the .target div go behind the .inner div procentually according to how much the average exceeds the target.
CSS:

.outer, .inner, .target {
height: 14px;
margin-bottom: 5px;
}

.outer {
background-color: #cccccc;
width: 200px;
margin: 0 auto;
}

.inner {
background-color: #66a3ff;

}

.target {
background-color: black;
width: 3px;
height: 14px;
float: right;
}


HTML:

<div class="outer">
<div class="target"></div>
<div class="inner" style="width: <?php echo round( 100 * \Helper::getDataForTry($data)) ?>%;"></div>


</div>


Function for percentage :

public static function getDataForTry($data)
{
$target = number_format((float)$data->data[2][32][3], 2, '.', '');
$array = [];
$sum = 0;
$path = $data->data[2];
foreach($path as $key => $item){
if($key > 1 && isset($item[5])){
$array[] = (int)$item[5];
$sum += (int)$item[5];
}
}
$avg = ($sum / count($array));
$percent = $avg / $target;
return json_encode(number_format((float)$percent, 2, '.', ''));
}


Image of how the final product should look like:

image

In the first case scenario the average exceeds the target
In the second case the target is at the end of the outer div and the inner div procentually changes its width according to how much he has left until he reaches the target (which I already have done).

Answer

Instead of using a black background and floating the inside divs, use positioning and borders to achieve the desired behaviour.

Also, you need to define the base value of the outer div first (PHP):

$target =  9.33;
$avg    = 14.77;

$base   = max($target, $avg);

$base will now be set to the highest value, in this case, it's the average (14.77). Since your outer div shall be 200px wide, you can calculate the sizes of the inner divs in PHP first:

$bar_width    = 200px; // Change that to whatever you want.
$target_width = $bar_width / 100 * ($target / $base * 100);
$avg_width    = $bar_width / 100 * ($avg / $base * 100);

OR calculate the width in CSS directly (calc):

<div class="outer"> 
    <div class="target" style="width: calc(<?php echo $bar_width; ?> / 100 * (<?php echo $target; ?> / <?php echo $base; ?> * 100))"></div>                   
    <div class="inner" style="width: calc(<?php echo $bar_width; ?> / 100 * (<?php echo $avg; ?> / <?php echo $base; ?> * 100))"></div>
</div>

For styling, position the outer div relatively and the inner ones absolutely, use a black border for the target without background.

See an example below:

.outer, .inner, .target {
      height: 14px;
      margin-bottom: 5px;
    }

    .outer {
      background-color: #cccccc;
      width: 200px;
      margin: 0 auto;
      position: relative;
      font-size: 10px;
      line-height: 14px;
      font-family: sans-serif;
    }

    .inner {
      background-color: #66a3ff;
      position: absolute;
      z-index: 1;
      width: calc(200 / 100 * 14.77px);
      color: white;
    }

    .target {
      background-color: transparent;
      width: 19px;
      position: absolute;
      border-right: 3px solid black;
      z-index: 2;
      color: black;
      text-align: right;
    }
<h3>Average higher than target</h3>
<div class="outer"> 
        <div class="target" style="width: calc(200px / 100 * (9.33 / 14.77 * 100))">9.33%&nbsp;</div>                   
        <div class="inner" style="width: calc(200px / 100 * (14.77 / 14.77 * 100))">&nbsp;14.77%</div>
</div>

<h3>Average lower than target</h3>
<div class="outer"> 
        <div class="target" style="width: calc(200px / 100 * (14.77 / 14.77 * 100))">14.77%&nbsp;</div>                   
        <div class="inner" style="width: calc(200px / 100 * (9.33 / 14.77 * 100))">&nbsp;9.33%</div>
</div>

Comments