142 lines
3.9 KiB
JavaScript
142 lines
3.9 KiB
JavaScript
import BasePanel from './BasePanel';
|
|
import { hertz } from '../Humanize';
|
|
class AvailableFskPairsPanel extends BasePanel {
|
|
constructor() {
|
|
super('Available FSK Pairs');
|
|
this.exclude = [];
|
|
this.fskPairs = [];
|
|
this.originalSelectedFskPairs = [];
|
|
this.sampleRate = 48000;
|
|
|
|
this.addCanvas('fsk-spectrum', 200, 32);
|
|
this.addNewLine();
|
|
|
|
this.addCheckboxes('fsk-pairs', this.fskPairs);
|
|
this.addDynamicText('fsk-available', 'None');
|
|
|
|
this.addEventListener('select', this.handleSelect);
|
|
|
|
this.drawFskSpectrum();
|
|
};
|
|
setSampleRate = (value) => {
|
|
this.sampleRate = value;
|
|
this.drawFskSpectrum();
|
|
}
|
|
|
|
handleSelect = (event) => {
|
|
if(event.checked) {
|
|
this.exclude = this.exclude.filter(id => id !== event.id)
|
|
} else if(!this.exclude.includes(event.id)) {
|
|
this.exclude.push(event.id);
|
|
}
|
|
this.checkChanges();
|
|
this.drawFskSpectrum();
|
|
};
|
|
|
|
checkChanges = () => {
|
|
const selected = this.getSelectedFskPairs();
|
|
const original = this.originalSelectedFskPairs;
|
|
let changed = false;
|
|
if(original.length !== selected.length) {
|
|
changed = true;
|
|
} else {
|
|
const hertz = selected.flat();
|
|
changed = original.flat().some((hz, i) => hz !== hertz[i]);
|
|
}
|
|
if(changed) {
|
|
this.originalSelectedFskPairs = selected;
|
|
this.dispatcher.emit('change', {selected});
|
|
}
|
|
}
|
|
getSelectedFskPairs = () => this.fskPairs
|
|
.filter(this.isSelected);
|
|
|
|
getSelectedIndexes = () => this.fskPairs.map((_, id) => id).filter(id => !this.exclude.includes(id));
|
|
setSelectedIndexes = (values) => {
|
|
this.exclude = values;
|
|
this.setFskPairs(this.fskPairs);
|
|
this.checkChanges();
|
|
}
|
|
|
|
setFskPairs = fskPairs => {
|
|
this.fskPairs = fskPairs;
|
|
this.setValueById('fsk-available', fskPairs.length === 0 ? 'None' : '');
|
|
const items = fskPairs.map(([lowHz, highHz], index) => ({
|
|
text: `${index}: ${hertz(lowHz)} / ${hertz(highHz)}`,
|
|
id: index,
|
|
value: index,
|
|
checked: !this.exclude.includes(index),
|
|
eventName: 'select'
|
|
}));
|
|
this.replaceCheckedInputs('checkbox', 'fsk-pairs', items);
|
|
this.checkChanges();
|
|
this.drawFskSpectrum();
|
|
}
|
|
|
|
drawFskSpectrum = () => {
|
|
|
|
const ultimateFrequency = this.sampleRate / 2;
|
|
const fskPairs = this.fskPairs;
|
|
const canvas = this.getElement('fsk-spectrum');
|
|
const ctx = canvas.getContext('2d');
|
|
const {height, width} = canvas;
|
|
ctx.clearRect(0, 0, width, height);
|
|
|
|
if(fskPairs.length === 0) return;
|
|
const minHz = fskPairs.reduce(
|
|
(min, fsk) => {
|
|
const lowestHz = fsk.reduce((min, hz) => Math.min(min, hz), Infinity)
|
|
return Math.min(min, lowestHz)
|
|
}, Infinity
|
|
);
|
|
const maxHz = fskPairs.reduce(
|
|
(max, fsk) => {
|
|
const lowestHz = fsk.reduce((max, hz) => Math.max(max, hz), -Infinity)
|
|
return Math.max(max, lowestHz)
|
|
}, -Infinity
|
|
);
|
|
const range = maxHz - minHz;
|
|
|
|
// Human Hearing
|
|
let x1 = Math.max(0, ((20-minHz)/range) * width);
|
|
let x2 = Math.min(width, ((20000-minHz)/range) * width);
|
|
if(x1 !== x2) {
|
|
ctx.fillStyle = 'hsla(0, 0%, 100%, 20%)';
|
|
ctx.fillRect(
|
|
x1,
|
|
0,
|
|
x2 - x1,
|
|
height
|
|
);
|
|
}
|
|
|
|
// Telephone
|
|
x1 = Math.max(0, ((300-minHz)/range) * width);
|
|
x2 = Math.min(width, ((3400-minHz)/range) * width);
|
|
if(x1 !== x2) {
|
|
ctx.fillStyle = 'hsla(60, 50%, 50%, 20%)';
|
|
ctx.fillRect(
|
|
x1,
|
|
0,
|
|
x2 - x1,
|
|
height
|
|
);
|
|
}
|
|
|
|
ctx.lineWith = 1;
|
|
const plotHz = hz => {
|
|
const hue = Math.floor(hz/ultimateFrequency * 360);
|
|
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
|
|
const x = ((hz-minHz) / range) * width;
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, 0);
|
|
ctx.lineTo(x, height);
|
|
ctx.stroke();
|
|
}
|
|
|
|
fskPairs.filter(this.isSelected).forEach(fsk => fsk.forEach(plotHz));
|
|
}
|
|
isSelected = (delude, allude) => !this.exclude.includes(allude);
|
|
}
|
|
|
|
export default AvailableFskPairsPanel; |