Подсчитать прогресс активности
есть прогресс бар который заполняется на 100% когда пользователь потратит определенное кол-во денег, например 100т
до 80% нужно что бы 100р было равно 1%
после 80% и до 90% 1000р=1%
после 90% и до 100% 10000р=1%
есть функция, в которой проблема
function getActivityLevelPercent($money, $level){
$activity_level = $level;
$d = 100;
if($activity_level >= 80)$d = 1000;
if($activity_level >= 90)$d = 10000;
$add_percent = $money/$d;
return round($add_percent, 2);
}
если например имея прогресс от 0-80, то потраченные 10000р поднимут прогресс до 100%
подскажите как пропорционально и правильно увеличивать прогресс
Ответы (2 шт):
Необходимо контролировать количество добавляемых процентов в зависимости от количества уже имеющихся. Вычисляем лимит (количество процентов, которое мы можем добавить до ближайшего барьера 80/90/100) и переводим в проценты столько денег, сколько в него влазит, далее запускаем рекурсию для оставшихся денег. Код сильно не отлаживал, возможны ошибки, но основную идею он передает:
function getActivityLevelPercent($money, $level){
if($level < 80){
$d = 100;
$max_percent = 80 - $level;
}elseif($level < 90){
$d = 1000;
$max_percent = 90 - $level;
}elseif($level < 100){
$d = 10000;
$max_percent = 100 - $level;
}else{
return 0;
}
$max_money = $max_percent * $d;
if($money > $max_money){
return $max_percent + getActivityLevelPercent(
$money - $max_money,
$level + $max_percent
);
}
return $money / $d;
}
Можно сделать универсальнее и переписать так:
function getActivityLevelPercent($money, $level){
$ranges = [
80 => 100,
90 => 1000,
100 => 10000,
];
foreach($ranges as $level_border => $percent_cost){
if($level < $level_border){
$max_percent = $level_border - $level;
$max_money = $max_percent * $percent_cost;
if($money > $max_money){
return $max_percent + getActivityLevelPercent(
$money - $max_money,
$level + $max_percent
);
}
return $money / $percent_cost;
}
}
return 0;
}
Как я понимаю, вы хотите создать прогресс-бар, который быстро заполняется в начале и всё медленнее в конце. Если так, то требования, которые вы сформулировали в задаче, неверные (0.1 * 0.8 + 1 * 0.1 + 10 * 0.1 = 1,18 -- 118%). Можно поправить коэффициенты. Надо разделить 100 процентов денег на три части, например: 20, 30, 50, при этом 20 процентов денег заполнят 80 процентов прогресс-бара, следующие 30 -- 10 процентов прогресс-бара и остальные 50 -- оставшиеся 10 процентов прогресс-бара. Мы будто растягиваем и сжимаем прогресс-бар на разных участках. Можно написать функцию, которая считает эти искажения:
<?php
function transformProgress(float $ratio): float {
$progress = min($ratio, 0.2) * (0.8 / 0.2); // первые 20% должны распределиться на участке до 80% прогресс-бара
if ($ratio > 0.2) {
$progress += min($ratio - 0.2, 0.3) * (0.1 / 0.3); // следуюющие 30% -- на 10% прогресс-бара
}
if ($ratio > 0.5) {
$progress += ($ratio - 0.5) * (0.1 / 0.5); // последние 50% -- на 10% прогресс-бара
}
return $progress;
}
var_dump(transformProgress(0.01)); // потрачено 1% денег -- 4% на прогресс-баре
var_dump(transformProgress(0.2)); // потрачено 20% денег -- 80% на прогресс-баре
var_dump(transformProgress(0.21)); // потрачено 21% денег -- 80,3% на прогресс-баре
var_dump(transformProgress(0.5)); // потрачено 50% денег -- 90% на прогресс-баре
var_dump(transformProgress(0.51)); // потрачено 51% денег -- 90.2% на прогресс-баре
var_dump(transformProgress(1.0)); // потрачено 100% денег -- 100% на прогресс-баре
var_dump(transformProgress(0.0)); // потрачено 0% денег -- 0% на прогресс-баре
Как видно, функция никак не зависит от количества денег и управляется просто набором констант -- получает y из x. Из школьного курса математики можно вспомнить множество таких функций, некоторые ведут себя похожим образом. Например функция y = √x.
<?php
function transformProgress(float $ratio): float {
return $ratio ** (1 / 5);
}
Обратите внимание, что в этом случае гораздо удобнее представлять проценты как часть целого, то есть число от 0 до 1.