feat:131的一些修改

This commit is contained in:
liyuanhu 2025-04-24 18:53:32 +08:00
parent 32f38e1efb
commit 1928b112fb
6 changed files with 916 additions and 893 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, memo } from "react";
import { useEffect, useMemo, useRef, memo, useState } from "react";
import * as echarts from "echarts";
// import 'echarts-gl';
// import { useQueryClient } from "@tanstack/react-query";
@ -19,58 +19,9 @@ interface LinesItemType {
}
type LinesDataType = [LinesItemType, LinesItemType];
type LinesType = [string, LinesDataType[]];
// 从国家经纬度数据中随机生成涟漪效果
// const createRandomCountryRipples = (count = 10) => {
// // 获取所有国家代码
// const countryCodes = Object.keys(geoCoordMap);
// // 创建随机点数据
// const randomPoints = [];
// // 随机选择国家
// for (let i = 0; i < count; i++) {
// // 随机选择一个国家代码
// const randomIndex = Math.floor(Math.random() * countryCodes.length);
// const countryCode = countryCodes[randomIndex];
// // 获取该国家的坐标
// const coords = geoCoordMap[countryCode];
// // 添加一些微小的随机偏移,使点不完全重叠在国家中心
// const offsetLon = (Math.random() - 0.5) * 5; // ±2.5度的经度偏移
// const offsetLat = (Math.random() - 0.5) * 5; // ±2.5度的纬度偏移
// randomPoints.push({
// name: countryCode,
// value: [coords[0] + offsetLon, coords[1] + offsetLat],
// // 可以随机设置涟漪大小
// symbolSize: 3 + Math.random() * 5,
// // 可以存储国家代码用于显示信息
// countryCode: countryCode,
// });
// }
// // 返回涟漪效果系列
// return {
// type: "effectScatter",
// coordinateSystem: "geo",
// zlevel: 2,
// symbol: "circle",
// // 使用数据中的symbolSize
// symbolSize: (data: any) => data.symbolSize || 5,
// rippleEffect: {
// period: 4 + Math.random() * 4, // 随机周期
// brushType: "stroke",
// scale: 4 + Math.random() * 3, // 随机大小
// },
// itemStyle: {
// color: "#0ea5e9",
// shadowBlur: 10,
// shadowColor: "#0ea5e9",
// },
// data: randomPoints,
// // 确保不显示标签
// label: {
// show: false,
// },
// // 确保不响应鼠标事件
// silent: true,
// } as echarts.SeriesOption;
// };
// 连线动画的间隔时间(毫秒)
const LINE_ANIMATION_INTERVAL = 3000; // 3秒
// 创建单个国家的涟漪效果
const createCountryRipple = (countryCode: string) => {
@ -85,21 +36,67 @@ const createCountryRipple = (countryCode: string) => {
};
export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
// const queryClient = useQueryClient()
const proxyGeoRef = useRef<EChartsType | null>(null);
const preMainToData = useRef<{ country_code: string }[]>([]);
// 添加状态来跟踪当前显示的连线索引
const [currentLineIndex, setCurrentLineIndex] = useState(-1);
// 添加状态来存储所有连线数据
const [lineConnections, setLineConnections] = useState<{from: string, to: string}[]>([]);
// 添加状态来存储所有点
const [allPoints, setAllPoints] = useState<any[]>([]);
// 使用ref来跟踪动画状态避免重新渲染
const animationTimerRef = useRef<NodeJS.Timeout | null>(null);
// 添加状态来跟踪数据是否已经变化
const dataKeyRef = useRef<string>("");
// 处理代理数据
const mainToData = useMemo(() => {
// 使用新的数据结构
const proxiesList = screenData?.proxy_info?.proxies ?? [{data:[{country_code: 'AI', ingress_country_code: 'AE'}], isLine: true}];
// 初始化数据数组 - 不再包含 startCountry
// 初始化数据数组
const data: any = [];
console.log(proxiesList, 'proxiesList');
// 收集所有点和连线信息
const points: any[] = [];
const connections: {from: string, to: string}[] = [];
// 遍历代理列表
proxiesList.forEach((proxyItem: any) => {
// 检查是否有数据数组
if (proxyItem.data && Array.isArray(proxyItem.data)) {
// 遍历数据数组中的每个项目
proxyItem.data.forEach((item: any) => {
// 添加起点到点集合
const fromCode = item.country_code.toUpperCase();
const fromPoint = createCountryRipple(fromCode);
if (fromPoint && !points.some(p => p.country_code === fromCode)) {
points.push(fromPoint);
}
// 如果有终点,也添加到点集合
if (item.ingress_country_code) {
const toCode = item.ingress_country_code.toUpperCase();
const toPoint = createCountryRipple(toCode);
if (toPoint && !points.some(p => p.country_code === toCode)) {
points.push(toPoint);
}
// 如果需要连线,添加到连线集合
if (proxyItem.isLine === true) {
connections.push({
from: fromCode,
to: toCode
});
}
}
// 如果有 ingress_country_code则添加一对起点和终点
if (item.ingress_country_code) {
// 添加起点country_code
@ -125,9 +122,67 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
}
});
// 更新点和连线状态
setAllPoints(points);
setLineConnections(connections);
// 生成当前数据的唯一键
const currentDataKey = JSON.stringify(proxiesList);
// 检查数据是否变化
if (currentDataKey !== dataKeyRef.current) {
// 数据变化,重置连线索引
setCurrentLineIndex(-1);
dataKeyRef.current = currentDataKey;
// 清除任何现有的动画定时器
if (animationTimerRef.current) {
clearTimeout(animationTimerRef.current);
animationTimerRef.current = null;
}
// 启动连线动画
if (connections.length > 0) {
setTimeout(() => {
startLineAnimation(connections);
}, 500); // 短暂延迟,确保点已经显示
}
}
return data;
}, [screenData]);
// 启动连线动画的函数
const startLineAnimation = (connections: {from: string, to: string}[]) => {
if (connections.length === 0) return;
let index = 0;
// 递归函数,用于按顺序显示连线
const animateNextLine = () => {
setCurrentLineIndex(index);
index++;
if (index < connections.length) {
animationTimerRef.current = setTimeout(animateNextLine, LINE_ANIMATION_INTERVAL);
}
};
// 开始动画
animateNextLine();
};
// 组件卸载时清除定时器
useEffect(() => {
return () => {
if (animationTimerRef.current) {
clearTimeout(animationTimerRef.current);
animationTimerRef.current = null;
}
};
}, []);
const getLineItem = (
preCode: string,
nextCode: string
@ -150,56 +205,10 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
// 实现数据处理
const solidData: LinesType[] = [["main", []]]; // 使用"main"替代startCountry.country_code
// 收集需要显示涟漪效果的所有点(包括连线和不连线的)
const ripplePoints: any[] = [];
// 处理主路径数据
for (let i = 0; i < mainToData.length; i++) {
// 如果是最后一个元素,则跳过(因为没有下一个元素作为终点)
if (i === mainToData.length - 1) continue;
const currentItem = mainToData[i];
const nextItem = mainToData[i + 1];
// 获取当前国家代码
const countryCode = currentItem.country_code.toUpperCase();
// 如果当前项是起点,下一项是终点
if (currentItem.type === "start" && nextItem.type === "end") {
const startCode = countryCode;
const endCode = nextItem.country_code.toUpperCase();
// 无论是否连线,都添加点的涟漪效果
const startPoint = createCountryRipple(startCode);
const endPoint = createCountryRipple(endCode);
if (startPoint) ripplePoints.push(startPoint);
if (endPoint) ripplePoints.push(endPoint);
// 检查是否应该绘制连线
if (currentItem.isLine !== false) {
solidData[0]?.[1].push(getLineItem(startCode, endCode));
}
// 跳过下一项,因为已经处理了
i++;
}
// 常规情况:当前项到下一项
else {
const nextCountryCode = nextItem.country_code.toUpperCase();
// 无论是否连线,都添加点的涟漪效果
const currentPoint = createCountryRipple(countryCode);
const nextPoint = createCountryRipple(nextCountryCode);
if (currentPoint) ripplePoints.push(currentPoint);
if (nextPoint) ripplePoints.push(nextPoint);
// 检查是否应该绘制连线
if (currentItem.isLine !== false) {
solidData[0]?.[1].push(
getLineItem(countryCode, nextCountryCode)
);
}
}
// 只显示到当前索引的连线
for (let i = 0; i <= currentLineIndex && i < lineConnections.length; i++) {
const connection = lineConnections[i];
solidData[0]?.[1].push(getLineItem(connection.from, connection.to));
}
// 虚线数据处理(保持原有逻辑)
@ -212,7 +221,7 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
return {
solidData,
otherLineList,
ripplePoints
ripplePoints: allPoints // 使用所有点,无论是否连线
};
};
@ -348,7 +357,7 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
const getLianData = (series: echarts.SeriesOption[]) => {
const { solidData, otherLineList, ripplePoints } = getLine();
// 如果有需要显示涟漪效果但不连线的点,添加它们
// 添加所有点的涟漪效果,无论是否连线
if (ripplePoints.length > 0) {
// 添加外层蓝色点,带涟漪效果
series.push({
@ -397,6 +406,7 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
} as echarts.SeriesOption);
}
// 添加连线
solidData.forEach((item) => {
// 如果没有连线数据,则跳过
if (item[1].length === 0) {
@ -440,6 +450,7 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
series.push(...exitNodes);
}
});
otherLineList.forEach((line: any) => {
line.forEach((item: any) => {
const lastExit = item[1]?.[item[1].length - 1]?.[1] ?? null;
@ -589,11 +600,6 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
const series: echarts.SeriesOption[] = [];
getLianData(series);
getMianLineTipData(series);
// 添加随机涟漪效果 - 可以添加多组不同参数的涟漪
// series.push(createRandomCountryRipples(15)); // 添加15个随机涟漪点
// 可以添加第二组不同参数的涟漪
// const secondRippleEffect = createRandomCountryRipples(20);
// series.push(secondRippleEffect); // 添加10个随机涟漪点
const regions = getRegions();
const option = {
backgroundColor: "transparent",
@ -665,6 +671,13 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
const handleResize = () => {
proxyGeoRef.current?.resize();
};
// 更新图表
useEffect(() => {
const option = getOption();
proxyGeoRef.current?.setOption(option);
}, [currentLineIndex]); // 当当前连线索引变化时更新图表
useEffect(() => {
preMainToData.current?.some(
(item, index) =>
@ -674,6 +687,7 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => {
const option = getOption();
proxyGeoRef.current?.setOption(option);
}, [screenData, mainToData]);
useEffect(() => {
const chartDom = document.getElementById("screenGeo");
proxyGeoRef.current = echarts.init(chartDom);

View File

@ -189,6 +189,12 @@ const DecentralizedElasticNetwork = () => {
// return () => clearInterval(interval);
// }, [dispatch]);
useEffect(()=>{
return ()=>{
dispatch(setProxiesLine(false));
}
},[])
return (
<div className="decentralized w-full h-full flex flex-col relative">
<div className="box"></div>
@ -226,19 +232,19 @@ const DecentralizedElasticNetwork = () => {
/>
</div>
<img src={Web3Box2Png} className="w-full h-full" />
<div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div>
{/* <div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div> */}
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5 z-20">
{/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
{item.transactions}
</div> */}
<div className="!text-xs">{item?.balanceToFixed} SOL</div>
<div className="!text-xs my-[6px]">
{item.txs.length}
</div>
{/* <div className="!text-xs">{item?.balanceToFixed} SOL</div> */}
<div className="!text-xs my-[6px]">#{item.height}</div>
<div className="!text-xs opacity-60 mb-[6px]">
{item.timerstamp}
</div>
<div className="!text-xs opacity-60">{item.height} H</div>
<div className="!text-xs opacity-60">
{item.txs.length}
</div>
</div>
</div>
);
@ -250,7 +256,7 @@ const DecentralizedElasticNetwork = () => {
</div>
<div className="w-[795px] h-full flex items-center justify-start gap-10 ">
<div className="carousel-container justify-start">
{web3List2.map((item, index) => {
{web3List2.map((item, index) => {
const randomDelay = Math.floor(Math.random() * 35) * 1;
return (
<div
@ -275,14 +281,13 @@ const DecentralizedElasticNetwork = () => {
className="w-full h-full"
/>
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5">
<div className="!text-xs">{item.balance} SOL</div>
<div className="!text-xs my-[6px]">
{item.numberTransactions}
</div>
<div className="!text-xs my-[6px]">#{item.height}</div>
<div className="!text-xs opacity-60 mb-[6px]">
{item.timerstamp}
</div>
<div className="!text-xs opacity-60">{item.height} H</div>
<div className="!text-xs opacity-60">
{item.numberTransactions}
</div>
</div>
</div>
);
@ -318,7 +323,8 @@ const DecentralizedElasticNetwork = () => {
<div
className="bt1 cursor-pointer"
onClick={() => {
dispatch(setProxiesLine());
console.log(proxy_info,'proxy_infoproxy_info')
dispatch(setProxiesLine(true));
}}
>
<InterSvg />

View File

@ -69,6 +69,7 @@ export const WorldGeo = memo(
selectedApp && selectedApp ? [...newList, selectedApp] : newList ?? [];
// 初始化数据数组 - 不再包含 startCountry
const data: any = [];
console.log(proxiesList,'proxiesList')
// 遍历代理列表
proxiesList.forEach((proxyItem: any) => {
// 检查是否有数据数组
@ -182,7 +183,7 @@ export const WorldGeo = memo(
) {
// 设置提示框位置
customTooltipRef.current.style.left = `${screenCoord[0] + 232 + 7}px`;
customTooltipRef.current.style.top = `${screenCoord[1] + 40 - 190}px`;
customTooltipRef.current.style.top = `${screenCoord[1] + 40 + 15}px`;
}
} catch (error) {
console.error("Error positioning tooltip:", error);
@ -256,7 +257,7 @@ export const WorldGeo = memo(
screenCoord[0] - 626 + 20
}px`;
customTooltip2Ref.current.style.top = `${
screenCoord[1] + 40 - 218
screenCoord[1] + 40 - 13
}px`;
}
} catch (error) {

View File

@ -73,7 +73,6 @@ const NewHome = () => {
const [dialogLoading] = useState(false);
const [selectedApp, setSelectedApp] = useState<any>(null);
const [tooltipClosed, setTooltipClosed] = useState(true);
const [tooltipType, setTooltipType] = useState(
@ -108,10 +107,6 @@ const NewHome = () => {
setSelectedApp(item);
};
const [dataInfo, setDataInfo] = useState<any>({
passAuthentication: {
type: "PASS_AUTHENTICATION",
@ -190,7 +185,7 @@ const NewHome = () => {
}
setIsProxyLoading(true);
console.log("????");
// 切换代理状态
await dispatch(isProxyEnabled ? disableProxy() : enableProxy()).unwrap();
} catch (error) {
@ -238,9 +233,9 @@ const NewHome = () => {
alt=""
/> */}
{/* <div className="w-[90%] absolute top-0 left-0"></div> */}
<div className="w-[1693px] h-full flex items-center justify-center absolute top-[90px]">
<div className="w-[795px] h-full flex items-center justify-end gap-10 z-10">
<div className="carousel-container !justify-end">
<div className="w-[1693px] h-full flex items-center justify-center ">
<div className="w-[795px] flex items-center justify-end gap-10 z-[99]">
<div className="carousel-container !justify-end ">
{newWeb3List.map((item, index) => {
// 随机0-10的整数
const randomDelay = Math.floor(Math.random() * 35) * 1;
@ -265,20 +260,18 @@ const NewHome = () => {
/>
</div>
<img src={Web3Box2Png} className="w-full h-full" />
<div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div>
{/* <div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div> */}
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5 z-20">
{/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
{item.transactions}
</div> */}
<div className="!text-xs">{item?.balanceToFixed} SOL</div>
<div className="!text-xs my-[6px]">
{item.txs.length}
</div>
{/* <div className="!text-xs">{item?.balanceToFixed} SOL</div> */}
<div className="!text-xs my-[6px]">#{item.height}</div>
<div className="!text-xs opacity-60 mb-[6px]">
{item.timerstamp}
</div>
<div className="!text-xs opacity-60">
{item.height} H
{item.txs.length}
</div>
</div>
</div>
@ -291,7 +284,7 @@ const NewHome = () => {
</div>
<div className="w-[795px] h-full flex items-center justify-start gap-10 ">
<div className="carousel-container justify-start">
{web3List2.map((item, index) => {
{web3List2.map((item, index) => {
const randomDelay = Math.floor(Math.random() * 35) * 1;
return (
<div
@ -316,15 +309,12 @@ const NewHome = () => {
className="w-full h-full"
/>
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5">
<div className="!text-xs">{item.balance} SOL</div>
<div className="!text-xs my-[6px]">
{item.numberTransactions}
</div>
<div className="!text-xs my-[6px]">#{item.height}</div>
<div className="!text-xs opacity-60 mb-[6px]">
{item.timerstamp}
</div>
<div className="!text-xs opacity-60">
{item.height} H
{item.numberTransactions}
</div>
</div>
</div>
@ -390,7 +380,6 @@ const NewHome = () => {
);
})}
</div>
</div>
);
};

View File

@ -1,6 +1,7 @@
import { createSlice } from "@reduxjs/toolkit";
import { createSlice,createAsyncThunk } from "@reduxjs/toolkit";
import { v4 as uuid } from "uuid";
import { data1, data2 } from "./datas";
export interface Iweb3 {
id?: string;
name?: string;
@ -32,6 +33,13 @@ interface Iweb3Slice {
nodeDownList: any[]; // 节点下线
}
export const setProxiesList = createAsyncThunk(
'web3/setProxiesList',
async (payload, { dispatch }) => {
dispatch(setProxiesLine());
}
);
// 随机生成 0-100 之间的数字,保留一位小数或整数
const randomBalance = (): string => {
const value = Math.random() * 100;
@ -90,7 +98,9 @@ const initialState: Iweb3Slice = {
wg: false,
change_time: 0,
change_at: 0,
proxies: [],
proxies: [
],
},
newHomeProxies: [
{
@ -201,7 +211,7 @@ export const appSlice = createSlice({
state.proxy_info.proxies.push(data2);
}
},
setProxiesLine: (state) => {
setProxiesLine: (state,action) => {
if (state.proxy_info.proxies.length === 0) return;
// 判断一下如果state.proxy_info.proxies.lengt === 2并且 web3List.length ===1 那么 添加一个web3
// 如果state.proxy_info.proxies.lengt === 2并且 web3List.length ===2 那么不添加web3
@ -213,7 +223,7 @@ export const appSlice = createSlice({
if (state.proxy_info.proxies.length === 0) return;
// 标记所有代理为在线 - 这个操作仍然需要
state.proxy_info.proxies = state.proxy_info.proxies.map((item: any) => {
item.isLine = true;
item.isLine = action.payload;
return item;
});
},