当前位置: 首页 > 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

请添加图片描述

相关文章:

  • Kafka入门- 基础命令操作指南
  • P1064 [NOIP 2006 提高组] 金明的预算方案——依赖背包
  • k8s热更新-subPath 不支持热更新
  • 界面组件DevExpress WPF中文教程:Grid - 如何识别行和卡片?
  • 数据结构(7)—— 二叉树(1)
  • 微信小程序动态组件加载的应用场景与实现方式
  • 字节开源FlowGram:AI时代可视化工作流新利器
  • 【Axure视频教程】下载和安装Axure汉化包
  • 深度解析Mysql中MVCC的工作机制
  • 内存管理【Linux操作系统】
  • .Net Framework 4/C# 面向对象编程进阶
  • 【2025】通过idea把项目到私有仓库(3)
  • 宏基因组产品升级——微生物菌群木质素降解能力评估!
  • 中科君芯JFG150N40B 40V-N沟道增强模式功率驱动器
  • Go语言依赖管理与版本控制-《Go语言实战指南》
  • [蓝桥杯]最大比例
  • [蓝桥杯]三元组中心问题
  • 如何在mac上安装podman
  • 机器学习监督学习sklearn实战三:八种算法对印第安人糖尿病预测数据进行分类和比较
  • 在WPS中如何启用宏VBA wps.vba.exe下载和安装
  • 服装设计公司主要做什么/天津优化代理
  • 招聘网站系统怎么做/app平台搭建
  • wordpress forum/seo站长综合查询
  • 不懂代码用cms做网站/湖南网站建设平台
  • 刷网站流量有用吗/手机版百度入口
  • 核工业华南建设集团网站/百度首页关键词优化