progress
This commit is contained in:
parent
ec7a1af1d0
commit
0fd0ee8929
@ -119,30 +119,7 @@
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/* thumb */
|
||||
.range-colored::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #0d6efd;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border: 2px solid #fff;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
.range-colored::-moz-range-thumb {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #0d6efd;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border: 2px solid #fff;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
|
||||
.range-scale-item {
|
||||
position: absolute;
|
||||
@ -243,7 +220,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($hal === $halPertama)
|
||||
<div class="card border-0 shadow-sm mb-4" id="head_soal">
|
||||
<div class="card-body">
|
||||
@ -344,6 +320,8 @@
|
||||
$rangeStep = 1;
|
||||
$rangeDefault = null;
|
||||
$rangeTicks = [];
|
||||
$rangeSubTickCount = 4;
|
||||
$rangeMajorStep = 10;
|
||||
if ($useDualForm && $currentAnswer) {
|
||||
if (preg_match('/([0-9]+)\\s*\\(Tahun\\)/i', $currentAnswer, $matchYear)) {
|
||||
$dualYearOld = $matchYear[1];
|
||||
@ -376,18 +354,74 @@
|
||||
}
|
||||
$rangeSpan = max($rangeMax - $rangeMin, 1);
|
||||
|
||||
$startTick = (int) ceil($rangeMin);
|
||||
$endTick = (int) floor($rangeMax);
|
||||
|
||||
for ($v = $startTick; $v <= $endTick; $v++) {
|
||||
$position = (($v - $rangeMin) / $rangeSpan) * 100;
|
||||
|
||||
$rangeTicks[] = [
|
||||
'value' => $v, // nilai asli
|
||||
'label' => ($v === 1 || $v % 10 === 0) ? $v : null, // label hanya 1 & kelipatan 10
|
||||
'position' => max(0, min(100, $position)),
|
||||
];
|
||||
$majorAnchors = [$rangeMin, $rangeMax];
|
||||
if ($rangeMin <= 1 && $rangeMax >= 1) {
|
||||
$majorAnchors[] = 1;
|
||||
}
|
||||
$firstMajor = max($rangeMin, ($rangeMin <= 1 ? 10 : ceil($rangeMin / $rangeMajorStep) * $rangeMajorStep));
|
||||
for ($v = $firstMajor; $v <= $rangeMax; $v += $rangeMajorStep) {
|
||||
$majorAnchors[] = $v;
|
||||
}
|
||||
|
||||
sort($majorAnchors);
|
||||
$uniqueAnchors = [];
|
||||
foreach ($majorAnchors as $anchor) {
|
||||
if (empty($uniqueAnchors) || abs(end($uniqueAnchors) - $anchor) > 0.0001) {
|
||||
$uniqueAnchors[] = $anchor;
|
||||
}
|
||||
}
|
||||
$majorAnchors = array_values(array_filter($uniqueAnchors, function ($value) use ($rangeMin, $rangeMax) {
|
||||
return $value >= $rangeMin && $value <= $rangeMax;
|
||||
}));
|
||||
|
||||
$ticks = [];
|
||||
$addTick = function ($value, $isMajor = false) use (&$ticks, $rangeMin, $rangeSpan, $rangeMajorStep) {
|
||||
$position = $rangeSpan > 0 ? (($value - $rangeMin) / $rangeSpan) * 100 : 0;
|
||||
$isOne = abs($value - 1) < 0.0001;
|
||||
$isMultiple = $rangeMajorStep > 0 ? abs(fmod($value, $rangeMajorStep)) < 0.0001 : false;
|
||||
$ticks[] = [
|
||||
'value' => $value,
|
||||
'label' => ($isOne || $isMultiple) ? (int) round($value) : null,
|
||||
'position' => max(0, min(100, $position)),
|
||||
'is_major' => $isMajor,
|
||||
'is_one' => $isOne,
|
||||
];
|
||||
};
|
||||
|
||||
$countAnchors = count($majorAnchors);
|
||||
if ($countAnchors === 0) {
|
||||
$addTick($rangeMin, true);
|
||||
} else {
|
||||
for ($i = 0; $i < $countAnchors; $i++) {
|
||||
$currentAnchor = $majorAnchors[$i];
|
||||
$addTick($currentAnchor, true);
|
||||
|
||||
if ($i === $countAnchors - 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$nextAnchor = $majorAnchors[$i + 1];
|
||||
$segmentLength = $nextAnchor - $currentAnchor;
|
||||
if ($segmentLength <= 0 || $rangeSubTickCount <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ($sub = 1; $sub <= $rangeSubTickCount; $sub++) {
|
||||
$fraction = $sub / ($rangeSubTickCount + 1);
|
||||
$value = $currentAnchor + ($segmentLength * $fraction);
|
||||
$addTick($value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usort($ticks, function ($a, $b) {
|
||||
if ($a['value'] == $b['value']) {
|
||||
return 0;
|
||||
}
|
||||
return ($a['value'] < $b['value']) ? -1 : 1;
|
||||
});
|
||||
|
||||
$rangeTicks = $ticks;
|
||||
}
|
||||
}
|
||||
$rangeMinDisplay = ($rangeMin !== null && floor($rangeMin) == $rangeMin) ? (int) $rangeMin : $rangeMin;
|
||||
@ -481,10 +515,9 @@
|
||||
<div class="range-scale" aria-hidden="true">
|
||||
@foreach ($rangeTicks as $tick)
|
||||
@php
|
||||
$value = (int) $tick['value'];
|
||||
$label = $tick['label']; // bisa null
|
||||
$isMajor = ($value === 1) || ($value % 10 === 0);
|
||||
$isOneTick = ($value === 1);
|
||||
$label = $tick['label'] ?? null;
|
||||
$isMajor = !empty($tick['is_major']);
|
||||
$isOneTick = !empty($tick['is_one']);
|
||||
@endphp
|
||||
|
||||
<div class="range-scale-item
|
||||
@ -1015,57 +1048,57 @@
|
||||
}
|
||||
}
|
||||
|
||||
function setupRangeInputs() {
|
||||
const rangeInputs = form.querySelectorAll('[data-range-input]');
|
||||
function setupRangeInputs() {
|
||||
const rangeInputs = form.querySelectorAll('[data-range-input]');
|
||||
|
||||
rangeInputs.forEach(function (input) {
|
||||
const detailId = input.getAttribute('data-range-input');
|
||||
const output = detailId ? form.querySelector('[data-range-output="' + detailId + '"]') : null;
|
||||
const manualInput = detailId ? form.querySelector('[data-range-manual="' + detailId + '"]') : null;
|
||||
rangeInputs.forEach(function (input) {
|
||||
const detailId = input.getAttribute('data-range-input');
|
||||
const output = detailId ? form.querySelector('[data-range-output="' + detailId + '"]') : null;
|
||||
const manualInput = detailId ? form.querySelector('[data-range-manual="' + detailId + '"]') : null;
|
||||
|
||||
const minValue = parseFloat(input.dataset.rangeMinValue || input.min || '0');
|
||||
const maxValue = parseFloat(input.dataset.rangeMaxValue || input.max || '100');
|
||||
const stepValue = parseFloat(input.step || '1') || 1;
|
||||
const minValue = parseFloat(input.dataset.rangeMinValue || input.min || '0');
|
||||
const maxValue = parseFloat(input.dataset.rangeMaxValue || input.max || '100');
|
||||
const stepValue = parseFloat(input.step || '1') || 1;
|
||||
|
||||
function clampAndSnap(rawVal) {
|
||||
let v = parseFloat(rawVal);
|
||||
if (isNaN(v)) v = minValue;
|
||||
if (v < minValue) v = minValue;
|
||||
if (v > maxValue) v = maxValue;
|
||||
return snapToStep(v, minValue, stepValue);
|
||||
}
|
||||
function clampAndSnap(rawVal) {
|
||||
let v = parseFloat(rawVal);
|
||||
if (isNaN(v)) v = minValue;
|
||||
if (v < minValue) v = minValue;
|
||||
if (v > maxValue) v = maxValue;
|
||||
return snapToStep(v, minValue, stepValue);
|
||||
}
|
||||
|
||||
function updateBoth(fromManual) {
|
||||
const current = fromManual && manualInput ? manualInput.value : input.value;
|
||||
const value = clampAndSnap(current);
|
||||
function updateBoth(fromManual) {
|
||||
const current = fromManual && manualInput ? manualInput.value : input.value;
|
||||
const value = clampAndSnap(current);
|
||||
|
||||
input.value = value;
|
||||
input.value = value;
|
||||
|
||||
if (output) {
|
||||
output.textContent = formatRangeDisplay(value);
|
||||
}
|
||||
if (manualInput && !fromManual) {
|
||||
manualInput.value = value;
|
||||
}
|
||||
if (output) {
|
||||
output.textContent = formatRangeDisplay(value);
|
||||
}
|
||||
if (manualInput && !fromManual) {
|
||||
manualInput.value = value;
|
||||
}
|
||||
|
||||
updateRangeFill(input, minValue, maxValue);
|
||||
}
|
||||
updateRangeFill(input, minValue, maxValue);
|
||||
}
|
||||
|
||||
input.addEventListener('input', function () {
|
||||
updateBoth(false);
|
||||
input.addEventListener('input', function () {
|
||||
updateBoth(false);
|
||||
});
|
||||
|
||||
if (manualInput) {
|
||||
manualInput.addEventListener('input', function () {
|
||||
updateBoth(true);
|
||||
});
|
||||
}
|
||||
|
||||
// initial
|
||||
updateBoth(false);
|
||||
});
|
||||
|
||||
if (manualInput) {
|
||||
manualInput.addEventListener('input', function () {
|
||||
updateBoth(true);
|
||||
});
|
||||
}
|
||||
|
||||
// initial
|
||||
updateBoth(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function formatRangeDisplay(value) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user