<template>
  <div :id="chartId" class="chart">
  </div>
</template>

<script setup lang="ts" name='ThreeChart'>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { Lut } from 'three/examples/jsm/math/Lut'
import {
  drawSinLine,
  drawLine,
  draw2DText,
  drawPlan,
  createAxisInfo,
} from './utils.ts';
const lut = new Lut()
lut.addColorMap('axis', [
  [0.0, 0x00ee00],
  [0.25, 0xeeee00],
  [0.75, 0xee0000],
  [1.0, 0x4e0211],
]);
lut.setColorMap('axis', 32);
interface Props {
    period?: number;
    phase?: number;
    height?: number;
    width?: number;
    type?: number | string;
    monitorType?: number | string;
    maxValue?: number | string;
    chartId?: string;
    chartData?: any[];
    range?: number;
    clearMesh?: boolean;
}
const props = withDefaults(defineProps<Props>(),{
    period: 50,
    phase: 128,
    height: 200,
    width: 200,
    type: 1,
    monitorType: 1,
    maxValue: 100,
    chartId: 'box3D-warning',
    chartData: [],
    range: 100,
    clearMesh: false,
});
const count = ref<number>(0);//InstancedMesh的count
const maxNum = ref<number>(80);
const minNum = ref<number>(0);
const maxArray = ref<number[]>([]);

let renderer: THREE.WebGLRenderer | null = null;
let scene: THREE.Scene | null = null;
let camera: THREE.OrthographicCamera | null = null;
let controls: OrbitControls | null = null;
let axisGroup: THREE.Group | null = null;
let chartGroup: THREE.Group | null = null;
let dummy: THREE.Object3D | null = null;
let planes: THREE.Plane[] | null = null;

//controls,axisGroup,chartGroup,pointsList,geometry,materials,initInstancedMesh,pointPositions,pointsColor,dummy,planes;
const setCamera = (k,s) => {
    const setCameraArr = props.type == 2 ? [600, 0, 0] : [500, 300, 500];
     //创建相机对象
    if(!camera){
        camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 0.1, 1000);
    }
    camera.position.set(...setCameraArr); //设置相机位置
    camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
};
const setControls = () => {
    if(!controls){
        controls = new OrbitControls(camera, renderer.domElement);
    }
    // 设置左右方向的最大、最小角度限制为 90 度和 0 度
    controls.minAzimuthAngle = 0;
    controls.maxAzimuthAngle = Math.PI / 2;
    // 设置上下方向的最大、最小角度限制为 90 度和 0 度
    controls.minPolarAngle = 0;
    controls.maxPolarAngle = Math.PI / 2;
    //设置控制器中心点
    controls.target.set(25, 0, 180);
    controls.maxZoom = 2;
    controls.minZoom = 0.5;
    controls.enableRotate = props.type !== 2; //启用或禁用摄像机水平或垂直旋转
    controls.enableZoom = props.type !== 2; //启用或禁用摄像机的缩放
    controls.enablePan = props.type !== 2; //启用或禁用摄像机平移
    
};
const drawAxis = (size, minNum, type) => {
    if (!scene) {
        return
    }
    const options = ['prps', 'prpd', 'prpd3d']
    let key = options[type - 1]
    const data = createAxisInfo(size, minNum)
    let [x, y, z] = data['set']
    scene.remove(...scene.children.filter((item) => item.name === 'axisNumberText'))
    if (axisGroup.children.length) {
    axisGroup.remove(...axisGroup.children)
    }
    let axisText = new THREE.Group()
    axisText.name = 'axisNumberText'
    scene.add(axisText)
    if (type == 3) {
    axisGroup.scale.set(y, x, z)
    chartGroup.scale.set(y, x, z)
    } else {
    axisGroup.scale.set(x, y, z)
    chartGroup.scale.set(x, y, z)
    }
    data[key].forEach(async (item) => {
    switch (item.type) {
        case 'plan':
        axisGroup.add(drawPlan(item))
        break
        case 'line':
        axisGroup.add(...drawLine(item))
        break
        case 'curveLine':
        axisGroup.add(drawSinLine(item))
        break
        case 'text':
        axisText.add(draw2DText(item))
    }
    })
};
const initChart = () => {
    if(props.type === 1){

    }else if(props.type === 2){

    }
};
const render = () =>{
    //获取摄像机的视锥体
    const frustum = new THREE.Frustum()
    const cameraViewProjectionMatrix = new THREE.Matrix4()
    camera.updateMatrixWorld() // 确保摄像机的世界矩阵已更新
    cameraViewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
    frustum.setFromProjectionMatrix(cameraViewProjectionMatrix)
    // 遍历场景中的每个对象，并根据视锥体进行剔除
    scene.traverse((object) => {
        if (object.isMesh) {
            object.visible = frustum.intersectsObject(object)
        }
    })
    requestAnimationFrame(render)
    renderer.render(scene, camera)
};
const onWindowResize = () => {
    if (!scene) {
        return
    }
    const isPrpd = props.type == 2,
    isPrps3d = props.type == 3;
    let box = document.getElementById(props.chartId);
    let width = box.clientWidth;
    let height = props.height ? props.height : box.clientHeight;
    let k = width / height //窗口宽高比
    let s = isPrpd ? 250 : minNum.value ? 350 : 350 //三维场景显示范围控制系数，系数越大，显示的范围越大
    camera.left = -s * k - (isPrpd ? 200 : 20)
    camera.right = s * k - (isPrpd ? 200 : 20)
    camera.top = s + (isPrpd ? (minNum.value ? -30 : 155) : isPrps3d ? 60 : minNum.value ? -80 : 60)
    camera.bottom = -s + (isPrpd ? (minNum.value ? -30 : 155) : isPrps3d ? 60 : minNum.value ? -80 : 60)
    camera.aspect = k

    camera.updateProjectionMatrix()
    renderer.setSize(width, height)
    renderer.setPixelRatio(window.devicePixelRatio) //设备像素比，优化渲染效果
};
const getSAndK = () => {
    let box = document.getElementById(props.chartId);
    let width = box.clientWidth; //
    let height = props.height ? props.height : box.clientHeight;
    let k = width / height //窗口宽高比
    let s = props.type == 2 ? 260 : 420 //三维场景显示范围控制系数，系数越大，显示的范围越大
    return [s,k]
}
const init = () => {
    renderer = null;
    scene = null;
    camera = null;
    controls = null;
    axisGroup = new THREE.Group();
    chartGroup = new THREE.Group(); //图例柱子
    chartGroup.name = 'chartsMesh';
    //geometry = ''; //InstancedMesh的初始几何体
    //materials = []; //InstancedMesh的材质集合
    //initInstancedMesh = ''; //InstancedMesh实例
    //pointPositions = '';
    //pointsColor = ''; //Points实例的位置及颜色的集合
    dummy = new THREE.Object3D();
    
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.autoClear = false;

    if(props.type !== 3) {
        renderer.localClippingEnabled = true;
        let constant = (360 / (maxNum.value + -minNum.value)) * maxNum.value + 1;
        planes = [
          new THREE.Plane(new THREE.Vector3(0, -1, 0), constant), //y轴正值截取
          new THREE.Plane(new THREE.Vector3(0, 1, 0), constant), //y轴负值截取
        ];
        renderer.clippingPlanes = planes;
    }
    document.getElementById(props.chartId).append(renderer.domElement); //body元素中插入canvas对象
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xffffff);
    scene.add(axisGroup, chartGroup);

    drawAxis(maxNum.value, minNum.value, props.type);
    setCamera(...getSAndK());
    setControls();
    render();
    onWindowResize();
    

};
//const setType

watch([()=>props.width, ()=>props.height],onWindowResize);

watch(()=> props.type,()=> {
    drawAxis(maxNum.value, minNum.value, props.type);
    setCamera(...getSAndK());
    setControls();
    onWindowResize()
})

watchEffect()

onMounted(() => {
    init();
    // window.onresize = () => {
    //     onWindowResize()
    // }
})


</script>

<style lang='less' scoped>

</style>