437 lines
11 KiB
HTML
437 lines
11 KiB
HTML
<!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>
|