🕹️ Fixes vertical range input

This commit is contained in:
Rune Harlyk
2025-03-07 21:42:38 +01:00
parent d14446d09e
commit 37f9238c55
2 changed files with 156 additions and 151 deletions
@@ -1,34 +1,34 @@
<script lang="ts"> <script lang="ts">
interface Props { interface Props {
min?: number; min?: number
max?: number; max?: number
step?: number; step?: number
value?: any; value?: any
} oninput?: any
}
let { let {
min = 0, min = 0,
max = 100, max = 100,
step = 1, step = 1,
value = $bindable((max - min) / 2), value = $bindable((max - min) / 2),
...rest ...rest
}: Props = $props(); }: Props = $props()
</script> </script>
<input <input
type="range" type="range"
style="writing-mode: vertical-lr; direction: rtl" style="writing-mode: vertical-lr; direction: rtl"
class="cursor-pointer" class="cursor-pointer"
{min} {min}
{max} {max}
{step} {step}
bind:value bind:value
{...rest} {...rest} />
/>
<style> <style>
input[type='range']::-webkit-slider-runnable-track { input[type='range']::-webkit-slider-runnable-track {
background: oklch(var(--p) / 1); background: oklch(var(--p) / 1);
border-radius: var(--rounded-box, 1rem); border-radius: var(--rounded-box, 1rem);
} }
</style> </style>
+130 -125
View File
@@ -1,145 +1,150 @@
<script lang="ts"> <script lang="ts">
import nipplejs from 'nipplejs'; import nipplejs from 'nipplejs'
import { onMount } from 'svelte'; import { onMount } from 'svelte'
import { capitalize, throttler, toInt8 } from '$lib/utilities'; import { capitalize, throttler, toInt8 } from '$lib/utilities'
import { input, outControllerData, mode, modes, type Modes, ModesEnum } from '$lib/stores'; import { input, outControllerData, mode, modes, type Modes, ModesEnum } from '$lib/stores'
import type { vector } from '$lib/types/models'; import type { vector } from '$lib/types/models'
import { VerticalSlider } from '$lib/components/input'; import { VerticalSlider } from '$lib/components/input'
let throttle = new throttler(); let throttle = new throttler()
let left: nipplejs.JoystickManager; let left: nipplejs.JoystickManager
let right: nipplejs.JoystickManager; let right: nipplejs.JoystickManager
let throttle_timing = 40; let throttle_timing = 40
let data = new Array(8); let data = new Array(8)
onMount(() => { onMount(() => {
left = nipplejs.create({ left = nipplejs.create({
zone: document.getElementById('left') as HTMLElement, zone: document.getElementById('left') as HTMLElement,
color: '#15191e80', color: '#15191e80',
dynamicPage: true, dynamicPage: true,
mode: 'static', mode: 'static',
restOpacity: 1 restOpacity: 1
}); })
right = nipplejs.create({ right = nipplejs.create({
zone: document.getElementById('right') as HTMLElement, zone: document.getElementById('right') as HTMLElement,
color: '#15191e80', color: '#15191e80',
dynamicPage: true, dynamicPage: true,
mode: 'static', mode: 'static',
restOpacity: 1 restOpacity: 1
}); })
left.on('move', (_, data) => handleJoyMove('left', data.vector)); left.on('move', (_, data) => handleJoyMove('left', data.vector))
left.on('end', (_, __) => handleJoyMove('left', { x: 0, y: 0 })); left.on('end', (_, __) => handleJoyMove('left', { x: 0, y: 0 }))
right.on('move', (_, data) => handleJoyMove('right', data.vector)); right.on('move', (_, data) => handleJoyMove('right', data.vector))
right.on('end', (_, __) => handleJoyMove('right', { x: 0, y: 0 })); right.on('end', (_, __) => handleJoyMove('right', { x: 0, y: 0 }))
}); })
const handleJoyMove = (key: 'left' | 'right', data: vector) => { const handleJoyMove = (key: 'left' | 'right', data: vector) => {
input.update((inputData) => { input.update(inputData => {
inputData[key] = data; inputData[key] = data
return inputData; return inputData
}); })
throttle.throttle(updateData, throttle_timing); throttle.throttle(updateData, throttle_timing)
}; }
const updateData = () => { const updateData = () => {
data[0] = 0; data[0] = 0
data[1] = toInt8($input.left.x, -1, 1); data[1] = toInt8($input.left.x, -1, 1)
data[2] = toInt8($input.left.y, -1, 1); data[2] = toInt8($input.left.y, -1, 1)
data[3] = toInt8($input.right.x, -1, 1); data[3] = toInt8($input.right.x, -1, 1)
data[4] = toInt8($input.right.y, -1, 1); data[4] = toInt8($input.right.y, -1, 1)
data[5] = toInt8($input.height, 0, 100); data[5] = toInt8($input.height, 0, 100)
data[6] = toInt8($input.speed, 0, 100); data[6] = toInt8($input.speed, 0, 100)
data[7] = toInt8($input.s1, 0, 100); data[7] = toInt8($input.s1, 0, 100)
outControllerData.set(data); outControllerData.set(data)
}; }
const handleKeyup = (event: KeyboardEvent) => { const handleKeyup = (event: KeyboardEvent) => {
const down = event.type === 'keydown'; const down = event.type === 'keydown'
input.update((data) => { input.update(data => {
if (event.key === 'w') data.left.y = down ? -1 : 0; if (event.key === 'w') data.left.y = down ? -1 : 0
if (event.key === 'a') data.left.x = down ? -1 : 0; if (event.key === 'a') data.left.x = down ? -1 : 0
if (event.key === 's') data.left.y = down ? 1 : 0; if (event.key === 's') data.left.y = down ? 1 : 0
if (event.key === 'd') data.left.x = down ? 1 : 0; if (event.key === 'd') data.left.x = down ? 1 : 0
return data; return data
}); })
throttle.throttle(updateData, throttle_timing); throttle.throttle(updateData, throttle_timing)
}; }
const handleRange = (event: Event, key: 'speed' | 'height' | 's1') => { const handleRange = (event: Event, key: 'speed' | 'height' | 's1') => {
const value: number = event.target?.value; const value: number = event.target?.value
input.update((inputData) => { input.update(inputData => {
inputData[key] = value; inputData[key] = value
return inputData; return inputData
}); })
throttle.throttle(updateData, throttle_timing); throttle.throttle(updateData, throttle_timing)
}; }
const changeMode = (modeValue: Modes) => { const changeMode = (modeValue: Modes) => {
mode.set(modes.indexOf(modeValue)); mode.set(modes.indexOf(modeValue))
}; }
</script> </script>
<div class="absolute top-0 left-0 w-screen h-screen"> <div class="absolute top-0 left-0 w-screen h-screen">
<div class="absolute top-0 left-0 h-full w-full flex portrait:hidden"> <div class="absolute top-0 left-0 h-full w-full flex portrait:hidden">
<div id="left" class="flex w-60 items-center justify-end"></div> <div id="left" class="flex w-60 items-center justify-end"></div>
<div class="flex-1"></div> <div class="flex-1"></div>
<div id="right" class="flex w-60 items-center"></div> <div id="right" class="flex w-60 items-center"></div>
</div> </div>
<div class="absolute bottom-0 right-0 p-4 z-10 gap-2 flex-col hidden lg:flex"> <div class="absolute bottom-0 right-0 p-4 z-10 gap-2 flex-col hidden lg:flex">
<div class="flex justify-center w-full"> <div class="flex justify-center w-full">
<kbd class="kbd">W</kbd> <kbd class="kbd">W</kbd>
</div> </div>
<div class="flex justify-center gap-2 w-full"> <div class="flex justify-center gap-2 w-full">
<kbd class="kbd">A</kbd> <kbd class="kbd">A</kbd>
<kbd class="kbd">S</kbd> <kbd class="kbd">S</kbd>
<kbd class="kbd">D</kbd> <kbd class="kbd">D</kbd>
</div> </div>
<div class="flex justify-center w-full"></div> <div class="flex justify-center w-full"></div>
</div> </div>
<div class="absolute bottom-0 z-10 flex items-end"> <div class="absolute bottom-0 z-10 flex items-end">
<div class="flex items-center flex-col bg-base-300 bg-opacity-50 p-3 pb-2 gap-2 rounded-tr-xl"> <div class="flex items-center flex-col bg-base-300 bg-opacity-50 p-3 pb-2 gap-2 rounded-tr-xl">
<VerticalSlider min={0} max={100} on:input={(e) => handleRange(e, 'height')} /> <VerticalSlider min={0} max={100} oninput={(e: Event) => handleRange(e, 'height')} />
<label for="height">Ht</label> <label for="height">Ht</label>
</div> </div>
<div class="flex items-end gap-4 bg-base-300 bg-opacity-50 h-min rounded-tr-xl pl-0 p-3 portrait:hidden"> <div
<div class="join"> class="flex items-end gap-4 bg-base-300 bg-opacity-50 h-min rounded-tr-xl pl-0 p-3 portrait:hidden">
{#each modes as modeValue} <div class="join">
<button {#each modes as modeValue}
class="btn join-item" <button
class:btn-primary={$mode === modes.indexOf(modeValue)} class="btn join-item"
onclick={() => changeMode(modeValue)} class:btn-primary={$mode === modes.indexOf(modeValue)}
> onclick={() => changeMode(modeValue)}>
{capitalize(modeValue)} {capitalize(modeValue)}
</button> </button>
{/each} {/each}
</div> </div>
{#if $mode === ModesEnum.Walk || $mode === ModesEnum.Crawl} {#if $mode === ModesEnum.Walk || $mode === ModesEnum.Crawl}
<div class="flex gap-4"> <div class="flex gap-4">
<div> <div>
<label for="s1">S1</label> <label for="s1">S1</label>
<input <input
type="range" type="range"
name="s1" name="s1"
min="0" min="0"
max="100" max="100"
oninput={(e) => handleRange(e, 's1')} oninput={e => handleRange(e, 's1')}
class="range range-sm range-primary" class="range range-sm range-primary" />
/> </div>
</div> <div>
<div> <label for="speed">Speed</label>
<label for="speed">Speed</label> <input
<input type="range" name="speed" min="0" max="100" oninput={(e) => handleRange(e, 'speed')} class="range range-sm range-primary" /> type="range"
</div> name="speed"
</div> min="0"
{/if} max="100"
</div> oninput={e => handleRange(e, 'speed')}
</div> class="range range-sm range-primary" />
</div>
</div>
{/if}
</div>
</div>
</div> </div>
<svelte:window onkeyup={handleKeyup} onkeydown={handleKeyup} /> <svelte:window onkeyup={handleKeyup} onkeydown={handleKeyup} />