2025-11-25 17:49:53 +08:00

437 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ECharts 热图实现</title>
<!-- 引入ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
#chartContainer {
width: 800px;
height: 600px;
margin: 0 auto;
}
</style>
</head>
<body>
<div id="chartContainer"></div>
<script>
// 初始化图表
const myChart = echarts.init(document.getElementById('chartContainer'))
// 响应窗口大小变化
window.addEventListener('resize', function () {
myChart.resize()
})
var graph = {
nodes: [
{
name: 'A',
value: ['教授', '在职', '党委办公室、校长办公室'],
category: '中心教师',
symbolSize: 50,
tooltip: {
formatter: '{b0}:{c0}',
},
},
{
name: 'B',
category: '论文',
value: ['期刊论文', '2005'],
symbolSize: 20,
tooltip: {
formatter: '{b0}:{c0}',
},
},
{
name: 'C',
category: '论文合作教师',
symbolSize: 50,
},
{
name: 'D',
category: '项目',
value: ['信息与通信工程学院', '立项日期20131101'],
symbolSize: 20,
tooltip: {
formatter: '{b0}:{c0}',
},
},
{
name: 'N',
category: '项目合作教师',
symbolSize: 50,
},
{
name: 'Q',
category: '项目',
symbolSize: 20,
},
{
name: 'S',
category: '项目',
symbolSize: 20,
},
{
name: 'E',
category: '专著专利',
symbolSize: 20,
value: ['专利文献', '2009-07-21'],
tooltip: {
formatter: '{b0}:{c0}',
},
},
{
name: 'W',
category: '专著专利',
symbolSize: 20,
},
{
name: 'Y',
category: '专著专利',
symbolSize: 20,
},
{
name: 'Z',
category: '专著专利',
symbolSize: 20,
},
{
name: 'F',
category: '专著专利合作教师',
symbolSize: 50,
},
{
name: 'O',
category: '专著专利合作教师',
symbolSize: 50,
},
{
name: 'P',
category: '专著专利合作教师',
symbolSize: 50,
},
{
value: ['信息与通信工程学院', '信息工程 '],
name: 'G',
category: '课程',
symbolSize: 20,
tooltip: {
formatter: '{b0}:{c0}',
},
},
{
name: 'I',
category: '课程',
symbolSize: 20,
},
{
name: 'L',
category: '课程',
symbolSize: 20,
},
{
name: 'H',
category: '课程合作教师',
symbolSize: 50,
},
{
name: 'M',
category: '课程合作教师',
symbolSize: 50,
},
],
links: [
{
source: 'A',
target: 'B',
},
{
source: 'B',
target: 'C',
},
{
source: 'A',
target: 'D',
},
{
source: 'D',
target: 'N',
},
{
source: 'N',
target: 'Q',
},
{
source: 'N',
target: 'R',
},
{
source: 'A',
target: 'E',
},
{
source: 'E',
target: 'F',
},
{
source: 'F',
target: 'W',
},
{
source: 'F',
target: 'Y',
},
{
source: 'P',
target: 'Z',
},
{
source: 'E',
target: 'O',
},
{
source: 'E',
target: 'P',
},
{
source: 'A',
target: 'G',
},
{
source: 'G',
target: 'H',
},
{
source: 'G',
target: 'M',
},
{
source: 'M',
target: 'I',
},
{
source: 'M',
target: 'L',
},
],
}
const defaultCategory = '中心教师'
const graphTitle = '力导向关系图--实现点击节点展开折叠'
const currentGraph = {
nodes: {},
links: {},
}
const nodeMap = {}
// 页面加载时,第一次初始化图
function init() {
// 根据定义的常量产生currentGraph的默认数据
// 遍历全部nodes和links产生node映射map
for (let i = 0; i < graph.nodes.length; i++) {
if (graph.nodes[i].category === defaultCategory) {
currentGraph.nodes[graph.nodes[i].name] = graph.nodes[i]
}
nodeMap[graph.nodes[i].name] = graph.nodes[i]
nodeMap[graph.nodes[i].name]['links'] = {}
nodeMap[graph.nodes[i].name]['nodes'] = {}
nodeMap[graph.nodes[i].name]['hasAppend'] = false
}
for (let i = 0; i < graph.links.length; i++) {
let link = graph.links[i]
if (
nodeMap[link.source] !== undefined &&
nodeMap[link.target] !== undefined
) {
nodeMap[link.source].links[link.target] = link
nodeMap[link.source].nodes[nodeMap[link.target].name] =
nodeMap[link.target]
}
}
for (let i = 0; i < graph.nodes.length; i++) {
graph.nodes[i].itemStyle = null
graph.nodes[i].label = {
normal: {
show: graph.nodes[i].symbolSize > 15,
},
}
}
redrawGraph()
}
// 处理点击节点展开
function append(nodeName) {
// 根据nodeName从nodeMap里拿出对应的nodes和links并append到currentGraph.nodes currentGraph.links
let node = nodeMap[nodeName]
if (
node.hasAppend === true ||
Object.keys(node.nodes).length === 0 ||
Object.keys(node.links).length === 0
) {
alert('无法继续展开')
return
}
Object.values(node.nodes).forEach((n) => {
currentGraph.nodes[n.name] = n
})
Object.values(node.links).forEach((l) => {
currentGraph.links[l.source + '_' + l.target] = l
})
node.hasAppend = true
redrawGraph()
}
// 处理点击节点收缩
function remove(nodeName) {
//根据nodeName从nodeMap里拿出对应的nodes和links从currentGraph.nodes currentGraph.links删除当前节点的nodes和links并且递归
let node = nodeMap[nodeName]
Object.values(node.nodes).forEach((n) => {
delete currentGraph.nodes[n.name]
if (n.hasAppend === true && Object.keys(n.nodes).length > 0) {
remove(n.name)
}
})
Object.values(node.links).forEach((l) => {
delete currentGraph.links[l.source + '_' + l.target]
})
// 设置flag 等于false
node.hasAppend = false
redrawGraph()
}
// 根据更新后的option重新画图
function redrawGraph() {
option.series[0].data = Object.values(currentGraph.nodes)
option.series[0].links = Object.values(currentGraph.links)
console.log(option)
myChart.setOption(option)
}
const option = {
title: {
text: graphTitle,
top: 'top',
left: 'center',
},
tooltip: {},
legend: [],
animation: false,
series: [
{
type: 'graph',
layout: 'force',
data: Object.values(currentGraph.nodes),
links: Object.values(currentGraph.links),
categories: [
{
name: '中心教师',
itemStyle: {
color: '#c23531',
},
},
{
name: '专著专利合作教师',
itemStyle: {
color: '#749f83',
},
},
{
name: '课程合作教师',
itemStyle: {
color: '#6e7074',
},
},
{
name: '论文合作教师',
itemStyle: {
color: '#2f4554',
},
},
{
name: '论文',
itemStyle: {
color: '#61a0a8',
},
},
{
name: '专著专利',
itemStyle: {
color: '#91c7ae',
},
},
{
name: '课程',
itemStyle: {
color: '#999ea4',
},
},
{
name: '项目合作教师',
itemStyle: {
color: '#DEB887',
},
},
{
name: '项目',
itemStyle: {
color: '#bda29a',
},
},
],
roam: true,
focusNodeAdjacency: false,
itemStyle: {
normal: {
borderColor: '#fff',
borderWidth: 1,
shadowBlur: 10,
shadowColor: 'rgba(0, 0, 0, 0.3)',
},
},
label: {
position: 'right',
formatter: '{b}',
},
lineStyle: {
color: 'target',
opacity: 0.6,
curveness: 0.3,
},
emphasis: {
lineStyle: {
width: 10,
},
},
force: {
layoutAnimation: false,
repulsion: 500,
},
},
],
}
init()
// 设置配置项
myChart.setOption(option)
myChart.on('click', function (params) {
if (params.dataType === 'node') {
const node = nodeMap[params.data.name]
if (node.hasAppend === true) {
remove(node.name)
} else {
append(node.name)
}
}
})
</script>
</body>
</html>