gasPump.threejs.under.ts 14 KB

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