<template>
  <div class="view-box">
    <div ref="graphContainer" style="height: 100%; width: 100%;"></div>
  </div>
</template>

<script setup name="MindGraph">
import { ref, onBeforeUnmount } from "vue"
import * as G6 from '@antv/g6';

// 初始化画布
const graphContainer = ref(null);
let graph = null;
const onInitGraph = () => {
	const container = graphContainer.value;
	const width = container.clientWidth;
	const height = container.clientHeight;
	graph = new G6.Graph({
		container: container,
		width, height,
		// fitView: true,
		// fitViewPadding: 50,
		defaultNode: {
			type: "rect",
			size: [250, 45],
			style: {
				fill: "#F6FAFF",
				stroke: "#B9DCFF",
				lineWidth: 1
			},
			labelCfg: {
				style: {
					fill: "#055FC2",
					fontSize: 18,
					lineHeight: 25,
					fontWeight: "bold",
					fontFamily: "Source Han Sans CN",
				}
			}
		},
		defaultEdge: {
			type: "cubic-horizontal",
			style: {
				stroke: "#B9DCFF",
				lineWidth: 2,
				endArrow: true,
			}
		},
		layout: {
			type: 'dagre', // 层次布局
			rankdir: 'LR', // 布局从左向右
			controlPoints: true, // 节点间连线的控制点
			nodesep: 10, // 同一层节点之间的距离
			ranksep: 100, // 不同层节点之间的距离
			// begin: [250, 100], // 左上角坐标
		},
		modes: {
			default: [
				'drag-canvas',    // 鼠标拖拽移动画布
				'zoom-canvas',    // 鼠标滚轮缩放
				// 'drag-node'       // 可选：允许拖拽节点
			]
		},
	});
}

// 加载思维导图数据
const onMindGraphData = (nodes=[], edges=[]) => {
	let data = { nodes:[], edges }
	nodes.forEach(node => {
		if (node.maxWidth) onFormatLineFeed(node);
		data.nodes.push(node);
	})

	if (!graph) onInitGraph();

	graph.data(data);
	graph.render();
}

// 获取文本宽度
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const getLabelWidth = (label, size, family) => {
	ctx.font = `${size}px ${family}`;
	return ctx.measureText(label).width;
}

// 文本插入换行符
const onFormatLineFeed = (node) => {
	let size = node?.labelCfg?.style?.fontSize || '16'
	let family = node?.labelCfg?.style?.fontFamily || 'Source Han Sans CN'
	const lines = [];
	let line = '';
	for (let char of node.label) {
		const testLine = line + char;
		const width = getLabelWidth(testLine, size, family);
		if (width > node.maxWidth-40) {
			lines.push(line);
			line = char;
		} else {
			line = testLine;
		}
	}
	if (line) lines.push(line);
	node.label = lines.join("\n")
	node.size = [node.maxWidth, 25*lines.length+20]
}

defineExpose({ onMindGraphData })

onBeforeUnmount(() => {
	graph?.destroy()
})

</script>

<style scoped lang="scss">
.view-box {
  width: 100%;
  height: 100%;
}
</style>