<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts';


export interface GraphNode {
    id: string
    name: string
    type: string
    x: number
    y: number
}

export interface GraphLink {
    source: string
    target: string
    type: string
}

// 定义组件属性
const props = defineProps({

    nodes: {
        type: Array<GraphNode>,
        default: () => []
    }
    , links: {
        type: Array<GraphLink>,
        default: () => []
    }
});


const chartDom = ref()

let myChart = null

onMounted(async () => {

})

watch(() => props.nodes, () => {
    nodeTopBottomLayout(props.nodes)
    updateCharts()
})
watch(() => props.links, updateCharts)

onUnmounted(() => myChart?.dispose())

function nodeTopBottomLayout(nodes: Array<any>) {
    if (nodes.length < 1) return

    // 中心节点放在中间
    const centerNode = nodes[0]
    centerNode.x = 0
    centerNode.y = 0

    // 其余节点分成上下两列
    const otherNodes = nodes.slice(1)
    const tops = []
    const bottoms = []
    otherNodes.forEach((item) => {
        if (item.type === 'to') {
            tops.push(item)
        } else {
            bottoms.push(item)
        }
    })
    // 计算每列的节点数
    const topCount = tops.length
    const bottomCount = bottoms.length

    // 列间距
    const columnSpacing = 60
    // 上下列距离中心的距离
    const verticalDistance = 100

    let ci = (topCount - 1) / 2
    // 处理上列节点
    for (let i = 0; i < topCount; i++) {
        const node = tops[i]
        // 计算x坐标，居中排列
        const offsetX = (i - ci) * columnSpacing
        node.x = offsetX
        node.y = -verticalDistance
    }
    ci = (bottomCount - 1) / 2
    // 处理下列节点
    for (let i = 0; i < bottomCount; i++) {
        const node = bottoms[i]
        // 计算x坐标，居中排列
        const offsetX = (i - ci) * columnSpacing
        node.x = offsetX
        node.y = verticalDistance
    }
}
// 辅助函数：更新图表数据
function updateCharts() {
    // 销毁现有图表实例
    if (myChart) {
        myChart.dispose()
    }
    myChart = echarts.init(chartDom.value)

    const ys = props.nodes.map((item) => item.y)
    const minY = Math.min(...ys)
    const maxY = Math.max(...ys)

    myChart.setOption({

        grid: {
            top: 0,
            bottom: 0,
            left: 0,
            right: 0,
        },
        // 关闭不必要的交互以提高性能
        tooltip: {
            show: false
        },
        // 优化渲染性能
        // progressive: 500,
        // progressiveThreshold: 300,
        animation: false,
        animationDuration: 1000,
        animationEasing: 'cubicOut',
        series: [{
            type: 'graph',
            // zoom: Math.max(1, props.nodes.length / 10.0), // 放大显示
            itemStyle: {
                color: '#73C0DE'
            },
            height: '80%',
            layout: 'none',
            data: props.nodes,
            links: props.links,
            center: [0, (minY + maxY) / 2 + 10],
            nodeScaleRatio: 0,
            // categories: categories,
            roam: true,
            label: {
                show: true,
                position: 'bottom',
                offset: [0, -10],
                formatter: '{b}',
                fontSize: 14,
                textBorderColor: 'rgb(255 255 255)',
                // fontWeight: 'bold',
                color: 'rgb(5, 95, 194)',
                padding: [4, 6],
                borderRadius: 4,
                // 限制宽度并自动换行
                width: 120, // 限制标签宽度
                overflow: 'break', // 超出宽度自动换行
                lineHeight: 16 // 设置行高，确保多行显示正常
            },
            lineStyle: {
                // color: 'source',
                curveness: 0,
                width: 1,
                color: '#AED6FF'
            },
            edgeSymbol: ['arrow', 'none'],
        }]
    })
}


</script>

<template>
    <div class="flex-display content-box">
        <div ref="chartDom" class="chart-container"></div>
    </div>
</template>

<style lang="scss" scoped>
.content-box {
    padding: 10px;
    gap: 10px;
    flex-direction: column;
}

.chart-container {
    height: 500px;
    width: 100%;
}
</style>