<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">{{info.name}}</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: {},
    // 自定义事件
    emits: {
        when: null,
    },
    // 数据
    data() {
        return {
            pointer: false,
            htmlLayer: [
                { // 麻黄山
                    id: "fan-mhs",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: 50,
                    oy: 10,
                    position: null,
                    name: "麻黄山",
                },
                { // 牛首山
                    id: "fan-nss",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: 35,
                    oy: 0,
                    position: null,
                    name: "牛首山",
                },
                { // 青山
                    id: "fan-qs",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: 60,
                    oy: 10,
                    position: null,
                    name: "青山",
                },
                { // 石板泉
                    id: "fan-sbq",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: 40,
                    oy: 0,
                    position: null,
                    name: "石板泉",
                },
                { // 香山
                    id: "fan-qs",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: 25,
                    oy: 20,
                    position: null,
                    name: "香山",
                },
                { // 大武口
                    id: "light-dwk",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: 0,
                    oy: 110,
                    position: null,
                    name: "大武口",
                },
                { // 平罗
                    id: "light-pl",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: 30,
                    oy: 100,
                    position: null,
                    name: "平罗",
                },
                { // 马场湖
                    id: "light-mch",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: -120,
                    oy: 110,
                    position: null,
                    name: "马场湖",
                },
                { // 宣和
                    id: "light-xh",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: -90,
                    oy: 120,
                    position: null,
                    name: "宣和",
                },
                { // 海子井
                    id: "light-hzj",
                    x: 0,
                    y: 0,
                    show: true,
                    ox: -80,
                    oy: 150,
                    position: null,
                    name: "海子井",
                },
            ],
            circleXY: [
                { x: -(200*Math.sin(0/180*Math.PI)), y: -(200*Math.cos(0/180*Math.PI)) },
                { x: -(200*Math.sin(-30/180*Math.PI)), y: -(200*Math.cos(-30/180*Math.PI)) },
                { x: -(200*Math.sin(-60/180*Math.PI)), y: -(200*Math.cos(-60/180*Math.PI)) },
                { x: -(200*Math.sin(-90/180*Math.PI)), y: -(200*Math.cos(-90/180*Math.PI)) },
                { x: -(200*Math.sin(-120/180*Math.PI)), y: -(200*Math.cos(-120/180*Math.PI)) },
                { x: -(200*Math.sin(-150/180*Math.PI)), y: -(200*Math.cos(-150/180*Math.PI)) },
                { x: -(200*Math.sin(-180/180*Math.PI)), y: -(200*Math.cos(-180/180*Math.PI)) },
            ],
            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: {
        // Vector3 to screen
        vector3ToScreen: function(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: function() {
            scene = new THREE.Scene();
            // scene.background = new THREE.Color(0xa0a0a0);
        },
        // 相机
        initCamera: function() {
            camera = new THREE.PerspectiveCamera(45, this.$el.scrollWidth / this.$el.scrollHeight, 0.1, 10000);
            camera.position.set(50, 50, 50);
        },
        // 坐标轴
        initAxesHelper: function() {
            const axesHelper = new THREE.AxesHelper(150);
            scene.add(axesHelper);
            axesHelper.position.set(0, 0, 0);
        },
        // 渲染器
        initRender: function() {
            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: function() {
            // let light = new THREE.PointLight(0xffffff, 2);
            let light = new THREE.AmbientLight(0xffffff, 5);
            // light.position.set(50, 50, 50);
            scene.add(light);
        },
        // 控制器
        initControls: function() {
            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: function(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: function() {
            // 加载3D地面
            let loaderGround = new GLTFLoader(); /*实例化加载器*/
            loaderGround.load(
                "static/3d/fanvar.gltf",
                (gltf) => {
                    gltf.scene.position.set(17, 10, -12);
                    // console.log(gltf);
                    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/lightvar.gltf",
                (gltf) => {
                    gltf.scene.position.set(17, 10, -12);
                    // console.log(gltf);
                    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(10, 0, -50);
                    scene.add(gltf.scene);
                    gltf.scene.rotateY(120);
                    scene.onAfterRender = () => {
                        this.$emit("when");
                        this.$refs.pageLoading.hide();
                    }
                },
                (xhr) => {},
                function(error) {
                    console.error("load error!" + error.getWebGLErrorMessage());
                }
            );
        },
        // 改变元素底盘的颜色（带底盘的）
        changeObjectColor: function (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,
                opacity: 0.8,
                transparent: true,
            });
        },
        // 改变元素的颜色（光伏）
        changeElColor: function (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: function (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: function (rootNode, obj) {
            // 麻黄山
            let fan_mhs = obj.clone(true);
            fan_mhs.position.set(10, 5, -4);
            this.setFanName(fan_mhs, "fan_mhs");
            rootNode.add(fan_mhs);
            // this.initCylinderGeometry(fan_mhs.position);
            this.htmlLayer[0].position = fan_mhs.position;
            // 牛首山
            let fan_nss = obj.clone(true);
            fan_nss.position.set(-4, 4, -15);
            this.setFanName(fan_nss, "fan_nss");
            rootNode.add(fan_nss);
            // this.initCylinderGeometry(fan_nss.position);
            this.htmlLayer[1].position = fan_nss.position;
            // 青山
            let fan_qs = obj.clone(true);
            fan_qs.position.set(15, 5, -9);
            this.setFanName(fan_qs, "fan_qs");
            rootNode.add(fan_qs);
            // this.initCylinderGeometry(fan_qs.position);
            this.htmlLayer[2].position = fan_qs.position;
            // 石板泉
            let fan_sbq = obj.clone(true);
            fan_sbq.position.set(4, 5, -2);
            this.setFanName(fan_sbq, "fan_sbq");
            rootNode.add(fan_sbq);
            // this.initCylinderGeometry(fan_sbq.position);
            this.htmlLayer[3].position = fan_sbq.position;
            // 香山
            let fan_xs = obj.clone(true);
            fan_xs.position.set(-9, 7, 21);
            this.setFanName(fan_xs, "fan_xs");
            rootNode.add(fan_xs);
            // this.initCylinderGeometry(fan_xs.position);
            this.htmlLayer[4].position = fan_xs.position;

            // 改一下颜色
            this.changeObjectColor(fan_mhs, 'green'); // 麻黄山
            this.changeObjectColor(fan_nss, 'xd'); // 牛首山
            this.changeObjectColor(fan_qs, '检修'); // 青山
            this.changeObjectColor(fan_sbq, 'white'); // 石板泉
            this.changeObjectColor(fan_xs, '运行'); // 香山

            // 风机存入数组
            fans.push(fan_mhs);
            fans.push(fan_nss);
            fans.push(fan_qs);
            fans.push(fan_sbq);
            fans.push(fan_xs);

            // 开始风机动画
            this.startFanAnimate();

            // 设置位置
            this.setEveryHTML();
        },
        // 设置光伏name
        setLightName: function (obj, name) {
            obj.name = name;
            obj.userData.name = name;
            let Box661 = obj.getObjectByName("Box661");
            let Box668 = obj.getObjectByName("Box668");
            let Box669 = obj.getObjectByName("Box669");
            let Box664 = obj.getObjectByName("Box664");
            let Box667 = obj.getObjectByName("Box667");
            let Box670 = obj.getObjectByName("Box670");
            Box661.name = `${name}_item_1`;
            Box661.userData.name = `${name}_item_1`;
            Box668.name = `${name}_item_2`;
            Box668.userData.name = `${name}_item_2`;
            Box669.name = `${name}_item_3`;
            Box669.userData.name = `${name}_item_3`;
            Box664.name = `${name}_item_4`;
            Box664.userData.name = `${name}_item_4`;
            Box667.name = `${name}_item_5`;
            Box667.userData.name = `${name}_item_5`;
            Box670.name = `${name}_item_6`;
            Box670.userData.name = `${name}_item_6`;
        },
        // 设置光伏位置 颜色
        setLightPosition: function (rootNode, obj) {
            let Box660 = obj.getObjectByName("Box660");
            let Box666 = obj.getObjectByName("Box666");
            let Box662 = obj.getObjectByName("Box662");
            let Box663 = obj.getObjectByName("Box663");
            let Box659 = obj.getObjectByName("Box659");
            let Box665 = obj.getObjectByName("Box665");
            obj.remove(Box660);
            obj.remove(Box666);
            obj.remove(Box662);
            obj.remove(Box663);
            obj.remove(Box659);
            obj.remove(Box665);
            // 大武口
            let light_dwk = obj.clone(true);
            light_dwk.position.set(-6, 0.13, -50);
            this.setLightName(light_dwk, "light_dwk");
            rootNode.add(light_dwk);
            this.htmlLayer[5].position = light_dwk.position;
            // 平罗
            let light_pl = obj.clone(true);
            light_pl.position.set(-3, 0.13, -55);
            this.setLightName(light_pl, "light_pl");
            rootNode.add(light_pl);
            this.htmlLayer[6].position = light_pl.position;
            // 马场湖
            let light_mch = obj.clone(true);
            light_mch.position.set(-27, 2, -30);
            this.setLightName(light_mch, "light_mch");
            rootNode.add(light_mch);
            this.htmlLayer[7].position = light_mch.position;
            // 宣和
            let light_xh = obj.clone(true);
            light_xh.position.set(-18, 4, -27);
            this.setLightName(light_xh, "light_xh");
            rootNode.add(light_xh);
            this.htmlLayer[8].position = light_xh.position;
            // 海子井
            let light_hzj = obj.clone(true);
            light_hzj.position.set(-10, 2, -26);
            this.setLightName(light_hzj, "light_hzj");
            rootNode.add(light_hzj);
            this.htmlLayer[9].position = light_hzj.position;

            // 改变颜色
            this.changeElColor(light_dwk, 'green'); // 大武口
            this.changeElColor(light_pl, '离线'); // 平罗
            this.changeElColor(light_mch, 'yx'); // 马场湖
            this.changeElColor(light_xh, 'red'); // 宣和
            this.changeElColor(light_hzj, '受累'); // 海子井
        },
        // 创建一个圆柱
        initCylinderGeometry: function(position, cr=2) {
            let geometry = new THREE.CylinderGeometry(cr, cr, 7, 64);
            //加载纹理
            let texture = new THREE.TextureLoader().load("static/3d/beam-texture.png");
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping; //每个都重复
            texture.repeat.set(1, 1);
            texture.needsUpdate = true;
            let materials = [
                //圆柱侧面材质，使用纹理贴图
                new THREE.MeshBasicMaterial({
                    map: texture,
                    side: THREE.DoubleSide,
                    transparent: true,
                }),
                //圆柱顶材质
                new THREE.MeshBasicMaterial({
                    transparent: true,
                    opacity: 0,
                    side: THREE.DoubleSide,
                }),
                //圆柱底材质
                new THREE.MeshBasicMaterial({
                    transparent: true,
                    opacity: 0,
                    side: THREE.DoubleSide,
                }),
            ];
            cylinder = new THREE.Mesh(geometry, materials);
            cylinder.position.set(position.x + 5.75, position.y + 8, position.z);
            scene.add(cylinder);
        },
        // 设置每一个html的位置
        setEveryHTML: function() {
            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;
                }
            });
        },
        // 初始化云
        initCloud: function () {
            
        },
        // 初始化
        initThree: function() {
            this.initScene();
            // this.initAxesHelper();
            this.initCamera();
            this.initRender();
            this.initLight();
            this.initControls();
            this.initContent();
            this.initCloud();
            renderer.setAnimationLoop(this.animate);
        },
        // 动画
        animate: function() {
            renderer.render(scene, camera);
        },
    },
    // 生命周期钩子
    beforeCreate() {
        // 创建前
    },
    created() {
        // 创建后
    },
    beforeMount() {
        // 渲染前
    },
    mounted() {
        // 渲染后
        this.initThree();
    },
    beforeUpdate() {
        // 数据更新前
    },
    updated() {
        // 数据更新后
    },
    beforeUnmount() {
        // 销毁前
        renderer.setAnimationLoop(null);
        camera = null;
        scene = null;
        renderer = null;
    },
};
</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;
        }
    
    }
}
</style>
