Skip to content

Commit

Permalink
feat: mouse velocity mode
Browse files Browse the repository at this point in the history
  • Loading branch information
TobbenTM committed May 6, 2024
1 parent 2d3eb00 commit e4b527d
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 14 deletions.
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default defineConfig({
text: 'Components',
items: [
{ text: 'Knob', link: '/components/knob' },
{ text: 'MouseControl', link: '/components/mouse-control' },
],
},
],
Expand Down
55 changes: 54 additions & 1 deletion docs/components/knob.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Its most basic usage merely requires a `v-model` binding (or alternatively a `:m
```vue
<script setup>
import { ref } from 'vue'
import { Knob, KnobAssetStack } from 'acousti-kit'
import { Knob } from 'acousti-kit'
const volume = ref(100)
</script>
Expand Down Expand Up @@ -44,6 +44,32 @@ const volume = ref(100)

Volume: {{ volume }}

## Props

The following props are available for the `<Knob />` component:

| Prop | Type | Default | Optional | Note |
| ---------------- | ---------------------- | -------- | -------- | ------------------------------------------------------------------------- |
| `modelValue` | `number` | | No | Used for two-way data binding |
| `min` | `number` | `0` | Yes | The minimum value of the knob |
| `max` | `number` | `100` | Yes | The maximum value of the knob |
| `tabIndex` | `number` | `0` | Yes | Sets the tabindex for assistive technologies |
| `normalStrength` | `number` | `0` | Yes | Configures the normal strength of mouse movement effect on value |
| `fineStrength` | `number` | `0` | Yes | Configures the fine adjustment strength of mouse movement effect on value |
| `fineKey` | `string` | `Alt` | Yes | Sets the key used for enabling fine adjustment |
| `captureMouse` | `boolean` | `true` | Yes | Enables mouse capture when adjusting |
| `mouseBehaviour` | `'Flat' \| 'Velocity'` | `'Flat'` | Yes | Configures the mouse control mode |

## Events

The following events are available for the `<Knob />` component:

| Prop | Type | Note |
| -------------------- | -------- | ---------------------------------------------------------- |
| `@update:modelValue` | `number` | Emitted on any value update, used for two-way data binding |
| `@start` | `void` | Emitted when the user starts adjusting |
| `@end` | `void` | Emitted when the user ends adjusting |

## Advanced Usage

The component comes with a couple of features that are all adjustable:
Expand Down Expand Up @@ -98,6 +124,33 @@ Example:

Volume: {{ volume }}

### Mouse mode

The knob supports two different kinds of mouse adjustment modes:

1. **Flat**: This is the default, and changes the value with as much as the mouse moves
1. **Velocity**: An alternative move where instead the velocity of the mouse is being considered

For more details on this, check the documentation of the [MouseControl](./mouse-control.md) component which is being used internally by the `<Knob />`. To change to the Velocity mode, use the `mouse-behaviour` prop:

```vue
<template>
<Knob
v-model="volume"
mouse-behaviour="Velocity"
/>
</template>
```

Example:

<Knob
v-model="volume"
mouse-behaviour="Velocity"
/>

Volume: {{ volume }}

### Specific min/max

If you have a different range than 0 to 100, you can use the `min` and `max` props to tweak the range:
Expand Down
218 changes: 218 additions & 0 deletions docs/components/mouse-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
---
outline: deep
---

# MouseControl Component

The `<MouseControl />` component is a tool to add complex mouse control to any custom component. It is used internally by several of the other components in this package.

## Basic Usage

The main output of the `<MouseControl />` is a `change` event, with a delta value representing the change in input. This change is derived from mouse movement, where positive X and negative Y (right and up) movement contributes to an increased delta.

```vue
<script setup>
import { ref } from 'vue'
import { MouseControl } from 'acousti-kit'
const delta = ref(0)
</script>
<template>
<MouseControl
@change="delta = $event"
@start="console.log('Started change')"
@end="console.log('Finished change')"
>
<div>
{{ delta }}
</div>
</MouseControl>
</template>
```

It will automatically lock the pointer to the element, making sure all mouse movements are registered for the value changes emitted by the control.

## Example

<script setup>
import { ref } from 'vue'
import { MouseControl } from '../../src'

const delta = ref('')
</script>

<MouseControl
@change="delta = Math.round($event*10)/10"
@start="console.log('Started change')"
@end="console.log('Finished change')"
>
<div
:style="{
height: '64px',
width: '64px',
borderRadius: '10%',
border: fine ? '1px solid green' : '1px solid blue',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'all .25s ease',
pointer: 'cursor',
}"
>
<span>{{ delta }}</span>
</div>
</MouseControl>
## Props

The following props are available for the `<Knob />` component:

| Prop | Type | Default | Optional | Note |
| ---------------- | ---------------------- | -------- | -------- | ------------------------------------------------------------------------- |
| `normalStrength` | `number` | `0` | Yes | Configures the normal strength of mouse movement effect on value |
| `fineStrength` | `number` | `0` | Yes | Configures the fine adjustment strength of mouse movement effect on value |
| `fineKey` | `string` | `Alt` | Yes | Sets the key used for enabling fine adjustment |
| `captureMouse` | `boolean` | `true` | Yes | Enables mouse capture when adjusting |
| `behaviour` | `'Flat' \| 'Velocity'` | `'Flat'` | Yes | Configures the mode of value adjustments |
| `friction` | `number` | `0.5` | Yes | Sets the friction used when using the `Velocity` mode |

## Events

The following events are available for the `<Knob />` component:

| Prop | Type | Note |
| --------- | -------- | -------------------------------------- |
| `@change` | `number` | Emitted on any change in mouse input |
| `@start` | `void` | Emitted when the user starts adjusting |
| `@end` | `void` | Emitted when the user ends adjusting |

## Advanced Usage

The component comes with a couple of features that are all adjustable:

### Mouse capture

By default, the control will capture the mouse pointer to prevent it leaving the position while adjusting.
This can be turned off using the `capture-mouse` prop:

```vue
<template>
<MouseControl :capture-mouse="false">
<div />
</MouseControl>
</template>
```

Example:

<MouseControl
:capture-mouse="false"
@change="delta = Math.round($event*10)/10"
@end="delta = ''"
>
<div
:style="{
height: '64px',
width: '64px',
borderRadius: '10%',
border: fine ? '1px solid green' : '1px solid blue',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'all .25s ease',
pointer: 'cursor',
}"
>
<span>{{ delta }}</span>
</div>
</MouseControl>
### Fine Adjustment

To enable finer input control, the control will by default scale down the intensity of change when the `Alt` key is held down. The current state is exposed through slot scoped props, as `fine`.
Both the key and the intensity can be configured:

```vue
<template>
<MouseControl
v-slot="{ fine }"
:normal-strength="10"
:fine-strength="0.1"
fine-key="Control"
>
<div :class="[fine ? 'fine' : '']" />
</MouseControl>
</template>
```

Example:

<MouseControl
:normal-strength="10"
:fine-strength="0.1"
fine-key="Control"
@change="delta = Math.round($event*10)/10"
@end="delta = ''"
v-slot="{ fine }"
>
<div
:style="{
height: '64px',
width: '64px',
borderRadius: '10%',
border: fine ? '1px solid green' : '1px solid blue',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'all .25s ease',
pointer: 'cursor',
}"
>
<span>{{ delta }}</span>
</div>
</MouseControl>
### Mouse mode

The control supports two different kinds of mouse adjustment modes:

1. **Flat**: This is the default, and changes the value with as much as the mouse moves
1. **Velocity**: An alternative move where instead the velocity of the mouse is being considered

This can be configured through the `mode` prop:

```vue
<template>
<MouseControl
mode="Velocity"
>
<div />
</MouseControl>
</template>
```

Example:

<MouseControl
mode="Velocity"
@change="delta = Math.round($event*10)/10"
@end="delta = ''"
v-slot="{ fine }"
>
<div
:style="{
height: '64px',
width: '64px',
borderRadius: '10%',
border: fine ? '1px solid green' : '1px solid blue',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'all .25s ease',
pointer: 'cursor',
}"
>
<span>{{ delta }}</span>
</div>
</MouseControl>
23 changes: 23 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,31 @@ outline: deep

# Getting started

All the components of this package are ready to go, headless by design, with simple fallback implementations for testing early.

## 📦 Install

Start by installing using your favourite package manager:

```bash
yarn add acousti-kit
```

## 🔧 Use

Then use components where necessary by importing them:

```vue
<script setup>
import { ref } from 'vue'
import { Knob } from 'acousti-kit'
const volume = ref(100)
</script>
<template>
<Knob v-model="volume" />
</template>
```

Read more about the components available through the menu.
5 changes: 4 additions & 1 deletion src/components/Knob.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import MouseControl from './MouseControl.vue'
import MouseControl from './MouseControl/MouseControl.vue'
import type { MouseBehaviour } from './MouseControl/types'
const props = withDefaults(defineProps<{
modelValue: number
Expand All @@ -11,6 +12,7 @@ const props = withDefaults(defineProps<{
fineStrength?: number
fineKey?: string
captureMouse?: boolean
mouseBehaviour?: MouseBehaviour
}>(), {
min: 0,
max: 100,
Expand Down Expand Up @@ -60,6 +62,7 @@ const percentage = computed(() => 100 / (props.max - props.min) * (clamp(props.m
:fine-strength="fineStrength"
:fine-key="fineKey"
:capture-mouse="captureMouse"
:behaviour="mouseBehaviour"
@change="handleChange"
@start="$emit('start')"
@end="$emit('end')"
Expand Down
2 changes: 1 addition & 1 deletion src/components/KnobAssetStack/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export class KnobAssetStackCanvasRenderer {
}

update(percentage: number) {
this.draw(percentage)
requestAnimationFrame(() => this.draw(percentage))
}

draw(percentage: number) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/KnobAssetStack/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum TrackBehaviour {
Clip,
Fill,
Clip = 'Clip',
Fill = 'Fill',
}
Loading

0 comments on commit e4b527d

Please sign in to comment.