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,100 @@
<script setup lang="ts">
const props = defineProps<{
// 定义传入的数据类型
data: Array<[number, number]>;
}>();
// 获取 iframe 的 DOM 引用
const iframeRef = ref<HTMLIFrameElement | null>(null);
// iframe 的 src URL
const src = computed(() => import.meta.env.BASE_URL + 'html-page/ConstellationDiagram.html');
// 标记 iframe 是否已加载完成并已发送初始化指令
const isIframeInitialized = ref(false);
// iframe 加载完成后的回调
function onIframeLoad() {
console.log('Vue 组件iframe 已加载');
// 发送初始化指令给 iframe
if (iframeRef.value?.contentWindow) {
console.log('Vue 组件:向 iframe 发送 INIT_WIDGET 指令');
// targetOrigin 设置为 '*' 为了简单,生产环境应指定确切来源
iframeRef.value.contentWindow.postMessage({ type: 'INIT_WIDGET' }, '*');
isIframeInitialized.value = true; // 标记已发送初始化指令
// 发送初始数据(如果已有)
// 稍微延迟发送,给 iframe 一点时间处理 INIT_WIDGET
// 注意:这是一种简化处理,更健壮的方式是等待 iframe 回复 WIDGET_READY 消息
setTimeout(() => {
if (props.data && props.data.length > 0 && isIframeInitialized.value) {
console.log('Vue 组件:发送初始数据');
sendDataToIframe(props.data);
}
}, 0); // 延迟 100 毫秒,可以根据实际情况调整
} else {
console.error('Vue 组件:无法访问 iframe 的 contentWindow');
}
}
// 将数据发送到 iframe 的函数
function sendDataToIframe(payload: Array<[number, number]>) {
// 确保 iframe 存在、其 contentWindow 可访问且已发送初始化指令
if (iframeRef.value?.contentWindow && isIframeInitialized.value) {
console.log('Vue 组件:向 iframe 发送数据:', payload);
iframeRef.value.contentWindow.postMessage({ type: 'FEED_DATA', payload }, '*');
} else {
console.warn('Vue 组件iframe 未初始化或数据无效,无法发送 FEED_DATA 消息。');
}
}
// 监听 props.data 的变化
watch(
() => props.data,
(newData) => {
// 确保新数据有效且 iframe 已初始化
if (newData && newData.length > 0 && isIframeInitialized.value) {
// 直接发送更新后的数据
sendDataToIframe(newData);
} else if (!isIframeInitialized.value) {
console.log('Vue 组件:数据已更改,但 iframe 尚未初始化。初始数据将在加载并初始化后发送。');
}
},
{
deep: true, // 保持深度监听,以防 data 内部变化
immediate: false, // 不在初始渲染时立即执行,等待 iframe 加载和初始化
},
);
// 可选:监听来自 iframe 的 WIDGET_READY 消息以实现更精确的控制
// onMounted(() => {
// window.addEventListener('message', handleIframeMessage);
// });
// onUnmounted(() => {
// window.removeEventListener('message', handleIframeMessage);
// });
// function handleIframeMessage(event: MessageEvent) {
// // 验证来源 event.origin
// if (event.source === iframeRef.value?.contentWindow && event.data.type === 'WIDGET_READY') {
// console.log('Vue 组件:收到来自 iframe 的 WIDGET_READY 消息');
// isIframeInitialized.value = true; // 确认 widget 已就绪
// // 现在可以安全地发送初始数据了
// if (props.data && props.data.length > 0) {
// sendDataToIframe(props.data);
// }
// }
// }
</script>
<template>
<iframe ref="iframeRef" :src="src" frameborder="0" allowfullscreen @load="onIframeLoad"></iframe>
</template>
<style scoped>
iframe {
width: 100%; /* 让 iframe 宽度充满容器 */
height: 100%; /* 让 iframe 高度充满容器 */
display: block; /* 避免可能的底部空白 */
border: none; /* 移除边框 */
}
</style>

View File

@ -1,147 +0,0 @@
<!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().toLocaleTimeString();
this.waterWidget.addData(data, time);
};
// 首次更新
updateData();
// 定期更新数据
setInterval(updateData, 1000);
</script>
</body>
</html>

View File

@ -1,3 +1,4 @@
// @ts-nocheck
colormapwidget.names = ['default', 'blue', 'gray', 'cooledit'];
colormapwidget.prototype.getGradientColors = function (name) {

View File

@ -1,73 +0,0 @@
(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);

View File

@ -0,0 +1,18 @@
<!-- eslint-disable unicorn/numeric-separators-style -->
<script setup lang="ts">
definePage({
meta: {
title: '星座图 iframe',
},
});
const data: Array<[number, number]> = [
[0.20898877234451796, 0.8329353515647436],
[-0.6589349632101078, 0.5886313023998213],
[-0.5525702944049637, -0.7953057951401711],
];
</script>
<template>
<IframeConstellationDiagram :data />
</template>