import type { WorkerFunc } from './worketBlob'; import dayjs from 'dayjs'; import { serverIp } from '@/gis/common/config'; import EventBus from '@/gis/common/eventBus/eventBus.ts'; import { fitViewByExtent } from '@/gis/ol/index.ts'; import { setShouldAnimate } from '@/gis/ol/olClock'; import { addCustomGridLayer } from '@/gis/ol/olGirdHeatmap'; import { addHeatmapLayer } from '@/gis/ol/olHeatmap'; // import { addIsolineLayer } from '@/gis/ol/olIsoLine'; import playbackWorker from './playbackWorker'; import { getWorketImportUrl } from './worketBlob'; // 导入 WorkerFunc 类型 // 定义 Worker 消息数据的类型接口 interface WorkerMessage { code: string; [key: string]: any; // 允许其他自定义字段 } // 定义初始化参数的类型接口(根据实际业务补充字段) interface InitRealWorketOpt { [key: string]: any; // 可根据实际使用场景扩展具体字段 } // 定义发送给 Worker 的消息类型(根据实际业务补充) type PostMessageData = Record; // 子线程的对象(明确类型为 Worker | null) let playbackWorkerObj: Worker | null = null; export const playback_EventBusCallback = new EventBus(); let hsjmnType = '浓度分布'; /** * 计算经纬度点集合的 extent(地理范围) * @param points 经纬度点数组 [{ lon: 经度, lat: 纬度, ... }] * @returns extent 数组 [minLon, minLat, maxLon, maxLat],若无有效点返回 null */ function calculatePointsExtent(points: Array<{ lon: number; lat: number }>): number[] | null { if (!points || points.length === 0) { console.warn('无有效经纬度点,无法计算 extent'); return null; } // 提取所有经度和纬度 const lons = points.map(p => p.lon); const lats = points.map(p => p.lat); // 计算最小/最大经纬度(添加 0.01 缓冲,避免点贴边) const minLon = Math.min(...lons) - 0.01; const minLat = Math.min(...lats) - 0.01; const maxLon = Math.max(...lons) + 0.01; const maxLat = Math.max(...lats) + 0.01; return [minLon, minLat, maxLon, maxLat]; } /** * 初始化 Web Worker 实例 * @param opt 初始化参数 */ export function initPlaybackWorkerMa(): void { // 校验 playbackWorker 是符合要求的 Worker 函数(类型约束) if (typeof playbackWorker !== 'function' || !playbackWorker.name) { throw new Error('playbackWorker 必须是具名函数,且无外部依赖'); } // 创建 worket 对象(getWorketImportUrl 已约束入参为 WorkerFunc) const workerUrl = getWorketImportUrl(playbackWorker as WorkerFunc); playbackWorkerObj = new Worker(workerUrl); const token = localStorage.getItem('token'); playbackWorkerObj.postMessage({ code: 'init', value: { serverIp, token, }, }); // 监听来自 Web Worker 的消息(明确 event 类型) playbackWorkerObj.onmessage = function (event: MessageEvent) { const weaData = event.data; switch (weaData.code) { case 'querySYMNFirstSuccess':{ // 输运模拟第一次接口请求完成,开始绘制自定义热力图 // 定义最大值 let maxValue = 0; let minValue = 0; // 处理数据 const gridData = weaData.data.result.map((item: any) => { if (item.value > maxValue) { maxValue = item.value; } if (item.value !== '-Infinity' && item.value < minValue) { minValue = item.value; } return { lon: item.lon, lat: item.lat, value: item.value, width: weaData.data.lonWidth, height: weaData.data.latWidth, }; }); // 加载自定义热力图 addCustomGridLayer(gridData, maxValue, minValue); // 开始播放 setShouldAnimate(true); // 显示图例 // playback_EventBusCallback.publish('legendUiData', { // key: 'showLengend', // value: true, // }); // 更改图例最大值 // playback_EventBusCallback.publish('symnLegendUpdateMax', { // maxValue, // minValue, // }); } break; case 'drawSYMN':{ // 绘制输运模拟自定义热力图 // 定义最大值 let maxValue = 0; let minValue = 0; // 加工数据 const gridData = weaData.data.map((item: any) => { if (item.value > maxValue) { maxValue = item.value; } if (item.value !== '-Infinity' && item.value < minValue) { minValue = item.value; } return { lon: item.lon, lat: item.lat, value: item.value, width: weaData.lonWidth, height: weaData.latWidth, }; }); // 加载自定义热力图 addCustomGridLayer(gridData, maxValue, minValue); // 更改最大值 // playback_EventBusCallback.publish('symnLegendUpdateMax', { // maxValue, // minValue, // }); } break; case 'querySYMNOneFail': // 输运模拟接口请求失败 // 处理失败场景(如提示用户、重试循环) console.error('⚠️ 请求失败', weaData.data); break; case 'querySYMNAllSuccess': // 输运模拟所有接口请求完成 // 解除进度条禁用 playback_EventBusCallback.publish('timeSliderUiData', { key: 'isDisabledSlider', value: false, }); break; case 'queryHSJMNType': hsjmnType = weaData.data; break; case 'queryHSJMNFirstSuccess': { // 核事件模拟第一次请求完成,开始绘制 // 显示图例 playback_EventBusCallback.publish('legendUiData', { key: 'showLengend', value: true, }); let data = null; if (hsjmnType === '浓度分布') { data = weaData.data.result; // 加工数据 const gridData = data.dataList.map((item: any) => { return { lon: item[0], lat: item[1], value: item[2] === 0 ? 0.08 : item[2], }; }); const extent = calculatePointsExtent(gridData); if (extent) { // 定位 fitViewByExtent(extent); } // 添加热力图 addHeatmapLayer(gridData, data.max === 0 ? 1 : data.max); // 动态改变图例最大值 playback_EventBusCallback.publish('symnLegendUpdateMax', { maxValue: data.max, minValue: data.min, }); } else { data = weaData.data.result; // 加工数据 const fitData = data.dataList.map((item: any) => { return { lon: item[0], lat: item[1], }; }); const extent = calculatePointsExtent(fitData); if (extent) { // 定位 fitViewByExtent(extent); } // 加工数据 const gridData = data.dataList.filter(item => item[2] >= 1.5).map((item: any) => { return { lon: item[0], lat: item[1], value: item[2], }; }); // 添加热力图 addHeatmapLayer(gridData, data.max === 0 ? 1 : data.max); // 渲染等值线 // addIsolineLayer(gridData); // 可自定义等值线间隔 // 动态改变图例最大值 playback_EventBusCallback.publish('symnLegendUpdateMax', { maxValue: data.max, minValue: data.min, }); } // 开始播放 setShouldAnimate(true); } break; case 'drawHSJMN':{ // 绘制核事件模拟自定义热力图 // 加工数据 if (!weaData.data) return; let data = null; if (hsjmnType === '浓度分布') { data = weaData.data.hsjmnResult1Count; if (data) { const gridData = data.dataList.map((item: any) => { return { lon: item[0], lat: item[1], value: item[2] === 0 ? 0.08 : item[2], }; }); // 添加热力图 addHeatmapLayer(gridData, data.max === 0 ? 1 : data.max); // 动态改变图例最大值 playback_EventBusCallback.publish('symnLegendUpdateMax', { maxValue: data.max, minValue: data.min, }); } } else { data = weaData.data.hsjmnResult2Count; if (data) { const gridData = data.dataList.filter(item => item[2] >= 1.5).map((item: any) => { return { lon: item[0], lat: item[1], value: item[2], }; }); // 添加热力图 addHeatmapLayer(gridData, data.max === 0 ? 1 : data.max); // 渲染等值线 // addIsolineLayer(gridData); // 可自定义等值线间隔 // 动态改变图例最大值 playback_EventBusCallback.publish('symnLegendUpdateMax', { maxValue: data.max, minValue: data.min, }); } } } break; case 'queryHSJMNAllSuccess': // 核事件模拟所有接口请求完成 // 解除进度条禁用 playback_EventBusCallback.publish('timeSliderUiData', { key: 'isDisabledSlider', value: false, }); break; } }; // 监听 Worker 错误(可选:增强错误处理) playbackWorkerObj.onerror = function (error) { console.error('Worker 执行错误:', error.message, '行号:', error.lineno); // 可根据需求添加错误上报或重试逻辑 }; } /** * 向 Web Worker 发送消息 * @param massage 发送给 Worker 的数据 * @param opt 初始化参数(首次发送时使用) */ export function sendPlaybackPostMassage( massage: PostMessageData, opt: InitRealWorketOpt, ): void { // console.log('发送给 Worker 的消息:', massage, '初始化参数:', opt); // 无对象时初始化线程对象 if (!playbackWorkerObj) { initPlaybackWorkerMa(opt); } // 确保 playbackWorkerObj 已初始化(TS 类型守卫) if (playbackWorkerObj) { playbackWorkerObj.postMessage(massage); } else { throw new Error('Web Worker 初始化失败,无法发送消息'); } } /** * 销毁 Web Worker 实例(可选:添加资源释放方法) */ export function destroyRealWorket(): void { if (playbackWorkerObj) { playbackWorkerObj.terminate(); // 终止 Worker 线程 playbackWorkerObj = null; // 清空引用 } }