|
@@ -0,0 +1,978 @@
|
|
|
+<template>
|
|
|
+ <div class="three-model">
|
|
|
+ <loading ref="pageLoading"></loading>
|
|
|
+ <div class="map-3d" :style="'transform: rotate(' + mapDeg + 'deg);'">
|
|
|
+ <img :src="require('@assets/png/3dmap.png')" alt="" />
|
|
|
+ </div>
|
|
|
+ <div class="three-html-layer">
|
|
|
+ <div v-for="(info, index) of htmlLayer" :key="index" class="three-html-dom fan-info" :id="info.id"
|
|
|
+ v-show="info.show" :style="'left: ' + info.x + 'px; top: ' + info.y + 'px;'">
|
|
|
+ <div class="fan-name pointer" @click.stop="info.clickName">
|
|
|
+ {{ info.name }}
|
|
|
+ </div>
|
|
|
+ <div class="fan-can-click" @click.stop="info.clickFan" :style="
|
|
|
+ 'left: ' +
|
|
|
+ info.fanX +
|
|
|
+ 'px; top: ' +
|
|
|
+ info.fanY +
|
|
|
+ 'px; width: ' +
|
|
|
+ info.fanW +
|
|
|
+ 'px; height: ' +
|
|
|
+ info.fanH +
|
|
|
+ 'px;'
|
|
|
+ "></div>
|
|
|
+ </div>
|
|
|
+ <div class="three-html-dom build-info" :id="fanInfoLayer.id" v-show="fanInfoLayer.show" :style="
|
|
|
+ 'left: ' + fanInfoLayer.x + 'px; top: ' + fanInfoLayer.y + 'px;'
|
|
|
+ ">
|
|
|
+ <div class="build-info-close" @click.stop="hideFanInfo">
|
|
|
+ <i class="el-icon-close"></i>
|
|
|
+ </div>
|
|
|
+ <div class="build-info-item purple" :style="
|
|
|
+ 'left: ' + circleXY[0].x + 'px; top: -' + circleXY[0].y + 'px'
|
|
|
+ ">
|
|
|
+ <div class="build-info-item-num">{{ jkd }}</div>
|
|
|
+ <div class="build-info-item-text">健康度</div>
|
|
|
+ </div>
|
|
|
+ <div class="build-info-item blue" :style="
|
|
|
+ 'left: ' + circleXY[1].x + 'px; top: -' + circleXY[1].y + 'px'
|
|
|
+ ">
|
|
|
+ <div class="build-info-item-num">{{ ysl }}</div>
|
|
|
+ <div class="build-info-item-text">优</div>
|
|
|
+ </div>
|
|
|
+ <div class="build-info-item yellow" :style="
|
|
|
+ 'left: ' + circleXY[2].x + 'px; top: -' + circleXY[2].y + 'px'
|
|
|
+ ">
|
|
|
+ <div class="build-info-item-num">{{ lsl }}</div>
|
|
|
+ <div class="build-info-item-text">良</div>
|
|
|
+ </div>
|
|
|
+ <div class="build-info-item orange" :style="
|
|
|
+ 'left: ' + circleXY[3].x + 'px; top: -' + circleXY[3].y + 'px'
|
|
|
+ ">
|
|
|
+ <div class="build-info-item-num">{{ csl }}</div>
|
|
|
+ <div class="build-info-item-text">差</div>
|
|
|
+ </div>
|
|
|
+ <div class="build-info-item red" :style="
|
|
|
+ 'left: ' + circleXY[4].x + 'px; top: -' + circleXY[4].y + 'px'
|
|
|
+ ">
|
|
|
+ <div class="build-info-item-num">{{ gzsl }}</div>
|
|
|
+ <div class="build-info-item-text">故障</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+ import loading from "@com/coms/loading/loading.vue";
|
|
|
+ import * as THREE from "three";
|
|
|
+ import {
|
|
|
+ GLTFLoader
|
|
|
+ } from "@node/three/examples/jsm/loaders/GLTFLoader.js";
|
|
|
+ import {
|
|
|
+ OrbitControls
|
|
|
+ } from "@node/three/examples/jsm/controls/OrbitControls.js";
|
|
|
+ import {
|
|
|
+ GeometryUtils
|
|
|
+ } from "@node/three/examples/jsm/utils/GeometryUtils.js";
|
|
|
+ let camera, scene, renderer, controls;
|
|
|
+ let mixers = [];
|
|
|
+ let clock = new THREE.Clock();
|
|
|
+ let fanAnimates = [];
|
|
|
+ let fans = [];
|
|
|
+ // let cylinder = null;
|
|
|
+ export default {
|
|
|
+ // 名称
|
|
|
+ name: "ThreeModel1",
|
|
|
+ // 使用组件
|
|
|
+ components: {
|
|
|
+ loading,
|
|
|
+ },
|
|
|
+ // 传入参数
|
|
|
+ props: {
|
|
|
+ data: {
|
|
|
+ type: Object,
|
|
|
+ default: () => {},
|
|
|
+ },
|
|
|
+ },
|
|
|
+ // 自定义事件
|
|
|
+ emits: {
|
|
|
+ when: null,
|
|
|
+ },
|
|
|
+ // 数据
|
|
|
+ data() {
|
|
|
+ const that = this;
|
|
|
+ return {
|
|
|
+ mapSource: {},
|
|
|
+ pointer: false,
|
|
|
+ jkd: null,
|
|
|
+ ysl: null,
|
|
|
+ lsl: null,
|
|
|
+ csl: null,
|
|
|
+ gzsl: null,
|
|
|
+ htmlLayer: [
|
|
|
+ //惠安
|
|
|
+ {
|
|
|
+ id: "fan-huian",
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ show: true,
|
|
|
+ ox: 28,
|
|
|
+ oy: 10,
|
|
|
+ fanW: 70,
|
|
|
+ fanH: 100,
|
|
|
+ fanX: -15,
|
|
|
+ fanY: -110,
|
|
|
+ position: null,
|
|
|
+ name: "惠安风场",
|
|
|
+ clickName: function () {
|
|
|
+ that.clickMapItem(
|
|
|
+ [
|
|
|
+ "XS_FDC_SC",
|
|
|
+ "XG01_26_TD",
|
|
|
+ "XG01_27_TD",
|
|
|
+ "XG01_29_TD",
|
|
|
+ "XG01_30_TD",
|
|
|
+ "XG01_31_TD",
|
|
|
+ ],
|
|
|
+ "XS_FDC"
|
|
|
+ );
|
|
|
+ },
|
|
|
+ clickFan: () => {
|
|
|
+ that.showFanInfo(that.htmlLayer[0].position);
|
|
|
+ that.jkd = that.htmlLayer[0].jkd;
|
|
|
+ that.ysl = that.htmlLayer[0].ysl;
|
|
|
+ that.lsl = that.htmlLayer[0].lsl;
|
|
|
+ that.csl = that.htmlLayer[0].csl;
|
|
|
+ that.gzsl = that.htmlLayer[0].gzsl;
|
|
|
+ that.clickMapItem(
|
|
|
+ [
|
|
|
+ "XS_FDC_SC",
|
|
|
+ "XG01_26_TD",
|
|
|
+ "XG01_27_TD",
|
|
|
+ "XG01_29_TD",
|
|
|
+ "XG01_30_TD",
|
|
|
+ "XG01_31_TD",
|
|
|
+ ],
|
|
|
+ "XS_FDC"
|
|
|
+ );
|
|
|
+ },
|
|
|
+ },
|
|
|
+ // 大楼
|
|
|
+ {
|
|
|
+ id: "build",
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ show: true,
|
|
|
+ ox: 27,
|
|
|
+ oy: 20,
|
|
|
+ fanW: 60,
|
|
|
+ fanH: 100,
|
|
|
+ fanX: -260,
|
|
|
+ fanY: -200,
|
|
|
+ position: null,
|
|
|
+ name: "宁夏分公司",
|
|
|
+ clickName: function () {
|
|
|
+ that.clickMapItem(
|
|
|
+ [
|
|
|
+ "SBQ_FDC_SC",
|
|
|
+ "NSS_FDC_SC",
|
|
|
+ "QS_FDC_SC",
|
|
|
+ "MHS_FDC_SC",
|
|
|
+ "XS_FDC_SC",
|
|
|
+ "PL_GDC_SC",
|
|
|
+ ],
|
|
|
+ "0"
|
|
|
+ );
|
|
|
+ },
|
|
|
+ clickFan: () => {
|
|
|
+ that.showFanInfo(that.htmlLayer[1].position);
|
|
|
+ that.jkd = that.htmlLayer[1].jkd;
|
|
|
+ that.ysl = that.htmlLayer[1].ysl;
|
|
|
+ that.lsl = that.htmlLayer[1].lsl;
|
|
|
+ that.csl = that.htmlLayer[1].csl;
|
|
|
+ that.gzsl = that.htmlLayer[1].gzsl;
|
|
|
+ that.clickMapItem(
|
|
|
+ [
|
|
|
+ "SBQ_FDC_SC",
|
|
|
+ "NSS_FDC_SC",
|
|
|
+ "QS_FDC_SC",
|
|
|
+ "MHS_FDC_SC",
|
|
|
+ "XS_FDC_SC",
|
|
|
+ "PL_GDC_SC",
|
|
|
+ ],
|
|
|
+ "0"
|
|
|
+ );
|
|
|
+ },
|
|
|
+ },
|
|
|
+ // 宁东光伏
|
|
|
+ {
|
|
|
+ id: "light-ndgf",
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ show: true,
|
|
|
+ ox: 315,
|
|
|
+ oy: 100,
|
|
|
+ fanW: 60,
|
|
|
+ fanH: 80,
|
|
|
+ fanX: 0,
|
|
|
+ fanY: -80,
|
|
|
+ position: null,
|
|
|
+ name: "宁东光伏",
|
|
|
+ clickName: function () {
|
|
|
+ console.log("宁东光伏");
|
|
|
+ },
|
|
|
+ clickFan: () => {
|
|
|
+ console.log("宁东光伏");
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ fanInfoLayer: {
|
|
|
+ id: "fan-info",
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ show: false,
|
|
|
+ ox: 70,
|
|
|
+ oy: -40,
|
|
|
+ position: null,
|
|
|
+ },
|
|
|
+ circleXY: [{
|
|
|
+ x: 130 * Math.cos((180 / 180) * Math.PI) - 33,
|
|
|
+ y: 130 * Math.sin((180 / 180) * Math.PI) + 33,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ x: 130 * Math.cos((135 / 180) * Math.PI) - 33,
|
|
|
+ y: 130 * Math.sin((135 / 180) * Math.PI) + 33,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ x: 130 * Math.cos((90 / 180) * Math.PI) - 33,
|
|
|
+ y: 130 * Math.sin((90 / 180) * Math.PI) + 33,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ x: 130 * Math.cos((45 / 180) * Math.PI) - 33,
|
|
|
+ y: 130 * Math.sin((45 / 180) * Math.PI) + 33,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ x: 130 * Math.cos((0 / 180) * Math.PI) - 33,
|
|
|
+ y: 130 * Math.sin((0 / 180) * Math.PI) + 33,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ colors: [{
|
|
|
+ colorName: "green",
|
|
|
+ state: "dj",
|
|
|
+ stateName: "待机",
|
|
|
+ color: 0x05bb4c
|
|
|
+ },
|
|
|
+ {
|
|
|
+ colorName: "blue",
|
|
|
+ state: "yx",
|
|
|
+ stateName: "运行",
|
|
|
+ color: 0x4b55ae
|
|
|
+ },
|
|
|
+ {
|
|
|
+ colorName: "pink",
|
|
|
+ state: "xd",
|
|
|
+ stateName: "限电",
|
|
|
+ color: 0xc531c7
|
|
|
+ },
|
|
|
+ {
|
|
|
+ colorName: "red",
|
|
|
+ state: "gz",
|
|
|
+ stateName: "故障",
|
|
|
+ color: 0xba3237
|
|
|
+ },
|
|
|
+ {
|
|
|
+ colorName: "orange",
|
|
|
+ state: "jx",
|
|
|
+ stateName: "检修",
|
|
|
+ color: 0xe17e23,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ colorName: "gray",
|
|
|
+ state: "lx",
|
|
|
+ stateName: "离线",
|
|
|
+ color: 0x606769
|
|
|
+ },
|
|
|
+ {
|
|
|
+ colorName: "white",
|
|
|
+ state: "sl",
|
|
|
+ stateName: "受累",
|
|
|
+ color: 0xffffff
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ fanName: "",
|
|
|
+ playAnimation: true,
|
|
|
+ mapDeg: 0,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 函数
|
|
|
+ methods: {
|
|
|
+ rinseData() {
|
|
|
+ if (this.mapSource && this.mapSource.MHS_FDC) {
|
|
|
+ for (let pKey in this.mapSource) {
|
|
|
+ if (pKey === "all") {
|
|
|
+ for (let cKey in this.mapSource[pKey]) {
|
|
|
+ this.htmlLayer[10][cKey] = this.mapSource[pKey][cKey];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.htmlLayer.forEach((ele) => {
|
|
|
+ if (
|
|
|
+ pKey.toLowerCase().indexOf(ele.id.toLowerCase().split("-")[1]) !==
|
|
|
+ -1
|
|
|
+ ) {
|
|
|
+ for (let cKey in this.mapSource[pKey]) {
|
|
|
+ ele[cKey] = this.mapSource[pKey][cKey];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 点击风场或者光伏传回点击的值
|
|
|
+ clickMapItem(videoArray = [], wpId = "") {
|
|
|
+ this.$emit("clickMapItem", videoArray, wpId);
|
|
|
+ },
|
|
|
+ // Vector3 to screen
|
|
|
+ vector3ToScreen(position) {
|
|
|
+ const centerX = this.$el.scrollWidth / 2;
|
|
|
+ const centerY = this.$el.scrollHeight / 2;
|
|
|
+ const v3 = new THREE.Vector3(position.x, position.y, position.z);
|
|
|
+ const standardVec = v3.project(camera);
|
|
|
+ const screenX = Math.round(centerX * standardVec.x + centerX);
|
|
|
+ const screenY = Math.round(-centerY * standardVec.y + centerY);
|
|
|
+ return {
|
|
|
+ x: screenX,
|
|
|
+ y: screenY
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 场景
|
|
|
+ initScene() {
|
|
|
+ scene = new THREE.Scene();
|
|
|
+ // scene.background = new THREE.Color(0xa0a0a0);
|
|
|
+ },
|
|
|
+ // 相机
|
|
|
+ initCamera() {
|
|
|
+ camera = new THREE.PerspectiveCamera(
|
|
|
+ 45,
|
|
|
+ this.$el.scrollWidth / this.$el.scrollHeight,
|
|
|
+ 0.1,
|
|
|
+ 10000
|
|
|
+ );
|
|
|
+ camera.position.set(50, 50, 50);
|
|
|
+ },
|
|
|
+ // 坐标轴
|
|
|
+ initAxesHelper() {
|
|
|
+ const axesHelper = new THREE.AxesHelper(150);
|
|
|
+ scene.add(axesHelper);
|
|
|
+ axesHelper.position.set(0, 0, 0);
|
|
|
+ },
|
|
|
+ // 渲染器
|
|
|
+ initRender() {
|
|
|
+ renderer = new THREE.WebGLRenderer({
|
|
|
+ antialias: true,
|
|
|
+ alpha: true
|
|
|
+ });
|
|
|
+ // renderer.setClearAlpha(0);
|
|
|
+ renderer.setSize(this.$el.scrollWidth, this.$el.scrollHeight);
|
|
|
+ this.$el.append(renderer.domElement);
|
|
|
+ },
|
|
|
+ // 灯光
|
|
|
+ initLight() {
|
|
|
+ // let light = new THREE.PointLight(0xffffff, 2);
|
|
|
+ let light = new THREE.AmbientLight(0xffffff, 5);
|
|
|
+ // light.position.set(50, 50, 50);
|
|
|
+ scene.add(light);
|
|
|
+ },
|
|
|
+ // 控制器
|
|
|
+ initControls() {
|
|
|
+ controls = new OrbitControls(camera, renderer.domElement);
|
|
|
+ controls.enablePan = false;
|
|
|
+ controls.maxPolarAngle = (45 / 180) * Math.PI;
|
|
|
+ controls.minPolarAngle = (45 / 180) * Math.PI;
|
|
|
+ controls.maxAzimuthAngle = (45 / 180) * Math.PI;
|
|
|
+ controls.minAzimuthAngle = (45 / 180) * Math.PI;
|
|
|
+ controls.enableKeys = false;
|
|
|
+ controls.enableZoom = false;
|
|
|
+ controls.update();
|
|
|
+ // controls.maxAzimuthAngle = 50 / 180 * Math.PI;
|
|
|
+ // controls.minAzimuthAngle = 40 / 180 * Math.PI;
|
|
|
+ // controls.addEventListener("change", () => {
|
|
|
+ // let cDeg = controls.getAzimuthalAngle() / Math.PI * 180;
|
|
|
+ // this.mapDeg = cDeg - 40 - 5;
|
|
|
+ // this.setEveryHTML();
|
|
|
+ // });
|
|
|
+ },
|
|
|
+ // 初始化一个风机动画
|
|
|
+ initFanAnimate(obj) {
|
|
|
+ let fanAnimateObj = {
|
|
|
+ speed: 0.05,
|
|
|
+ rotate: 0,
|
|
|
+ fan: obj.getObjectByName(`${obj.name}_leaf`),
|
|
|
+ fan1: obj.getObjectByName(`${obj.name}_leaf_1`),
|
|
|
+ fan2: obj.getObjectByName(`${obj.name}_leaf_2`),
|
|
|
+ fan3: obj.getObjectByName(`${obj.name}_leaf_3`),
|
|
|
+ };
|
|
|
+ let fanAnimateFunction = function () {
|
|
|
+ // fanAnimateObj.fan.rotateOnAxis(new THREE.Vector3(0, 1, 0), fanAnimateObj.speed);
|
|
|
+ fanAnimateObj.fan.rotateY(fanAnimateObj.speed);
|
|
|
+ // fanAnimateObj.fan1.rotateZ(fanAnimateObj.speed);
|
|
|
+ // fanAnimateObj.fan2.rotateZ(fanAnimateObj.speed);
|
|
|
+ // fanAnimateObj.fan3.rotateZ(fanAnimateObj.speed);
|
|
|
+ // fanAnimateObj.rotate += fanAnimateObj.speed;
|
|
|
+ // if (fanAnimateObj.rotate >= 360) {
|
|
|
+ // fanAnimateObj.rotate = 0;
|
|
|
+ // }
|
|
|
+ fanAnimateObj.animateId =
|
|
|
+ window.requestAnimationFrame(fanAnimateFunction);
|
|
|
+ };
|
|
|
+ fanAnimateObj.stop = function () {
|
|
|
+ window.cancelAnimationFrame(fanAnimateObj.animateId);
|
|
|
+ };
|
|
|
+ fanAnimateObj.start = function () {
|
|
|
+ fanAnimateFunction();
|
|
|
+ };
|
|
|
+ fanAnimateFunction();
|
|
|
+ fanAnimates.push(fanAnimateObj);
|
|
|
+ return fanAnimateObj;
|
|
|
+ },
|
|
|
+ // 清空风机动画
|
|
|
+ clearFanAnimate: function () {
|
|
|
+ while (fanAnimates.length > 0) {
|
|
|
+ let fanAnimateObj = fanAnimates.shift();
|
|
|
+ fanAnimateObj.stop();
|
|
|
+ }
|
|
|
+ this.playAnimation = false;
|
|
|
+ },
|
|
|
+ // 开始风机动画
|
|
|
+ startFanAnimate: function () {
|
|
|
+ fans.forEach((fan) => {
|
|
|
+ this.initFanAnimate(fan);
|
|
|
+ });
|
|
|
+ this.playAnimation = true;
|
|
|
+ },
|
|
|
+ // 内容
|
|
|
+ initContent() {
|
|
|
+ // 加载3D地面
|
|
|
+ let loaderGround = new GLTFLoader(); /*实例化加载器*/
|
|
|
+ loaderGround.load(
|
|
|
+ "static/3d/fanvar.gltf",
|
|
|
+ (gltf) => {
|
|
|
+ gltf.scene.position.set(17, 10, -12);
|
|
|
+ scene.add(gltf.scene);
|
|
|
+ let rootNode = gltf.scene.children[0];
|
|
|
+ let fan = gltf.scene.children[0].children[0];
|
|
|
+ rootNode.remove(fan);
|
|
|
+ this.setFanPosition(rootNode, fan);
|
|
|
+ },
|
|
|
+ (xhr) => {},
|
|
|
+ function (error) {
|
|
|
+ console.error("load error!" + error.getWebGLErrorMessage());
|
|
|
+ }
|
|
|
+ );
|
|
|
+ loaderGround.load(
|
|
|
+ "static/3d/light.gltf",
|
|
|
+ (gltf) => {
|
|
|
+ gltf.scene.position.set(17, 10, -12);
|
|
|
+ scene.add(gltf.scene);
|
|
|
+ let rootNode = gltf.scene.children[0];
|
|
|
+ let light = gltf.scene.children[0].children[0];
|
|
|
+ rootNode.remove(light);
|
|
|
+ this.setLightPosition(rootNode, light);
|
|
|
+ },
|
|
|
+ (xhr) => {},
|
|
|
+ function (error) {
|
|
|
+ console.error("load error!" + error.getWebGLErrorMessage());
|
|
|
+ }
|
|
|
+ );
|
|
|
+ loaderGround.load(
|
|
|
+ "static/3d/build.gltf",
|
|
|
+ (gltf) => {
|
|
|
+ gltf.scene.position.set(0, 0, -35); // 10, 0, -50 -6, 0.13, -50
|
|
|
+ scene.add(gltf.scene);
|
|
|
+ gltf.scene.rotateY(120);
|
|
|
+ this.htmlLayer[1].position = {
|
|
|
+ x: -6,
|
|
|
+ y: -4,
|
|
|
+ z: -35,
|
|
|
+ };
|
|
|
+ scene.onAfterRender = () => {
|
|
|
+ this.$emit("when");
|
|
|
+ this.$refs.pageLoading.hide();
|
|
|
+ this.setEveryHTML();
|
|
|
+ };
|
|
|
+ },
|
|
|
+ (xhr) => {},
|
|
|
+ function (error) {
|
|
|
+ console.error("load error!" + error.getWebGLErrorMessage());
|
|
|
+ }
|
|
|
+ );
|
|
|
+ },
|
|
|
+ // 改变元素底盘的颜色(带底盘的)
|
|
|
+ changeObjectColor(obj, colorName) {
|
|
|
+ for (let i = 1; i <= 4; i++) {
|
|
|
+ let c = obj.getObjectByName(`${obj.name}_c_${i}`);
|
|
|
+ c.material = new THREE.MeshBasicMaterial({
|
|
|
+ color: 0xf0f0f0,
|
|
|
+ opacity: 0.8,
|
|
|
+ transparent: true,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ let leaf = obj.getObjectByName(`${obj.name}_leaf`);
|
|
|
+ for (let chind of leaf.children) {
|
|
|
+ chind.material = new THREE.MeshBasicMaterial({
|
|
|
+ color: 0xf0f0f0,
|
|
|
+ opacity: 0.8,
|
|
|
+ transparent: true,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ let chassis = obj.getObjectByName(`${obj.name}_chassis`);
|
|
|
+ // let color = this.colors.find(t => t.colorName == colorName || t.state == colorName || t.stateName == colorName).color;
|
|
|
+ chassis.material = new THREE.MeshBasicMaterial({
|
|
|
+ // color: color,
|
|
|
+ color: 0xf0f0f0,
|
|
|
+ opacity: 0.8,
|
|
|
+ transparent: true,
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 改变元素的颜色(光伏)
|
|
|
+ changeElColor(obj, colorName) {
|
|
|
+ // let color = this.colors.find(t => t.colorName == colorName || t.state == colorName || t.stateName == colorName).color;
|
|
|
+ // for (let i = 1; i <= 6; i++) {
|
|
|
+ // let el = obj.getObjectByName(`${obj.name}_item_${i}`);
|
|
|
+ // el.material = new THREE.MeshBasicMaterial({
|
|
|
+ // color: color,
|
|
|
+ // opacity: 0.8,
|
|
|
+ // transparent: true,
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ // 设置风机name
|
|
|
+ setFanName(obj, name) {
|
|
|
+ obj.name = name;
|
|
|
+ obj.userData.name = name;
|
|
|
+ // "Cylinder881" "Cone277"
|
|
|
+ let Cylinder881 = obj.getObjectByName("Cylinder881");
|
|
|
+ let Cylinder882 = obj.getObjectByName("Cylinder882");
|
|
|
+ let Cylinder883 = obj.getObjectByName("Cylinder883");
|
|
|
+ let Cone277 = obj.getObjectByName("Cone277");
|
|
|
+ Cylinder881.name = `${name}_c_1`;
|
|
|
+ Cylinder881.userData.name = `${name}_c_1`;
|
|
|
+ Cylinder882.name = `${name}_c_2`;
|
|
|
+ Cylinder882.userData.name = `${name}_c_2`;
|
|
|
+ Cylinder883.name = `${name}_c_3`;
|
|
|
+ Cylinder883.userData.name = `${name}_c_3`;
|
|
|
+ Cone277.name = `${name}_c_4`;
|
|
|
+ Cone277.userData.name = `${name}_c_4`;
|
|
|
+ // "Box719")
|
|
|
+ let fanBig1_1 = obj.getObjectByName("Box719");
|
|
|
+ let fanBig1_2 = obj.getObjectByName("Box720");
|
|
|
+ let fanBig1_3 = obj.getObjectByName("Box721");
|
|
|
+ fanBig1_1.name = `${name}_leaf_1`;
|
|
|
+ fanBig1_1.userData.name = `${name}_leaf_1`;
|
|
|
+ fanBig1_2.name = `${name}_leaf_2`;
|
|
|
+ fanBig1_2.userData.name = `${name}_leaf_2`;
|
|
|
+ fanBig1_3.name = `${name}_leaf_3`;
|
|
|
+ fanBig1_3.userData.name = `${name}_leaf_3`;
|
|
|
+ obj.children[obj.children.length - 1].name = `${name}_chassis`;
|
|
|
+ obj.children[obj.children.length - 1].userData.name = `${name}_chassis`;
|
|
|
+ obj.remove(fanBig1_1, fanBig1_2, fanBig1_3);
|
|
|
+ var group = new THREE.Group();
|
|
|
+ // var group = new THREE.Mesh(new THREE.BoxGeometry(0.01, 0.01, 0.01),
|
|
|
+ // new THREE.MeshBasicMaterial({
|
|
|
+ // color: 0xff0000
|
|
|
+ // })
|
|
|
+ // );
|
|
|
+ group.position.set(
|
|
|
+ group.position.x + 0.0067,
|
|
|
+ group.position.y,
|
|
|
+ group.position.z + 0.01
|
|
|
+ );
|
|
|
+ fanBig1_1.position.set(
|
|
|
+ fanBig1_1.position.x - 0.0067,
|
|
|
+ fanBig1_1.position.y,
|
|
|
+ fanBig1_1.position.z - 0.01
|
|
|
+ );
|
|
|
+ fanBig1_2.position.set(
|
|
|
+ fanBig1_2.position.x - 0.0067,
|
|
|
+ fanBig1_2.position.y,
|
|
|
+ fanBig1_2.position.z - 0.01
|
|
|
+ );
|
|
|
+ fanBig1_3.position.set(
|
|
|
+ fanBig1_3.position.x - 0.0067,
|
|
|
+ fanBig1_3.position.y,
|
|
|
+ fanBig1_3.position.z - 0.01
|
|
|
+ );
|
|
|
+ group.add(fanBig1_1, fanBig1_2, fanBig1_3);
|
|
|
+ obj.add(group);
|
|
|
+ group.name = `${name}_leaf`;
|
|
|
+ },
|
|
|
+ // 设置风机位置 颜色
|
|
|
+ setFanPosition(rootNode, obj) {
|
|
|
+
|
|
|
+ //惠安
|
|
|
+ let fan_huian = obj.clone(true);
|
|
|
+ fan_huian.position.set(-9, -15, -20);
|
|
|
+ this.setFanName(fan_huian, "fan_huian");
|
|
|
+ rootNode.add(fan_huian);
|
|
|
+ this.htmlLayer[0].position = fan_huian.position;
|
|
|
+ fan_huian.score = this.htmlLayer[0].jkd;
|
|
|
+ this.initCylinderGeometry(fan_huian);
|
|
|
+
|
|
|
+ // 改一下颜色
|
|
|
+ this.changeObjectColor(fan_huian, "检修"); // 惠安
|
|
|
+
|
|
|
+ // 风机存入数组
|
|
|
+ fans.push(fan_huian);
|
|
|
+
|
|
|
+ // 开始风机动画
|
|
|
+ this.startFanAnimate();
|
|
|
+
|
|
|
+ // 设置位置
|
|
|
+ this.setEveryHTML();
|
|
|
+ },
|
|
|
+ // 设置光伏位置 颜色
|
|
|
+ setLightPosition(rootNode, obj) {
|
|
|
+ obj.scale.set(200, 200, 200);
|
|
|
+
|
|
|
+ // 宁东光伏
|
|
|
+ let light_ndgf = obj.clone(true);
|
|
|
+ light_ndgf.position.set(-30, -7, -18);
|
|
|
+ rootNode.add(light_ndgf);
|
|
|
+ this.htmlLayer[2].position = light_ndgf.position;
|
|
|
+
|
|
|
+ // 改变颜色
|
|
|
+ this.changeElColor(light_ndgf, "受累"); // 宁东光伏
|
|
|
+
|
|
|
+ // 设置位置
|
|
|
+ this.setEveryHTML();
|
|
|
+ },
|
|
|
+ // 创建一个圆柱
|
|
|
+ initCylinderGeometry(obj, mode = "fan") {
|
|
|
+ let cr = 1.7;
|
|
|
+ let xyz = [5.75, 6.85, -0.63];
|
|
|
+ switch (mode) {
|
|
|
+ case "fan":
|
|
|
+ cr = 1.7;
|
|
|
+ xyz = [5.75, 6.85, -0.63];
|
|
|
+ break;
|
|
|
+ case "light":
|
|
|
+ cr = 3;
|
|
|
+ xyz = [5.75, 6.85, -0.63];
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ let geometry = new THREE.CylinderGeometry(cr, cr, 4, 128, 1, true);
|
|
|
+ //加载纹理
|
|
|
+ let texture = new THREE.TextureLoader().load(
|
|
|
+ obj.score < 60 ?
|
|
|
+ "static/3d/beam-texture-red.png" :
|
|
|
+ "static/3d/beam-texture-blue.png"
|
|
|
+ );
|
|
|
+ texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复
|
|
|
+ texture.repeat.set(1, 1);
|
|
|
+ texture.needsUpdate = true;
|
|
|
+ let materials = [
|
|
|
+ //圆柱侧面材质,使用纹理贴图
|
|
|
+ new THREE.MeshBasicMaterial({
|
|
|
+ map: texture,
|
|
|
+ side: THREE.FrontSide,
|
|
|
+ transparent: true,
|
|
|
+ }),
|
|
|
+ //圆柱顶材质
|
|
|
+ new THREE.MeshBasicMaterial({
|
|
|
+ transparent: true,
|
|
|
+ opacity: 0,
|
|
|
+ side: THREE.DoubleSide,
|
|
|
+ // side: THREE.DoubleSide,THREE.FrontSide THREE.BackSide
|
|
|
+ }),
|
|
|
+ //圆柱底材质
|
|
|
+ new THREE.MeshBasicMaterial({
|
|
|
+ transparent: true,
|
|
|
+ opacity: 0,
|
|
|
+ side: THREE.DoubleSide,
|
|
|
+ }),
|
|
|
+ ];
|
|
|
+ let cylinder = new THREE.Mesh(geometry, materials);
|
|
|
+ cylinder.position.set(
|
|
|
+ obj.position.x + xyz[0],
|
|
|
+ obj.position.y + xyz[1],
|
|
|
+ obj.position.z + xyz[2]
|
|
|
+ );
|
|
|
+ scene.add(cylinder);
|
|
|
+ },
|
|
|
+ // 设置每一个html的位置
|
|
|
+ setEveryHTML() {
|
|
|
+ this.htmlLayer.forEach((value) => {
|
|
|
+ if (value.show && value.position) {
|
|
|
+ const screen = this.vector3ToScreen(value.position);
|
|
|
+ value.x = screen.x + value.ox;
|
|
|
+ value.y = screen.y + value.oy;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 判断时候是可点击对象 返回null 或object
|
|
|
+ getClickObject(intersects) {
|
|
|
+ const names = ["fan"];
|
|
|
+ const namesRoot = ["fanvar"];
|
|
|
+ let x = true;
|
|
|
+ let obj = null;
|
|
|
+ for (let intersect of intersects) {
|
|
|
+ let temObj = intersect.object;
|
|
|
+ while (x) {
|
|
|
+ for (let name of names) {
|
|
|
+ if (temObj.name.indexOf(`${name}_`) == 0) {
|
|
|
+ obj = temObj;
|
|
|
+ x = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (x && temObj.parent) {
|
|
|
+ temObj = temObj.parent;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (obj) {
|
|
|
+ while (obj.parent && !namesRoot.includes(obj.parent.name)) {
|
|
|
+ obj = obj.parent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (obj && !namesRoot.includes(obj.parent.name)) {
|
|
|
+ obj = null;
|
|
|
+ }
|
|
|
+ return obj;
|
|
|
+ },
|
|
|
+ // 显示风机弹出层
|
|
|
+ showFanInfo(position) {
|
|
|
+ this.fanInfoLayer.position = {
|
|
|
+ x: position.x,
|
|
|
+ y: position.y,
|
|
|
+ z: position.z,
|
|
|
+ };
|
|
|
+ const screen = this.vector3ToScreen(this.fanInfoLayer.position);
|
|
|
+ this.fanInfoLayer.x = screen.x + this.fanInfoLayer.ox;
|
|
|
+ this.fanInfoLayer.y = screen.y + this.fanInfoLayer.oy;
|
|
|
+ this.fanInfoLayer.show = true;
|
|
|
+ },
|
|
|
+ // 隐藏风机弹出层
|
|
|
+ hideFanInfo() {
|
|
|
+ this.fanInfoLayer.show = false;
|
|
|
+ },
|
|
|
+ // 初始化云
|
|
|
+ initCloud() {},
|
|
|
+ // 初始化
|
|
|
+ initThree() {
|
|
|
+ this.initScene();
|
|
|
+ // this.initAxesHelper();
|
|
|
+ this.initCamera();
|
|
|
+ this.initRender();
|
|
|
+ this.initLight();
|
|
|
+ this.initControls();
|
|
|
+ this.initContent();
|
|
|
+ this.initCloud();
|
|
|
+ renderer.setAnimationLoop(this.animate);
|
|
|
+ },
|
|
|
+ // 动画
|
|
|
+ animate() {
|
|
|
+ renderer.render(scene, camera);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ // 生命周期钩子
|
|
|
+ beforeCreate() {
|
|
|
+ // 创建前
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ // 创建后
|
|
|
+ },
|
|
|
+ beforeMount() {
|
|
|
+ // 渲染前
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // 渲染后
|
|
|
+ this.initThree();
|
|
|
+ this.mapSource = this.data;
|
|
|
+ this.rinseData();
|
|
|
+ },
|
|
|
+ beforeUpdate() {
|
|
|
+ // 数据更新前
|
|
|
+ },
|
|
|
+ updated() {
|
|
|
+ // 数据更新后
|
|
|
+ },
|
|
|
+ beforeUnmount() {
|
|
|
+ // 销毁前
|
|
|
+ renderer.setAnimationLoop(null);
|
|
|
+ camera = null;
|
|
|
+ scene = null;
|
|
|
+ renderer = null;
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ data(res) {
|
|
|
+ this.mapSource = res;
|
|
|
+ this.rinseData();
|
|
|
+ },
|
|
|
+ },
|
|
|
+ };
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+ .three-model {
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ // left: -112px;
|
|
|
+
|
|
|
+ .map-3d {
|
|
|
+ position: absolute;
|
|
|
+ width: 1118px;
|
|
|
+ height: 678px;
|
|
|
+ left: calc(50% - 559px);
|
|
|
+ top: calc(50% - 339px);
|
|
|
+ z-index: -1;
|
|
|
+
|
|
|
+ map {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .three-html-layer {
|
|
|
+ .three-html-dom {
|
|
|
+ position: absolute;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fan-name {
|
|
|
+ display: inline-block;
|
|
|
+ height: 22px;
|
|
|
+ background: #222632;
|
|
|
+ border: 1px solid #646464;
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 0 10px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #ffffff;
|
|
|
+ line-height: 22px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fan-can-click {
|
|
|
+ position: absolute;
|
|
|
+ background: #ff0000;
|
|
|
+ opacity: 0;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .build-info {
|
|
|
+ width: 166px;
|
|
|
+ height: 33px;
|
|
|
+ // position: relative;
|
|
|
+
|
|
|
+ .build-info-close {
|
|
|
+ position: absolute;
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ top: -20px;
|
|
|
+ left: -20px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #1a1f2fd8;
|
|
|
+ border: 1px solid #05bb4c;
|
|
|
+ box-shadow: 0px 8px 17px 1px #05bb4c66;
|
|
|
+ cursor: pointer;
|
|
|
+ color: @gray-l;
|
|
|
+ transition: all 0.3s;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 14px;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #05bb4c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .build-info-item {
|
|
|
+ width: 66px;
|
|
|
+ height: 66px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #1a1f2fe5;
|
|
|
+ position: absolute;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: "";
|
|
|
+ position: absolute;
|
|
|
+ width: 44px;
|
|
|
+ height: 2px;
|
|
|
+ left: calc(50% - 22px);
|
|
|
+ top: calc(50% - 1px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .build-info-item-num {
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #ffffff;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 1.2;
|
|
|
+ margin-top: 6px;
|
|
|
+ margin-bottom: 3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .build-info-item-text {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #ffffff;
|
|
|
+ font-weight: 400;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.blue {
|
|
|
+ border: 2px solid #1da0d7;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ background: #1da0d7;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.red {
|
|
|
+ border: 2px solid #ff0000;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ background: #ff0000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.green {
|
|
|
+ border: 2px solid #05bb4c;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ background: #05bb4c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.purple {
|
|
|
+ border: 2px solid #323e6f;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ background: #323e6f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.orange {
|
|
|
+ border: 2px solid #db5520;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ background: #db5520;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.yellow {
|
|
|
+ border: 2px solid #edb32f;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ background: #edb32f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|