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

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 }