fix: smooth issue
This commit is contained in:
@@ -19,57 +19,26 @@ const emit = defineEmits<{
|
|||||||
(e: 'mousedown', event: MouseEvent): void
|
(e: 'mousedown', event: MouseEvent): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const sliderRef = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
function clamp(value: number, min: number, max: number): number {
|
function clamp(value: number, min: number, max: number): number {
|
||||||
return Math.min(Math.max(value, min), max)
|
return Math.min(Math.max(value, min), max)
|
||||||
}
|
}
|
||||||
|
|
||||||
const sliderRef = ref<HTMLElement | null>(null)
|
|
||||||
const isDragging = ref(false)
|
|
||||||
|
|
||||||
// Scale factor for internal calculations
|
|
||||||
const SCALE_FACTOR = 100
|
|
||||||
|
|
||||||
function getStepPrecision(step: number): number {
|
function getStepPrecision(step: number): number {
|
||||||
const stepStr = step.toString()
|
const stepStr = step.toString()
|
||||||
if (stepStr.includes('e-')) {
|
if (stepStr.includes('e-')) {
|
||||||
return Number.parseInt(stepStr.split('e-')[1], 10)
|
return Number.parseInt(stepStr.split('e-')[1], 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
const decimals = stepStr.includes('.') ? stepStr.split('.')[1].length : 0
|
const decimals = stepStr.includes('.') ? stepStr.split('.')[1].length : 0
|
||||||
return decimals
|
return decimals
|
||||||
}
|
}
|
||||||
|
|
||||||
function scaleUp(value: number): number {
|
|
||||||
return value * SCALE_FACTOR
|
|
||||||
}
|
|
||||||
|
|
||||||
function scaleDown(value: number): number {
|
|
||||||
return value / SCALE_FACTOR
|
|
||||||
}
|
|
||||||
|
|
||||||
function roundToStep(value: number, step: number): number {
|
function roundToStep(value: number, step: number): number {
|
||||||
const scaledValue = scaleUp(value)
|
|
||||||
const scaledStep = scaleUp(step)
|
|
||||||
const precision = getStepPrecision(step)
|
const precision = getStepPrecision(step)
|
||||||
|
const factor = 10 ** (precision + 3)
|
||||||
const rounded = Math.round(scaledValue / scaledStep) * scaledStep
|
return Number.parseFloat((value * factor / factor).toFixed(precision))
|
||||||
const scaledBack = scaleDown(rounded)
|
|
||||||
|
|
||||||
return Number(scaledBack.toFixed(precision))
|
|
||||||
}
|
|
||||||
|
|
||||||
function valueToPercent(value: number, min: number, max: number) {
|
|
||||||
const scaledValue = scaleUp(value)
|
|
||||||
const scaledMin = scaleUp(min)
|
|
||||||
const scaledMax = scaleUp(max)
|
|
||||||
return ((scaledValue - scaledMin) * 100) / (scaledMax - scaledMin)
|
|
||||||
}
|
|
||||||
|
|
||||||
function percentToValue(percent: number, min: number, max: number) {
|
|
||||||
const scaledMin = scaleUp(min)
|
|
||||||
const scaledMax = scaleUp(max)
|
|
||||||
const scaledValue = (scaledMax - scaledMin) * percent + scaledMin
|
|
||||||
const value = scaleDown(scaledValue)
|
|
||||||
return roundToStep(value, props.step)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentValue = computed(() => {
|
const currentValue = computed(() => {
|
||||||
@@ -77,10 +46,10 @@ const currentValue = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const sliderStyle = computed(() => {
|
const sliderStyle = computed(() => {
|
||||||
const sliderPercent = valueToPercent(currentValue.value, props.min, props.max)
|
const percent = ((currentValue.value - props.min) / (props.max - props.min)) * 100
|
||||||
return {
|
return {
|
||||||
width: `${sliderPercent}%`,
|
width: `${percent}%`,
|
||||||
backgroundSize: `${sliderPercent}% 100%`,
|
backgroundSize: `${percent}% 100%`,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -88,9 +57,23 @@ function getNewValue(event: MouseEvent) {
|
|||||||
if (!sliderRef.value)
|
if (!sliderRef.value)
|
||||||
return currentValue.value
|
return currentValue.value
|
||||||
|
|
||||||
const { width, left } = sliderRef.value.getBoundingClientRect()
|
const rect = sliderRef.value.getBoundingClientRect()
|
||||||
const percent = clamp((event.clientX - left) / width, 0, 1)
|
const x = event.clientX - rect.left
|
||||||
return percentToValue(percent, props.min, props.max)
|
const percent = x / rect.width
|
||||||
|
const range = props.max - props.min
|
||||||
|
const value = props.min + (range * percent)
|
||||||
|
|
||||||
|
// Round to nearest step
|
||||||
|
const steps = Math.round(value / props.step) * props.step
|
||||||
|
return Math.min(Math.max(steps, props.min), props.max)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseMove(event: MouseEvent) {
|
||||||
|
if (props.disabled)
|
||||||
|
return
|
||||||
|
|
||||||
|
const newValue = getNewValue(event)
|
||||||
|
emit('update:modelValue', newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMouseDown(event: MouseEvent) {
|
function handleMouseDown(event: MouseEvent) {
|
||||||
@@ -98,33 +81,24 @@ function handleMouseDown(event: MouseEvent) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
isDragging.value = true
|
|
||||||
emit('mousedown', event)
|
|
||||||
|
|
||||||
const newValue = getNewValue(event)
|
const newValue = getNewValue(event)
|
||||||
emit('update:modelValue', newValue)
|
emit('update:modelValue', newValue)
|
||||||
}
|
|
||||||
|
|
||||||
function handleMouseMove(event: MouseEvent) {
|
window.addEventListener('mousemove', handleMouseMove)
|
||||||
if (!isDragging.value || props.disabled)
|
window.addEventListener('mouseup', handleMouseUp)
|
||||||
return
|
|
||||||
|
|
||||||
const newValue = getNewValue(event)
|
|
||||||
emit('update:modelValue', newValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMouseUp(_: MouseEvent) {
|
function handleMouseUp(_: MouseEvent) {
|
||||||
if (!isDragging.value)
|
window.removeEventListener('mousemove', handleMouseMove)
|
||||||
return
|
window.removeEventListener('mouseup', handleMouseUp)
|
||||||
|
|
||||||
isDragging.value = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMouseLeave(event: MouseEvent) {
|
// Lifecycle hooks
|
||||||
if (!isDragging.value)
|
onUnmounted(() => {
|
||||||
return
|
window.removeEventListener('mousemove', handleMouseMove)
|
||||||
handleMouseUp(event)
|
window.removeEventListener('mouseup', handleMouseUp)
|
||||||
}
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -134,15 +108,12 @@ function handleMouseLeave(event: MouseEvent) {
|
|||||||
:class="{ disabled }"
|
:class="{ disabled }"
|
||||||
bg="[#e6e1fc] dark:[#676085]" touch-action-none relative inline-block w-full cursor-ew-resize rounded-sm
|
bg="[#e6e1fc] dark:[#676085]" touch-action-none relative inline-block w-full cursor-ew-resize rounded-sm
|
||||||
@mousedown="handleMouseDown"
|
@mousedown="handleMouseDown"
|
||||||
@mousemove="handleMouseMove"
|
|
||||||
@mouseup="handleMouseUp"
|
|
||||||
@mouseleave="handleMouseLeave"
|
|
||||||
>
|
>
|
||||||
<span :style="sliderStyle" bg="[#cabeff] dark:[#4e34b9]" relative block rounded-sm h="[14px]" />
|
<span :style="sliderStyle" bg="[#cabeff] dark:[#4e34b9]" relative block rounded-sm h="[14px]" />
|
||||||
<span
|
<span
|
||||||
role="slider"
|
role="slider"
|
||||||
class="slider-thumb"
|
class="slider-thumb"
|
||||||
:style="{ left: `${valueToPercent(currentValue, min, max)}%` }"
|
:style="{ left: `${((currentValue - min) / (max - min)) * 100}%` }"
|
||||||
absolute rounded-sm w="[1px]" h="[14px]" bg="zinc-100 dark:zinc-400" top="50%" transform="translate-x-[50%] translate-y-[-50%]"
|
absolute rounded-sm w="[1px]" h="[14px]" bg="zinc-100 dark:zinc-400" top="50%" transform="translate-x-[50%] translate-y-[-50%]"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const vrmModelPositionZ = ref(-0.3)
|
|||||||
<label w-full flex items-center gap-2>
|
<label w-full flex items-center gap-2>
|
||||||
<DataGuiRange v-model="cameraPositionX" :min="-10" :max="10" :step="0.01" />
|
<DataGuiRange v-model="cameraPositionX" :min="-10" :max="10" :step="0.01" />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div text-right>
|
||||||
<span>{{ cameraPositionX }}</span>
|
<span>{{ cameraPositionX }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ const vrmModelPositionZ = ref(-0.3)
|
|||||||
<label w-full flex items-center gap-2>
|
<label w-full flex items-center gap-2>
|
||||||
<DataGuiRange v-model="cameraPositionY" :min="-10" :max="10" :step="0.01" />
|
<DataGuiRange v-model="cameraPositionY" :min="-10" :max="10" :step="0.01" />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div text-right>
|
||||||
<span>{{ cameraPositionY }}</span>
|
<span>{{ cameraPositionY }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ const vrmModelPositionZ = ref(-0.3)
|
|||||||
<label w-full flex items-center gap-2>
|
<label w-full flex items-center gap-2>
|
||||||
<DataGuiRange v-model="cameraPositionZ" :min="-10" :max="10" :step="0.01" />
|
<DataGuiRange v-model="cameraPositionZ" :min="-10" :max="10" :step="0.01" />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div text-right>
|
||||||
<span>{{ cameraPositionZ }}</span>
|
<span>{{ cameraPositionZ }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,7 +74,7 @@ const vrmModelPositionZ = ref(-0.3)
|
|||||||
<label w-full flex items-center gap-2>
|
<label w-full flex items-center gap-2>
|
||||||
<DataGuiRange v-model="vrmModelPositionX" :min="-10" :max="10" :step="0.01" />
|
<DataGuiRange v-model="vrmModelPositionX" :min="-10" :max="10" :step="0.01" />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div text-right>
|
||||||
<span>{{ vrmModelPositionX }}</span>
|
<span>{{ vrmModelPositionX }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ const vrmModelPositionZ = ref(-0.3)
|
|||||||
<label w-full flex items-center gap-2>
|
<label w-full flex items-center gap-2>
|
||||||
<DataGuiRange v-model="vrmModelPositionY" :min="-10" :max="10" :step="0.01" />
|
<DataGuiRange v-model="vrmModelPositionY" :min="-10" :max="10" :step="0.01" />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div text-right>
|
||||||
<span>{{ vrmModelPositionY }}</span>
|
<span>{{ vrmModelPositionY }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ const vrmModelPositionZ = ref(-0.3)
|
|||||||
<label w-full flex items-center gap-2>
|
<label w-full flex items-center gap-2>
|
||||||
<DataGuiRange v-model="vrmModelPositionZ" :min="-10" :max="10" :step="0.01" />
|
<DataGuiRange v-model="vrmModelPositionZ" :min="-10" :max="10" :step="0.01" />
|
||||||
</label>
|
</label>
|
||||||
<div>
|
<div text-right>
|
||||||
<span>{{ vrmModelPositionZ }}</span>
|
<span>{{ vrmModelPositionZ }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user