You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

446 lines
16 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import {
LittleEndian,
BigEndian,
hexStringToBytes,
intBitsToFloat,
bytesToShort,
bytesToLong,
bytesToInt,
bytesToString,
fillIntToBytes,
fillShortToBytes,
fillLongToBytes,
fillStringToBytes,
bytesToHexString,
} from './byteConvert.js'
import { drawChartsContent, drawAxis, drawAxis2D, draw2DText, initPoints, pointColors } from './draw.js';
let renderer, scene, camera, controls, renderer2D, scene2D, camera2D, controls2D;
let axis = new THREE.Group();
let axis2D = new THREE.Group();
let initAxis = 80;//正值最大值
let box3D = document.getElementById("box3D2");
let box2D = document.getElementById("box2D2");
const lut = new THREE.Lut();
lut.addColorMap('axis', [[0.0, 0x00ee00], [0.25, 0xeeee00], [0.75, 0xee0000], [1.0, 0x4e0211]],);
lut.setColorMap('axis', 500)
let meshList = new THREE.Group();//图例柱子
const dummy = new THREE.Object3D();
const dummyPoint = new THREE.Object3D();
meshList.name = 'chartsMesh';
let pointsList = new THREE.Group();//图例散点
pointsList.name = 'chartsPoint';
let axisTextGroup = new THREE.Group();
axisTextGroup.name = 'axisText';
let axisTextGroup2D = new THREE.Group();
axisTextGroup2D.name = 'axisText';
// 周期,相位 柱子数
let period = 50, phase = 128, count = period * phase;
const geometry = new THREE.BoxGeometry(0.6, 1, 2.5);
geometry.computeVertexNormals()
const initInstancedMesh = new THREE.InstancedMesh(geometry, new THREE.MeshBasicMaterial(), count);
initInstancedMesh.name = 'initInstancedMesh';
/* prpd初始Instanced点 */
let initInstancedPoints,//prpd实例
pointsGeometry = new THREE.BoxGeometry(0, 0.8, (360 / initAxis) * 0.8,),// prpd位置属性数组
pointCount;
pointsGeometry.computeVertexNormals()
document.getElementById('folderInput').addEventListener('change', processFolder);
const phaseSelect = document.getElementById('phase');
const openModal = document.getElementById('openModal');
openModal.addEventListener('click', toggleFileModal);
init();
init2D();
render();
render2D();
const dataList = { list2d: [], list3d: [] };
let allList = [];
document.getElementById('fileModal').style.display = 'none';
function toggleFileModal() {
var fileModal = document.getElementById('fileModal');
var fileList = document.getElementById('fileList');
fileList.innerHTML = ''; // 清空文件列表
var folderInput = document.getElementById('folderInput');
var files = folderInput.files;
if (files.length > 0) {
for (var i = 0; i < files.length; i++) {
var li = document.createElement('li');
li.textContent = files[i].name;
fileList.appendChild(li);
}
}
fileModal.style.display = fileModal.style.display === 'none' ? 'block' : 'none';
}
async function processFolder(event) {
//const folderInput = event.target.files;
const output = document.getElementById('output');
const files = event.target.files;
if (files.length === 0) {
alert('请选择文件夹');
return;
}
await processFolderRecursive(files);
}
async function processFolderRecursive(folder) {
const promises = []; allList = [];
for (let id = 0; id < folder.length; id++) {
const fileType = folder[id].name.replace(/.+\./, "");
if (fileType == 'dat') {
const pathArr = folder[id].webkitRelativePath.split('/');
promises.push(readAsText(folder[id], pathArr))
}
}
await Promise.all(promises);
let valArr = [], valNumArr = [], list2d = [];
let dBmData = allList.map(i => i.toString());
for (let i of dBmData) {
let index = valArr.indexOf(i);
if (index == -1) {
valArr.push(i);
valNumArr.push(1);
list2d.push([...i.split(','), 1])
} else {
valNumArr[index]++;
list2d[index][2]++;
}
}
dataList.list3d = _.chunk(allList, phaseSelect.value)
dataList.list2d = list2d;
loopDraw(dataList.list3d, true)
drawPRPD(dataList.list2d)
console.log(dataList);
}
let timers = []; // 声明一个全局变量来保存定时器
function clearTimers() {
timers.forEach(timerId => {
clearTimeout(timerId);
});
timers = [];
}
function loopDraw(data, isNew) {
if (timers.length && isNew) {
clearTimers();
}
for (let i = 0; i < data.length; i++) {
if (timers[i]) {
clearTimeout(timers[i]);
}
timers[i] = setTimeout(() => {
drawPRPS(data[i]);
if (i === data.length - 1) {
// 最后一个定时器触发时,清除所有定时器并进行下一轮循环
clearTimers();
loopDraw(data);
}
}, 20 + 20 * i);
}
}
//FileReader异步解析文件
function readAsText(file, pathArr) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = event => {
// 读取文件完成后,将文件内容和额外参数一起传递给 resolve 函数
loadImgUrl(event.target.result, pathArr);
resolve({ res: event.target.result, pathArr });
};
reader.onerror = event => {
reject(new Error("Error reading the file"));
};
reader.readAsArrayBuffer(file);
});
}
//加载图片数据
function loadImgUrl(res, pathArr) {
var phaseNum = phaseSelect.value;
let dBmData = [];
let bytes = new Int8Array(res)
for (let i = 0, offset = 0; i < bytes.length / 4; i++, offset += 4) {
let j = parseInt(i / phaseNum) + 1; //周期
let phase = parseInt((i - (j - 1) * phaseNum + 1) * (360 / phaseNum));// 相位
let value = parseInt(intBitsToFloat(bytesToInt(LittleEndian, bytes, offset, 4))); // 幅值
value = value + 80;
dBmData[i] = [phase, value]//.toString();
}
allList.push(...dBmData)
}
let counter = 1;
initCharts()
function initCharts(type) {
if (type == 'open') {
meshList.visible = true;
return;
} else if (type == 'close') {
meshList.visible = false;
let k = 1, s = 1;
for (let j = 0; j < period; j++) {
for (let i = 0; i < 128; i++) {
initInstancedMesh.getMatrixAt(k, dummy.matrix);
dummy.position.setFromMatrixPosition(dummy.matrix);
dummy.scale.setFromMatrixScale(dummy.matrix);
dummy.position.y = 99999;
dummy.scale.y = Math.abs(1);
const color = lut.getColor(Math.abs(0) / initAxis);
initInstancedMesh.setColorAt(k, color);
dummy.updateMatrix();
initInstancedMesh.setMatrixAt(k, dummy.matrix);
k++;
}
}
initInstancedMesh.instanceMatrix.needsUpdate = true;
initInstancedMesh.instanceColor.needsUpdate = true;
for (let i = 0; i < pointCount; i++) {
dummyPoint.position.set(1, 99999, 1);
dummyPoint.updateMatrix();
initInstancedPoints.setMatrixAt(i, dummyPoint.matrix);
}
initInstancedPoints.instanceMatrix.needsUpdate = true;
return;
}
let k = 0, initList = [];
for (let i = 0; i < period; i++) {
initList.push(generateArray());
}
for (let j = 0; j < initList.length; j++) {
for (let i = 0; i < initList[j].length; i++) {
const [a, b, c] = initList[j][i];
dummy.position.set(j, 9999, b);
dummy.scale.y = 0;
dummy.updateMatrix();
initInstancedMesh.setMatrixAt(k, dummy.matrix);
const color = lut.getColor(Math.abs(c) / initAxis);
initInstancedMesh.setColorAt(k, color);
k++;
}
}
initInstancedMesh.instanceMatrix.needsUpdate = true;
initInstancedMesh.instanceColor.needsUpdate = true;
const object = meshList.getObjectByName('initInstancedMesh');
if (!object) {
meshList.add(initInstancedMesh);
}
let maxYPointsMap = [800, 10000, 10000, 7000];
let maxYPoints = maxYPointsMap[0];
pointCount = phase * maxYPoints;
initInstancedPoints = new THREE.InstancedMesh(pointsGeometry, new THREE.MeshBasicMaterial(), pointCount);
let j = 0;
for (let i = 0; i < pointCount; i++) {
dummyPoint.position.set(i, 9999, i)
dummyPoint.updateMatrix()
initInstancedPoints.setMatrixAt(j, dummyPoint.matrix)
const color = new THREE.Color(0x0082df)
initInstancedPoints.setColorAt(j, color)
j++
}
initInstancedPoints.instanceMatrix.needsUpdate = true;
initInstancedPoints.instanceColor.needsUpdate = true;
initInstancedPoints.name = 'initInstancedPoints';
// const object1 = meshList.getObjectByName('initInstancedMesh');
// if (!object1) {
pointsList.add(initInstancedPoints);
// }
}
//prps初始化
function init() {
let box = $('#box3D');
let width = box.width();
let height = width;
renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true, });
renderer.setSize(width, height);//设置渲染区域尺寸
renderer.setClearColor(0x000d13, 1); //设置背景颜色
//renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
renderer.setPixelRatio(window.devicePixelRatio)//设备像素比,优化渲染效果
box?.append(renderer.domElement); //body元素中插入canvas对象
scene = new THREE.Scene();
scene.add(meshList, axis, pointsList, axisTextGroup);
drawAxis(initAxis, 0, true)
var k = width / height; //窗口宽高比
var s = 360; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
camera = new THREE.OrthographicCamera(-s * k + 20, s * k + 20, s + 100, -s + 100, 1, 1600);
camera.position.set(500, 200, 500); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
controls = new THREE.OrbitControls(camera, renderer.domElement);
// 设置左右方向的最大、最小角度限制为 90 度和 0 度
controls.minAzimuthAngle = 0;
controls.maxAzimuthAngle = Math.PI / 2;
// 设置上下方向的最大、最小角度限制为 90 度和 0 度
controls.minPolarAngle = 0;
controls.maxPolarAngle = Math.PI / 2;
//设置放大缩小上下限
controls.minZoom = 0.5;
controls.maxZoom = 2;
//controls.enablePan = false;
//设置控制器中心点
controls.target.set(25, 0, 180);
renderer.render(scene, camera);
//controls.addEventListener('change', render);
}
//prpd初始化
function init2D() {
let box = $('#box2D');
let width = box.width();
let height = width;
renderer2D = new THREE.WebGLRenderer({ preserveDrawingBuffer: true, });
renderer2D.setSize(width, height);//设置渲染区域尺寸
renderer2D.setClearColor(0x000d13, 1); //设置背景颜色
renderer2D.setPixelRatio(window.devicePixelRatio)//设备像素比,优化渲染效果
box?.append(renderer2D.domElement); //body元素中插入canvas对象
scene2D = new THREE.Scene();
const List = pointsList.clone()
scene2D.add(axis2D, List, axisTextGroup2D, pointsList)
drawAxis2D(initAxis, 0)
// 辅助坐标系 参数250表示坐标系大小可以根据场景大小去设置
// let axisHelper = new THREE.AxesHelper(250);
// scene2D.add(axisHelper);
var k = width / height; //窗口宽高比
var s = 240; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
camera2D = new THREE.OrthographicCamera(-s * k - 200, s * k - 200, s + 160, -s + 160, 1, 1200);
camera2D.position.set(600, 0, 0); //设置相机位置
camera2D.lookAt(scene2D.position); //设置相机方向(指向的场景对象)
controls2D = new THREE.OrbitControls(camera2D, renderer2D.domElement);
//controls2D.enablePan = false//右键位移禁用
//controls2D.enableZoom = false//放大缩小禁用
//设置放大缩小上下限
controls2D.minZoom = 0.5;
controls2D.maxZoom = 2;
controls2D.enableRotate = false
//renderer2D.render(scene2D, camera2D);
//controls2D.addEventListener('change', render2D);
}
function onWindowResize() {
let box = $('#box3D');
let width = box.width();
let height = width;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
renderer.setPixelRatio(window.devicePixelRatio)//设备像素比,优化渲染效果
camera2D.updateProjectionMatrix();
renderer2D.setSize(width, height);
renderer2D.setPixelRatio(window.devicePixelRatio)//设备像素比,优化渲染效果
}
function render() {
// 获取摄像机的视锥体
const frustum = new THREE.Frustum();
const cameraViewProjectionMatrix = new THREE.Matrix4();
camera.updateMatrixWorld(); // 确保摄像机的世界矩阵已更新
cameraViewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
frustum.setFromProjectionMatrix(cameraViewProjectionMatrix);
// 遍历场景中的每个对象,并根据视锥体进行剔除
scene.traverse((object) => {
if (object.isMesh) {
object.visible = frustum.intersectsObject(object);
}
});
// 更新帧率显示器
renderer.render(scene, camera);
requestAnimationFrame(render)
}
function render2D() {
//scene.rotateY(0.001);//每次绕y轴旋转0.01弧度
requestAnimationFrame(render2D)
renderer2D.render(scene2D, camera2D);
}
function drawPRPD(list) {
const colors = [
{
color: new THREE.Color(0x50A3BA),
num: 5,
},
{
color: new THREE.Color(0x9DB578),
num: 7,
},
{
color: new THREE.Color(0xEAC736),
num: 10,
},
{
color: new THREE.Color(0xE28B4A),
num: 14,
},
];
list.forEach((item, index) => {
// 更新颜色
const color = item[2] <= 3 ? new THREE.Color(0x0082df) : (item[2] >= 15 ? new THREE.Color(0xD94E5D) : colors.find(i => item[2] <= i.num).color);
initInstancedPoints.setColorAt(index, color);
// 更新位置
dummyPoint.position.set(1, item[1], item[0]);
dummyPoint.updateMatrix();
initInstancedPoints.setMatrixAt(index, dummyPoint.matrix);
})
for (let i = list.length; i < pointCount; i++) {
dummyPoint.position.set(1, 999999, 0);
dummyPoint.updateMatrix();
initInstancedPoints.setMatrixAt(i, dummyPoint.matrix);
}
initInstancedPoints.instanceMatrix.needsUpdate = true;
initInstancedPoints.instanceColor.needsUpdate = true;
}
function drawPRPS(list) {
let k = 1;
for (let j = 0; j < period; j++) {
for (let i = 0; i < list.length; i++) {
initInstancedMesh.getMatrixAt(k, dummy.matrix);
dummy.position.setFromMatrixPosition(dummy.matrix);
dummy.scale.setFromMatrixScale(dummy.matrix);
if (dummy.position.x > 0) {
dummy.position.x -= 1;
} else {
let [y, h] = list[i];
const max = initAxis;
h = h > max ? max : h;
dummy.position.x = 49
dummy.position.y = h / 2;
dummy.scale.y = Math.abs(h);
const color = lut.getColor(Math.abs(h) / max);
initInstancedMesh.setColorAt(k, color);
}
dummy.updateMatrix();
initInstancedMesh.setMatrixAt(k, dummy.matrix);
k++;
}
}
initInstancedMesh.instanceMatrix.needsUpdate = true;
initInstancedMesh.instanceColor.needsUpdate = true;
}
function generateArray() {
const newArray = [];
const step = 360 / phase;
for (let i = 1; i <= phase; i++) {
newArray.push([counter, parseInt(i * step), getRandomInt(20, 35)]);
}
counter = (counter % period) + 1;
return newArray;
}
// 生成指定范围内的随机整数
function getRandomInt(min, max) {
const randomNumber = Math.random() * (max - min) + min;
const roundedNumber = randomNumber.toFixed(1);
return parseFloat(roundedNumber);
}
// 页面放大缩小时
$(window).resize(function () {
onWindowResize()
})
export { scene, axis, meshList, pointsList, axis2D, scene2D }