gasPump.threejs.under.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. import * as THREE from 'three';
  2. import { CSS3DObject, CSS3DSprite } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
  3. import { getModelMonitorTags } from './gasPump.data';
  4. import ArrowFlow from '../../comment/threejs/ArrowFlow';
  5. // import * as dat from 'dat.gui';
  6. // const gui = new dat.GUI();
  7. // gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
  8. class gasPumpUnder {
  9. model;
  10. modelName = 'gas-pump-underground';
  11. group: THREE.Object3D | null = null;
  12. modelMonitorTags = getModelMonitorTags();
  13. /** 进气管道动画,指总进气连接左边泵的那条 */
  14. airInA: ArrowFlow | null = null;
  15. /** 进气管道动画,指总进气连接右边泵的那条 */
  16. airInB: ArrowFlow | null = null;
  17. /** 进气管道动画,指靠右的那条进气 */
  18. airInR: ArrowFlow | null = null;
  19. /** 进气管道动画,指靠左的那条进气 */
  20. airInL: ArrowFlow | null = null;
  21. /** 出气管道动画,指总出气连接左边泵的那条 */
  22. airOutA: ArrowFlow | null = null;
  23. /** 出气管道动画,指总出气连接右边泵的那条 */
  24. airOutB: ArrowFlow | null = null;
  25. /** 出气管道动画,指靠右的那条出气 */
  26. airOutR: ArrowFlow | null = null;
  27. /** 出气管道动画,指靠左的那条出气 */
  28. airOutL: ArrowFlow | null = null;
  29. /** 进水管道动画,指总进水连接左边泵的那条 */
  30. waterInA: ArrowFlow | null = null;
  31. /** 进水管道动画,指总进水连接右边泵的那条 */
  32. waterInB: ArrowFlow | null = null;
  33. /** 进水管道动画,指靠右的那条进水 */
  34. waterInR: ArrowFlow | null = null;
  35. /** 进水管道动画,指靠左的那条进水 */
  36. waterInL: ArrowFlow | null = null;
  37. /** 排水管道动画,指总排水连接左边泵的那条 */
  38. waterOutA: ArrowFlow | null = null;
  39. /** 排水管道动画,指总排水连接右边泵的那条 */
  40. waterOutB: ArrowFlow | null = null;
  41. /** 排水管道动画,指靠右的那条排水 */
  42. waterOutR: ArrowFlow | null = null;
  43. /** 排水管道动画,指靠左的那条排水 */
  44. waterOutL: ArrowFlow | null = null;
  45. constructor(model) {
  46. this.model = model;
  47. }
  48. addLight() {
  49. const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  50. directionalLight.position.set(-48, 107, 36);
  51. this.group?.add(directionalLight);
  52. directionalLight.target = this.group as THREE.Object3D;
  53. }
  54. // addCssText = () => {
  55. // if (!this.group) return;
  56. // if (!this.group.getObjectByName('text1')) {
  57. // const element = document.getElementById('FlowSensor') as HTMLElement;
  58. // if (element) {
  59. // const parentElement = document.getElementById('gas3DCSS') as HTMLElement;
  60. // parentElement.appendChild(element);
  61. // const fanLocalCSS3D = new CSS3DObject(element);
  62. // fanLocalCSS3D.name = 'text1';
  63. // fanLocalCSS3D.scale.set(0.007, 0.007, 0.007);
  64. // fanLocalCSS3D.position.set(0, 1.6, 0);
  65. // this.group.add(fanLocalCSS3D);
  66. // }
  67. // }
  68. // };
  69. addCssText = () => {
  70. if (!this.group) return;
  71. const parentElement = document.getElementById('gas3DCSS') as HTMLElement;
  72. for (let i = 0; i < this.modelMonitorTags.length; i++) {
  73. const tag = this.modelMonitorTags[i];
  74. if (!this.group.getObjectByName(tag.domId)) {
  75. const element = document.getElementById(tag.domId) as HTMLElement;
  76. if (element) {
  77. parentElement.appendChild(element);
  78. const fanLocalCSS3D = new CSS3DSprite(element);
  79. fanLocalCSS3D.name = tag.domId;
  80. fanLocalCSS3D.scale.set(0.009, 0.009, 0.009);
  81. fanLocalCSS3D.position.set(tag.position[0], tag.position[1], tag.position[2]);
  82. this.group.add(fanLocalCSS3D);
  83. }
  84. }
  85. }
  86. };
  87. /** 根据各个泵的状态控制动画 */
  88. handleAnimation(monitorData?: any) {
  89. if (!monitorData) return;
  90. this.airInA?.hideElement();
  91. this.airInB?.hideElement();
  92. this.airInR?.hideElement();
  93. this.airInL?.hideElement();
  94. this.airOutA?.hideElement();
  95. this.airOutB?.hideElement();
  96. this.airOutR?.hideElement();
  97. this.airOutL?.hideElement();
  98. this.waterInA?.hideElement();
  99. this.waterInB?.hideElement();
  100. this.waterInR?.hideElement();
  101. this.waterInL?.hideElement();
  102. this.waterOutA?.hideElement();
  103. this.waterOutB?.hideElement();
  104. this.waterOutR?.hideElement();
  105. this.waterOutL?.hideElement();
  106. // 进气动画控制
  107. const jqf1Open = this.modelMonitorTags.find((e) => e.domId === 'jqf1' && parseInt(monitorData[e.code]) > 0);
  108. const jqf2Open = this.modelMonitorTags.find((e) => e.domId === 'jqf2' && parseInt(monitorData[e.code]) > 0);
  109. if (jqf1Open && jqf2Open) {
  110. this.airInB?.showElement();
  111. this.airInR?.showElement();
  112. this.airInL?.showElement();
  113. } else if (jqf1Open) {
  114. this.airInA?.showElement();
  115. this.airInL?.showElement();
  116. } else if (jqf2Open) {
  117. this.airInB?.showElement();
  118. this.airInR?.showElement();
  119. }
  120. // 出气动画控制
  121. const cqf1Open = this.modelMonitorTags.find((e) => e.domId === 'cqf1' && parseInt(monitorData[e.code]) > 0);
  122. const cqf2Open = this.modelMonitorTags.find((e) => e.domId === 'cqf2' && parseInt(monitorData[e.code]) > 0);
  123. if (cqf1Open && cqf2Open) {
  124. this.airOutB?.showElement();
  125. this.airOutR?.showElement();
  126. this.airOutL?.showElement();
  127. } else if (cqf1Open) {
  128. this.airOutA?.showElement();
  129. this.airOutL?.showElement();
  130. } else if (cqf2Open) {
  131. this.airOutB?.showElement();
  132. this.airOutR?.showElement();
  133. }
  134. // 进水动画控制
  135. const jsf1Open = this.modelMonitorTags.find((e) => e.domId === 'jsf1' && parseInt(monitorData[e.code]) == 1);
  136. const jsf2Open = this.modelMonitorTags.find((e) => e.domId === 'jsf2' && parseInt(monitorData[e.code]) == 1);
  137. if (jsf1Open && jsf2Open) {
  138. this.waterInB?.showElement();
  139. this.waterInR?.showElement();
  140. this.waterInL?.showElement();
  141. } else if (jsf1Open) {
  142. this.waterInA?.showElement();
  143. this.waterInL?.showElement();
  144. } else if (jsf2Open) {
  145. this.waterInB?.showElement();
  146. this.waterInR?.showElement();
  147. }
  148. // 出水动画控制
  149. const csf1Open = this.modelMonitorTags.find((e) => e.domId === 'csf1' && parseInt(monitorData[e.code]) == 1);
  150. const csf2Open = this.modelMonitorTags.find((e) => e.domId === 'csf2' && parseInt(monitorData[e.code]) == 1);
  151. if (csf1Open && csf2Open) {
  152. this.waterOutB?.showElement();
  153. this.waterOutR?.showElement();
  154. this.waterOutL?.showElement();
  155. } else if (csf1Open) {
  156. this.waterOutA?.showElement();
  157. this.waterOutL?.showElement();
  158. } else if (csf2Open) {
  159. this.waterOutB?.showElement();
  160. this.waterOutR?.showElement();
  161. }
  162. }
  163. clearCssText = () => {
  164. const fanLocalCSS3D = this.group?.getObjectByName('text1') as THREE.Object3D;
  165. this.group?.remove(fanLocalCSS3D);
  166. };
  167. mountedThree() {
  168. return new Promise((resolve) => {
  169. this.model.setGLTFModel([this.modelName]).then((gltf) => {
  170. this.group = gltf[0];
  171. if (this.group) {
  172. // this.group?.scale.set(0.1, 0.1, 0.1);
  173. // this.group.position.y += 40;
  174. resolve(null);
  175. this.addLight();
  176. this.addArrowFlows();
  177. this.handleAnimation(); // 流动动画在这里写吧
  178. }
  179. });
  180. });
  181. }
  182. destroy() {
  183. this.model.clearGroup(this.group);
  184. this.model = null;
  185. this.group = null;
  186. }
  187. /** 添加进气、进水、出气、排水的箭头流线,不负责启动动画 */
  188. addArrowFlows() {
  189. const arrows = [
  190. {
  191. texturePath: '/model/img/redArrow.png',
  192. id: 'airInA',
  193. offsetY: 0.5,
  194. repeatX: 10,
  195. radius: 0.09,
  196. points: [new THREE.Vector3(-12.284, 0.942, -0.359), new THREE.Vector3(-7.276, 0.942, -0.377)],
  197. },
  198. {
  199. texturePath: '/model/img/redArrow.png',
  200. id: 'airInB',
  201. offsetY: 0.25,
  202. repeatX: 20,
  203. radius: 0.09,
  204. points: [new THREE.Vector3(-12.284, 0.942, -0.359), new THREE.Vector3(-3.909, 0.942, -0.359)],
  205. },
  206. {
  207. texturePath: '/model/img/redArrow.png',
  208. id: 'airInR',
  209. offsetY: 0.5,
  210. repeatX: 22,
  211. radius: 0.09,
  212. points: [
  213. // new THREE.Vector3(-3.909, 0.942, -0.359),
  214. // new THREE.Vector3(-3.819, 0.942, -0.207),
  215. // new THREE.Vector3(-3.924, 0.942, -0.06),
  216. // new THREE.Vector3(-5.153, 0.942, -0.06),
  217. // new THREE.Vector3(-5.153, 0.725, -0.06),
  218. new THREE.Vector3(-12.284, 0.942, -0.359),
  219. new THREE.Vector3(-4.012, 0.942, -0.359),
  220. new THREE.Vector3(-4.012, 0.942, -0.207),
  221. new THREE.Vector3(-4.012, 0.942, -0.06),
  222. new THREE.Vector3(-4.356, 0.942, -0.06),
  223. new THREE.Vector3(-5.153, 0.942, -0.06),
  224. new THREE.Vector3(-5.173, 0.725, -0.06),
  225. ],
  226. },
  227. {
  228. texturePath: '/model/img/redArrow.png',
  229. id: 'airInL',
  230. offsetY: 0.5,
  231. repeatX: 5,
  232. radius: 0.09,
  233. points: [
  234. new THREE.Vector3(-7.276, 0.942, -0.377),
  235. new THREE.Vector3(-7.276, 0.942, -0.181),
  236. new THREE.Vector3(-7.414, 0.942, -0.063),
  237. new THREE.Vector3(-8.78, 0.942, -0.063),
  238. new THREE.Vector3(-8.78, 0.725, -0.063),
  239. ],
  240. },
  241. {
  242. texturePath: '/model/img/blueArrow.png',
  243. id: 'airOutA',
  244. offsetY: 0.5,
  245. repeatX: 10,
  246. radius: 0.09,
  247. points: [new THREE.Vector3(-9.697, 1.618, -0.069), new THREE.Vector3(-12.284, 1.618, -0.08)],
  248. },
  249. {
  250. texturePath: '/model/img/blueArrow.png',
  251. id: 'airOutB',
  252. offsetY: 0.75,
  253. repeatX: 20,
  254. radius: 0.09,
  255. points: [new THREE.Vector3(-6.197, 1.619, -0.08), new THREE.Vector3(-12.284, 1.618, -0.08)],
  256. },
  257. {
  258. texturePath: '/model/img/blueArrow.png',
  259. id: 'airOutR',
  260. offsetY: 0.75,
  261. repeatX: 5,
  262. radius: 0.09,
  263. points: [
  264. new THREE.Vector3(-5.628, 0.606, -0.08),
  265. new THREE.Vector3(-5.628, 0.788, -0.08),
  266. new THREE.Vector3(-5.732, 0.916, -0.08),
  267. new THREE.Vector3(-5.962, 0.916, -0.08),
  268. new THREE.Vector3(-6.067, 1.073, -0.08),
  269. new THREE.Vector3(-6.067, 1.618, -0.08),
  270. ],
  271. },
  272. {
  273. texturePath: '/model/img/blueArrow.png',
  274. id: 'airOutL',
  275. offsetY: 0.75,
  276. repeatX: 5,
  277. radius: 0.09,
  278. points: [
  279. new THREE.Vector3(-9.257, 0.606, -0.069),
  280. new THREE.Vector3(-9.257, 0.819, -0.069),
  281. new THREE.Vector3(-9.388, 0.916, -0.069),
  282. new THREE.Vector3(-9.593, 0.916, -0.069),
  283. new THREE.Vector3(-9.697, 1.073, -0.069),
  284. new THREE.Vector3(-9.697, 1.618, -0.069),
  285. ],
  286. },
  287. {
  288. texturePath: '/model/img/greenArrow.png',
  289. id: 'waterInA',
  290. offsetY: 0.25,
  291. repeatX: 10,
  292. radius: 0.04,
  293. points: [new THREE.Vector3(-10.808, 0.124, 0.808), new THREE.Vector3(-9.008, 0.124, 0.808)],
  294. },
  295. {
  296. texturePath: '/model/img/greenArrow.png',
  297. id: 'waterInB',
  298. offsetY: 0.25,
  299. repeatX: 20,
  300. radius: 0.04,
  301. points: [new THREE.Vector3(-10.808, 0.124, 0.808), new THREE.Vector3(-5.374, 0.124, 0.808)],
  302. },
  303. {
  304. texturePath: '/model/img/greenArrow.png',
  305. id: 'waterInR',
  306. offsetY: 0.5,
  307. repeatX: 5,
  308. radius: 0.04,
  309. points: [
  310. new THREE.Vector3(-5.374, 0.124, 0.808),
  311. new THREE.Vector3(-5.374, 0.124, 0.019),
  312. new THREE.Vector3(-5.368, 0.215, 0.001),
  313. new THREE.Vector3(-5.204, 0.219, 0.001),
  314. ],
  315. },
  316. {
  317. texturePath: '/model/img/greenArrow.png',
  318. id: 'waterInL',
  319. offsetY: 0.5,
  320. repeatX: 5,
  321. radius: 0.04,
  322. points: [
  323. new THREE.Vector3(-9.008, 0.124, 0.808),
  324. new THREE.Vector3(-9.008, 0.124, 0.019),
  325. new THREE.Vector3(-9.003, 0.215, 0.001),
  326. new THREE.Vector3(-8.839, 0.219, 0.001),
  327. ],
  328. },
  329. {
  330. texturePath: '/model/img/greenArrow.png',
  331. id: 'waterOutA',
  332. offsetY: 0.5,
  333. repeatX: 10,
  334. radius: 0.04,
  335. points: [
  336. new THREE.Vector3(-9.268, 0.175, 0.589),
  337. new THREE.Vector3(-9.725, 0.175, 0.609),
  338. new THREE.Vector3(-9.777, 0.175, 0.007),
  339. new THREE.Vector3(-10.843, 0.175, -0.04),
  340. ],
  341. },
  342. {
  343. texturePath: '/model/img/greenArrow.png',
  344. id: 'waterOutB',
  345. offsetY: 0.75,
  346. repeatX: 20,
  347. radius: 0.04,
  348. points: [
  349. new THREE.Vector3(-5.614, 0.175, 0.609),
  350. new THREE.Vector3(-9.725, 0.175, 0.609),
  351. new THREE.Vector3(-9.777, 0.175, 0.007),
  352. new THREE.Vector3(-10.843, 0.175, -0.04),
  353. ],
  354. },
  355. {
  356. texturePath: '/model/img/greenArrow.png',
  357. id: 'waterOutR',
  358. offsetY: 0.5,
  359. repeatX: 2,
  360. radius: 0.04,
  361. points: [new THREE.Vector3(-5.614, 0.175, 0.238), new THREE.Vector3(-5.614, 0.175, 0.609)],
  362. },
  363. {
  364. texturePath: '/model/img/greenArrow.png',
  365. id: 'waterOutL',
  366. offsetY: 0.5,
  367. repeatX: 2,
  368. radius: 0.04,
  369. points: [new THREE.Vector3(-9.268, 0.175, 0.237), new THREE.Vector3(-9.268, 0.175, 0.593)],
  370. },
  371. ];
  372. arrows.forEach(({ points, id, texturePath, offsetY, repeatX, radius }) => {
  373. // 初始化箭头,偏移设置为0.25可以让贴图在管道上方
  374. const arrow = new ArrowFlow(texturePath as any, {
  375. offsetY,
  376. repeatX,
  377. });
  378. // 这里开启动画后隐藏元素可以让后续动画控制仅调用 show/hideElement 即可
  379. arrow.startAnimation();
  380. arrow.hideElement();
  381. // 曲线,张力设置为 0 可以让曲线不使用平滑过渡效果从而贴合管道
  382. const curve = new THREE.CatmullRomCurve3(points, false, 'catmullrom', 0.2);
  383. // 添加几何,这样设置该几何体可以略大于依附的管道,其贴图不会出现被覆盖的现象
  384. const geometry = new THREE.TubeGeometry(curve, 32, radius, 8, false);
  385. const mesh = new THREE.Mesh(geometry, arrow);
  386. this[id] = arrow;
  387. this.group?.add(mesh);
  388. });
  389. }
  390. }
  391. export default gasPumpUnder;