Skip to content
This repository has been archived by the owner on May 24, 2021. It is now read-only.

Commit

Permalink
feat(speed-slider): Use two linear functions for better speed sliding
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-heimbuch committed Jun 5, 2017
1 parent 69cd82e commit c37ef85
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/components/player/progress-bar/Progress.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
data () {
let playtime = this.$select('playtime')
let duration = this.$select('duration')
return {
playtime,
duration,
Expand Down
13 changes: 3 additions & 10 deletions src/components/shared/Slider.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@
export default {
props: ['min', 'max', 'step', 'value', 'onChange', 'onInput', 'thumbColor'],
data () {
return {
thumbPosition: relativePosition(this.value, this.min || 0, this.max || 100)
}
},
watch: {
value: function () {
this.thumbPosition = relativePosition(this.value, this.minValue, this.maxValue)
}
},
computed: {
minValue: function () {
return isUndefined(this.min) ? 0 : this.min
Expand All @@ -50,6 +40,9 @@
},
sliderSteps: function () {
return isUndefined(this.step) ? 0.1 : this.step
},
thumbPosition: function () {
return relativePosition(this.value, this.minValue, this.maxValue)
}
},
mounted: function () {
Expand Down
70 changes: 66 additions & 4 deletions src/components/tabs/settings/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
<div class="input-slider">
<ButtonComponent class="slider-button" :click="changeRate(-5, rate)" :style="buttonStyle(theme)">-</ButtonComponent>
<ButtonComponent class="slider-button" :click="changeRate(5, rate)" :style="buttonStyle(theme)">+</ButtonComponent>
<SliderComponent class="input-slider" min="0.5" max="4" :value="rate" step="0.001" :onInput="setRate" :thumbColor="theme.tabs.slider.thumb"></SliderComponent>
<SliderComponent class="input-slider"
min="0" max="1" step="0.001"
:value="sliderRate" :onInput="toStateRate" :thumbColor="theme.tabs.slider.thumb"></SliderComponent>
</div>
</div>
<div class="footer">
Expand All @@ -32,7 +34,7 @@
import store from 'store'
import { compose, curry } from 'lodash/fp'
import { toPercent, roundUp } from 'utils/math'
import { toPercent, roundUp, round } from 'utils/math'
import SliderComponent from 'shared/Slider.vue'
import ButtonComponent from 'shared/Button.vue'
Expand All @@ -44,14 +46,67 @@
const buttonStyle = (theme) => ({
color: theme.tabs.button.text,
border: `1px solid ${theme.tabs.button.text}`,
background: theme.tabs.button.background
})
// Speed Modifiers
const normalizeSliderValue = (value = 0) => {
if (value < 0) {
value = 0
}
if (value > 1) {
value = 1
}
return value
}
const normalizeRateValue = (value = 0) => {
if (value < 0.5) {
value = 0.5
}
if (value > 4) {
value = 4
}
return value
}
const speedSliderToState = (value = 0) => {
value = parseFloat(value)
if (value <= 0.5) {
value = 0.5 + value
} else {
value = 2 * value + (value - 0.5) * 4
}
return value
}
const stateToSpeedSlider = (value = 0) => {
value = parseFloat(value)
if (value <= 1) {
value = value - 0.5
} else {
value = (value + 2) / 6
}
return value
}
// State Changers
const setVolume = compose(store.dispatch.bind(store), store.actions.setVolume)
const changeVolume = (offset, rate) => () => compose(setVolume, roundUp(offset))(rate)
const setRate = compose(store.dispatch.bind(store), store.actions.setRate)
const toStateRate = compose(setRate, round, speedSliderToState, normalizeSliderValue)
const toSliderRate = compose(round, stateToSpeedSlider, normalizeRateValue)
const changeVolume = (offset, rate) => () => compose(setVolume, roundUp(offset))(rate)
const changeRate = (offset, rate) => () => compose(setRate, roundUp(offset))(rate)
export default {
Expand All @@ -63,10 +118,17 @@
theme: this.$select('theme')
}
},
computed: {
sliderRate: function () {
return toSliderRate(this.rate)
}
},
methods: {
exportStore,
setVolume,
setRate,
toStateRate,
toSliderRate,
changeRate,
changeVolume,
buttonStyle,
Expand Down
6 changes: 4 additions & 2 deletions src/components/tabs/share/ShareDownload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@
<div class="input-element">
<h4 class="title">{{ $t('SHARE.DOWNLOAD') }}</h4>
<div class="input-row input-group">
<input type="text" class="input-text" disabled :value="activeAudioFile(share.download.files)" />
<a class="button input-button truncate"
:href="activeAudioFile(share.download.files)"
:style="buttonStyle(theme)">
{{ $t('SHARE.ACTIONS.DOWNLOAD') }}
</a>
<input type="text" class="input-text" disabled :value="activeAudioFile(share.download.files)" />
</div>
<div class="input-row" v-if="share.download.files.length > 1">
<div></div>
<div>
<label class="input-label">{{ $t('SHARE.LABELS.TYPE') }}</label>
<select class="input-select" v-on:change="switchAudioType">
<option v-for="option in share.download.files" v-bind:value="option.file" :selected="activeAudioType(share.download.files) === option.type">
<option v-for="option in share.download.files"
v-bind:value="option.file"
:selected="activeAudioType(share.download.files) === option.type">
{{ option.type }}
</option>
</select>
Expand Down
2 changes: 1 addition & 1 deletion src/components/tabs/share/ShareEmbed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<div class="embed input-element">
<h4 class="title">{{ $t('SHARE.EMBED') }}</h4>
<div class="input-row input-group">
<input type="text" class="input-text" disabled :value="clipboardContent(reference, share.embed, playtime)" />
<ButtonComponent
class="input-button truncate"
:data-clipboard-text="clipboardContent(reference, share.embed, playtime)"
v-clipboard
:style="buttonStyle(theme)">
{{ $t('SHARE.ACTIONS.COPY') }}
</ButtonComponent>
<input type="text" class="input-text" disabled :value="clipboardContent(reference, share.embed, playtime)" />
</div>
<div class="input-row">
<div class="share-config--time">
Expand Down
6 changes: 4 additions & 2 deletions src/components/tabs/share/ShareLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
<div class="input-element">
<h4 class="title">{{ $t('SHARE.LINK') }}</h4>
<div class="input-row input-group">
<input type="text" class="input-text" disabled :value="clipboardContent(reference, share.link, playtime)" />
<ButtonComponent
class="input-button truncate"
:data-clipboard-text="clipboardContent(reference, share.link, playtime)"
v-clipboard
:style="buttonStyle(theme)">
{{ $t('SHARE.ACTIONS.COPY') }}
</ButtonComponent>
<input type="text" class="input-text" disabled :value="clipboardContent(reference, share.link, playtime)" />
</div>
<div class="input-row">
<div>
<label class="input-label"><input type="checkbox" class="input-checkbox" :value="share.link.start" v-on:change="toggleStart(playtime)"/> {{ $t('SHARE.LABELS.START') }}</label>
<label class="input-label">
<input type="checkbox" class="input-checkbox" :value="share.link.start" v-on:change="toggleStart(playtime)"/> {{ $t('SHARE.LABELS.START') }}
</label>
<input type="text" class="input-text" :value="secondsToTime(share.link.starttime)" v-on:input="setStarttime"/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/store/reducers/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const themeColors = (colors = {}) => {
},
button: {
background: color(primary).fade(0.8),
text: primary
text: negative ? dark : light
}
},
overlay: {
Expand Down
7 changes: 4 additions & 3 deletions src/styles/_inputs.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import 'variables';
@import 'utils';

$input-group-height: 35px;
$input-height: 25px;
$input-secondary-height: 1em;
Expand Down Expand Up @@ -53,9 +54,9 @@ $slider-button-size: 30px;
.input-text {
padding: $padding / 2;
width: calc(100% - #{$addon-button-width});
border-radius: 2px 0 0 2px;
border-radius: 0 2px 2px 0;
font-size: 1em;
border-width: 1px 0 1px 1px;
border-width: 1px 1px 1px 0;
height: $input-group-height;
}
.input-button {
Expand All @@ -75,7 +76,7 @@ $slider-button-size: 30px;

.slider-button {
font-weight: bold;
font-size: 1.2em;
font-size: 1em;
height: $slider-button-size;
width: $slider-button-size;
margin-right: $margin / 2;
Expand Down
9 changes: 7 additions & 2 deletions src/utils/math.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { curry } from 'lodash/fp'

const toPercent = input => {
const toPercent = (input = 0) => {
input = parseFloat(input) * 100
return Math.round(input)
}

const round = (input = 0) => {
return Math.ceil(input * 100) / 100
}

const roundUp = curry((base, number) => {
number = Math.ceil(number * 100)

Expand All @@ -17,5 +21,6 @@ const roundUp = curry((base, number) => {

export {
toPercent,
roundUp
roundUp,
round
}
31 changes: 31 additions & 0 deletions src/utils/math.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import test from 'ava'
import { toPercent, roundUp, round } from './math'

test('exports a method called toPercent', t => {
t.is(typeof toPercent, 'function')
})

test('exports a method called roundUp', t => {
t.is(typeof roundUp, 'function')
})

test('exports a method called round', t => {
t.is(typeof round, 'function')
})

test(`toPrecent: transforms absolute value to percentage`, t => {
t.is(toPercent(), 0)
t.is(toPercent(1.5), 150)
})

test(`round: rounds to floats with 2 nachkomma`, t => {
t.is(round(), 0.00)
t.is(round(1), 1.00)
t.is(round(1.33777777), 1.34)
})

test(`roundUp: rounds to next full float quantile`, t => {
t.is(roundUp(5)(1), 1.05)
t.is(roundUp(5)(1.05), 1.10)
t.is(roundUp(5)(1.06), 1.10)
})

0 comments on commit c37ef85

Please sign in to comment.