当前位置: 首页 > news >正文

echarts使用graph、lines实现拓扑,可以拖动增加effect效果

options.js

// import React from 'react'
// import * as echarts from 'echarts'import './index.less'export const useEchartsOptionFun = ({ nodeDataList, getNodeLinksDataList, getLinesCoordsFun }) => {const option = {title: {text: '拓扑关系图',top: 'top',left: 'center',},itemStyle: {normal: {color: '#67C23A',},shadowBlur: 0,},textStyle: {color: '#444',fontSize: 16,fontWeight: 600,},legend: [{// formatter: function (name) {//     return echarts.format.truncateText(name, 200, '12px', '…')// },tooltip: {show: false,},selectedMode: 'false',bottom: 20,},],animationDuration: 500,animationEasingUpdate: 'quinticInOut',xAxis: {show: false,max: 500,type: 'value',},yAxis: {show: false,type: 'value',max: 500,},tooltip: {formatter(params) {const { itemInfo = [] } = params.data || {}if (itemInfo.length === 0) return nulllet itemInfoStr = ''itemInfo.map(item => {itemInfoStr += `<div key=${item.name} class='topoEchartsBox_tooltip_title'>${item.name}:<span class='topoEchartsBox_tooltip_title_span'>${item.value}</span></div>`})const str = `<div class='topoEchartsBox_tooltip'> ${itemInfoStr} </div>`return str},},series: [{// focusNodeAdjacency:true,id: 'nodes',type: 'graph',// layout: 'force',layout: 'none',// roam: true, //鼠标缩放及平移coordinateSystem: 'cartesian2d',// coordinateSystem: 'cartesian2d',legendHoverLink: false,hoverAnimation: true,nodeScaleRatio: false,//建头edgeSymbol: ['circle', 'none'],edgeSymbolSize: [2, 15],edgeLabel: {show: true,normal: {show: true,position: 'middle',textStyle: {fontSize: 12,},// formatter: '{c}',},// formatter: '{c}',},emphasis: {scale: true,},cursor: 'pointer',roam: true,draggable: true,// focusNodeAdjacency: true,//圆形上面的文字label: {normal: {position: 'bottom',show: true,textStyle: {fontSize: 12,},},},itemStyle: {normal: {color: '#409eff',},shadowBlur: 0,},data: nodeDataList,links: getNodeLinksDataList(nodeDataList),lineStyle: {normal: {curveness: 0,color: '#67c23a',width: 2,},emphasis: {color: 'red',width: 3,type: 'dashed', //虚线},},},// ].concat([]),].concat([...getLinesCoordsFun()]),}return {option,}
}

topoEchartsBox.js

import React, { useCallback, useState, useEffect, useRef } from 'react'
import { Row, Col, Select, Button, Spin, Input, Modal, modal, message, Form, Radio, Tooltip, Descriptions, DatePicker } from 'antd'
import RsFlowSearch from '@/components/RsFlowSearch'
import { TooltipBox } from '@/components/utils/common'
import TableTooltip from '@/components/TableTooltip'
import * as IPServe from '@/serve/IPServe/IPServe'
import _ from 'lodash-es'
import Chart from '@/components/Chart-Topo'
import * as echarts from 'echarts'
import { useEchartsOptionFun } from './echarts/index.js'
import './index.less'
import bnc from '@/assets/ComImg/topoImg/bnc.png'
import jiaoHuanJi from '@/assets/ComImg/topoImg/jiaoHuanJi.png'
import olt from '@/assets/ComImg/topoImg/olt.png'
// -- 断开异常图标
const imgae_ = 'image://'
let errorEffectSymbol ='path://M671.830688 511.699001l319.059377-319.059377c43.945914-43.945914 43.945914-115.583774 0-159.529688-43.945914-43.945914-115.583774-43.945914-159.529688 0l-319.059377 319.059377-319.059377-319.059377c-43.945914-43.945914-115.583774-43.945914-159.529688 0-43.945914 43.945914-43.945914 115.583774 0 159.529688l319.059377 319.059377-319.059377 319.059377c-43.945914 43.945914-43.945914 115.583774 0 159.529688 43.945914 43.945914 115.583774 43.945914 159.529688 0l319.059377-319.059377 319.059377 319.059377c43.945914 43.945914 115.583774 43.945914 159.529688 0 43.945914-43.945914 43.945914-115.583774 0-159.529688L671.830688 511.699001z'
// 节点数据export default function (props) {const [nodeDataList, setnodeDataList] = useState([{// 当前设备名称name: 'liuqing',id: '1',// 要连接的设备名称linkTargetName: ['2', '3', '4'],linkValue: '好好学习',coordConfig: { level: 0 },symbolSize: 40,symbol: imgae_ + bnc,// draggable: true,value: [250, 450],itemInfo: [{ name: 'liuqing', value: '12台' },{ name: 'liuqing', value: '260个' },{ name: 'liuqing', value: '10%' },{ name: 'liuqing', value: '10%' },{ name: 'liuqing', value: '10%' },{ name: 'liuqing', value: '10%' },{ name: 'liuqing liuqing 连接数', value: '100' },{ name: 'liuqing liuqing', value: '10%' },{ name: 'IP liuqing', value: '10%' },],},//交换机,C,D ....n{name: '交换机',id: '2',linkTargetName: ['5', '6'],linkValue: '好好学习 ',coordConfig: {level: '1',},symbol: imgae_ + jiaoHuanJi,symbolSize: 40,// draggable: true,value: [160, 350],},{name: '交换机',id: '3',linkTargetName: ['5', '6', '8'],linkValue: '111',coordConfig: {level: '1',},symbol: imgae_ + jiaoHuanJi,symbolSize: 40,// draggable: true,value: [250, 350],},{name: '智能城域网',id: '4',linkTargetName: ['6', '7'],linkValue: '好好学习 ',coordConfig: {level: '1',},symbol: imgae_ + jiaoHuanJi,symbolSize: 40,// draggable: true,value: [340, 350],},{name: 'liuqing-1', // 节点名id: '5', // 节点名linkTargetName: [], // 连线目标节点linkValue: '好好学习 ', // 连线介绍coordConfig: {level: '2-error',effect: {// show: true,show: false,smooth: false,trailLength: 0,symbol: errorEffectSymbol,color: '#fb3f3f',symbolSize: 10,period: 3,delay: 1500,loop: true,},lineStyle: {normal: {curveness: 0,color: '#fb3f3f',width: 2,},},}, // 连线动态箭头配置,没有就不需要此配置value: [90, 100],// draggable: true,// fixed: true,symbol: imgae_ + olt,symbolSize: 40,itemStyle: {color: '#fb3f3f',},},{name: 'liuqing-2',id: '6',linkTargetName: [],linkValue: ' 好好学习',coordConfig: {level: '2',},value: [190, 100],// draggable: true,// fixed: true,symbol: imgae_ + olt,symbolSize: 40,},{name: 'liuqing-3',id: '7',linkTargetName: [],linkValue: '好好学习 ',coordConfig: {level: '2',},value: [250, 100],// draggable: true,fixed: true,symbol: imgae_ + olt,symbolSize: 40,},{name: 'liuqing-4',id: '8',linkTargetName: [],linkValue: ' 好好学习',coordConfig: {level: '2',},value: [350, 100],// draggable: true,symbol: imgae_ + olt,symbolSize: 40,},])const [boxHeight, setboxHeight] = useState('300px')const [myChart, setmyChart] = useState(null)const resizeFun = () => {const box = document.querySelector('.rsflowSearchContent .topoEcharts')const boxTop = box?.getBoundingClientRect()?.topsetboxHeight(`calc(${window.innerHeight}px - ${boxTop}px - 30px)`)}useEffect(() => {if (parseFloat(boxHeight) < 300) {setboxHeight('300px')}}, [boxHeight])useEffect(() => {window.addEventListener('resize', resizeFun)setTimeout(() => {resizeFun()})// nodeDataList 改变的时候 说明是拖动页面元素的时候// 重新 setOptionif (myChart) {let currentLinks = getNodeLinksDataList(nodeDataList) // 或者更高效地只更新受影响的 linkmyChart &&myChart.setOption({series: [{id: 'nodes',data: nodeDataList,links: currentLinks,},].concat([...getLinesCoordsFun()]),})}return () => {window.removeEventListener('resize', resizeFun)}}, [nodeDataList])const getNodeLinksDataList = function (nodeDataList) {let coordData = []nodeDataList.map(item => {item.linkTargetName.map(i => {const { id, name } = nodeDataList.find(i_find => i === i_find.id)coordData = [...coordData,{// 光点流动效果symbol: ['none', 'arrow'],symbolSize: [4, 8],label: {show: false,position: 'middle',formatter: item.name + '--' + name,},source: item.id,target: id,roam: true, // 允许缩放和平移focusNodeAdjacency: true, // 聚焦邻接点id: item.name + '---to---' + name,},]})})return coordData}// type === lines 的线条const getLinesCoordsFun = function () {let coorDataDict = {}let defaultConfig = {type: 'lines', //块1,2...n到节点A,B...NcoordinateSystem: 'cartesian2d',z: 1,effect: {show: true,smooth: true,trailLength: 0,symbol: 'arrow',color: '#67c23a',width: 20,symbolSize: 10,period: 3,delay: 1500,// loop: false,loop: true,},lineStyle: {width: 2,color: '#67c23a',},data: [],}nodeDataList.map(item => {if (item.coordConfig !== undefined) {if (!(item.coordConfig.level in coorDataDict)) {let coorConfig = JSON.parse(JSON.stringify(defaultConfig))// 自定义好的样式 lineStyleif (item.coordConfig.lineStyle !== undefined) {coorConfig.lineStyle = item.coordConfig.lineStyle}// 自定义好的样式 effectif (item.coordConfig.effect !== undefined) {coorConfig.effect = item.coordConfig.effect}// 根据 level 存起来各自的 coordConfigcoorDataDict[item.coordConfig.level] = coorConfig}// 设置连线 coordsitem.linkTargetName.map(i => {const { value, name } = nodeDataList.find(i_find => i === i_find.id)coorDataDict[item.coordConfig.level].data.push({coords: [item.value, value],})})}})return Object.values(coorDataDict)}const onChartdrag = ({ draggingNode, dataCoord }) => {// 更新 nodeDataList 中对应节点的位置const nodeDataListNew = nodeDataList.map(n => {if (n.id === draggingNode.data.id) {n.value = dataCoord}return n})setnodeDataList(nodeDataListNew)}// myChart 初始后调用的第一个方法// 展示接口返回的数据 nodeDataListconst returnMyChartFun = myChart => {const { option } = useEchartsOptionFun({ nodeDataList, getNodeLinksDataList, getLinesCoordsFun })setmyChart(myChart)myChart.setOption(option)}return (<div className="topoEchartsBox"><RsFlowSearch title="BNC/BRAS跨域综合分析拓扑关系图" isShowRightIcon={false}><Chart className={'topoEcharts'} onChartdrag={onChartdrag} returnMyChartFun={returnMyChartFun} style={{ height: boxHeight, width: '100%' }} /></RsFlowSearch></div>)
}

Chat-Topo.js

import React, { useEffect, useRef, useState } from 'react'
import useEchartsSize from '@/components/useEchartsSize'
var echarts = require('echarts')
const debounce = () => {let timer = nullconst newDebounce = function (fn, wait, ...args) {return new Promise((resolve, reject) => {if (timer !== null) {clearTimeout(timer)}timer = setTimeout(_ => {try {resolve(fn(...args))} catch (e) {reject(e)}}, wait)})}return newDebounce
}
const newDebounce = debounce()
let draggingNode = nullfunction chart(props) {const { style, className, onChartClick, onChartdrag, returnMyChartFun } = propsconst chartRef = useRef(null)const [barChart, setBarChart] = useState()useEchartsSize(barChart)useEffect(() => {const chartDom = chartRef.currentconst myChart = echarts.init(chartDom)myChart.clear()myChart.resize()returnMyChartFun(myChart)setBarChart(myChart)onChartClick &&myChart.on('click', params => {onChartClick(params.name)})myChart.on('mousedown', params => {if (params.componentType === 'series' && params.seriesType === 'graph' && params.dataType === 'node') {draggingNode = params}})myChart.getDom().addEventListener('mouseup', params => {newDebounce(() => {if (draggingNode) {const pixel = [params.layerX, params.layerY]const dataCoord = myChart.convertFromPixel({ seriesIndex: 0 }, pixel)onChartdrag({ draggingNode, dataCoord, myChart })draggingNode = null}}, 16)})// }}, [])return <div className={className} ref={chartRef} style={style || { width: '100%', height: '300px' }} />
}export default chart

请添加图片描述

http://www.xdnf.cn/news/876043.html

相关文章:

  • 力扣HOT100之二分查找:35. 搜索插入位置
  • PH热榜 | 2025-06-04
  • Facebook接入说明
  • JavaScript 二维数组初始化:为什么 fill([]) 是个大坑?
  • 群论在现代密码学中的应用探索与实践 —— 从理论到C语言实现
  • 列出浏览器所有的启动参数,并解释说明每个参数的含义
  • 行为型-模板模式
  • 【高校论文】DFORMER重新思考用于语义分割的RGBD表示学习[南开国防科大]
  • 电路图识图基础知识-直接启动/接触器启动(十四)
  • 分布式训练下的多进程环境
  • [Java 基础]枚举
  • NLP中的input_ids是什么?
  • Pycharm 配置解释器
  • mybatis实现插入postgresql的json类型数据
  • DA14531_beacon_大小信标设备开发
  • 如何安装并使用RustDesk
  • Java Fork/Join框架:三大核心组件深度解析
  • 功率估计和功率降低方法指南(1~2)
  • 2025年6月4日收获
  • 如何进行股票回测?
  • 第三方检测:软件适配测试报告
  • SAFe/LeSS/DAD等框架的核心适用场景如何选择?
  • Paraformer分角色语音识别-中文-通用 FunASR
  • SEO长尾关键词布局优化法
  • 二维码生成器
  • 宝马集团推进数字化转型:强化生产物流与财务流程,全面引入SAP现代架构
  • expect程序交互学习
  • 电子电路:共集电极放大器原理与作用解析
  • GO语言----基础类型取别名
  • PhpStorm设置中文