首页 > 其他分享 >react中使用echarts关系图

react中使用echarts关系图

时间:2024-09-05 11:36:13浏览次数:6  
标签:关系 const name 节点 react item gid time echarts

 

一,工作需求,展示几类数据关系,可缩放大小,可拖拽位置,在节点之间的连线上展示相关日期,每个节点展示本身信息,并且要求每个关系节点能点击。

实现情况如图所示:

二,实现过程中遇到的问题: 关系图完美呈现,但关系节点点击后,整个关系图会杂乱无章的浮动,导致不知道点击了哪个关系节点。

 

 

三,解决思路,等关系图稳定后,获取每个关系节点的位置坐标,再次将关系节点定在相应的位置。

四,整体代码:

相关参数options.js

export default {
  title: {
    text: '综合关系图(以GID为中心)',
  },
  tooltip: {
    backgroundColor: '#666',
    formatter(params) {
      //  console.log("wq",params)
      return `
      <div>
      ${params.name}
      </div>
      `;
    },
  },
  animationDurationUpdate: 1000, // 1500
  animationEasingUpdate: 'quinticInOut',
  label: {
    normal: {
      show: true,
      textStyle: {
        fontSize: 12,
      },
    },
  },
  legend: {
    x: 'center',
    show: true,
    data: ['GID', 'UID', 'DID', 'IP', 'PHONE'],
  },
  series: [
    {
      type: 'graph',
      layout: 'force',
      symbolSize: 35, // 关系节点大小
      focusNodeAdjacency: true, // 是否在鼠标移到节点上的时候突出显示节点以及节点的边和邻接节点。
      roam: true, // 是否开启鼠标缩放和平移漫游 可以设置成 'scale' 或者 'move'。设置成 true 为都开启
      categories: [
        {
          // 节点分类类目
          name: 'GID',
          itemStyle: {
            normal: {
              color: '#C23531',
            },
          },
        },
        {
          name: 'UID',
          itemStyle: {
            normal: {
              color: '#2F4554',
            },
          },
        },
        {
          name: 'DID',
          itemStyle: {
            normal: {
              color: '#F9AB3F',
            },
          },
        },
        {
          name: 'IP',
          itemStyle: {
            normal: {
              color: '#6F9B03',
            },
          },
        },
        {
          name: 'PHONE',
          itemStyle: {
            normal: {
              color: '#1890FF',
            },
          },
        },
      ],
      label: {
        normal: {
          show: true,
          textStyle: {
            fontSize: 12,
          },
        },
      },
      force: {
        repulsion: 1000, // 节点之间的斥力因子。支持数组表达斥力范围,值越大斥力越大。
        gravity: 0.03, // 节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
        edgeLength: 160, // 边的两个节点之间的距离,这个距离也会受 repulsion。[10, 50] 。值越小则长度越长
        layoutAnimation: true, // 这个参数决定是否显示布局的迭代动画,在浏览器端节点数据较多(>100)的时候不建议关闭,布局过程会造成浏览器假死。
      },
      // edgeSymbolSize: [4, 50],
      edgeLabel: {
        normal: {
          show: true,
          textStyle: {
            fontSize: 10,
          },
          formatter: '{c}',
        },
      },
      data: [],
      links: [],
      lineStyle: {
        normal: {
          opacity: 0.9,
          width: 1,
          curveness: 0,
        },
      },
    },
  ],
};

 

实现页代码:在react代码中实现的关系图

import React, { PureComponent } from 'react';
import { Card, Form, Modal, } from 'antd';
import { connect } from 'dva';
import echarts from 'echarts/lib/echarts';
import PageHeaderWrapper from '../../../components/PageHeaderWrapper';
import IpMoudle from './ipMoudle';
import GidMoudle from './gidMoudle';
import UidMoudle from './accountMoudle';
import DidMoudle from './didMoudle';
import PhoneMoudle from './phoneMoudle';
import 'echarts/lib/chart/graph';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/legend';
import 'echarts/lib/component/title';
import options from './options';

const getzf = val => {
return val * 1 < 10 ? `0${val}` : val;
};

const shortFormatDate = d => {
if (d === undefined) {
return '';
}
const now = new Date(d * 1000);
const year = now.getFullYear();
const month = now.getMonth() + 1;
const date = now.getDate();
return `${year}/${getzf(month)}/${getzf(date)}`;
};
@connect(({ allVal, loading }) => ({
allVal,
loading: loading.models.allVal,
}))
@Form.create()
class Over extends PureComponent {
constructor(props) {
super(props);
this.state = {
start: '',
end: '',
flog: 'gid',
lei: '',
};
}

componentDidMount() {
const myChart = echarts.init(document.getElementById('main'));
// 节点绑定点击事件
myChart.on('click', params => {
this.openShow(params);
});
this.getCharts();
}

getCharts = () => {
const myChart = echarts.init(document.getElementById('main'));
const {
allVal: { baseData },
} = this.props;
// baseData: [
// {uid: "1553919784", gid: "000000002548ba6e", create_time: 1595606400, update_time: 1638979200},
// {ip: "123.157.158.59", gid: "000000002548ba6e", create_time: 1601049600, update_time: 1639065600},
// {did: "EFBA0B48-4B7E-42B1-9D5D-B33359C3AEDF", gid: "000000015508f569", create_time: 1609516800,update_time: 1642608000},
// {uid: "1553919784", gid: "000000015508f569", create_time: 1612454400, update_time: 1642608000},
// {did: "ANDROID_04b0673ccef36422", gid: "000000002548ba6e", create_time: 1634227200,update_time: 1638979200},
// {ip: "112.10.61.105", gid: "000000015508f569", create_time: 1636214400, update_time: 1638547200},
// {ip: "115.195.90.61", gid: "000000015508f569", create_time: 1637164800, update_time: 1637164800},
// {ip: "60.163.254.188", gid: "000000015508f569", create_time: 1638460800, update_time: 1638460800},
// {ip: "122.231.208.82", gid: "000000015508f569", create_time: 1638806400, update_time: 1638806400},
// {did: "ANDROID_04b0673ccef36423", gid: "000000002548ba6e", create_time: 1638979200,update_time: 1639065600},
// {ip: "115.220.137.100", gid: "000000015508f569", create_time: 1638979200, update_time: 1639238400},
// {ip: "39.182.14.22", gid: "000000015508f569", create_time: 1641657600, update_time: 1641657600},
// {ip: "223.104.19.214", gid: "000000015508f569", create_time: 1642608000, update_time: 1642608000},
// ],

const newdata = this.getNewData(baseData); // 处理点的数据
const newlinks = this.getNewlinks(baseData); // 处理节点之间的关系

options.series[0].data = newdata;
options.series[0].links = newlinks;

// 绘制图表
myChart.setOption(options);
   // 获取图表固定坐标,再次绘制图表
    const layout = myChart._chartsViews[0]._symbolDraw._data._itemLayouts;

layout.map((item, index) => {
newdata[index].x = item[0];
newdata[index].y = item[1];
});
options.series[0].data = newdata;
myChart.setOption(options);
   // 节点被选中的操作

myChart.on('legendselectchanged', params => {
      // const { selected } = params;
// ...
});
};

// 再次获取关系节点数据后重绘,暂未调用,有需要再次重绘的可以调用
handleSubmit = e => {
e.preventDefault();
const {
form: { validateFields },
} = this.props;
validateFields((err, values) => {
if (!err) {
const { dispatch } = this.props;
const { idtype, idvalue } = values;
const { start, end } = this.state;
const date1 = new Date(start);
const date2 = new Date(end);
const s = date1.getTime() / 1000;
const en = date2.getTime() / 1000;
const val = { idtype, idvalue, s, en };
if (idtype === 'phone') {
dispatch({
type: 'allVal/fetchAllValP',
payload: val,
});
} else {
dispatch({
type: 'allVal/fetchAllVal',
payload: val,
});
}
}
});
setTimeout(this.getCharts, 1000);
};

// 节点点击触发函数
openShow = e => {
if (e.dataType === 'node') {
const { data } = e;
this.showSelect(data);
}
};

// 根据节点类型不同请求不同的接口 ["GID", "UID", 'DID','IP']
showSelect = data => {
const { category, name } = data;
switch (category) {
case 'GID':
this.gidSearch(name);
break;
case 'UID':
this.uidSearch(name);
break;
case 'IP':
this.ipSearch(name);
break;
case 'PHONE':
this.phoneSearch(name);
break;
case 'DID':
this.didSearch(name);
break;
default:
break;
}
};

ipSearch = name => {
const { dispatch } = this.props;
dispatch({
type: 'allVal/fetchIpVal',
payload: name,
});
this.setState({ lei: 'ip' });
this.showModal();
};

phoneSearch = phone => {
const { dispatch } = this.props;
dispatch({
type: 'allVal/fetchPhoneVal',
payload: { phone },
});
this.setState({ lei: 'phone' });
};

gidSearch = name => {
const { dispatch } = this.props;
dispatch({
type: 'allVal/fetchGidVal',
payload: name,
});
this.setState({ lei: 'gid' });
this.showModal();
};

uidSearch = name => {
const { dispatch } = this.props;
dispatch({
type: 'allVal/fetchUidVal',
payload: { phone: name },
});
this.setState({ lei: 'uid' });
this.showModal();
};

didSearch = name => {
const { dispatch } = this.props;
dispatch({
type: 'allVal/fetchDidVal',
payload: { did: name },
});
this.setState({ lei: 'did' });
this.showModal();
};

// 模态框展示
showModal = () => {
const { dispatch } = this.props;
dispatch({
type: 'allVal/showM',
payload: true,
});
};

// 模态框隐藏
handleCancel = () => {
const { dispatch } = this.props;
dispatch({
type: 'allVal/showM',
payload: false,
});
};

// 判断节点类目
getGrade = (val, b) => {
const a = Object.keys(val);
const c = a.indexOf(b);
a.splice(c, 1);
let grade = '';
for (let i = 0; i < a.length; i += 1) {
switch (a[i]) {
case 'gid':
if (a.indexOf('gid') > -1) {
grade = 'GID';
}
break;
case 'did':
if (a.indexOf('did') > -1) {
grade = 'DID';
}
break;
case 'uid':
if (a.indexOf('uid') > -1) {
grade = 'UID';
}
break;
case 'ip':
if (a.indexOf('ip') > -1) {
grade = 'IP';
}
break;
case 'phone':
if (a.indexOf('phone') > -1) {
grade = 'PHONE';
}
break;
default:
break;
}
}
return grade;
};

// 处理成需要的data格式
getNewData = val => {
const { flog } = this.state;
if (val.length === 0) {
return [];
}
const arr = val.map(item => item.gid);
const newArr = Array.from(new Set(arr));
const newdata = [];
// eslint-disable-next-line array-callback-return
newArr.map(item => {
newdata.push({
name: item,
draggable: false,
label: {
show: false,
},
category: 'GID',
});
});
// eslint-disable-next-line array-callback-return
val.map(item => {
newdata.push({
name: item[this.getGrade(item, flog).toLowerCase()],
draggable: false,
label: {
show: false,
},
category: this.getGrade(item, flog),
});
});
const hash = {};
const data = newdata.reduce(function(item, next) {
// eslint-disable-next-line no-unused-expressions
hash[next.name] ? '' : (hash[next.name] = true && item.push(next));
return item;
}, []);
return data;
};

// 处理成需要的links 格式
getNewlinks = val => {
const { flog } = this.state;
if (val.length === 0) {
return [];
}
const newlinks = [];
// eslint-disable-next-line array-callback-return
val.map(item => {
newlinks.push({
source: item[this.getGrade(item, flog).toLowerCase()],
target: item[flog],
value: `${shortFormatDate(item.create_time)}-${shortFormatDate(item.update_time)}`,
});
});
return newlinks;
};


render() {
const { lei } = this.state;
const {
allVal: { visible },
} = this.props;
return (
<PageHeaderWrapper>
<Card style={{ position: 'relative' }}>
<div id="main" style={{ height: '1000px', width: '100%' }}>
{' '}
</div>
<Modal
visible={visible}
title="详细信息"
onCancel={this.handleCancel}
footer={null}
width="800px"
>
<div>
{lei === 'gid' && <GidMoudle />}
{lei === 'ip' && <IpMoudle />}
{lei === 'phone' && <PhoneMoudle />}
{lei === 'uid' && <UidMoudle />}
{lei === 'did' && <DidMoudle />}
</div>
</Modal>
</Card>
</PageHeaderWrapper>
);
}
}

export default Over;

 

标签:关系,const,name,节点,react,item,gid,time,echarts
From: https://www.cnblogs.com/class1/p/13692539.html

相关文章

  • 【思考模型框架】因果关系图和因果回路图,通过绘制因果关系图,深入了解问题的本质,并找到
    一、定义1.1因果关系图因果关系图,是一种图形化表示方法,用于展示变量之间的因果关系。因果关系图,通常由节点(代表变量)和边(代表因果关系)组成。因果关系图,帮助人们理解复杂系统中不同因素是如何相互作用的。因果关系图,是一种用于分析问题原因和结果的思维工具。因果关系......
  • Vue前端开发 转 React 指南
    JSX先介绍React唯一的一个语法糖:JSX。理解JSX语法并不困难,简单记住一句话,遇到{}符号内部解析为JS代码,遇到成对的<>符号内部解析为HTML代码。当你写下这个React组件时:importReactfrom'react';functionMyComponent(props){return<div>{props.hello}<......
  • 【Linux】进程间的关系(第十三篇)
    目录1.亲缘关系:2.进程组关系:3.会话关系4.进程、进程组与会话的关系5.例子1.亲缘关系:2.进程组关系:3.进程间会话关系1.亲缘关系:多个进程间可能存在亲缘关系(多个进程间可能是父子进程结构,也可能更为复杂的层级亲缘结构)2.进程组关系:定义:进程组是一个或多个进程的集......
  • React18+TypeScript4+Vue3:‌入门到实战,‌灵活技术选型指南
    React18+TypeScript4+Vue3:‌入门到实战,‌灵活技术选型指南在当今的前端开发领域,‌React、‌TypeScript和Vue是三大热门技术,‌它们各自拥有独特的优势和广泛的应用场景。‌掌握这些技术,‌不仅能够提升你的开发效率,‌还能帮助你在不同项目中做出更加合适的技术选型。‌本文将带......
  • React 18 系统精讲:‌前端教程与最新特性源码级剖析
    React18系统精讲:‌前端教程与最新特性源码级剖析引言React18带来了许多激动人心的新特性和改进,‌旨在提高应用的性能和用户体验。‌本教程将深入探讨React18的核心特性,‌包括并发特性、‌新的API、‌以及源码层面的解析,‌帮助前端开发者更好地理解和应用这些新技术。‌......
  • React18+TS+NestJS+GraphQL+AntD+TypeOrm+Mysql全栈开发在线教育平台
    ‌标题‌:‌构建在线教育平台:‌React18+TypeScript+NestJS+GraphQL+AntDesign+TypeORM+MySQL全栈技术栈解析‌引言‌:‌在当今数字化时代,‌在线教育平台的需求日益增长。‌为了构建一个高效、‌可扩展且用户友好的在线教育平台,‌选择合适的技术栈至关重要。‌本文......
  • PART1-Oracle关系数据结构-分区、视图以及其他的对象
    4.分区、视图与其他对象4.1.分区概述分区允许您将非常大的表和索引分解成更小、更易于管理的部分,称为分区。每个分区是一个独立的对象,有自己的名称,并且可以选择拥有自己的存储特性。为了说明分区的概念,假设一个人力资源经理有一个大盒子,里面装着员工文件夹。每个文件夹都列出......
  • react中的弹幕效果怎么实现
    就像这样下面有完整代码一、引入的模块和组件引入React的核心库以及useEffect和useState这两个用于处理副作用和管理状态的ReactHook。引入rc-bullets库中。这个库可用于创建弹幕效果二、组件内部状态管理//弹幕屏幕const[screen,setScreen]=useState(null)......
  • 科研绘图系列:python语言散点相关系数图(scatter plot)
    介绍采用plot_pairwise_density函数对数据画图,展示数据的散点分布和密度分布。散点图(ScatterPlot)是一种数据可视化技术,用于显示两个变量之间的关系。它通过在直角坐标系中绘制数据点来展示数据的分布和趋势。每个数据点在横轴(X轴)和纵轴(Y轴)上都有一个坐标值,分别对应两个......
  • Java中类与类之间的关系
    一.类与类之间有哪些关系1.继承关系:继承指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力。在Java中继承关系通过关键字extends明确标识,在设计时一般没有争议性。在UML类图设计中,继承用一条带空心三角箭头的实线表示,从子类指......