SourceTermAnalysisSystem_vue/src/gis/worker/playbackWorkerMa.ts

341 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<string, any>;
// 子线程的对象(明确类型为 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<WorkerMessage>) {
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; // 清空引用
}
}