首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >echarts 制作关系图

echarts 制作关系图

原创
作者头像
小焱
发布2025-09-11 15:54:54
发布2025-09-11 15:54:54
12800
代码可运行
举报
文章被收录于专栏:前端开发前端开发
运行总次数:0
代码可运行
代码语言:javascript
代码运行次数:0
运行
复制
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ECharts 关系图示例</title>
    <!-- 引入 Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- 引入 Font Awesome -->
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <!-- 引入 ECharts -->
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
    
    <script>
        // 配置 Tailwind
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#10B981',
                        accent: '#8B5CF6',
                        dark: '#1E293B',
                        light: '#F8FAFC'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .graph-container {
                height: calc(100vh - 12rem);
            }
            .card-shadow {
                box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
            }
        }
    </style>
</head>
<body class="bg-gray-50 text-gray-800 font-sans">
    <!-- 页面头部 -->
    <header class="bg-white shadow-md">
        <div class="container mx-auto px-4 py-6">
            <h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-dark flex items-center">
                <i class="fa fa-project-diagram text-primary mr-3"></i>
                ECharts 关系图可视化
            </h1>
            <p class="text-gray-600 mt-2">展示节点与节点之间的关联关系</p>
        </div>
    </header>

    <!-- 主内容区 -->
    <main class="container mx-auto px-4 py-8">
        <!-- 控制面板 -->
        <div class="bg-white rounded-lg p-6 mb-8 card-shadow">
            <div class="flex flex-wrap gap-4 items-center">
                <div class="flex-1 min-w-[200px]">
                    <label class="block text-sm font-medium text-gray-700 mb-1">布局类型</label>
                    <select id="layoutType" class="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary focus:border-primary">
                        <option value="force">力导向布局</option>
                        <option value="circular">环形布局</option>
                        <option value="radial">辐射状布局</option>
                    </select>
                </div>
                
                <div class="flex-1 min-w-[200px]">
                    <label class="block text-sm font-medium text-gray-700 mb-1">节点大小</label>
                    <input type="range" id="nodeSize" min="10" max="50" value="20" 
                           class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
                </div>
                
                <div class="flex-1 min-w-[200px]">
                    <label class="block text-sm font-medium text-gray-700 mb-1">关系线粗细</label>
                    <input type="range" id="lineWidth" min="1" max="5" value="2" 
                           class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary">
                </div>
                
                <div class="flex items-end">
                    <button id="refreshGraph" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-md transition duration-200 flex items-center">
                        <i class="fa fa-refresh mr-2"></i>刷新图表
                    </button>
                </div>
            </div>
        </div>
        
        <!-- 图表容器 -->
        <div class="bg-white rounded-lg p-4 card-shadow">
            <div id="graphContainer" class="graph-container w-full rounded-md"></div>
        </div>
        
        <!-- 说明面板 -->
        <div class="bg-white rounded-lg p-6 mt-8 card-shadow">
            <h2 class="text-xl font-semibold mb-4 text-dark">关系图说明</h2>
            <div class="grid md:grid-cols-2 gap-6">
                <div>
                    <h3 class="text-lg font-medium mb-2 text-primary">交互操作</h3>
                    <ul class="list-disc pl-5 space-y-2 text-gray-700">
                        <li>拖动节点可以调整位置</li>
                        <li>鼠标滚轮可以缩放视图</li>
                        <li>点击节点可以查看详细信息</li>
                        <li>按住鼠标左键拖动可以平移视图</li>
                    </ul>
                </div>
                <div>
                    <h3 class="text-lg font-medium mb-2 text-primary">节点含义</h3>
                    <ul class="list-disc pl-5 space-y-2 text-gray-700">
                        <li><span class="inline-block w-3 h-3 rounded-full bg-blue-500 mr-2"></span>蓝色:个人</li>
                        <li><span class="inline-block w-3 h-3 rounded-full bg-green-500 mr-2"></span>绿色:组织</li>
                        <li><span class="inline-block w-3 h-3 rounded-full bg-purple-500 mr-2"></span>紫色:项目</li>
                        <li><span class="inline-block w-3 h-3 rounded-full bg-yellow-500 mr-2"></span>黄色:文档</li>
                    </ul>
                </div>
            </div>
        </div>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark text-white py-6 mt-12">
        <div class="container mx-auto px-4 text-center">
            <p>© 2023 ECharts 关系图可视化示例 | 使用 ECharts、Tailwind CSS 构建</p>
        </div>
    </footer>

    <script>
        // 初始化图表
        const chartDom = document.getElementById('graphContainer');
        const myChart = echarts.init(chartDom);
        let option;

        // 生成随机数据
        function generateData() {
            // 节点数据
            const nodes = [
                { id: 1, name: '张三', category: 0, value: 30, symbolSize: 30 },
                { id: 2, name: '李四', category: 0, value: 25, symbolSize: 25 },
                { id: 3, name: '王五', category: 0, value: 28, symbolSize: 28 },
                { id: 4, name: '赵六', category: 0, value: 22, symbolSize: 22 },
                { id: 5, name: '技术部', category: 1, value: 40, symbolSize: 40 },
                { id: 6, name: '市场部', category: 1, value: 35, symbolSize: 35 },
                { id: 7, name: '产品A', category: 2, value: 32, symbolSize: 32 },
                { id: 8, name: '产品B', category: 2, value: 29, symbolSize: 29 },
                { id: 9, name: '需求文档', category: 3, value: 20, symbolSize: 20 },
                { id: 10, name: '设计方案', category: 3, value: 22, symbolSize: 22 },
                { id: 11, name: '测试报告', category: 3, value: 21, symbolSize: 21 },
                { id: 12, name: '钱七', category: 0, value: 26, symbolSize: 26 },
                { id: 13, name: '研发中心', category: 1, value: 45, symbolSize: 45 },
                { id: 14, name: '产品C', category: 2, value: 31, symbolSize: 31 },
                { id: 15, name: '用户手册', category: 3, value: 19, symbolSize: 19 }
            ];

            // 关系数据
            const links = [
                { source: 1, target: 5, value: 5, label: { show: true, formatter: '隶属' } },
                { source: 2, target: 5, value: 5, label: { show: true, formatter: '隶属' } },
                { source: 3, target: 6, value: 5, label: { show: true, formatter: '隶属' } },
                { source: 4, target: 6, value: 5, label: { show: true, formatter: '隶属' } },
                { source: 12, target: 13, value: 5, label: { show: true, formatter: '隶属' } },
                { source: 1, target: 7, value: 3, label: { show: true, formatter: '负责' } },
                { source: 2, target: 8, value: 3, label: { show: true, formatter: '负责' } },
                { source: 12, target: 14, value: 3, label: { show: true, formatter: '负责' } },
                { source: 3, target: 7, value: 2, label: { show: true, formatter: '参与' } },
                { source: 4, target: 8, value: 2, label: { show: true, formatter: '参与' } },
                { source: 7, target: 9, value: 4, label: { show: true, formatter: '关联' } },
                { source: 7, target: 10, value: 4, label: { show: true, formatter: '关联' } },
                { source: 8, target: 11, value: 4, label: { show: true, formatter: '关联' } },
                { source: 14, target: 15, value: 4, label: { show: true, formatter: '关联' } },
                { source: 1, target: 2, value: 1, label: { show: false } },
                { source: 3, target: 4, value: 1, label: { show: false } },
                { source: 5, target: 6, value: 2, label: { show: true, formatter: '协作' } },
                { source: 5, target: 13, value: 2, label: { show: true, formatter: '协作' } },
                { source: 7, target: 8, value: 1, label: { show: false } },
                { source: 1, target: 12, value: 1, label: { show: false } }
            ];

            // 类别数据
            const categories = [
                { name: '个人', itemStyle: { color: '#3B82F6' } },
                { name: '组织', itemStyle: { color: '#10B981' } },
                { name: '项目', itemStyle: { color: '#8B5CF6' } },
                { name: '文档', itemStyle: { color: '#F59E0B' } }
            ];

            return { nodes, links, categories };
        }

        // 更新图表配置
        function updateChart() {
            const layoutType = document.getElementById('layoutType').value;
            const nodeSize = parseInt(document.getElementById('nodeSize').value);
            const lineWidth = parseInt(document.getElementById('lineWidth').value);
            const data = generateData();

            // 根据选择的布局类型设置布局配置
            let layoutConfig;
            switch (layoutType) {
                case 'force':
                    layoutConfig = {
                        type: 'force',
                        repulsion: 200,
                        edgeLength: 100,
                        layoutAnimation: true
                    };
                    break;
                case 'circular':
                    layoutConfig = {
                        type: 'circular',
                        circular: {
                            rotateLabel: true
                        }
                    };
                    break;
                case 'radial':
                    layoutConfig = {
                        type: 'radial',
                        center: ['50%', '50%'],
                        radius: ['20%', '80%'],
                        sortBy: 'value'
                    };
                    break;
            }

            // 更新节点大小
            data.nodes.forEach(node => {
                node.symbolSize = node.symbolSize * (nodeSize / 20);
            });

            option = {
                tooltip: {
                    formatter: function(params) {
                        return `<div class="font-semibold">${params.name}</div>
                                <div>类型: ${data.categories[params.data.category].name}</div>
                                <div>值: ${params.data.value}</div>`;
                    }
                },
                legend: {
                    data: data.categories.map(cat => cat.name),
                    top: 10,
                    textStyle: {
                        color: '#666'
                    }
                },
                series: [
                    {
                        name: '关系图',
                        type: 'graph',
                        layout: layoutType,
                        force: layoutType === 'force' ? layoutConfig : null,
                        circular: layoutType === 'circular' ? layoutConfig.circular : null,
                        radial: layoutType === 'radial' ? layoutConfig : null,
                        data: data.nodes,
                        links: data.links.map(link => ({
                            ...link,
                            lineStyle: {
                                width: link.value * (lineWidth / 2),
                                curveness: 0.2
                            }
                        })),
                        categories: data.categories,
                        roam: true, // 允许缩放和平移
                        label: {
                            show: true,
                            position: 'right',
                            formatter: '{b}',
                            fontSize: 12
                        },
                        lineStyle: {
                            opacity: 0.9,
                            width: 2,
                            curveness: 0
                        },
                        emphasis: {
                            focus: 'adjacency',
                            lineStyle: {
                                width: 5
                            }
                        },
                        // 动画配置
                        animationDuration: 1500,
                        animationEasingUpdate: 'quinticInOut'
                    }
                ]
            };

            myChart.setOption(option);
        }

        // 初始化图表
        updateChart();

        // 监听窗口大小变化,调整图表尺寸
        window.addEventListener('resize', () => {
            myChart.resize();
        });

        // 事件监听
        document.getElementById('layoutType').addEventListener('change', updateChart);
        document.getElementById('nodeSize').addEventListener('input', updateChart);
        document.getElementById('lineWidth').addEventListener('input', updateChart);
        document.getElementById('refreshGraph').addEventListener('click', updateChart);

        // 节点点击事件
        myChart.on('click', function(params) {
            if (params.dataType === 'node') {
                alert(`你点击了: ${params.name}\n类型: ${data.categories[params.data.category].name}`);
            }
        });
    </script>
</body>
</html>

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档