Toggle navigation
在线编辑器
在线代码
文本比较
jQuery下载
前端库
在线手册
登录/注册
下载代码
html
css
js
分享到微信朋友圈
X
html
delay
att
hold
dec
sus
rel
tension
tension
css
* { box-sizing: border-box; } html, body { width: 100%; height: 100%; } body { padding: 1px; background: -webkit-radial-gradient(#1a1d22, #121318); background: radial-gradient(#1a1d22, #121318); } .defs { position: absolute; width: 0; height: 0; opacity: 0; } .fl-studio-asdr { position: absolute; left: 50%; top: 50%; width: 600px; padding: 20px; overflow: hidden; background: #363c40; border: 2px solid #272d31; box-shadow: 0 10px 70px rgba(0, 0, 0, 0.6); -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); } .fl-studio-asdr__visualizer { height: 200px; background: #21272b; border: 2px solid #191f23; } .fl-studio-asdr__visualizer .envelope-visualizer { width: 100%; height: 100%; overflow: visible; } .fl-studio-asdr__controls, .fl-studio-asdr__tension { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between; -webkit-box-align: center; -ms-flex-align: center; align-items: center; } .fl-studio-asdr__controls { padding: 30px 0 0; } .fl-studio-asdr__control { -webkit-box-flex: 1; -ms-flex: 1 0 auto; flex: 1 0 auto; 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; } .fl-studio-asdr__label { -webkit-box-flex: 0; -ms-flex: 0 0 auto; flex: 0 0 auto; display: inline-block; padding: 10px 0; width: 80px; color: #c1c5c5; font-size: 10px; font-family: 'Helvetica', sans-serif; font-weight: 700; text-align: center; letter-spacing: 1px; text-transform: uppercase; } .fl-studio-asdr__knob { -webkit-box-flex: 0; -ms-flex: 0 0 auto; flex: 0 0 auto; } .fl-studio-asdr__knob.envelope-knob { width: 80px; height: 80px; } .fl-studio-asdr__knob.tension-knob { padding: 10px; width: 80px; height: 80px; } .fl-studio-asdr__knob .control-knob__visual { overflow: visible; } .fl-studio-asdr__knob .dial { -webkit-transform-origin: 20px 20px; transform-origin: 20px 20px; -webkit-transition: all 600ms cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 600ms cubic-bezier(0.39, 0.575, 0.565, 1); } .fl-studio-asdr__knob .dial-highlight { opacity: 0; -webkit-transition: all 300ms cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 300ms cubic-bezier(0.39, 0.575, 0.565, 1); } .fl-studio-asdr__knob:hover .dial, .fl-studio-asdr__knob.drag-active .dial { -webkit-transform: scale(0.9); transform: scale(0.9); -webkit-filter: brightness(10.2); filter: brightness(10.2); -webkit-transition: all 300ms cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 300ms cubic-bezier(0.39, 0.575, 0.565, 1); } .fl-studio-asdr__knob:hover .dial-highlight, .fl-studio-asdr__knob.drag-active .dial-highlight { opacity: 0.05; } .fl-studio-asdr__knob .focus-indicator { opacity: 0; -webkit-transition: all 300ms cubic-bezier(0.39, 0.575, 0.565, 1); transition: all 300ms cubic-bezier(0.39, 0.575, 0.565, 1); } .fl-studio-asdr__knob.focus-active .focus-indicator { opacity: 0.8; } .control-knob { position: relative; } .control-knob__visual { pointer-events: none; width: 100%; height: 100%; } .control-knob__input { cursor: -webkit-grab; cursor: grab; position: absolute; left: 0; top: 0; width: 100%; height: 100%; opacity: 0; -webkit-transform: rotate(-90deg); transform: rotate(-90deg); } body.control-knob__drag-active, body.control-knob__drag-active * { cursor: -webkit-grabbing !important; cursor: grabbing !important; }
JavaScript
// TODO: add input label for screenreaders // KnobInput class class KnobInput { constructor(containerElement, options) { if (!options) { options = {}; } // settings var step = options.step || "any"; var min = typeof options.min === "number" ? options.min : 0; var max = typeof options.max === "number" ? options.max : 1; this.initial = typeof options.initial === "number" ? options.initial : 0.5 * (min + max); this.visualElementClass = options.visualElementClass || "control-knob__visual"; this.dragResistance = typeof options.dragResistance === "number" ? options.dragResistance : 300; this.dragResistance /= max - min; this.wheelResistance = typeof options.wheelResistance === "number" ? options.wheelResistance : 4000; this.wheelResistance /= max - min; this.setupVisualContext = typeof options.visualContext === "function" ? options.visualContext : KnobInput.setupRotationContext(0, 360); this.updateVisuals = typeof options.updateVisuals === "function" ? options.updateVisuals : KnobInput.rotationUpdateFunction; // setup input var rangeInput = document.createElement("input"); rangeInput.type = "range"; rangeInput.step = step; rangeInput.min = min; rangeInput.max = max; rangeInput.value = this.initial; containerElement.appendChild(rangeInput); // elements this._container = containerElement; this._container.classList.add("control-knob"); this._input = rangeInput; this._input.classList.add("control-knob__input"); this._visualElement = this._container.querySelector( `.${this.visualElementClass}` ); this._visualElement.classList.add("control-knob__visual"); // visual context this._visualContext = { element: this._visualElement }; this.setupVisualContext.apply(this._visualContext); this.updateVisuals = this.updateVisuals.bind(this._visualContext); // internals this._activeDrag = false; // define event listeners // have to store bound versions of handlers so they can be removed later this._handlers = { inputChange: this.handleInputChange.bind(this), touchStart: this.handleTouchStart.bind(this), touchMove: this.handleTouchMove.bind(this), touchEnd: this.handleTouchEnd.bind(this), touchCancel: this.handleTouchCancel.bind(this), mouseDown: this.handleMouseDown.bind(this), mouseMove: this.handleMouseMove.bind(this), mouseUp: this.handleMouseUp.bind(this), mouseWheel: this.handleMouseWheel.bind(this), doubleClick: this.handleDoubleClick.bind(this), focus: this.handleFocus.bind(this), blur: this.handleBlur.bind(this) }; // add listeners this._input.addEventListener("change", this._handlers.inputChange); this._input.addEventListener("touchstart", this._handlers.touchStart); this._input.addEventListener("mousedown", this._handlers.mouseDown); this._input.addEventListener("wheel", this._handlers.mouseWheel); this._input.addEventListener("dblclick", this._handlers.doubleClick); this._input.addEventListener("focus", this._handlers.focus); this._input.addEventListener("blur", this._handlers.blur); // init this.updateToInputValue(); } static setupRotationContext(minRotation, maxRotation) { return function() { this.minRotation = minRotation; this.maxRotation = maxRotation; }; } static rotationUpdateFunction(norm) { this.element.style[transformProp] = `rotate(${this.maxRotation * norm - this.minRotation * (norm - 1)}deg)`; } // handlers handleInputChange(evt) { // console.log('input change'); this.updateToInputValue(); } handleTouchStart(evt) { // console.log('touch start'); this.clearDrag(); evt.preventDefault(); var touch = evt.changedTouches.item(evt.changedTouches.length - 1); this._activeDrag = touch.identifier; this.startDrag(touch.clientY); // drag update/end listeners document.body.addEventListener("touchmove", this._handlers.touchMove); document.body.addEventListener("touchend", this._handlers.touchEnd); document.body.addEventListener("touchcancel", this._handlers.touchCancel); } handleTouchMove(evt) { // console.log('touch move'); var activeTouch = this.findActiveTouch(evt.changedTouches); if (activeTouch) { this.updateDrag(activeTouch.clientY); } else if (!this.findActiveTouch(evt.touches)) { this.clearDrag(); } } handleTouchEnd(evt) { // console.log('touch end'); var activeTouch = this.findActiveTouch(evt.changedTouches); if (activeTouch) { this.finalizeDrag(activeTouch.clientY); } } handleTouchCancel(evt) { // console.log('touch cancel'); if (this.findActiveTouch(evt.changedTouches)) { this.clearDrag(); } } handleMouseDown(evt) { // console.log('mouse down'); this.clearDrag(); evt.preventDefault(); this._activeDrag = true; this.startDrag(evt.clientY); // drag update/end listeners document.body.addEventListener("mousemove", this._handlers.mouseMove); document.body.addEventListener("mouseup", this._handlers.mouseUp); } handleMouseMove(evt) { // console.log('mouse move'); if (evt.buttons & 1) { this.updateDrag(evt.clientY); } else { this.finalizeDrag(evt.clientY); } } handleMouseUp(evt) { // console.log('mouse up'); this.finalizeDrag(evt.clientY); } handleMouseWheel(evt) { // console.log('mouse wheel'); this._input.focus(); this.clearDrag(); this._prevValue = parseFloat(this._input.value); this.updateFromDrag(evt.deltaY, this.wheelResistance); } handleDoubleClick(evt) { // console.log('double click'); this.clearDrag(); this._input.value = this.initial; this.updateToInputValue(); } handleFocus(evt) { // console.log('focus on'); this._container.classList.add("focus-active"); } handleBlur(evt) { // console.log('focus off'); this._container.classList.remove("focus-active"); } // dragging startDrag(yPosition) { this._dragStartPosition = yPosition; this._prevValue = parseFloat(this._input.value); this._input.focus(); document.body.classList.add("control-knob__drag-active"); this._container.classList.add("drag-active"); } updateDrag(yPosition) { var diff = yPosition - this._dragStartPosition; this.updateFromDrag(diff, this.dragResistance); this._input.dispatchEvent(new InputEvent("change")); } finalizeDrag(yPosition) { var diff = yPosition - this._dragStartPosition; this.updateFromDrag(diff, this.dragResistance); this.clearDrag(); this._input.dispatchEvent(new InputEvent("change")); } clearDrag() { document.body.classList.remove("control-knob__drag-active"); this._container.classList.remove("drag-active"); this._activeDrag = false; this._input.dispatchEvent(new InputEvent("change")); // clean up event listeners document.body.removeEventListener("mousemove", this._handlers.mouseMove); document.body.removeEventListener("mouseup", this._handlers.mouseUp); document.body.removeEventListener("touchmove", this._handlers.touchMove); document.body.removeEventListener("touchend", this._handlers.touchEnd); document.body.removeEventListener( "touchcancel", this._handlers.touchCancel ); } updateToInputValue() { var normVal = this.normalizeValue(parseFloat(this._input.value)); this.updateVisuals(normVal); } updateFromDrag(dragAmount, resistance) { var newVal = this.clampValue(this._prevValue - dragAmount / resistance); this._input.value = newVal; this.updateVisuals(this.normalizeValue(newVal)); } // utils clampValue(val) { var min = parseFloat(this._input.min); var max = parseFloat(this._input.max); return Math.min(Math.max(val, min), max); } normalizeValue(val) { var min = parseFloat(this._input.min); var max = parseFloat(this._input.max); return (val - min) / (max - min); } findActiveTouch(touchList) { var i, len, touch; for (i = 0, len = touchList.length; i < len; i++) if (this._activeDrag === touchList.item(i).identifier) return touchList.item(i); return null; } // public passthrough methods addEventListener() { this._input.addEventListener.apply(this._input, arguments); } removeEventListener() { this._input.removeEventListener.apply(this._input, arguments); } focus() { this._input.focus.apply(this._input, arguments); } blur() { this._input.blur.apply(this._input, arguments); } // getters/setters get value() { return parseFloat(this._input.value); } set value(val) { this._input.value = val; this.updateToInputValue(); this._input.dispatchEvent(new Event("change")); } } // Utils function getSupportedPropertyName(properties) { for (var i = 0; i < properties.length; i++) if (typeof document.body.style[properties[i]] !== "undefined") return properties[i]; return null; } function getTransformProperty() { return getSupportedPropertyName([ "transform", "msTransform", "webkitTransform", "mozTransform", "oTransform" ]); } function debounce(func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; } // Demo Setup - Knobs var transformProp = getTransformProperty(); var envelopeKnobStartPositions = [0, 40, 75, 85, 20, 55]; var envelopeKnobs = [ ...document.querySelectorAll(".fl-studio-asdr__knob.envelope-knob") ]; var envelopeKnobs = envelopeKnobs.map( (el, idx) => new KnobInput(el, { visualContext: function() { this.indicatorRing = this.element.querySelector(".indicator-ring"); var ringStyle = getComputedStyle( this.element.querySelector(".indicator-ring-bg") ); this.r = parseFloat(ringStyle.r) - parseFloat(ringStyle.strokeWidth) / 2; this.indicatorDot = this.element.querySelector(".indicator-dot"); this.indicatorDot.style[`${transformProp}Origin`] = "20px 20px"; }, updateVisuals: function(norm) { var theta = Math.PI * 2 * norm + 0.5 * Math.PI; var endX = this.r * Math.cos(theta) + 20; var endY = this.r * Math.sin(theta) + 20; // using 2 arcs rather than flags since one arc collapses if it gets near 360deg this.indicatorRing.setAttribute( "d", `M20,20l0,${this.r}${norm > 0.5 ? `A${this.r},${this.r},0,0,1,20,${20 - this.r}` : ""}A-${this.r},${this.r},0,0,1,${endX},${endY}Z` ); this.indicatorDot.style[transformProp] = `rotate(${360 * norm}deg)`; }, min: 0, max: 100, initial: envelopeKnobStartPositions[idx] }) ); var tensionKnobStartPositions = [0, 0, -80]; var tensionKnobs = [ ...document.querySelectorAll(".fl-studio-asdr__knob.tension-knob") ]; var tensionKnobs = tensionKnobs.map( (el, idx) => new KnobInput(el, { visualContext: function() { this.indicatorRing = this.element.querySelector(".indicator-ring"); var ringStyle = getComputedStyle( this.element.querySelector(".indicator-ring-bg") ); this.r = parseFloat(ringStyle.r) - parseFloat(ringStyle.strokeWidth) / 2; }, updateVisuals: function(norm) { var theta = Math.PI * 2 * norm + 0.5 * Math.PI; var endX = this.r * Math.cos(theta) + 20; var endY = this.r * Math.sin(theta) + 20; this.indicatorRing.setAttribute( "d", `M20,20l0,-${this.r}A${this.r},${this.r},0,0,${norm < 0.5 ? 0 : 1},${endX},${endY}Z` ); }, min: -100, max: 100, initial: tensionKnobStartPositions[idx] }) ); // Demo Setup - Envelope Visualization var container = document.querySelector(".envelope-visualizer"); var enveloperVisualizer = { container: container, shape: container.querySelector(".envelope-shape"), delay: container.querySelector(".delay"), attack: container.querySelector(".attack"), hold: container.querySelector(".hold"), decay: container.querySelector(".decay"), release: container.querySelector(".release") }; var updateVisualization = debounce(function(evt) { var maxPtSeparation = 75; var ptDelay = maxPtSeparation * envelopeKnobs[0].value / 100; var ptAttack = ptDelay + maxPtSeparation * envelopeKnobs[1].value / 100; var ptHold = ptAttack + maxPtSeparation * envelopeKnobs[2].value / 100; var ptDecay = ptHold + maxPtSeparation * envelopeKnobs[3].value / 100 * (100 - envelopeKnobs[4].value) / 100; var ptSustain = 100 - envelopeKnobs[4].value; // y value var ptRelease = ptDecay + maxPtSeparation * envelopeKnobs[5].value / 100; // TODO: better tension visualization var tnAttack = (ptAttack - ptDelay) * tensionKnobs[0].value / 100; var tnDecay = (ptDecay - ptHold) * tensionKnobs[1].value / 100; var tnRelease = (ptRelease - ptDecay) * tensionKnobs[2].value / 100; enveloperVisualizer.shape.setAttribute( "d", `M${ptDelay},100` + `C${tnAttack < 0 ? ptDelay - tnAttack : ptDelay},100,${tnAttack > 0 ? ptAttack - tnAttack : ptAttack},0,${ptAttack},0` + `L${ptHold},0` + `C${tnDecay > 0 ? ptHold + tnDecay : ptHold},0,${tnDecay < 0 ? ptDecay + tnDecay : ptDecay},${ptSustain},${ptDecay},${ptSustain}` + `C${tnRelease > 0 ? ptDecay + tnRelease : ptDecay},${ptSustain},${tnRelease < 0 ? ptRelease + tnRelease : ptRelease},100,${ptRelease},100` ); enveloperVisualizer.delay.setAttribute("cx", ptDelay); enveloperVisualizer.attack.setAttribute("cx", ptAttack); enveloperVisualizer.hold.setAttribute("cx", ptHold); enveloperVisualizer.decay.setAttribute("cx", ptDecay); enveloperVisualizer.decay.setAttribute("cy", ptSustain); enveloperVisualizer.release.setAttribute("cx", ptRelease); }, 10); envelopeKnobs.concat(tensionKnobs).forEach(knob => { knob.addEventListener("change", updateVisualization); }); updateVisualization(); var panelElement = document.querySelector(".fl-studio-asdr"); var panel = { element: panelElement, originalTransform: getComputedStyle(panelElement)[transformProp], width: panelElement.getBoundingClientRect().width, height: panelElement.getBoundingClientRect().height }; var resizePanel = () => { var pw = (window.innerWidth - 40) / panel.width; var ph = (window.innerHeight - 40) / panel.height; var size = Math.min(pw, ph); if (size > 1.4) { size -= 0.4; } else if (size > 1) { size = Math.min(size, 1); } panel.element.style[ transformProp ] = `${panel.originalTransform} scale(${size})`; }; window.addEventListener("resize", resizePanel); resizePanel();
粒子
时间
文字
hover
canvas
3d
游戏
音乐
火焰
水波
轮播图
鼠标跟随
动画
css
加载动画
导航
菜单
按钮
滑块
tab
弹出层
统计图
svg
×
Close
在线代码下载提示
开通在线代码永久免费下载,需支付20jQ币
开通后,在线代码模块中所有代码可终身免费下!
您已开通在线代码永久免费下载,关闭提示框后,点下载代码可直接下载!
您已经开通过在线代码永久免费下载
对不起,您的jQ币不足!可通过发布资源 或
直接充值获取jQ币
取消
开通下载
<!doctype html> <html> <head> <meta charset="utf-8"> <title>旋钮输入组件-jq22.com</title> <script src="https://www.jq22.com/jquery/jquery-1.10.2.js"></script> <style>
</style> </head> <body>
<script>
</script>
</body> </html>
2012-2021 jQuery插件库版权所有
jquery插件
|
jq22工具库
|
网页技术
|
广告合作
|
在线反馈
|
版权声明
沪ICP备13043785号-1
浙公网安备 33041102000314号