html-page
Some checks failed
/ surge (push) Successful in 2m45s
/ build-and-deploy-to-vercel (push) Successful in 3m24s
/ lint-build-and-check (push) Successful in 4m44s
/ playwright (push) Has been cancelled

This commit is contained in:
严浩
2025-04-09 18:01:33 +08:00
parent 0dcc47519f
commit 4e56d311f1
15 changed files with 8095 additions and 81 deletions

View File

@ -0,0 +1,81 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>星座图的html页面</title>
</head>
<body>
<div id="planispherewidget-container"></div>
<script src="./lib/konva.2.4.2.min.js"></script>
<script src="./lib/jquery.3.6.0.min.js"></script>
<script src="./planispherewidget.js"></script>
<script>
window.planisphereWidgetInstance = null;
// 监听来自父窗口的消息
window.addEventListener('message', (event) => {
// 强烈建议在此处添加来源验证 (event.origin) 以提高安全性
// 例如: if (event.origin !== 'YOUR_VUE_APP_ORIGIN') return;
if (!event.data) return; // 如果没有数据,则忽略
// 处理初始化消息
if (event.data.type === 'INIT_WIDGET') {
console.log('HTML 页面:收到初始化指令');
if (!window.planisphereWidgetInstance) {
// 创建 PlanisphereWidget 实例,指定容器 ID
window.planisphereWidgetInstance = new PlanisphereWidget('planispherewidget-container', {
// 从 planispherewidget.js 获取的默认值
bg_color: '#27293D', // 背景色
fore_color: '#CCCCCC', // 前景色
coor_color: '#1B1B24', // 坐标颜色
border_color: '#CCCCCC', // 边框颜色
wave_color: '#1D8CF8', // 波形颜色
margin_left: 0, // 左边距
margin_top: 0, // 上边距
// 您可以在这里覆盖上面的默认值,或者从 event.data.options 获取配置
// ...event.data.options // 如果 Vue 组件传递了配置
});
console.log('HTML 页面PlanisphereWidget 已实例化');
} else {
console.log('HTML 页面PlanisphereWidget 已存在,无需重复实例化');
}
// 可选:通知父窗口已准备好接收数据
// if (window.parent !== window) {
// window.parent.postMessage({ type: 'WIDGET_READY' }, '*'); // 使用更具体的 targetOrigin
// }
}
// 处理数据馈送消息
else if (event.data.type === 'FEED_DATA') {
if (window.planisphereWidgetInstance) {
console.log('HTML 页面:收到来自父窗口的数据:', event.data.payload);
if (Array.isArray(event.data.payload)) {
window.planisphereWidgetInstance.feed(event.data.payload);
} else {
console.error('HTML 页面:收到的数据格式无效:', event.data.payload);
}
} else {
console.warn('HTML 页面Widget 尚未初始化,无法处理 FEED_DATA');
}
}
});
</script>
</body>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden; /* 防止滚动条出现 */
}
/* 确保容器占满整个 iframe */
body > div {
width: 100%;
height: 100%;
}
</style>
</html>

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="./lib/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="./lib/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().toLocaleTimeString();
this.waterWidget.addData(data, time);
};
// 首次更新
updateData();
// 定期更新数据
setInterval(updateData, 1000);
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,74 @@
(function ($, h, c) {
var a = $([]),
e = $.resize = $.extend($.resize, {}),
i,
k = "setTimeout",
j = "resize",
d = j + "-special-event",
b = "delay",
f = "throttleWindow";
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) {
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 ? o : q.width();
r.h = p !== c ? p : q.height();
n.apply(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),
m = n.width(),
l = n.height(),
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);

7380
public/html-page/lib/konva.2.4.2.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,428 @@
class PlanisphereWidget {
constructor(id, options) {
console.log("PlanisphereWidget " + id);
this.options = options;
this.container = document.getElementById(id);
this.bg_color = (options && options.bg_color) ? options.bg_color : '#27293D';
this.fore_color = (options && options.bg_color) ? options.bg_color : '#CCCCCC';
this.coor_color = (options && options.coor_color) ? options.coor_color : '#1B1B24';
this.border_color = (options && options.border_color) ? options.border_color : '#CCCCCC';
this.wave_color = (options && options.wave_color) ? options.wave_color : '#1D8CF8';
this.margin_left = (options && options.margin_left) ? options.margin_left : 0;
this.margin_top = (options && options.margin_top) ? options.margin_top : 0;
this.stage = new Konva.Stage({
container: id,
width: this.container.clientWidth || 500,
height: this.container.clientHeight || 500
});
this.layer_coor = new Konva.Layer();
this.layer_coor.hitGraphEnabled(false);
this.layer_wave = new Konva.Layer();
this.layer_wave.hitGraphEnabled(false);
this.stage.add(this.layer_coor);
this.stage.add(this.layer_wave);
this.canvas = document.createElement("canvas");
this.ctx_canvas = this.canvas.getContext("2d");
this.ctx_canvas.fillStyle = this.bg_color;
this.init();
this.initResize();
this.dAlpha = false;
this.d1 = null;
this.d2 = null;
this.d3 = null;
this.d4 = null;
}
init() {
if (this.container.clientHeight === 0) return;
this.stage.setWidth(this.container.clientWidth);
this.stage.setHeight(this.container.clientWidth);
this.area_x = this.margin_left;
this.area_y = this.margin_top;
this.area_width = this.stage.getWidth() - this.margin_left;
this.area_height = this.stage.getHeight() - this.margin_top;
this.drawCoor();
this.canvas.height = this.area_height;
this.canvas.width = this.area_width;
this.ctx_canvas.strokeStyle = this.wave_color;
this.ctx_canvas.lineWidth = 1;
this.pointer = new Konva.Circle({
x: 0,
y: 0,
radius: 1,
stroke: this.wave_color,
strokeWidth: 1
});
this.pointer.cache();
}
drawCoor() {
var layer = this.layer_coor;
layer.destroyChildren();
var len = this.area_width;
var rval = this.area_width / 2;
layer.add(new Konva.Rect({
x: this.area_x,
y: this.area_y,
width: this.area_width,
height: this.area_height,
stroke: this.border_color,
strokeWidth: 1
}));
layer.add(new Konva.Line({
points: [0, 0, this.area_width, this.area_height],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
layer.add(new Konva.Line({
points: [this.area_width, 0, 0, this.area_height],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
layer.add(new Konva.Line({
points: [0, rval, this.area_width, rval],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
layer.add(new Konva.Line({
points: [0, rval / 2, this.area_width, rval / 2],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
layer.add(new Konva.Line({
points: [0, rval / 2 * 3, this.area_width, rval / 2 * 3],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
///
layer.add(new Konva.Line({
points: [rval, 0, rval, len],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
layer.add(new Konva.Line({
points: [rval / 2, 0, rval / 2, len],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
layer.add(new Konva.Line({
points: [rval / 2 * 3, 0, rval / 2 * 3, len],
stroke: this.border_color,
strokeWidth: 1,
lineJoin: 'round',
dash: [1, 1]
}));
layer.add(new Konva.Circle({
x: rval,
y: rval,
radius: rval,
stroke: this.border_color,
strokeWidth: 1
}));
layer.add(new Konva.Circle({
x: rval,
y: rval,
radius: rval / 2,
stroke: this.border_color,
strokeWidth: 1
}));
layer.batchDraw();
}
setViewMode(vm) {
if (vm == 3) {//0=星座图3=余晖图。2021.03.31李伟添加;
this.dAlpha = true;
vm = 0;
} else {
this.dAlpha = false;
}
this.viewmodel = vm;
this.clear();
}
//星座图
feed(d, di, dq) {
if (!this.viewmodel || this.viewmodel == 0) {
this.drawWave_vector(d);
// this.drawWave_planis(d);
return;
}
}
//矢量图
feedVector(d) {
if (!this.viewmodel || this.viewmodel == 0) {
this.drawWave_vector(d);
return;
}
}
//眼图
feedIQ(di, dq) {
if (this.viewmodel == 1 && di != null) {
this.drawIQ(di);
}
else if (this.viewmodel == 2 && dq != null) {
this.drawIQ(dq);
}
}
drawIQ(IQBuff) {
this.clear();
for (var j = 0; j < IQBuff.length; j++) {
this.drawWave_eye(IQBuff[j]);
}
}
clear() {
this.imgData = null;
this.drawWave_planis([]);
this.drawWave_vector([]);
}
drawWave_eye(d) {
// console.log("in drawWave_eye" + d.length);
var layer = this.layer_wave;
var width = this.area_width;
var height = this.area_height;
var rwidth = width / 2;
var rHeight = height / 2;
var ctx_canvas = layer.getContext();
ctx_canvas.strokeStyle = this.wave_color;
ctx_canvas.lineWidth = 1;
ctx_canvas.beginPath();
for (var n = 0; n < d.length; n++) {
//var x = Math.floor(width*(1-1/1.4)/2+ n * width / d.length / 1.4);
var x = Math.floor( n * width / d.length );
var y = Math.floor(rHeight + d[n] * rHeight / 1.4);
if (n == 0) {
ctx_canvas.moveTo(x, y);
}
else {
ctx_canvas.lineTo(x, y);
}
}
ctx_canvas.stroke();
}
drawWave_planis(d) {
//console.log("in plan" + d.length);
var layer = this.layer_wave;
var width = this.getDrawWHByPixelRatio(this.area_width) ;
var height = this.getDrawWHByPixelRatio(this.area_height);
var rwidth = width / 2;
var rHeight = height / 2;
//不显示的时候不报错
if (!width || !height||width == 0 || height == 0) {
return;
}
var context = layer.getContext();
context.clearRect(0, 0, width, height);
var imgData = context.createImageData(width, height);
var dlen = imgData.data.length;
//2021.03.31 李伟增加余晖效果
if (this.dAlpha && d) {
this.drawWave_plainsD(rwidth, rHeight, width, imgData, dlen, this.d4, 32);
this.drawWave_plainsD(rwidth, rHeight, width, imgData, dlen, this.d3, 32);
this.drawWave_plainsD(rwidth, rHeight, width, imgData, dlen, this.d2, 64);
this.drawWave_plainsD(rwidth, rHeight, width, imgData, dlen, this.d1, 128);
this.d4 = this.d3;
this.d3 = this.d2;
this.d2 = this.d1;
this.d1 = d;
}
this.drawWave_plainsD(rwidth, rHeight, width, imgData, dlen, d, 255);
/*
for (var n = 0; n < d.length; n++) {
//console.log(rwidth+d[n][0] * rwidth);
var x = Math.floor(rwidth + d[n][0] * rwidth/1.4);
var y = Math.floor(rHeight+ d[n][1] * rHeight/1.4);
var p = ( y * width + x )* 4;
this.setWaveColor(imgData, p, dlen,width*4);
}
*/
context.putImageData(imgData, 0, 0);
}
drawWave_plainsD(rwidth, rHeight, width, imgData, dlen, d, a) {
if (!d)
return;
for (var n = 0; n < d.length; n++) {
//console.log(rwidth+d[n][0] * rwidth);
var x = Math.floor(rwidth + d[n][0] * rwidth / 1.4);
var y = Math.floor(rHeight + d[n][1] * rHeight / 1.4);
var p = (y * width + x) * 4;
this.setWaveColor(imgData, p, dlen, width * 4, a);
}
}
drawWave_vector(d) {
var maxLine = 100;
var dlen = Math.min(maxLine, d.length);
var layer = this.layer_wave;
var width = this.area_width;
var height = this.area_height;
var rwidth = width / 2;
var rHeight = height / 2;
//不显示的时候不报错
if (!width || !height || width == 0 || height == 0) {
return;
}
var context = layer.getContext();
context.clearRect(0, 0, width, height);
var ctx_canvas = layer.getContext();
ctx_canvas.strokeStyle = this.wave_color;
ctx_canvas.lineWidth = 1;
ctx_canvas.beginPath();
for (var n = 0; n < dlen; n++) {
var x = Math.floor(rwidth + d[n][0] * rwidth / 1.2);
var y = Math.floor(rHeight + d[n][1] * rHeight / 1.2);
if (n == 0) {
ctx_canvas.moveTo(x, y);
}
else {
ctx_canvas.lineTo(x, y);
}
}
ctx_canvas.stroke();
}
/*像素单位转css单位,该函数返回当前浏览器缩放比例所影响的 x y width height 的绘图位置
仅适用putImageData getImageData等函数*/
getDrawWHByPixelRatio(xory) {
if (xory == 0) return 0;
if (!xory) return xory;
var ret = Math.ceil(window.devicePixelRatio * xory);
//console.log(`xory=${xory} ratio=${window.devicePixelRatio} ret=${ret}`);
return ret;
}
setWaveColor_thin(imgData, p, dlen, rowlen) {
var dp = p + rowlen;
if (p < 0) return;
if (dp + 11 >= dlen) return;
imgData.data[p] = 33;
imgData.data[p + 1] = 129;
imgData.data[p + 2] = 247;
imgData.data[p + 3] = 255;
}
setWaveColor(imgData, p, dlen, rowlen, a = 255) {//2021.03.31 李伟增加余晖效果 a=alpha
var dp = p + rowlen;
if (p < 0) return;
if (dp + 11 >= dlen) return;
var r = 33;
var g = 129;
var b = 247;
if (a != 255) {
r = 0;
g = 255;
b = 0;
}
//console.log(a);
imgData.data[p] = r;
imgData.data[p + 1] = g;
imgData.data[p + 2] = b;
imgData.data[p + 3] = a;//255;//2021.03.31 李伟增加余晖效果
imgData.data[p + 4] = r;
imgData.data[p + 5] = g;
imgData.data[p + 6] = b;
imgData.data[p + 7] = a;//255;
imgData.data[p + 8] = r;
imgData.data[p + 9] = g;
imgData.data[p + 10] = b;
imgData.data[p + 11] = a;//255;
imgData.data[dp] = r;
imgData.data[dp + 1] = g;
imgData.data[dp + 2] = b;
imgData.data[dp + 3] = a;//255;
imgData.data[dp + 4] = r;
imgData.data[dp + 5] = g;
imgData.data[dp + 6] = b;
imgData.data[dp + 7] = a;//255;
imgData.data[dp + 8] = r;
imgData.data[dp + 9] = g;
imgData.data[dp + 10] = b;
imgData.data[dp + 11] = a;//255;
}
destroy() {
this.imgData = null;
this.stage.destroy();
this.color_map = null;
}
dispose() {
console.log("dispose wfmin");
this.destroy();
}
initResize() {
var _self = this;
$(this.container).resize(function () {
var target = this;
if (target.resizeFlag) {
clearTimeout(target.resizeFlag);
}
target.resizeFlag = setTimeout(function () {
_self.init();
target.resizeFlag = null;
}, 100);
});
}
}