Spectrogram.html
Some checks failed
/ build-and-deploy-to-vercel (push) Failing after 2m40s
/ lint-build-and-check (push) Failing after 3m9s
/ playwright (push) Successful in 1m5s
/ surge (push) Successful in 2m42s

This commit is contained in:
严浩
2025-04-08 17:51:10 +08:00
parent 1a7831c003
commit ef48de3846
8 changed files with 7765 additions and 3 deletions

View File

@ -9,6 +9,7 @@
"src/components/InspiraUI/**",
"**/planispherewidget.js",
"**/konva.2.4.2.min.js",
"**/konva.2.min.js",
"**/waterfallwidget.js",
"**/colormapwidget.js"
]

View File

@ -1,3 +1,9 @@
```
给我说一下 语谱图spectrogram是什么
卫星领域有什么用处?
```
在卫星领域语谱图spectrogram也发挥着重要的作用主要应用于以下方面
- **信号分析与识别:**

View File

@ -0,0 +1,147 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="data:;base64,iVBORw0KGgo=" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="waterfall" style="width: 100%; height: 100%"></div>
<script src="konva.2.4.2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
<script src="jquery.resize.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script src="colormapwidget.js"></script>
<script src="waterfallwidget.js"></script>
<script>
// 定义默认配置对象
const payload = {
minFreq: 0,
maxFreq: 200000000,
rtmode: 0,
doppler: false,
adjShow: true,
adjMaxbw: 100000,
enableWfBuff: false,
unitId: 0,
coorFreqType: 0,
showFreqLable: true,
wfFreqPointLable: true,
wfFreqPointLableList: [],
showWhitelist: false,
waveSplite: 0.5,
};
const wfOption = {
wfRulerEnable: true,
wfTheme: 'default',
wfRulerGravity: true,
wfRulerLocation: -100,
wfMindB: -120,
wfMaxdB: 0,
showPeakMarker: true,
wfShowAvg: true,
wfShowMin: false,
wfShowMax: false,
wfInfoPos: 0,
wfCurLine: true,
specColor: '#00ff00',
specAvgColor: '#ffff00',
specMaxColor: '#ff0000',
specMinColor: '#0000ff',
afterGlowColor: '#00ffff',
wfAdjStepType: 0,
wfAdjStep: 1000,
};
// 模拟频谱数据
const generateFakeData = (len) => {
const data = [];
for (let i = 0; i < len; i++) {
data.push(-80 - Math.random() * 20);
}
return data;
};
const id = 'waterfall';
// 定义 label_manager
const pl = {
label_manager: {
labels: [
// 这里可以添加一些示例标签,或者保持为空
// { name: 'FM', id: 'id1', bg_color: '#2bffc6', fore_color: '#000', location: 80000000, bw: 100000 },
// { name: 'AM', id: 'id2', bg_color: '#2bffc6', fore_color: '#000', location: 90000000, bw: 10000 },
// { name: 'AM', id: 'id2', bg_color: '#ff0000', fore_color: '#ff0000', location: 90000000, bw: 10000 },
],
onclick: function (label) {
console.log('Label clicked:', label);
},
load: function (start, end) {
// 简单的 load 实现,可以根据需要扩展
console.log(`Loading labels for range: ${start} - ${end}`);
// return this.labels.filter(label => label.location >= start && label.location <= end);
return []; // 返回空数组以避免依赖 this.labels
},
},
};
// 初始化频谱图组件
this.waterWidget = new waterfallwidget(id, {
wfOption: wfOption,
min_freq: payload.minFreq, //全局最小频率
max_freq: payload.maxFreq, //全局最大频率
min_band: 500, //最小选择带宽
max_band: 100000, //最大选择带宽
min_db: wfOption.wfMindB, //全局最小增益
max_db: wfOption.wfMaxdB, //全局最大增益
showPeakMarker: wfOption.showPeakMarker, //是否显示极值标注
showSpectrogramAvg: wfOption.wfShowAvg, //是否显示平均保持
showSpectrogramMin: wfOption.wfShowMin, //是否显示最小保持
showSpectrogramMax: wfOption.wfShowMax, //是否显示最大保持
spec_per: payload.waveSplite, //波形图占比
menuEnableHandle: this.getAnalysisRun,
menuDisableText: '---',
menuDoppler: payload.doppler,
allowRunMode: payload.rtmode, //实时选择模式
//allowCycleControl: payload.allowCycleControl,
info_Position: wfOption.wfInfoPos,
showCurLine: wfOption.wfCurLine,
adj_maxbw: payload.adjMaxbw,
adj_show: payload.adjShow,
fucFFTBuff: payload.enableWfBuff ? this.fucFFTBuff.bind(this) : null,
unitBuffId: payload.unitId,
wave_color: wfOption.specColor,
wave_color_avg: wfOption.specAvgColor,
wave_color_max: wfOption.specMaxColor,
wave_color_min: wfOption.specMinColor,
waveAfterglow_color: wfOption.afterGlowColor,
adj_step: wfOption.wfAdjStepType == 1 ? 0 : wfOption.wfAdjStep,
label_manager: pl.label_manager,
coorFreqType: payload.coorFreqType,
showFreqLable: payload.showFreqLable, //是否显示高亮频点
wfFreqPointLable: payload.wfFreqPointLable, //是否显示频点标注
wfFreqPointLableList: payload.wfFreqPointLableList, //频点标注数据
showWhitelist: payload.showWhitelist, //黑名单频谱阴影显示
});
// 监听用户框选范围变更事件
this.waterWidget.on('zoom-change', (e) => {
console.log('频率范围变更:', e.start, e.end);
});
// 生成模拟数据并更新频谱图
const updateData = () => {
const data = generateFakeData(100 /* 0 */);
console.debug(`data :>> `, data);
const time = new Date().toString();
this.waterWidget.addData(data, time);
};
// 首次更新
updateData();
// 定期更新数据
setInterval(updateData, 1000);
</script>
</body>
</html>

View File

@ -0,0 +1,152 @@
colormapwidget.names = ['default', 'blue', 'gray', 'cooledit'];
colormapwidget.prototype.getGradientColors = function (name) {
if (name == 'blue') {
return ['#050525', '#000CFF', '#33FFFF', '#F9FFFF'];
} else if (name == 'gray') {
return ['#050525', '#FBFBFB'];
} else if (name == 'cooledit') {
return ['#010E19', '#720271', '#D7032C', '#FDBC5F', '#F8FFED'];
} else {
return ['#050525', '#0000CF', '#00FF20', '#EFFF00', '#FF007C'];
}
};
// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
colormapwidget.prototype.colorRgb = function (sColor) {
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
var sColor = sColor.toLowerCase();
if (sColor && reg.test(sColor)) {
if (sColor.length === 4) {
var sColorNew = '#';
for (var i = 1; i < 4; i += 1) {
sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
}
sColor = sColorNew;
}
//处理六位的颜色值
var sColorChange = [];
for (var i = 1; i < 7; i += 2) {
sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)));
}
return sColorChange;
} else {
return sColor;
}
};
// 将rgb表示方式转换为hex表示方式
colormapwidget.prototype.colorHex = function (rgb) {
var reg = /(\d{1,3}),(\d{1,3}),(\d{1,3})/;
var arr = reg.exec(rgb);
function hex(x) {
return ('0' + parseInt(x).toString(16)).slice(-2);
}
var _hex = '#' + hex(arr[1]) + hex(arr[2]) + hex(arr[3]);
return _hex.toUpperCase();
};
//计算两个颜色的step个阶梯色
colormapwidget.prototype.gradientColor = function (startColor, endColor, step) {
var startRGB = this.colorRgb(startColor); //转换为rgb数组模式
var startR = startRGB[0];
var startG = startRGB[1];
var startB = startRGB[2];
var endRGB = this.colorRgb(endColor);
var endR = endRGB[0];
var endG = endRGB[1];
var endB = endRGB[2];
var sR = (endR - startR) / step; //总差值
var sG = (endG - startG) / step;
var sB = (endB - startB) / step;
var colorArr = [];
for (var i = 0; i < step; i++) {
//计算每一步的hex值
//var hex = this.colorHex('rgb('+parseInt((sR*i+startR))+','+parseInt((sG*i+startG))+','+parseInt((sB*i+startB))+')');
//colorArr.push(hex);
colorArr.push([parseInt(sR * i + startR), parseInt(sG * i + startG), parseInt(sB * i + startB)]);
}
return colorArr;
};
colormapwidget.prototype.setDbRange = function (count) {
this.count = count;
this.mapCount = count;
this.calColors();
};
colormapwidget.prototype.getColors = function () {
if (
this.name === this.buff_name &&
this.gravity === this.buff_gravity &&
this.gravity_value === this.buff_gravity_value &&
this.count === this.buff_count
)
return this.buff_colors;
return this.calColors();
};
colormapwidget.prototype.getMapColors = function () {
return this.buff_mapCountcolors;
};
colormapwidget.prototype.calColors = function () {
this.buff_name = this.name;
this.buff_gravity = this.gravity;
this.buff_gravity_value = this.gravity_value;
this.buff_count = this.count;
this.buff_colors = this._calColorsByCount(this.count);
this.buff_mapCountcolors = this._calColorsByCount(this.mapCount);
return this.buff_colors;
};
colormapwidget.prototype._calColorsByCount = function (count) {
//console.log("_calColorsByCount " + count)
var colors = this.getGradientColors(this.name);
var arr = [];
var stepSpan = colors.length - 1;
if (!this.gravity) {
var step = Math.ceil(count / stepSpan);
for (var i = 0; i < stepSpan; i++) {
var carr = this.gradientColor(colors[i], colors[i + 1], step);
arr = arr.concat(carr);
}
} else {
var pStart = this.gravity_value - 0.2;
pStart = pStart < 0 ? 0 : pStart;
var pEnd = this.gravity_value + 0.2;
pEnd = pEnd > 1 ? 1 : pEnd;
pStart = count * pStart;
pEnd = count * pEnd;
for (var i = 0; i < pStart; i++) {
arr.push(this.colorRgb(colors[0]));
}
var step = Math.ceil((pEnd - pStart + 1) / stepSpan);
for (var i = 0; i < stepSpan; i++) {
var carr = this.gradientColor(colors[i], colors[i + 1], step);
arr = arr.concat(carr);
}
for (var i = pEnd; i < count; i++) {
arr.push(this.colorRgb(colors[colors.length - 1]));
}
}
return arr;
};
function colormapwidget(option) {
this.name = option && option.name ? option.name : 'default';
this.gravity = option && option.gravity ? option.gravity : false;
this.gravity_value = option && option.gravity_value ? option.gravity_value : 0.5;
this.count = option && option.count ? option.count : 200;
this.mapCount = option && option.mapCount ? option.mapCount : 200;
this.getColors();
}

View File

@ -0,0 +1,3 @@
```bash
bunx http-server --port 8000
```

View File

@ -0,0 +1,73 @@
(function ($, h, c) {
var a = $([]),
b = 'delay',
j = 'resize',
d = j + '-special-event',
e = ($.resize = $.extend($.resize, {})),
f = 'throttleWindow',
i,
k = 'setTimeout';
e[b] = 250;
e[f] = true;
$.event.special[j] = {
setup: function () {
if (!e[f] && this[k]) {
return false;
}
var l = $(this);
a = a.add(l);
$.data(this, d, {
w: l.width(),
h: l.height(),
});
if (a.length === 1) {
g();
}
},
teardown: function () {
if (!e[f] && this[k]) {
return false;
}
var l = $(this);
a = a.not(l);
l.removeData(d);
if (a.length === 0) {
clearTimeout(i);
}
},
add: function (l) {
if (!e[f] && this[k]) {
return false;
}
var n;
function m(s, o, p) {
var q = $(this),
r = $.data(this, d) || {};
r.w = o === c ? q.width() : o;
r.h = p === c ? q.height() : p;
Reflect.apply(n, this, arguments);
}
if ($.isFunction(l)) {
n = l;
return m;
} else {
n = l.handler;
l.handler = m;
}
},
};
function g() {
i = h[k](function () {
a.each(function () {
var n = $(this),
l = n.height(),
m = n.width(),
o = $.data(this, d);
if (m !== o.w || l !== o.h) {
n.trigger(j, [(o.w = m), (o.h = l)]);
}
});
g();
}, e[b]);
}
})(jQuery, this);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
// @ts-nocheck
export class WsLabel {
class WsLabel {
constructor() {
this.name = 'label';
this.id = 'id';
@ -2639,8 +2639,8 @@ waterfallwidget.prototype.changeStart = async function (start, end, reDrawLabel
//await this.drawWfBuff();
}
if (reDrawLabel) {
var ret = await $.post('/setting/getIsShowLabelMasker');
this.darwLabel(ret.data);
// var ret = await $.post('/setting/getIsShowLabelMasker'); // 注释掉接口请求
this.darwLabel(true); // 使用模拟数据 true
this.drawWhiteList();
this.zoomChange();
}