jam-cloud/web/app/assets/javascripts/faderHelpers.js

256 lines
7.9 KiB
JavaScript

/**
* Functions related to faders (slider controls for volume).
* These functions are intimately tied to the markup defined in
* the templates in _faders.html.erb
*/
(function (g, $) {
"use strict";
g.JK = g.JK || {};
var $draggingFaderHandle = null;
var $draggingFader = null;
var draggingOrientation = null;
var logger = g.JK.logger;
function faderClick(e) {
e.stopPropagation();
var $fader = $(this);
var recordingDisabled = $fader.data('recording-disabled');
if(recordingDisabled) {
var recordingOpener = $fader.data('recording-opener');
window.JK.prodBubble($fader, 'recording-controls-disabled', {recordingOpener:recordingOpener}, {positions:['top'], offsetParent: $fader.closest('.screen')})
return false;
}
draggingOrientation = $fader.attr('orientation');
var offset = $fader.offset();
var position = { top: e.pageY - offset.top, left: e.pageX - offset.left}
var faderPct = faderValue($fader, e, position);
if (faderPct < 0 || faderPct > 100) {
return false;
}
$fader.parent().triggerHandler('fader_change', {percentage: faderPct, dragging: false})
setHandlePosition($fader, faderPct);
return false;
}
function setHandlePosition($fader, value) {
var ratio, position;
var $handle = $fader.find('div[control="fader-handle"]');
var orientation = $fader.attr('orientation');
var handleCssAttribute = getHandleCssAttribute($fader);
// required because this method is entered directly when from a callback
if (draggingOrientation === "horizontal") {
ratio = value / 100;
position = ((ratio * $fader.width()) - (ratio * handleWidth(draggingOrientation))) + 'px';
}
else {
ratio = (100 - value) / 100;
position = ((ratio * $fader.height()) - (ratio * handleWidth(draggingOrientation))) + 'px';
}
$handle.css(handleCssAttribute, position);
}
function faderValue($fader, e, offset) {
var orientation = $fader.attr('orientation');
var getPercentFunction = getVerticalFaderPercent;
var relativePosition = offset.top;
if (orientation && orientation == 'horizontal') {
getPercentFunction = getHorizontalFaderPercent;
relativePosition = offset.left;
}
return getPercentFunction(relativePosition, $fader);
}
function getHandleCssAttribute($fader) {
var orientation = $fader.attr('orientation');
return (orientation === 'horizontal') ? 'left' : 'top';
}
function getVerticalFaderPercent(eventY, $fader) {
return getFaderPercent(eventY, $fader, 'vertical');
}
function getHorizontalFaderPercent(eventX, $fader) {
return getFaderPercent(eventX, $fader, 'horizontal');
}
/**
* Returns the current value of the fader as int percent 0-100
*/
function getFaderPercent(value, $fader, orientation) {
var faderSize, faderPct;
// the handle takes up room, and all calculations use top. So when the
// handle *looks* like it's at the bottom by the user, it won't give a 0% value.
// so, we subtract handleWidth from the size of it's parent
if (orientation === "horizontal") {
faderSize = $fader.width();
faderPct = Math.round(( value + (value / faderSize * handleWidth(orientation))) / faderSize * 100);
}
else {
faderSize = $fader.height();
faderPct = Math.round((faderSize - handleWidth(orientation) - value) / (faderSize - handleWidth(orientation)) * 100);
}
return faderPct;
}
function onFaderDrag(e, ui) {
var faderPct = faderValue($draggingFader, e, ui.position);
// protect against attempts to drag outside of the slider, which jquery.draggable sometimes allows
if (faderPct < 0 || faderPct > 100) {
return false;
}
$draggingFader.parent().triggerHandler('fader_change', {percentage: faderPct, dragging: true})
}
function onFaderDragStart(e, ui) {
$draggingFaderHandle = $(this);
$draggingFader = $draggingFaderHandle.closest('div[control="fader"]');
draggingOrientation = $draggingFader.attr('orientation');
var recordingDisabled = $draggingFaderHandle.data('recording-disabled');
var recordingOpener = $draggingFaderHandle.data('recording-opener');
if(recordingDisabled) {
return false;
}
return true;
}
function onFaderDragStop(e, ui) {
var faderPct = faderValue($draggingFader, e, ui.position);
// protect against attempts to drag outside of the slider, which jquery.draggable sometimes allows
// do not return 'false' though, because that stops future drags from working, for some reason
if (faderPct < 0 || faderPct > 100) {
return;
}
$draggingFader.parent().triggerHandler('fader_change', {percentage: faderPct, dragging: false});
$draggingFaderHandle = null;
$draggingFader = null;
draggingOrientation = null;
}
function handleWidth(orientation) {
return orientation === "horizontal" ? 8 : 11;
}
g.JK.FaderHelpers = {
/**
* Render a fader into the element identifed by the provided
* selector, with the provided options.
*/
renderFader: function (selector, userOptions) {
selector = $(selector);
if (userOptions === undefined) {
throw ("renderFader: userOptions is required");
}
var renderDefaults = {
faderType: "vertical",
height: 83, // only used for vertical
width: 83 // only used for horizontal
};
var options = $.extend({}, renderDefaults, userOptions);
var templateSelector = (options.faderType === 'horizontal') ?
"#template-fader-h" : '#template-fader-v';
var templateSource = $(templateSelector).html();
selector.html(g._.template(templateSource, options));
selector.find('div[control="fader"]').data('recording-disabled', selector.data('recording-disabled')).data('recording-opener', selector.data('recording-opener'))
selector.find('div[control="fader-handle"]').draggable({
drag: onFaderDrag,
start: onFaderDragStart,
stop: onFaderDragStop,
containment: "parent",
axis: options.faderType === 'horizontal' ? 'x' : 'y'
}).data('recording-disabled', selector.data('recording-disabled')).data('recording-opener', selector.data('recording-opener'))
// Embed any custom styles, applied to the .fader below selector
if ("style" in options) {
for (var key in options.style) {
selector.find(' .fader').css(key, options.style[key]);
}
}
},
convertLinearToDb: function (input) {
// deal with extremes better
if (input <= 1) { return -80; }
if (input >= 99) { return 20; }
var temp;
temp = 0.0;
// coefficients
var a = -8.0013990435159329E+01;
var b = 4.1755639785242042E+00;
var c = -1.4036729740086906E-01;
var d = 3.1788545454166156E-03;
var f = -3.5148685730880861E-05;
var g = 1.4221429222004657E-07;
temp += a +
b * input +
c * Math.pow(input, 2.0) +
d * Math.pow(input, 3.0) +
f * Math.pow(input, 4.0) +
g * Math.pow(input, 5.0);
return temp;
},
convertPercentToAudioTaper: function (input) {
// composite function resembling audio taper
if (input <= 1) { return -80; }
if (input <= 28) { return (2 * input - 80); }
if (input <= 79) { return (0.5 * input - 38); }
if (input < 99) { return (0.875 * input - 67.5); }
if (input >= 99) { return 20; }
},
setFaderValue: function (faderId, faderValue) {
var $fader = $('[fader-id="' + faderId + '"]');
this.setHandlePosition($fader, faderValue);
},
setHandlePosition: function ($fader, faderValue) {
draggingOrientation = $fader.attr('orientation');
setHandlePosition($fader, faderValue);
draggingOrientation = null;
},
initialize: function () {
$('body').on('click', 'div[control="fader"]', faderClick);
}
};
})(window, jQuery);