progress
This commit is contained in:
parent
ec7a1af1d0
commit
0fd0ee8929
@ -119,30 +119,7 @@
|
|||||||
height: 10px;
|
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 {
|
.range-scale-item {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -243,7 +220,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if ($hal === $halPertama)
|
@if ($hal === $halPertama)
|
||||||
<div class="card border-0 shadow-sm mb-4" id="head_soal">
|
<div class="card border-0 shadow-sm mb-4" id="head_soal">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -344,6 +320,8 @@
|
|||||||
$rangeStep = 1;
|
$rangeStep = 1;
|
||||||
$rangeDefault = null;
|
$rangeDefault = null;
|
||||||
$rangeTicks = [];
|
$rangeTicks = [];
|
||||||
|
$rangeSubTickCount = 4;
|
||||||
|
$rangeMajorStep = 10;
|
||||||
if ($useDualForm && $currentAnswer) {
|
if ($useDualForm && $currentAnswer) {
|
||||||
if (preg_match('/([0-9]+)\\s*\\(Tahun\\)/i', $currentAnswer, $matchYear)) {
|
if (preg_match('/([0-9]+)\\s*\\(Tahun\\)/i', $currentAnswer, $matchYear)) {
|
||||||
$dualYearOld = $matchYear[1];
|
$dualYearOld = $matchYear[1];
|
||||||
@ -376,18 +354,74 @@
|
|||||||
}
|
}
|
||||||
$rangeSpan = max($rangeMax - $rangeMin, 1);
|
$rangeSpan = max($rangeMax - $rangeMin, 1);
|
||||||
|
|
||||||
$startTick = (int) ceil($rangeMin);
|
$majorAnchors = [$rangeMin, $rangeMax];
|
||||||
$endTick = (int) floor($rangeMax);
|
if ($rangeMin <= 1 && $rangeMax >= 1) {
|
||||||
|
$majorAnchors[] = 1;
|
||||||
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)),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
$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;
|
$rangeMinDisplay = ($rangeMin !== null && floor($rangeMin) == $rangeMin) ? (int) $rangeMin : $rangeMin;
|
||||||
@ -481,10 +515,9 @@
|
|||||||
<div class="range-scale" aria-hidden="true">
|
<div class="range-scale" aria-hidden="true">
|
||||||
@foreach ($rangeTicks as $tick)
|
@foreach ($rangeTicks as $tick)
|
||||||
@php
|
@php
|
||||||
$value = (int) $tick['value'];
|
$label = $tick['label'] ?? null;
|
||||||
$label = $tick['label']; // bisa null
|
$isMajor = !empty($tick['is_major']);
|
||||||
$isMajor = ($value === 1) || ($value % 10 === 0);
|
$isOneTick = !empty($tick['is_one']);
|
||||||
$isOneTick = ($value === 1);
|
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="range-scale-item
|
<div class="range-scale-item
|
||||||
@ -1015,57 +1048,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupRangeInputs() {
|
function setupRangeInputs() {
|
||||||
const rangeInputs = form.querySelectorAll('[data-range-input]');
|
const rangeInputs = form.querySelectorAll('[data-range-input]');
|
||||||
|
|
||||||
rangeInputs.forEach(function (input) {
|
rangeInputs.forEach(function (input) {
|
||||||
const detailId = input.getAttribute('data-range-input');
|
const detailId = input.getAttribute('data-range-input');
|
||||||
const output = detailId ? form.querySelector('[data-range-output="' + detailId + '"]') : null;
|
const output = detailId ? form.querySelector('[data-range-output="' + detailId + '"]') : null;
|
||||||
const manualInput = detailId ? form.querySelector('[data-range-manual="' + detailId + '"]') : null;
|
const manualInput = detailId ? form.querySelector('[data-range-manual="' + detailId + '"]') : null;
|
||||||
|
|
||||||
const minValue = parseFloat(input.dataset.rangeMinValue || input.min || '0');
|
const minValue = parseFloat(input.dataset.rangeMinValue || input.min || '0');
|
||||||
const maxValue = parseFloat(input.dataset.rangeMaxValue || input.max || '100');
|
const maxValue = parseFloat(input.dataset.rangeMaxValue || input.max || '100');
|
||||||
const stepValue = parseFloat(input.step || '1') || 1;
|
const stepValue = parseFloat(input.step || '1') || 1;
|
||||||
|
|
||||||
function clampAndSnap(rawVal) {
|
function clampAndSnap(rawVal) {
|
||||||
let v = parseFloat(rawVal);
|
let v = parseFloat(rawVal);
|
||||||
if (isNaN(v)) v = minValue;
|
if (isNaN(v)) v = minValue;
|
||||||
if (v < minValue) v = minValue;
|
if (v < minValue) v = minValue;
|
||||||
if (v > maxValue) v = maxValue;
|
if (v > maxValue) v = maxValue;
|
||||||
return snapToStep(v, minValue, stepValue);
|
return snapToStep(v, minValue, stepValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBoth(fromManual) {
|
function updateBoth(fromManual) {
|
||||||
const current = fromManual && manualInput ? manualInput.value : input.value;
|
const current = fromManual && manualInput ? manualInput.value : input.value;
|
||||||
const value = clampAndSnap(current);
|
const value = clampAndSnap(current);
|
||||||
|
|
||||||
input.value = value;
|
input.value = value;
|
||||||
|
|
||||||
if (output) {
|
if (output) {
|
||||||
output.textContent = formatRangeDisplay(value);
|
output.textContent = formatRangeDisplay(value);
|
||||||
}
|
}
|
||||||
if (manualInput && !fromManual) {
|
if (manualInput && !fromManual) {
|
||||||
manualInput.value = value;
|
manualInput.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRangeFill(input, minValue, maxValue);
|
updateRangeFill(input, minValue, maxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
input.addEventListener('input', function () {
|
input.addEventListener('input', function () {
|
||||||
updateBoth(false);
|
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) {
|
function formatRangeDisplay(value) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user