<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<!DOCTYPE html><html lang='en' class=''>
<head><script src='//production-assets.codepen.io/assets/editor/live/console_runner-079c09a0e3b9ff743e39ee2d5637b9216b3545af0de366d4b9aad9dc87e26bfd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/events_runner-73716630c22bbc8cff4bd0f07b135f00a0bdc5d14629260c3ec49e5606f98fdd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/css_live_reload_init-2c0dc5167d60a5af3ee189d570b1835129687ea2a61bee3513dee3a50c115a77.js'></script><meta charset='UTF-8'><meta name="robots" content="noindex"><link rel="shortcut icon" type="image/x-icon" href="//production-assets.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" /><link rel="mask-icon" type="" href="//production-assets.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" /><link rel="canonical" href="https://codepen.io/ispal/pen/zZbKqb?depth=everything&order=popularity&page=5&q=input&show_forks=false" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style class="cp-pen-styles">@import url("https://fonts.googleapis.com/css?family=Roboto:100,400");
*,
*::after,
*::before {
box-sizing: border-box;
}
html,
body {
height: 100%;
min-height: 100%;
}
body {
margin: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
font-family: 'Roboto', sans-serif;
background: -webkit-linear-gradient(bottom left, #524ad0 10%, #D099FA);
background: linear-gradient(to top right, #524ad0 10%, #D099FA);
background-repeat: no-repeat;
background-attachment: fixed;
-webkit-font-smoothing: antialiased;
}
[v-cloak] {
display: none;
}
.twitter {
position: absolute;
top: 1em;
left: 1em;
text-decoration: none;
color: rgba(255, 255, 255, 0.8);
}
.twitter > * {
vertical-align: middle;
}
.twitter svg {
fill: currentColor;
width: 1em;
height: 1em;
}
.app {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
padding: 2em;
color: rgba(255, 255, 255, 0.8);
}
.app__content {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.settings {
display: none;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
max-width: 30vw;
margin-right: 10vw;
}
@media (min-width: 780px) {
.settings {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
}
.settings__item {
padding: .2em;
}
.settings__thresholds {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
width: 100%;
}
.settings label {
display: block;
color: rgba(255, 255, 255, 0.8);
letter-spacing: 1px;
font-size: .8em;
margin-left: .5em;
margin-bottom: .2em;
}
.settings input {
background: rgba(255, 255, 255, 0.3);
border: none;
border-radius: 2em;
padding: .5em 1em;
font-size: .8em;
font-weight: 600;
color: rgba(255, 255, 255, 0.8);
}
.current {
text-align: center;
color: rgba(255, 255, 255, 0.3);
font-size: calc(60px + 10vh);
margin-bottom: 5vh;
}
.current-value-enter-active,
.current-value-leave-active {
-webkit-transition: all .2s ease;
transition: all .2s ease;
}
.current-value-enter,
.current-value-leave-to {
-webkit-transform: scale(1.1);
transform: scale(1.1);
opacity: .5;
}
.u-flex-center {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.input-spinner {
--position: 0%;
position: relative;
font-size: 20px;
}
.input-spinner:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 2em;
box-shadow: 0 0.1em 0.6em rgba(0, 0, 0, 0.4);
opacity: 0;
-webkit-transition: opacity .3s;
transition: opacity .3s;
}
.input-spinner.is-dragging .input-spinner__knob {
-webkit-transition: none;
transition: none;
}
.input-spinner.is-dragging .input-spinner__ball {
opacity: 1;
-webkit-transform: translate3d(calc(-50% + var(--position)), 0, 0);
transform: translate3d(calc(-50% + var(--position)), 0, 0);
-webkit-transition: opacity .2s;
transition: opacity .2s;
}
.input-spinner.is-dragging:after {
opacity: 1;
}
.input-spinner__track {
z-index: 2;
position: relative;
overflow: hidden;
width: 12em;
border-radius: 2em;
background: rgba(255, 255, 255, 0.4);
}
.input-spinner__track.is-max .input-spinner__icon--plus {
opacity: .3;
}
.input-spinner__track.is-min .input-spinner__icon--minus {
opacity: .3;
}
.input-spinner__icon {
position: absolute;
top: 50%;
width: 1.1em;
height: 1.1em;
fill: #fff;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%);
-webkit-transition: opacity .3s;
transition: opacity .3s;
}
.input-spinner__icon--plus {
right: .7em;
}
.input-spinner__icon--minus {
left: .7em;
}
.input-spinner__knob {
z-index: 1;
position: relative;
height: 2.5em;
width: 2.5em;
font-size: 1.2em;
color: rgba(0, 0, 0, 0.8);
border-radius: 50%;
background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
cursor: pointer;
-webkit-transform: translate3d(calc(var(--position)), 0, 0);
transform: translate3d(calc(var(--position)), 0, 0);
-webkit-transition: -webkit-transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: -webkit-transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275), -webkit-transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
will-change: transform;
}
.input-spinner__ball {
z-index: 3;
position: absolute;
overflow: hidden;
left: 50%;
bottom: 105%;
opacity: 0;
-webkit-transform: translate3d(calc(-50% + var(--position)), 0, 0);
transform: translate3d(calc(-50% + var(--position)), 0, 0);
-webkit-transition: opacity 0.2s, -webkit-transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: opacity 0.2s, -webkit-transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: opacity 0.2s, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transition: opacity 0.2s, transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), -webkit-transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
will-change: transform;
}
.input-spinner__values {
position: absolute;
top: -2px;
left: 0;
width: 100%;
height: 100%;
color: rgba(0, 0, 0, 0.8);
font-size: .6em;
}
.input-spinner__ball-bg {
width: 1.4em;
height: 1.4em;
fill: rgba(255, 255, 255, 0.4);
}
.list-item {
display: inline-block;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.list-enter-active {
opacity: 0;
-webkit-transform: translate3d(1em, 0, 0);
transform: translate3d(1em, 0, 0);
-webkit-transition: opacity .2s .12s, -webkit-transform 0.2s .1s;
transition: opacity .2s .12s, -webkit-transform 0.2s .1s;
transition: transform 0.2s .1s, opacity .2s .12s;
transition: transform 0.2s .1s, opacity .2s .12s, -webkit-transform 0.2s .1s;
}
.list-leave-active {
position: absolute;
top: 22%;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
-webkit-transition: opacity .2s, -webkit-transform .3s;
transition: opacity .2s, -webkit-transform .3s;
transition: transform .3s, opacity .2s;
transition: transform .3s, opacity .2s, -webkit-transform .3s;
}
.list-enter-to {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.list-leave-to {
position: absolute;
top: 22%;
opacity: 0;
-webkit-transform: translate3d(-1em, 0, 0);
transform: translate3d(-1em, 0, 0);
}
.list--reverse-enter-active {
opacity: 0;
-webkit-transform: translate3d(-1em, 0, 0);
transform: translate3d(-1em, 0, 0);
-webkit-transition: opacity .2s .1s, -webkit-transform 0.2s .1s;
transition: opacity .2s .1s, -webkit-transform 0.2s .1s;
transition: transform 0.2s .1s, opacity .2s .1s;
transition: transform 0.2s .1s, opacity .2s .1s, -webkit-transform 0.2s .1s;
}
.list--reverse-leave-active {
position: absolute;
top: 22%;
-webkit-transition: opacity .2s, -webkit-transform 0.3s;
transition: opacity .2s, -webkit-transform 0.3s;
transition: transform 0.3s, opacity .2s;
transition: transform 0.3s, opacity .2s, -webkit-transform 0.3s;
}
.list--reverse-enter-to {
opacity: 1;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.list--reverse-leave-to {
position: absolute;
top: 22%;
opacity: 0;
-webkit-transform: translate3d(1em, 0, 0);
transform: translate3d(1em, 0, 0);
}
</style></head><body>
<a href="https://twitter.com/irkopal" class="twitter" target="_blank">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="640" height="640" viewBox="0 0 640 640">
<path d="M554.112 199.872c0.256 5.184 0.352 10.432 0.352 15.616 0 159.68-121.504 343.744-343.68 343.744-68.256 0-131.712-20-185.184-54.304 9.472 1.12 19.072 1.696 28.8 1.696 56.64 0 108.704-19.328 150.016-51.68-52.832-0.992-97.472-35.872-112.832-83.872 7.36 1.376 14.944 2.112 22.72 2.112 11.040 0 21.728-1.44 31.84-4.192-55.264-11.136-96.896-59.936-96.896-118.496 0-0.512 0-0.992 0-1.504 16.288 9.056 34.944 14.496 54.72 15.136-32.416-21.696-53.76-58.624-53.76-100.576 0-22.112 5.952-42.88 16.384-60.736 59.552 73.12 148.608 121.184 248.992 126.24-2.048-8.864-3.104-18.048-3.104-27.552 0-66.688 54.048-120.736 120.768-120.736 34.752 0 66.144 14.624 88.192 38.112 27.488-5.44 53.344-15.488 76.704-29.312-9.024 28.192-28.192 51.872-53.12 66.816 24.448-2.944 47.68-9.376 69.376-19.008-16.192 24.256-36.672 45.504-60.288 62.496z"></path>
</svg> @irkopal
</a>
<div id="app" v-cloak>
<div class="app">
<div class="settings">
<div class="settings__item">
<label for="">Min value</label>
<input type="number" v-model.number="min">
</div>
<div class="settings__item">
<label for="">Max value</label>
<input type="number" v-model.number="max">
</div>
<div class="settings__item">
<label for="">Timer increase/decrease</label>
<input type="number" v-model.number="timerStep">
</div>
<div class="settings__item">
<label for="">Interval</label>
<input type="number" v-model.number="interval" min="500" step="100">
</div>
<div class="settings__thresholds">
<h3>Thresholds</h3>
<table>
<tr class="settings__threshold" v-for="(threshold, index) in thresholds" :key="index">
<td>
<label for="">Threshold</label>
<input type="number" @change="changeThreshold(index, $event)" :value="threshold.threshold" max="100" min="0">
</td>
<td>
<label for="">Value</label>
<input type="number" @change="changeThresholdValue(index, $event)" :value="threshold.value"></td>
</td>
</tr>
</table>
</div>
</div>
<div class="app__content">
<transition name="current-value" mode="out-in">
<div class="current" :key="currentVal">{{ currentVal }}</div>
</transition>
<input-spinner :min="min" :max="max" @update="updateValue" :interval="interval" :thresholds="thresholds" :timer-step="timerStep"></input-spinner>
<p style="margin-top: 3em;">
Drag and hold the knob in either end and see what happens.
</p>
</div>
</div>
</div>
<script src='//production-assets.codepen.io/assets/common/stopExecutionOnTimeout-b2a7b3fe212eaa732349046d8416e00a9dec26eb7fd347590fbced3ab38af52e.js'></script><script src='https://unpkg.com/vue/dist/vue.min.js'></script>
<script >'use strict';
var InputSpinner = {
name: "InputSpinner",
template: '\n <div \n class="input-spinner"\n :class="{\'is-dragging\': dragging }"\n >\n <div \n class="input-spinner__track u-flex-center"\n :class="{\'is-min\': isMin, \'is-max\': isMax }"\n >\n <svg class="input-spinner__icon input-spinner__icon--minus" version="1.1" xmlns="http://www.w3.org/2000/svg" width="640" height="640" viewBox="0 0 640 640">\n <path d="M512 320c0 17.696-1.536 32-19.232 32h-345.536c-17.664 0-19.232-14.304-19.232-32s1.568-32 19.232-32h345.568c17.664 0 19.2 14.304 19.2 32z"></path>\n </svg>\n <div \n class="input-spinner__knob u-flex-center"\n ref="knob"\n >\n <span>{{value}}</span>\n </div>\n <svg class="input-spinner__icon input-spinner__icon--plus" version="1.1" xmlns="http://www.w3.org/2000/svg" width="768" height="768" viewBox="0 0 768 768">\n <path d="M607.5 415.5h-192v192h-63v-192h-192v-63h192v-192h63v192h192v63z"></path>\n </svg>\n </div>\n <div class="input-spinner__ball u-flex-center">\n <svg class="input-spinner__ball-bg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 695.5"><title>drop</title><path d="M587.75,523.75,384,727.5,180.25,523.75a281.43,281.43,0,0,1-62.87-94.5,289.88,289.88,0,0,1,0-218.5A289.43,289.43,0,0,1,274.75,53.5a288.32,288.32,0,0,1,218.5,0A288.37,288.37,0,0,1,650.5,210.88a288.43,288.43,0,0,1-62.75,312.88Z" transform="translate(-96 -32)"/></svg>\n <transition-group\n :name="transitionName"\n tag="div"\n class="input-spinner__values u-flex-center"\n >\n <span v-for="item in activeValue" :key="item">\n {{ item }}\n </span>\n </transition-group>\n </div> \n </div>\n ',
props: {
defaultValue: {
type: Number,
default: 0
},
min: {
type: Number,
default: 0
},
max: {
type: Number
},
timerStep: {
type: Number,
default: 1
},
interval: {
type: Number,
default: 1000
},
thresholds: {
type: Array,
default: [{ threshold: 30, value: 1 }, { threshold: 100, value: 10 }]
}
},
data: function data() {
return {
value: this.defaultValue,
dragging: false,
position: 0,
activeValue: [0],
transitionName: 'list',
initialInterval: 1500
};
},
mounted: function mounted() {
this.width = this.$el.getBoundingClientRect().width;
this.halfWidth = this.width / 2;
this.knobWidth = this.$refs.knob.getBoundingClientRect().width;
this.knobWidthHalf = this.knobWidth / 2;
this.$refs.knob.addEventListener('mousedown', this.onStart);
this.$refs.knob.addEventListener('touchstart', this.onStart);
window.addEventListener('mousemove', this.onMove);
window.addEventListener('touchmove', this.onMove);
window.addEventListener('mouseup', this.onEnd);
window.addEventListener('touchend', this.onEnd);
},
beforeDestroy: function beforeDestroy() {
this.$refs.knob.removeEventListener('mousedown', this.onStart);
this.$refs.knob.addEventListener('touchstart', this.onStart);
window.removeEventListener('mousemove', this.onMove);
window.removeEventListener('touchmove', this.onMove);
window.removeEventListener('mouseup', this.onEnd);
window.removeEventListener('touchend', this.onEnd);
},
watch: {
'position': function position(val, oldVal) {
if (this.position <= 100) {
this.transitionName = val > oldVal ? 'list' : 'list--reverse';
}
}
},
methods: {
onStart: function onStart(e) {
this.dragging = true;
this.startX = this.getScreenX(e);
},
onEnd: function onEnd(e) {
var deltaX = this.getScreenX(e) - this.startX;
var position = this.positionPercent(deltaX);
var newValue = this.value + this.activeValue[0];
if (this.dragging) {
this.value = newValue;
if (newValue > this.max) {
this.value = this.max;
}
if (newValue < this.min) {
this.value = this.min;
}
}
this.$emit('update', this.value);
this.setPosition(0);
this.dragging = false;
},
onMove: function onMove(e) {
if (this.dragging) {
var deltaXFromCenter = this.getScreenX(e) - this.startX;
this.setPosition(deltaXFromCenter);
}
},
setPosition: function setPosition(deltaXFromCenter) {
this.position = this.positionPercent(deltaXFromCenter);
if (Math.abs(this.position) >= 100 && !this.timerEnabled) {
this.timerEnabled = true;
this.setActiveValue(this.getThresholdValue(this.position));
this.startTimer(this.position);
}
if (Math.abs(this.position) < 100) {
this.timerEnabled = false;
}
if (deltaXFromCenter <= this.halfWidth && deltaXFromCenter >= -this.halfWidth) {
this.setActiveValue(this.getThresholdValue(this.position));
this.$el.style.setProperty('--position', Math.round(deltaXFromCenter) + 'px');
}
},
setActiveValue: function setActiveValue(val) {
this.activeValue = [val];
},
startTimer: function startTimer() {
var _this = this;
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(function () {
if (_this.timerEnabled) {
var newValue = _this.position >= 0 ? _this.activeValue[0] + _this.timerStep : _this.activeValue[0] - _this.timerStep;
_this.setActiveValue(newValue);
_this.startTimer();
}
}, this.interval);
},
positionPercent: function positionPercent(deltaXFromCenter) {
return deltaXFromCenter / this.halfWidth * 100;
},
getThresholdValue: function getThresholdValue(val) {
var availableValues = this.thresholds.filter(function (item) {
return item.threshold <= Math.abs(Math.round(val));
});
var value = 0;
if (availableValues.length > 0) {
value = availableValues.pop().value;
}
return val >= 0 ? value : -1 * value;
},
getScreenX: function getScreenX(e) {
if (e.changedTouches) {
return e.changedTouches[0].screenX;
}
return e.screenX;
}
},
computed: {
isMin: function isMin() {
return this.value <= this.min;
},
isMax: function isMax() {
return this.value >= this.max;
}
}
};
new Vue({
el: '#app',
components: {
InputSpinner: InputSpinner
},
data: {
currentVal: 0,
min: 0,
max: 50,
interval: 1000,
timerStep: 5,
thresholds: [{ threshold: 30, value: 1 }, { threshold: 100, value: 10 }]
},
methods: {
updateValue: function updateValue(val) {
this.currentVal = val;
},
changeThreshold: function changeThreshold(thresholdIndex, evt) {
this.thresholds = this.thresholds.map(function (item, index) {
if (thresholdIndex === index) {
return {
threshold: evt.target.value,
value: item.value
};
}
return item;
});
},
changeThresholdValue: function changeThresholdValue(thresholdIndex, evt) {
this.thresholds = this.thresholds.map(function (item, index) {
if (thresholdIndex === index) {
return {
threshold: item.threshold,
value: evt.target.value
};
}
return item;
});
}
}
});
//# sourceURL=pen.js
</script>
</body></html>