luoyang-screen/src/babylonjs/LinePageBabylonNew.tsx
2025-02-21 11:10:35 +08:00

397 lines
13 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 { useEffect, useRef, useState } from "react";
import * as BABYLON from "@babylonjs/core";
import "@babylonjs/core/Debug/debugLayer";
import "@babylonjs/inspector";
import "@babylonjs/loaders/glTF";
import { GridMaterial } from "@babylonjs/materials/";
import { HemisphericLight, Vector3 } from "@babylonjs/core";
import { useAppSelector } from "../store/hooks";
import "../page/style/standard.css";
import EqInfoData from "./EqInfoData";
import AlarmTipGreen from "./../page/assets/icon/g.png";
import AlarmTipYellow from "./../page/assets/icon/y.png";
import AlarmTipRed from "./../page/assets/icon/r.png";
import {selectLine1Before} from "../store/LinePageSlice";
const lineNameNo = ["一","二","三","四","五"]
const myStyle = {
width: "1041px",
height: "562px",
outline: "none",
};
interface MybabylonJSProps {
modelPath: string; // 明确 modelPath 属性的类型为 string
}
interface EqListType {
[key: string]: EqMsg
}
interface EqMsg {
equipmentName?:string;
run?:boolean;
error?:boolean;
inputNum?:number;
outputNum?:number;
quantityTime?:number;
status?:string;
statusTime?:number;
localDateTime?:number;
equipmentCode?:string;
equipmentId?:number;
}
function MybabylonJS({ modelPath }: MybabylonJSProps) {
const [eqList, setEqList] = useState<EqListType>({});
const allData = useAppSelector(selectLine1Before) as any; // 使用`any`来绕过类型检查
const canvasRef = useRef(null);
const resetRef = useRef<(() => void) | null>(null);
const [selectedMeshName, setSelectedMeshName] = useState<string | null>(null);
const [selectedMeshId, setSelectedMeshId] = useState<string | null>(null);
const [selectedMeshObj, setSelectedMeshObj] = useState<EqMsg>({
equipmentName: "",
run: true,
error: false,
});
const [showInfo, setShowInfo] = useState(true);
// 使用 useRef 来存储当前加载的模型引用
const currentMeshesRef = useRef<Array<BABYLON.AbstractMesh>>([]);
useEffect(() => {
const equStatus = allData?.equStatus;
if (equStatus) {
setEqList(equStatus);
}
},[allData])
useEffect(() => {
const equStatus = allData?.equStatus;
if (equStatus) {
for (let i = 0; i < EqInfoData[modelPath].length; i++) {
for (let j = 0; j < EqInfoData[modelPath][i].data.length; j++) {
EqInfoData[modelPath][i].data[j].value = equStatus[EqInfoData[modelPath][i].data[j].code][EqInfoData[modelPath][i].data[j].label] ? equStatus[EqInfoData[modelPath][i].data[j].code][EqInfoData[modelPath][i].data[j].label] : 0
}
}
}
},[allData,modelPath])
useEffect(() => {
if (selectedMeshId && eqList[selectedMeshId]) {
setSelectedMeshObj({
equipmentName:eqList[selectedMeshId].equipmentName,
run:eqList[selectedMeshId].run ? eqList[selectedMeshId].run : true,
error:eqList[selectedMeshId].error ? eqList[selectedMeshId].error : false,
});
}
},[selectedMeshId])
useEffect(() => {
// 确保 canvas 引用存在
if (!canvasRef.current) return;
const canvas = canvasRef.current;
const engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true,
});
const createScene = async function () {
// This creates a basic Babylon Scene object (non-mesh)
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);
const baseLight = new HemisphericLight(
"hemiLight",
new Vector3(-1, 1, 0),
scene
);
baseLight.intensity = 1;
baseLight.diffuse = new BABYLON.Color3(1, 1, 1);
baseLight.specular = new BABYLON.Color3(0.25, 0.25, 0.25);
baseLight.groundColor = new BABYLON.Color3(0.5, 0.5, 0.5);
//add an arcRotateCamera to the scene
const camera = new BABYLON.ArcRotateCamera(
"camera",
BABYLON.Tools.ToRadians(245),
BABYLON.Tools.ToRadians(25),
modelPath.slice(-3) === "2-1"
? 120
: modelPath.slice(-1) === "1"
? 110
: modelPath.slice(-3) === "5-2"
? 100
: modelPath.slice(-3) === "1-2"
? 90
: 65,
new BABYLON.Vector3(-13, 0, 0)
);
camera.lowerRadiusLimit = 10;
camera.upperRadiusLimit = 600;
// This attaches the camera to the canvas
camera.attachControl(canvas, true);
//创建一个材质
const newMt = new BABYLON.StandardMaterial("newMt");
newMt.diffuseColor = BABYLON.Color3.Blue();
const ground = BABYLON.MeshBuilder.CreateGround(
"ground",
{
width: 1000,
height: 1000,
subdivisions: 1,
},
scene
);
ground.scaling.x = 100;
ground.scaling.z = ground.scaling.x;
ground.isPickable = false;
let grid = new GridMaterial("grid", scene);
grid.majorUnitFrequency = 10;
grid.minorUnitVisibility = 0.3;
grid.gridRatio = 0.04;
grid.backFaceCulling = !1;
grid.mainColor = new BABYLON.Color3(1, 1, 1);
grid.lineColor = new BABYLON.Color3(1, 1, 1);
grid.opacity = 0;
grid.zOffset = 1;
grid.opacityTexture = new BABYLON.Texture(
"/public/png/backgroundGround.png",
scene
);
ground.material = grid;
let hl = new BABYLON.HighlightLayer("hl1", scene);
let hl2 = new BABYLON.HighlightLayer("hl2", scene);
// 定义一个函数来加载或重新加载模型
const loadOrReloadModel = async () => {
// 在加载新模型之前卸载已加载的模型
currentMeshesRef.current.forEach((mesh) => {
if (mesh && mesh.parent) {
scene.removeMesh(mesh, true);
}
});
currentMeshesRef.current = []; // 重置模型数组
try {
// 使用 ImportMeshAsync 加载新模型
var LOD0MESH = await BABYLON.SceneLoader.ImportMeshAsync(
"",
"/Line/",
`${modelPath}.babylon`,
scene
);
// 将新加载的模型添加到 currentMeshesRef 中
currentMeshesRef.current.push(...LOD0MESH.meshes);
// ...为新加载的模型设置交互逻辑
LOD0MESH.meshes.map((mesh) => {
mesh.isPickable = true;
mesh.actionManager = new BABYLON.ActionManager(scene);
if (modelPath.slice(-1) === "1") {
if (
mesh.name.includes("磨边") ||
mesh.name.includes("清洗") ||
mesh.name.includes("镀膜") ||
mesh.name.includes("固化") ||
mesh.name.includes("丝印") ||
mesh.name.includes("打孔")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
} else {
if (
mesh.name.includes("钢化") ||
mesh.name.includes("包装") ||
mesh.name.includes("铺纸") ||
mesh.name.includes("下片机械手")
) {
// @ts-ignore
hl.addMesh(mesh, BABYLON.Color3.Green());
}
}
mesh._scene.onPointerDown = async (event, _pickResult) => {
console.log('_pickResult',_pickResult)
const pickInfo = mesh._scene.pick(
mesh._scene.pointerX,
mesh._scene.pointerY
);
//判断是否是右键
if (!(event.buttons === 1 && pickInfo.pickedMesh)) return;
const MeshName = pickInfo.pickedMesh.name;
const MeshNameId = pickInfo.pickedMesh.metadata.tags;
setSelectedMeshName(MeshName);
setSelectedMeshId(MeshNameId);
};
});
} catch (error) {
console.error("加载模型失败:", error);
}
};
// 调用函数以加载或重新加载模型
loadOrReloadModel();
function reset() {
camera.target = new BABYLON.Vector3(-13, 0, 0);
camera.alpha = BABYLON.Tools.ToRadians(245);
camera.beta = BABYLON.Tools.ToRadians(25);
camera.radius =
modelPath.slice(-3) === "2-1"
? 120
: modelPath.slice(-1) === "1"
? 110
: modelPath.slice(-3) === "5-2"
? 100
: modelPath.slice(-3) === "1-2"
? 90
: 65
setShowInfo(true);
setSelectedMeshName(null);
}
// 外部初始位置按钮
resetRef.current = reset;
let resetCamera = setTimeout(reset, 15000);
scene.onPointerObservable.add((pointerInfo) => {
switch (pointerInfo.type) {
case BABYLON.PointerEventTypes.POINTERMOVE:
clearTimeout(resetCamera);
resetCamera = setTimeout(reset, 15000);
setShowInfo(false);
}
});
return scene;
};
// call the createScene function
const scene = createScene();
// run the render loop
scene.then(
(scene) => {
console.log("createScene被调用了=====", scene);
engine.runRenderLoop(function () {
scene.render();
});
},
(reason) => {
console.log("reason=============", reason);
}
);
// Resize
window.addEventListener("resize", function () {
engine.resize();
});
// 组件卸载时的清理逻辑
return () => {
// 清理场景和引擎资源
engine.dispose();
};
}, [modelPath]);
const resetModel = () => {
//模型初始位置
if (resetRef.current) {
resetRef.current();
}
};
return (
<div style={myStyle}>
{/* <h2 className="model_name">当前选择: {selectedMeshName}</h2> */}
<div className="model_info">
<span className="reset_btn" onClick={resetModel}></span>
<span className="title">
{lineNameNo[Number(modelPath.slice(-3,-2))-1]}线{modelPath.slice(-1) === "1" ? "前段" : "后段"}
</span>
</div>
{selectedMeshName && (
<div className="eq_detail_info">
<div>
<span className="left_name"></span>
<span className="right_value">{selectedMeshObj.equipmentName}</span>
</div>
<div>
<span className="left_name"></span>
<span className="right_value">
{selectedMeshObj.error ? (
<>
<img
src={AlarmTipRed}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
) : (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span></span>
</>
)}
</span>
</div>
<div>
<span className="left_name">线</span>
<span className="right_value">
{selectedMeshObj.run ? (
<>
<img
src={AlarmTipGreen}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
) : (
<>
<img
src={AlarmTipYellow}
alt=""
width={17}
style={{ position: "relative", top: "2px", marginRight: 5 }}
/>
<span>线</span>
</>
)}
</span>
</div>
</div>
)}
{showInfo &&
EqInfoData[modelPath] &&
EqInfoData[modelPath].map((item) => {
return (
<div
className="eq_info"
key={item.data[0].code+item.data[0].label}
style={{ left: item.position[0], top: item.position[1] }}
>
<div className="eq_info_inner" style={{ color: "#00FFF0" }}>
{item.name}
</div>
{item.data.map((info) => {
return (
<div className="eq_info_inner" key={info.code+info.label}>
{info.name}{info.value}
</div>
);
})}
</div>
);
})}
<canvas ref={canvasRef} style={myStyle} />
</div>
);
}
export default MybabylonJS;