Skip to content

Commit 0dd42a1

Browse files
committed
Work with precision in slider widget
1 parent 07af71f commit 0dd42a1

File tree

1 file changed

+90
-13
lines changed

1 file changed

+90
-13
lines changed

src/components/graph/vueWidgets/WidgetSlider.vue

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@
1212
@update:model-value="onChange"
1313
/>
1414
<InputText
15-
:value="String(localValue)"
15+
v-model="inputDisplayValue"
1616
:disabled="readonly"
1717
type="number"
1818
:min="widget.options?.min"
1919
:max="widget.options?.max"
20-
:step="widget.options?.step"
20+
:step="stepValue"
2121
class="w-[4em] text-center text-xs px-0"
2222
size="small"
23-
@input="handleInputChange"
23+
@blur="handleInputBlur"
24+
@keydown="handleInputKeydown"
2425
/>
2526
</div>
2627
</div>
@@ -29,7 +30,7 @@
2930
<script setup lang="ts">
3031
import InputText from 'primevue/inputtext'
3132
import Slider from 'primevue/slider'
32-
import { computed } from 'vue'
33+
import { computed, ref, watch } from 'vue'
3334
3435
import { useNumberWidgetValue } from '@/composables/graph/useWidgetValue'
3536
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
@@ -59,16 +60,92 @@ const filteredProps = computed(() =>
5960
filterWidgetProps(props.widget.options, STANDARD_EXCLUDED_PROPS)
6061
)
6162
62-
const handleInputChange = (event: Event) => {
63+
// Get the precision value for proper number formatting
64+
const precision = computed(() => {
65+
const p = props.widget.options?.precision
66+
// Treat negative or non-numeric precision as undefined
67+
return typeof p === 'number' && p >= 0 ? p : undefined
68+
})
69+
70+
// Calculate the step value based on precision or widget options
71+
const stepValue = computed(() => {
72+
// If step is explicitly defined in options, use it
73+
if (props.widget.options?.step !== undefined) {
74+
return String(props.widget.options.step)
75+
}
76+
// Otherwise, derive from precision
77+
if (precision.value !== undefined) {
78+
if (precision.value === 0) {
79+
return '1'
80+
}
81+
// For precision > 0, step = 1 / (10^precision)
82+
// precision 1 → 0.1, precision 2 → 0.01, etc.
83+
return (1 / Math.pow(10, precision.value)).toFixed(precision.value)
84+
}
85+
// Default to 'any' for unrestricted stepping
86+
return 'any'
87+
})
88+
89+
// Format a number according to the widget's precision
90+
const formatNumber = (value: number): string => {
91+
if (precision.value === undefined) {
92+
// No precision specified, return as-is
93+
return String(value)
94+
}
95+
// Use toFixed to ensure correct decimal places
96+
return value.toFixed(precision.value)
97+
}
98+
99+
// Apply precision-based rounding to a number
100+
const applyPrecision = (value: number): number => {
101+
if (precision.value === undefined) {
102+
// No precision specified, return as-is
103+
return value
104+
}
105+
if (precision.value === 0) {
106+
// Integer precision
107+
return Math.round(value)
108+
}
109+
// Round to the specified decimal places
110+
const multiplier = Math.pow(10, precision.value)
111+
return Math.round(value * multiplier) / multiplier
112+
}
113+
114+
// Keep a separate display value for the input field
115+
const inputDisplayValue = ref(formatNumber(localValue.value))
116+
117+
// Update display value when localValue changes from external sources
118+
watch(localValue, (newValue) => {
119+
inputDisplayValue.value = formatNumber(newValue)
120+
})
121+
122+
const handleInputBlur = (event: Event) => {
63123
const target = event.target as HTMLInputElement
64-
const value = parseFloat(target.value)
65-
66-
if (!isNaN(value)) {
67-
const min = props.widget.options?.min ?? -Infinity
68-
const max = props.widget.options?.max ?? Infinity
69-
const clampedValue = Math.min(Math.max(value, min), max)
70-
localValue.value = clampedValue
71-
onChange(clampedValue)
124+
const value = target.value || '0'
125+
const parsed = parseFloat(value)
126+
127+
if (!isNaN(parsed)) {
128+
// Apply precision-based rounding
129+
const roundedValue = applyPrecision(parsed)
130+
onChange(roundedValue)
131+
// Update display value with proper formatting
132+
inputDisplayValue.value = formatNumber(roundedValue)
133+
}
134+
}
135+
136+
const handleInputKeydown = (event: KeyboardEvent) => {
137+
if (event.key === 'Enter') {
138+
const target = event.target as HTMLInputElement
139+
const value = target.value || '0'
140+
const parsed = parseFloat(value)
141+
142+
if (!isNaN(parsed)) {
143+
// Apply precision-based rounding
144+
const roundedValue = applyPrecision(parsed)
145+
onChange(roundedValue)
146+
// Update display value with proper formatting
147+
inputDisplayValue.value = formatNumber(roundedValue)
148+
}
72149
}
73150
}
74151
</script>

0 commit comments

Comments
 (0)