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 }