ThreeModel1.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. <template>
  2. <div class="three-model">
  3. <loading ref="pageLoading"></loading>
  4. <div class="map-3d" :style="'transform: rotate('+mapDeg+'deg);'">
  5. <img :src="require('@assets/png/3dmap.png')" alt="">
  6. </div>
  7. <div class="three-html-layer">
  8. <div v-for="(info, index) of htmlLayer" :key="index"
  9. class="three-html-dom fan-info"
  10. :id="info.id"
  11. v-show="info.show"
  12. :style="'left: ' + info.x + 'px; top: ' + info.y + 'px;'"
  13. >
  14. <div class="fan-name">{{info.name}}</div>
  15. </div>
  16. </div>
  17. </div>
  18. </template>
  19. <script>
  20. import loading from "@com/coms/loading/loading.vue";
  21. import * as THREE from "three";
  22. import { GLTFLoader } from "@node/three/examples/jsm/loaders/GLTFLoader.js";
  23. import { OrbitControls } from "@node/three/examples/jsm/controls/OrbitControls.js";
  24. import { GeometryUtils } from "@node/three/examples/jsm/utils/GeometryUtils.js";
  25. let camera, scene, renderer, controls;
  26. let mixers = [];
  27. let clock = new THREE.Clock();
  28. let fanAnimates = [];
  29. let fans = [];
  30. let cylinder = null;
  31. export default {
  32. // 名称
  33. name: "ThreeModel1",
  34. // 使用组件
  35. components: {
  36. loading,
  37. },
  38. // 传入参数
  39. props: {},
  40. // 自定义事件
  41. emits: {
  42. when: null,
  43. },
  44. // 数据
  45. data() {
  46. return {
  47. pointer: false,
  48. htmlLayer: [
  49. { // 麻黄山
  50. id: "fan-mhs",
  51. x: 0,
  52. y: 0,
  53. show: true,
  54. ox: 50,
  55. oy: 10,
  56. position: null,
  57. name: "麻黄山",
  58. },
  59. { // 牛首山
  60. id: "fan-nss",
  61. x: 0,
  62. y: 0,
  63. show: true,
  64. ox: 35,
  65. oy: 0,
  66. position: null,
  67. name: "牛首山",
  68. },
  69. { // 青山
  70. id: "fan-qs",
  71. x: 0,
  72. y: 0,
  73. show: true,
  74. ox: 60,
  75. oy: 10,
  76. position: null,
  77. name: "青山",
  78. },
  79. { // 石板泉
  80. id: "fan-sbq",
  81. x: 0,
  82. y: 0,
  83. show: true,
  84. ox: 40,
  85. oy: 0,
  86. position: null,
  87. name: "石板泉",
  88. },
  89. { // 香山
  90. id: "fan-qs",
  91. x: 0,
  92. y: 0,
  93. show: true,
  94. ox: 25,
  95. oy: 20,
  96. position: null,
  97. name: "香山",
  98. },
  99. { // 大武口
  100. id: "light-dwk",
  101. x: 0,
  102. y: 0,
  103. show: true,
  104. ox: 0,
  105. oy: 110,
  106. position: null,
  107. name: "大武口",
  108. },
  109. { // 平罗
  110. id: "light-pl",
  111. x: 0,
  112. y: 0,
  113. show: true,
  114. ox: 30,
  115. oy: 100,
  116. position: null,
  117. name: "平罗",
  118. },
  119. { // 马场湖
  120. id: "light-mch",
  121. x: 0,
  122. y: 0,
  123. show: true,
  124. ox: -120,
  125. oy: 110,
  126. position: null,
  127. name: "马场湖",
  128. },
  129. { // 宣和
  130. id: "light-xh",
  131. x: 0,
  132. y: 0,
  133. show: true,
  134. ox: -90,
  135. oy: 120,
  136. position: null,
  137. name: "宣和",
  138. },
  139. { // 海子井
  140. id: "light-hzj",
  141. x: 0,
  142. y: 0,
  143. show: true,
  144. ox: -80,
  145. oy: 150,
  146. position: null,
  147. name: "海子井",
  148. },
  149. ],
  150. circleXY: [
  151. { x: -(200*Math.sin(0/180*Math.PI)), y: -(200*Math.cos(0/180*Math.PI)) },
  152. { x: -(200*Math.sin(-30/180*Math.PI)), y: -(200*Math.cos(-30/180*Math.PI)) },
  153. { x: -(200*Math.sin(-60/180*Math.PI)), y: -(200*Math.cos(-60/180*Math.PI)) },
  154. { x: -(200*Math.sin(-90/180*Math.PI)), y: -(200*Math.cos(-90/180*Math.PI)) },
  155. { x: -(200*Math.sin(-120/180*Math.PI)), y: -(200*Math.cos(-120/180*Math.PI)) },
  156. { x: -(200*Math.sin(-150/180*Math.PI)), y: -(200*Math.cos(-150/180*Math.PI)) },
  157. { x: -(200*Math.sin(-180/180*Math.PI)), y: -(200*Math.cos(-180/180*Math.PI)) },
  158. ],
  159. colors: [
  160. { colorName: 'green', state: 'dj', stateName: '待机', color: 0x05bb4c, },
  161. { colorName: 'blue', state: 'yx', stateName: '运行', color: 0x4b55ae, },
  162. { colorName: 'pink', state: 'xd', stateName: '限电', color: 0xc531c7, },
  163. { colorName: 'red', state: 'gz', stateName: '故障', color: 0xBA3237, },
  164. { colorName: 'orange', state: 'jx', stateName: '检修', color: 0xe17e23, },
  165. { colorName: 'gray', state: 'lx', stateName: '离线', color: 0x606769, },
  166. { colorName: 'white', state: 'sl', stateName: '受累', color: 0xffffff, },
  167. ],
  168. fanName: "",
  169. playAnimation: true,
  170. mapDeg: 0,
  171. };
  172. },
  173. // 函数
  174. methods: {
  175. // Vector3 to screen
  176. vector3ToScreen: function(position) {
  177. const centerX = this.$el.scrollWidth / 2;
  178. const centerY = this.$el.scrollHeight / 2;
  179. const v3 = new THREE.Vector3(position.x, position.y, position.z);
  180. const standardVec = v3.project(camera);
  181. const screenX = Math.round(centerX * standardVec.x + centerX);
  182. const screenY = Math.round(-centerY * standardVec.y + centerY);
  183. return { x: screenX, y: screenY };
  184. },
  185. // 场景
  186. initScene: function() {
  187. scene = new THREE.Scene();
  188. // scene.background = new THREE.Color(0xa0a0a0);
  189. },
  190. // 相机
  191. initCamera: function() {
  192. camera = new THREE.PerspectiveCamera(45, this.$el.scrollWidth / this.$el.scrollHeight, 0.1, 10000);
  193. camera.position.set(50, 50, 50);
  194. },
  195. // 坐标轴
  196. initAxesHelper: function() {
  197. const axesHelper = new THREE.AxesHelper(150);
  198. scene.add(axesHelper);
  199. axesHelper.position.set(0, 0, 0);
  200. },
  201. // 渲染器
  202. initRender: function() {
  203. renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  204. // renderer.setClearAlpha(0);
  205. renderer.setSize(this.$el.scrollWidth, this.$el.scrollHeight);
  206. this.$el.append(renderer.domElement);
  207. },
  208. // 灯光
  209. initLight: function() {
  210. // let light = new THREE.PointLight(0xffffff, 2);
  211. let light = new THREE.AmbientLight(0xffffff, 1);
  212. // light.position.set(50, 50, 50);
  213. scene.add(light);
  214. },
  215. // 控制器
  216. initControls: function() {
  217. controls = new OrbitControls(camera, renderer.domElement);
  218. controls.enablePan = false;
  219. controls.maxPolarAngle = 45 / 180 * Math.PI;
  220. controls.minPolarAngle = 45 / 180 * Math.PI;
  221. controls.maxAzimuthAngle = 45 / 180 * Math.PI;
  222. controls.minAzimuthAngle = 45 / 180 * Math.PI;
  223. controls.enableKeys = false;
  224. controls.enableZoom = false;
  225. controls.update();
  226. // controls.maxAzimuthAngle = 50 / 180 * Math.PI;
  227. // controls.minAzimuthAngle = 40 / 180 * Math.PI;
  228. // controls.addEventListener("change", () => {
  229. // let cDeg = controls.getAzimuthalAngle() / Math.PI * 180;
  230. // this.mapDeg = cDeg - 40 - 5;
  231. // this.setEveryHTML();
  232. // });
  233. },
  234. // 初始化一个风机动画
  235. initFanAnimate: function(obj) {
  236. let fanAnimateObj = {
  237. speed: 0.05,
  238. rotate: 0,
  239. fan: obj.getObjectByName(`${obj.name}_leaf`),
  240. fan1: obj.getObjectByName(`${obj.name}_leaf_1`),
  241. fan2: obj.getObjectByName(`${obj.name}_leaf_2`),
  242. fan3: obj.getObjectByName(`${obj.name}_leaf_3`),
  243. };
  244. let fanAnimateFunction = function() {
  245. // fanAnimateObj.fan.rotateOnAxis(new THREE.Vector3(0, 1, 0), fanAnimateObj.speed);
  246. fanAnimateObj.fan.rotateY(-fanAnimateObj.speed);
  247. // fanAnimateObj.fan1.rotateZ(fanAnimateObj.speed);
  248. // fanAnimateObj.fan2.rotateZ(fanAnimateObj.speed);
  249. // fanAnimateObj.fan3.rotateZ(fanAnimateObj.speed);
  250. // fanAnimateObj.rotate += fanAnimateObj.speed;
  251. // if (fanAnimateObj.rotate >= 360) {
  252. // fanAnimateObj.rotate = 0;
  253. // }
  254. fanAnimateObj.animateId = window.requestAnimationFrame(fanAnimateFunction);
  255. };
  256. fanAnimateObj.stop = function() {
  257. window.cancelAnimationFrame(fanAnimateObj.animateId);
  258. };
  259. fanAnimateObj.start = function() {
  260. fanAnimateFunction();
  261. };
  262. fanAnimateFunction();
  263. fanAnimates.push(fanAnimateObj);
  264. return fanAnimateObj;
  265. },
  266. // 清空风机动画
  267. clearFanAnimate: function() {
  268. while (fanAnimates.length > 0) {
  269. let fanAnimateObj = fanAnimates.shift();
  270. fanAnimateObj.stop();
  271. }
  272. this.playAnimation = false;
  273. },
  274. // 开始风机动画
  275. startFanAnimate: function () {
  276. fans.forEach(fan => {
  277. this.initFanAnimate(fan);
  278. });
  279. this.playAnimation = true;
  280. },
  281. // 内容
  282. initContent: function() {
  283. // 加载3D地面
  284. let loaderGround = new GLTFLoader(); /*实例化加载器*/
  285. loaderGround.load(
  286. "static/3d/fanvar.gltf",
  287. (gltf) => {
  288. gltf.scene.position.set(17, 10, -12);
  289. // console.log(gltf);
  290. scene.add(gltf.scene);
  291. let rootNode = gltf.scene.children[0];
  292. let fan = gltf.scene.children[0].children[0];
  293. rootNode.remove(fan);
  294. this.setFanPosition(rootNode, fan);
  295. },
  296. (xhr) => {},
  297. function(error) {
  298. console.error("load error!" + error.getWebGLErrorMessage());
  299. }
  300. );
  301. loaderGround.load(
  302. "static/3d/lightvar.gltf",
  303. (gltf) => {
  304. gltf.scene.position.set(17, 10, -12);
  305. // console.log(gltf);
  306. scene.add(gltf.scene);
  307. let rootNode = gltf.scene.children[0];
  308. let light = gltf.scene.children[0].children[0];
  309. rootNode.remove(light);
  310. this.setLightPosition(rootNode, light);
  311. scene.onAfterRender = () => {
  312. this.$emit("when");
  313. this.$refs.pageLoading.hide();
  314. }
  315. },
  316. (xhr) => {},
  317. function(error) {
  318. console.error("load error!" + error.getWebGLErrorMessage());
  319. }
  320. );
  321. },
  322. // 改变元素底盘的颜色(带底盘的)
  323. changeObjectColor: function (obj, colorName) {
  324. let chassis = obj.getObjectByName(`${obj.name}_chassis`);
  325. let color = this.colors.find(t => t.colorName == colorName || t.state == colorName || t.stateName == colorName).color;
  326. chassis.material = new THREE.MeshBasicMaterial({
  327. color: color,
  328. opacity: 0.8,
  329. transparent: true,
  330. });
  331. },
  332. // 改变元素的颜色(光伏)
  333. changeElColor: function (obj, colorName) {
  334. let color = this.colors.find(t => t.colorName == colorName || t.state == colorName || t.stateName == colorName).color;
  335. for (let i = 1; i <= 6; i++) {
  336. let el = obj.getObjectByName(`${obj.name}_item_${i}`);
  337. el.material = new THREE.MeshBasicMaterial({
  338. color: color,
  339. opacity: 0.8,
  340. transparent: true,
  341. });
  342. }
  343. },
  344. // 设置风机name
  345. setFanName: function (obj, name) {
  346. obj.name = name;
  347. obj.userData.name = name;
  348. let fanBig1_1 = obj.getObjectByName("Box719");
  349. let fanBig1_2 = obj.getObjectByName("Box720");
  350. let fanBig1_3 = obj.getObjectByName("Box721");
  351. fanBig1_1.name = `${name}_leaf_1`;
  352. fanBig1_1.userData.name = `${name}_leaf_1`;
  353. fanBig1_2.name = `${name}_leaf_2`;
  354. fanBig1_2.userData.name = `${name}_leaf_2`;
  355. fanBig1_3.name = `${name}_leaf_3`;
  356. fanBig1_3.userData.name = `${name}_leaf_3`;
  357. obj.children[obj.children.length - 1].name = `${name}_chassis`;
  358. obj.children[obj.children.length - 1].userData.name = `${name}_chassis`;
  359. obj.remove(fanBig1_1, fanBig1_2, fanBig1_3);
  360. var group = new THREE.Group();
  361. // var group = new THREE.Mesh(new THREE.BoxGeometry(0.01, 0.01, 0.01),
  362. // new THREE.MeshBasicMaterial({
  363. // color: 0xff0000
  364. // })
  365. // );
  366. group.position.set(group.position.x + 0.0067, group.position.y, group.position.z + 0.01);
  367. fanBig1_1.position.set(fanBig1_1.position.x - 0.0067, fanBig1_1.position.y , fanBig1_1.position.z- 0.01);
  368. fanBig1_2.position.set(fanBig1_2.position.x - 0.0067, fanBig1_2.position.y, fanBig1_2.position.z- 0.01);
  369. fanBig1_3.position.set(fanBig1_3.position.x - 0.0067, fanBig1_3.position.y, fanBig1_3.position.z- 0.01);
  370. group.add(fanBig1_1, fanBig1_2, fanBig1_3);
  371. obj.add(group);
  372. group.name = `${name}_leaf`;
  373. },
  374. // 设置风机位置 颜色
  375. setFanPosition: function (rootNode, obj) {
  376. // 麻黄山
  377. let fan_mhs = obj.clone(true);
  378. fan_mhs.position.set(10, 5, -4);
  379. this.setFanName(fan_mhs, "fan_mhs");
  380. rootNode.add(fan_mhs);
  381. // this.initCylinderGeometry(fan_mhs.position);
  382. this.htmlLayer[0].position = fan_mhs.position;
  383. // 牛首山
  384. let fan_nss = obj.clone(true);
  385. fan_nss.position.set(-4, 4, -15);
  386. this.setFanName(fan_nss, "fan_nss");
  387. rootNode.add(fan_nss);
  388. // this.initCylinderGeometry(fan_nss.position);
  389. this.htmlLayer[1].position = fan_nss.position;
  390. // 青山
  391. let fan_qs = obj.clone(true);
  392. fan_qs.position.set(15, 5, -9);
  393. this.setFanName(fan_qs, "fan_qs");
  394. rootNode.add(fan_qs);
  395. // this.initCylinderGeometry(fan_qs.position);
  396. this.htmlLayer[2].position = fan_qs.position;
  397. // 石板泉
  398. let fan_sbq = obj.clone(true);
  399. fan_sbq.position.set(4, 5, -2);
  400. this.setFanName(fan_sbq, "fan_sbq");
  401. rootNode.add(fan_sbq);
  402. // this.initCylinderGeometry(fan_sbq.position);
  403. this.htmlLayer[3].position = fan_sbq.position;
  404. // 香山
  405. let fan_xs = obj.clone(true);
  406. fan_xs.position.set(-9, 7, 21);
  407. this.setFanName(fan_xs, "fan_xs");
  408. rootNode.add(fan_xs);
  409. // this.initCylinderGeometry(fan_xs.position);
  410. this.htmlLayer[4].position = fan_xs.position;
  411. // 改一下颜色
  412. this.changeObjectColor(fan_mhs, 'green'); // 麻黄山
  413. this.changeObjectColor(fan_nss, 'xd'); // 牛首山
  414. this.changeObjectColor(fan_qs, '检修'); // 青山
  415. this.changeObjectColor(fan_sbq, 'white'); // 石板泉
  416. this.changeObjectColor(fan_xs, '运行'); // 香山
  417. // 风机存入数组
  418. fans.push(fan_mhs);
  419. fans.push(fan_nss);
  420. fans.push(fan_qs);
  421. fans.push(fan_sbq);
  422. fans.push(fan_xs);
  423. // 开始风机动画
  424. this.startFanAnimate();
  425. // 设置位置
  426. this.setEveryHTML();
  427. },
  428. // 设置光伏name
  429. setLightName: function (obj, name) {
  430. obj.name = name;
  431. obj.userData.name = name;
  432. let Box661 = obj.getObjectByName("Box661");
  433. let Box668 = obj.getObjectByName("Box668");
  434. let Box669 = obj.getObjectByName("Box669");
  435. let Box664 = obj.getObjectByName("Box664");
  436. let Box667 = obj.getObjectByName("Box667");
  437. let Box670 = obj.getObjectByName("Box670");
  438. Box661.name = `${name}_item_1`;
  439. Box661.userData.name = `${name}_item_1`;
  440. Box668.name = `${name}_item_2`;
  441. Box668.userData.name = `${name}_item_2`;
  442. Box669.name = `${name}_item_3`;
  443. Box669.userData.name = `${name}_item_3`;
  444. Box664.name = `${name}_item_4`;
  445. Box664.userData.name = `${name}_item_4`;
  446. Box667.name = `${name}_item_5`;
  447. Box667.userData.name = `${name}_item_5`;
  448. Box670.name = `${name}_item_6`;
  449. Box670.userData.name = `${name}_item_6`;
  450. },
  451. // 设置光伏位置 颜色
  452. setLightPosition: function (rootNode, obj) {
  453. let Box660 = obj.getObjectByName("Box660");
  454. let Box666 = obj.getObjectByName("Box666");
  455. let Box662 = obj.getObjectByName("Box662");
  456. let Box663 = obj.getObjectByName("Box663");
  457. let Box659 = obj.getObjectByName("Box659");
  458. let Box665 = obj.getObjectByName("Box665");
  459. obj.remove(Box660);
  460. obj.remove(Box666);
  461. obj.remove(Box662);
  462. obj.remove(Box663);
  463. obj.remove(Box659);
  464. obj.remove(Box665);
  465. // 大武口
  466. let light_dwk = obj.clone(true);
  467. light_dwk.position.set(-6, 0.13, -53);
  468. this.setLightName(light_dwk, "light_dwk");
  469. rootNode.add(light_dwk);
  470. this.htmlLayer[5].position = light_dwk.position;
  471. // 平罗
  472. let light_pl = obj.clone(true);
  473. light_pl.position.set(-3, 0.13, -60);
  474. this.setLightName(light_pl, "light_pl");
  475. rootNode.add(light_pl);
  476. this.htmlLayer[6].position = light_pl.position;
  477. // 马场湖
  478. let light_mch = obj.clone(true);
  479. light_mch.position.set(-27, 2, -30);
  480. this.setLightName(light_mch, "light_mch");
  481. rootNode.add(light_mch);
  482. this.htmlLayer[7].position = light_mch.position;
  483. // 宣和
  484. let light_xh = obj.clone(true);
  485. light_xh.position.set(-18, 4, -27);
  486. this.setLightName(light_xh, "light_xh");
  487. rootNode.add(light_xh);
  488. this.htmlLayer[8].position = light_xh.position;
  489. // 海子井
  490. let light_hzj = obj.clone(true);
  491. light_hzj.position.set(-10, 2, -26);
  492. this.setLightName(light_hzj, "light_hzj");
  493. rootNode.add(light_hzj);
  494. this.htmlLayer[9].position = light_hzj.position;
  495. // 改变颜色
  496. this.changeElColor(light_dwk, 'green'); // 大武口
  497. this.changeElColor(light_pl, '离线'); // 平罗
  498. this.changeElColor(light_mch, 'yx'); // 马场湖
  499. this.changeElColor(light_xh, 'red'); // 宣和
  500. this.changeElColor(light_hzj, '受累'); // 海子井
  501. },
  502. // 创建一个圆柱
  503. initCylinderGeometry: function(position, cr=2) {
  504. let geometry = new THREE.CylinderGeometry(cr, cr, 7, 64);
  505. //加载纹理
  506. let texture = new THREE.TextureLoader().load("static/3d/beam-texture.png");
  507. texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复
  508. texture.repeat.set(1, 1);
  509. texture.needsUpdate = true;
  510. let materials = [
  511. //圆柱侧面材质,使用纹理贴图
  512. new THREE.MeshBasicMaterial({
  513. map: texture,
  514. side: THREE.DoubleSide,
  515. transparent: true,
  516. }),
  517. //圆柱顶材质
  518. new THREE.MeshBasicMaterial({
  519. transparent: true,
  520. opacity: 0,
  521. side: THREE.DoubleSide,
  522. }),
  523. //圆柱底材质
  524. new THREE.MeshBasicMaterial({
  525. transparent: true,
  526. opacity: 0,
  527. side: THREE.DoubleSide,
  528. }),
  529. ];
  530. cylinder = new THREE.Mesh(geometry, materials);
  531. cylinder.position.set(position.x + 5.75, position.y + 8, position.z);
  532. scene.add(cylinder);
  533. },
  534. // 设置每一个html的位置
  535. setEveryHTML: function() {
  536. this.htmlLayer.forEach(value => {
  537. if (value.show && value.position) {
  538. const screen = this.vector3ToScreen(value.position);
  539. value.x = screen.x + value.ox;
  540. value.y = screen.y + value.oy;
  541. }
  542. });
  543. },
  544. // 初始化云
  545. initCloud: function () {
  546. },
  547. // 初始化
  548. initThree: function() {
  549. this.initScene();
  550. // this.initAxesHelper();
  551. this.initCamera();
  552. this.initRender();
  553. this.initLight();
  554. this.initControls();
  555. this.initContent();
  556. this.initCloud();
  557. renderer.setAnimationLoop(this.animate);
  558. },
  559. // 动画
  560. animate: function() {
  561. renderer.render(scene, camera);
  562. },
  563. },
  564. // 生命周期钩子
  565. beforeCreate() {
  566. // 创建前
  567. },
  568. created() {
  569. // 创建后
  570. },
  571. beforeMount() {
  572. // 渲染前
  573. },
  574. mounted() {
  575. // 渲染后
  576. this.initThree();
  577. },
  578. beforeUpdate() {
  579. // 数据更新前
  580. },
  581. updated() {
  582. // 数据更新后
  583. },
  584. beforeUnmount() {
  585. // 销毁前
  586. renderer.setAnimationLoop(null);
  587. camera = null;
  588. scene = null;
  589. renderer = null;
  590. },
  591. };
  592. </script>
  593. <style lang="less" scoped>
  594. .three-model {
  595. position: relative;
  596. overflow: hidden;
  597. left: -112px;
  598. .map-3d {
  599. position: absolute;
  600. width: 1118px;
  601. height: 678px;
  602. left: calc(50% - 559px);
  603. top: calc(50% - 339px);
  604. z-index: -1;
  605. map {
  606. width: 100%;
  607. height: 100%;
  608. }
  609. }
  610. .three-html-layer {
  611. .three-html-dom {
  612. position: absolute;
  613. }
  614. .fan-name {
  615. display: inline-block;
  616. height: 22px;
  617. background: #222632;
  618. border: 1px solid #646464;
  619. border-radius: 10px;
  620. padding: 0 10px;
  621. font-size: 12px;
  622. font-weight: 400;
  623. color: #FFFFFF;
  624. line-height: 22px;
  625. }
  626. }
  627. }
  628. </style>