2020-01-18 20:33:10 +00:00
|
|
|
function FrequencyDisplay(element) {
|
2021-02-28 14:51:07 +00:00
|
|
|
this.prefixes = {
|
|
|
|
'k': 3,
|
|
|
|
'M': 6,
|
|
|
|
'G': 9,
|
|
|
|
'T': 12
|
|
|
|
};
|
2020-01-18 20:33:10 +00:00
|
|
|
this.element = $(element);
|
2020-01-18 23:00:51 +00:00
|
|
|
this.digits = [];
|
2021-03-01 00:19:06 +00:00
|
|
|
this.precision = 2;
|
2020-01-25 21:47:47 +00:00
|
|
|
this.setupElements();
|
|
|
|
this.setFrequency(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
FrequencyDisplay.prototype.setupElements = function() {
|
2020-01-25 21:35:44 +00:00
|
|
|
this.displayContainer = $('<div>');
|
2020-01-18 23:00:51 +00:00
|
|
|
this.digitContainer = $('<span>');
|
2021-02-28 14:51:07 +00:00
|
|
|
this.unitContainer = $('<span> Hz</span>');
|
|
|
|
this.displayContainer.html([this.digitContainer, this.unitContainer]);
|
2020-01-25 21:35:44 +00:00
|
|
|
this.element.html(this.displayContainer);
|
2020-01-25 21:47:47 +00:00
|
|
|
};
|
2020-01-18 20:33:10 +00:00
|
|
|
|
2021-02-28 14:51:07 +00:00
|
|
|
FrequencyDisplay.prototype.getPrefix = function() {
|
|
|
|
var me = this;
|
|
|
|
return Object.keys(me.prefixes).filter(function(key){
|
|
|
|
return me.prefixes[key] == me.exponent;
|
|
|
|
})[0] || "";
|
|
|
|
};
|
|
|
|
|
2020-01-18 20:33:10 +00:00
|
|
|
FrequencyDisplay.prototype.setFrequency = function(freq) {
|
2020-01-18 23:00:51 +00:00
|
|
|
this.frequency = freq;
|
2021-02-28 14:51:07 +00:00
|
|
|
this.exponent = Math.floor(Math.log10(this.frequency) / 3) * 3;
|
|
|
|
|
2021-03-01 00:19:06 +00:00
|
|
|
var digits = Math.max(0, this.exponent - this.precision);
|
2021-02-28 14:51:07 +00:00
|
|
|
var formatted = (freq / 10 ** this.exponent).toLocaleString(
|
2020-12-10 19:58:07 +00:00
|
|
|
undefined,
|
2021-03-01 00:19:06 +00:00
|
|
|
{maximumFractionDigits: digits, minimumFractionDigits: digits}
|
2020-12-10 19:58:07 +00:00
|
|
|
);
|
2020-01-18 23:00:51 +00:00
|
|
|
var children = this.digitContainer.children();
|
|
|
|
for (var i = 0; i < formatted.length; i++) {
|
|
|
|
if (!this.digits[i]) {
|
|
|
|
this.digits[i] = $('<span>');
|
|
|
|
var before = children[i];
|
|
|
|
if (before) {
|
|
|
|
$(before).after(this.digits[i]);
|
|
|
|
} else {
|
|
|
|
this.digitContainer.append(this.digits[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.digits[i][(isNaN(formatted[i]) ? 'remove' : 'add') + 'Class']('digit');
|
|
|
|
this.digits[i].html(formatted[i]);
|
|
|
|
}
|
|
|
|
while (this.digits.length > formatted.length) {
|
|
|
|
this.digits.pop().remove();
|
|
|
|
}
|
2021-02-28 14:51:07 +00:00
|
|
|
this.unitContainer.text(' ' + this.getPrefix() + 'Hz');
|
2020-01-18 23:00:51 +00:00
|
|
|
};
|
|
|
|
|
2021-03-01 00:19:06 +00:00
|
|
|
FrequencyDisplay.prototype.setTuningPrecision = function(precision) {
|
|
|
|
if (typeof(precision) == 'undefined') return;
|
2020-12-10 19:58:07 +00:00
|
|
|
this.precision = precision;
|
|
|
|
this.setFrequency(this.frequency);
|
|
|
|
};
|
|
|
|
|
2020-01-18 23:00:51 +00:00
|
|
|
function TuneableFrequencyDisplay(element) {
|
|
|
|
FrequencyDisplay.call(this, element);
|
|
|
|
this.setupEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
TuneableFrequencyDisplay.prototype = new FrequencyDisplay();
|
|
|
|
|
2020-01-25 21:47:47 +00:00
|
|
|
TuneableFrequencyDisplay.prototype.setupElements = function() {
|
|
|
|
FrequencyDisplay.prototype.setupElements.call(this);
|
|
|
|
this.input = $('<input>');
|
2021-02-28 16:28:22 +00:00
|
|
|
this.prefixInput = $('<select>');
|
|
|
|
this.prefixInput.append($('<option value="0">Hz</option>'));
|
|
|
|
this.prefixInput.append($.map(this.prefixes, function(e, p) {
|
|
|
|
return $('<option value="' + e + '">' + p + 'Hz</option>');
|
|
|
|
}));
|
|
|
|
this.inputGroup = $('<div class="input-group">');
|
|
|
|
this.inputGroup.append([this.input, this.prefixInput]);
|
|
|
|
this.inputGroup.hide();
|
|
|
|
this.element.append(this.inputGroup);
|
2020-01-25 21:47:47 +00:00
|
|
|
};
|
|
|
|
|
2020-01-18 23:00:51 +00:00
|
|
|
TuneableFrequencyDisplay.prototype.setupEvents = function() {
|
|
|
|
var me = this;
|
2020-01-25 21:47:47 +00:00
|
|
|
|
2021-02-28 16:28:22 +00:00
|
|
|
me.displayContainer.on('wheel', function(e){
|
2020-01-18 23:00:51 +00:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
var index = me.digitContainer.find('.digit').index(e.target);
|
|
|
|
if (index < 0) return;
|
|
|
|
|
2021-02-28 14:51:07 +00:00
|
|
|
var delta = 10 ** (Math.floor(Math.max(me.exponent, Math.log10(me.frequency))) - index);
|
2020-01-18 23:00:51 +00:00
|
|
|
if (e.originalEvent.deltaY > 0) delta *= -1;
|
|
|
|
var newFrequency = me.frequency + delta;
|
|
|
|
|
2020-05-01 22:05:20 +00:00
|
|
|
me.element.trigger('frequencychange', newFrequency);
|
2020-01-18 23:00:51 +00:00
|
|
|
});
|
2020-01-25 21:47:47 +00:00
|
|
|
|
|
|
|
var submit = function(){
|
2021-02-28 16:28:22 +00:00
|
|
|
var exponent = parseInt(me.prefixInput.val());
|
|
|
|
var freq = parseFloat(me.input.val()) * 10 ** exponent;
|
2020-01-25 21:47:47 +00:00
|
|
|
if (!isNaN(freq)) {
|
2020-05-01 22:05:20 +00:00
|
|
|
me.element.trigger('frequencychange', freq);
|
2020-01-25 21:47:47 +00:00
|
|
|
}
|
2021-02-28 16:28:22 +00:00
|
|
|
me.inputGroup.hide();
|
2020-01-25 21:47:47 +00:00
|
|
|
me.displayContainer.show();
|
|
|
|
};
|
2021-02-28 16:28:22 +00:00
|
|
|
$inputs = $.merge($(), me.input);
|
|
|
|
$inputs = $.merge($inputs, me.prefixInput);
|
|
|
|
$inputs.on('blur', function(e){
|
|
|
|
if ($inputs.toArray().indexOf(e.relatedTarget) >= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
submit();
|
|
|
|
});
|
|
|
|
me.input.on('keydown', function(e){
|
2020-01-25 21:47:47 +00:00
|
|
|
if (e.keyCode == 13) return submit();
|
2020-02-01 20:48:46 +00:00
|
|
|
if (e.keyCode == 27) {
|
2021-02-28 16:28:22 +00:00
|
|
|
me.inputGroup.hide();
|
2020-02-01 20:48:46 +00:00
|
|
|
me.displayContainer.show();
|
2021-02-28 16:28:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
var c = String.fromCharCode(e.which);
|
|
|
|
Object.entries(me.prefixes).forEach(function(e) {
|
|
|
|
if (e[0].toUpperCase() == c) {
|
|
|
|
me.prefixInput.val(e[1]);
|
|
|
|
return submit();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
var currentExponent;
|
|
|
|
me.prefixInput.on('change', function() {
|
|
|
|
var newExponent = me.prefixInput.val();
|
|
|
|
delta = currentExponent - newExponent;
|
|
|
|
if (delta >= 0) {
|
|
|
|
me.input.val(parseFloat(me.input.val()) * 10 ** delta);
|
|
|
|
} else {
|
|
|
|
// should not be necessary to handle this separately, but floating point precision in javascript
|
|
|
|
// does not handle this well otherwise
|
|
|
|
me.input.val(parseFloat(me.input.val()) / 10 ** -delta);
|
2020-02-01 20:48:46 +00:00
|
|
|
}
|
2021-02-28 16:28:22 +00:00
|
|
|
currentExponent = newExponent;
|
|
|
|
me.input.focus();
|
2020-01-25 21:47:47 +00:00
|
|
|
});
|
2021-02-28 16:28:22 +00:00
|
|
|
$inputs.on('click', function(e){
|
2020-01-25 21:47:47 +00:00
|
|
|
e.stopPropagation();
|
|
|
|
});
|
2020-01-25 21:35:44 +00:00
|
|
|
me.element.on('click', function(){
|
2021-02-28 16:28:22 +00:00
|
|
|
currentExponent = me.exponent;
|
|
|
|
me.input.val(me.frequency / 10 ** me.exponent);
|
|
|
|
me.prefixInput.val(me.exponent);
|
|
|
|
me.inputGroup.show();
|
2020-01-25 21:35:44 +00:00
|
|
|
me.displayContainer.hide();
|
2020-01-25 21:47:47 +00:00
|
|
|
me.input.focus();
|
2020-01-25 21:35:44 +00:00
|
|
|
});
|
2020-01-18 23:00:51 +00:00
|
|
|
};
|
|
|
|
|
2020-05-01 22:05:20 +00:00
|
|
|
$.fn.frequencyDisplay = function() {
|
|
|
|
if (!this.data('frequencyDisplay')) {
|
|
|
|
this.data('frequencyDisplay', new FrequencyDisplay(this));
|
|
|
|
}
|
|
|
|
return this.data('frequencyDisplay');
|
|
|
|
}
|
|
|
|
|
|
|
|
$.fn.tuneableFrequencyDisplay = function() {
|
|
|
|
if (!this.data('frequencyDisplay')) {
|
|
|
|
this.data('frequencyDisplay', new TuneableFrequencyDisplay(this));
|
|
|
|
}
|
|
|
|
return this.data('frequencyDisplay');
|
|
|
|
}
|