Skip to content

Commit

Permalink
nicer angle input for poses
Browse files Browse the repository at this point in the history
  • Loading branch information
jakmeier committed Oct 22, 2024
1 parent 93162d7 commit a8b0529
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 19 deletions.
35 changes: 16 additions & 19 deletions bouncy_frontend/src/lib/components/editor/PoseAnglesForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { SkeletonField } from '$lib/instructor/bouncy_instructor_bg';
import Svg from '../avatar/Svg.svelte';
import SvgAvatar from '../avatar/SvgAvatar.svelte';
import AngleInput from '../ui/AngleInput.svelte';
import Button from '../ui/Button.svelte';
let bodyParts = [
Expand Down Expand Up @@ -95,16 +96,11 @@
{#if index % 2 === 0}
<div class="body-part">
<label for="left-{index}">{$t(part.name)}</label>
<input
<AngleInput
name="left-{index}"
type="number"
class="angle-input"
bind:value={part.angle}
on:change={updateAvatar}
placeholder="Angle"
min={-360}
max={360}
/>
onChange={updateAvatar}
></AngleInput>
</div>
{/if}
{/each}
Expand All @@ -115,16 +111,11 @@
{#if index % 2 === 1}
<div class="body-part">
<label for="right-{index}">{$t(part.name)}</label>
<input
<AngleInput
name="right-{index}"
type="number"
class="angle-input"
bind:value={part.angle}
on:change={updateAvatar}
placeholder="Angle"
min={-360}
max={360}
/>
onChange={updateAvatar}
></AngleInput>
</div>
{/if}
{/each}
Expand Down Expand Up @@ -203,11 +194,9 @@
}
.left {
grid-area: left-values;
background-color: var(--theme-accent-light);
}
.right {
grid-area: right-values;
background-color: var(--theme-neutral-light);
}
.avatar {
grid-area: avatar;
Expand All @@ -220,13 +209,21 @@
}
.input-group {
padding: 5px;
width: 90%;
}
.body-part {
display: flex;
flex-direction: column;
align-items: center;
width: 90%;
margin: auto;
margin: 5px auto;
padding: 10px 5px;
}
.left .body-part {
background-color: var(--theme-accent-light);
}
.right .body-part {
background-color: var(--theme-neutral-light);
}
.angle-input {
width: 100%;
Expand Down
122 changes: 122 additions & 0 deletions bouncy_frontend/src/lib/components/ui/AngleInput.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<script>
export let value = 0;
export let min = -360;
export let max = 360;
export let name = '';
/** @param {number} angle */
export let onChange = (angle) => {};
let isDragging = false;
/** @type {HTMLDivElement} */
let slider;
function handleInput(event) {
value = event.target.value;
}
function handleSliderChange(event) {
if (!slider) return;
const rect = slider.getBoundingClientRect();
const newValue = Math.round(
((event.clientX - rect.left) / rect.width) * (max - min) + min
);
value = Math.max(min, Math.min(newValue, max));
onChange(value);
}
function startDragging(event) {
isDragging = true;
handleSliderChange(event);
window.addEventListener('mousemove', handleDragging);
window.addEventListener('mouseup', stopDragging);
}
function stopDragging() {
isDragging = false;
window.removeEventListener('mousemove', handleDragging);
window.removeEventListener('mouseup', stopDragging);
}
function handleDragging(event) {
if (!isDragging) return;
handleSliderChange(event);
}
function handleKeydown(event) {
if (event.key === 'ArrowRight' || event.key === 'ArrowUp') {
value = Math.min(value + 1, max);
} else if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') {
value = Math.max(value - 1, min);
}
}
</script>

<div class="slider-container">
<div class="value-display">
<input
type="number"
{name}
bind:value
{min}
{max}
on:input={handleInput}
on:change={() => onChange(value)}
aria-valuenow={value}
aria-valuemin={min}
aria-valuemax={max}
aria-label="Angle"
/>
</div>
<div
bind:this={slider}
class="slider"
role="slider"
tabindex="0"
aria-valuenow={value}
aria-valuemin={min}
aria-valuemax={max}
aria-label="Angle slider"
on:click={handleSliderChange}
on:mousedown={startDragging}
on:keydown={handleKeydown}
>
<div
class="slider-thumb"
style="left: calc({((value - min) / (max - min)) * 100}% - 10px)"
aria-hidden="true"
></div>
</div>
</div>

<style>
.slider-container {
width: 90%;
margin: auto;
text-align: center;
}
.value-display input {
border: none;
text-align: center;
font-size: 20px;
background: none;
width: 100%;
}
.slider {
position: relative;
height: 8px;
background-color: var(--theme-neutral-white);
border-radius: 4px;
margin-top: 10px;
outline: none;
}
.slider-thumb {
position: absolute;
top: -50%;
width: 20px;
height: 20px;
background-color: var(--theme-main);
border-radius: 50%;
cursor: pointer;
}
</style>

0 comments on commit a8b0529

Please sign in to comment.