You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用React.js实现带数据包传输动画的网络模拟系统

计算机网络模拟系统(含数据包传输动画)实现方案

是否可以(是否已有成熟方案)创建一套计算机网络模拟系统,使用对应图标(如计算机、路由器、交换机、防火墙、互联网等)作为节点,并展示数据包在网络中的传输动画?例如,以圆形代表的数据包沿边从节点1(如计算机)到节点2(如交换机)、节点3(如防火墙)再到节点4(如互联网)进行动画传输。

用户提供的基础代码

// Network.js
import React, { useState, useEffect } from 'react';
import { DataSet, Network } from 'vis-network/standalone/';

const NetworkComponent = () => {
  const [nodes, setNodes] = useState(new DataSet([
    { id: 1, label: 'Node 1' },
    { id: 2, label: 'Node 2' },
    { id: 3, label: 'Node 3' },
    { id: 4, label: 'Node 4' },
  ]));

  const [edges] = useState(new DataSet([
    { from: 1, to: 2 },
    { from: 2, to: 3 },
    { from: 3, to: 4 },
    { from: 2, to: 3 },
  ]));

  const container = React.createRef();

  useEffect(() => {
    const options = {
      nodes: {
        shape: 'circularImage',
        image: 'path/to/your/icon.png', // replace with your icon image path
      },
    };

    const data = {
      nodes: nodes,
      edges: edges,
    };

    const network = new Network(container.current, data, options);

    return () => {
      network.destroy();
    };
  }, [nodes, edges]);

  return (
    <div>
      <div ref={container} style={{ width: '800px', height: '600px' }} />
    </div>
  );
};

export default NetworkComponent;

示例效果说明

目标效果为:圆形数据包在网络节点间沿连接边平滑动画传输,依次经过计算机、交换机、防火墙、互联网等节点,模拟真实网络的数据转发流程。


实现方案

1. 替换节点为专业网络图标

将节点的image属性替换为对应网络设备的图标路径,示例修改:

const [nodes, setNodes] = useState(new DataSet([
  { id: 1, label: '计算机', image: '/icons/computer.png' },
  { id: 2, label: '交换机', image: '/icons/switch.png' },
  { id: 3, label: '防火墙', image: '/icons/firewall.png' },
  { id: 4, label: '互联网', image: '/icons/internet.png' },
]));

建议使用正方形图标,避免拉伸变形。

2. 实现数据包传输动画

通过自定义DOM元素+JavaScript动画帧实现,核心逻辑:

  • 获取节点在画布上的绝对坐标
  • 创建圆形数据包DOM元素,初始定位在源节点位置
  • 计算源节点到目标节点的路径,逐帧更新数据包位置
  • 动画完成后移除数据包元素

3. 完整实现代码

// Network.js
import React, { useState, useEffect } from 'react';
import { DataSet, Network } from 'vis-network/standalone/';

const NetworkComponent = () => {
  const [nodes, setNodes] = useState(new DataSet([
    { id: 1, label: '计算机', image: '/icons/computer.png' },
    { id: 2, label: '交换机', image: '/icons/switch.png' },
    { id: 3, label: '防火墙', image: '/icons/firewall.png' },
    { id: 4, label: '互联网', image: '/icons/internet.png' },
  ]));

  const [edges] = useState(new DataSet([
    { id: '1-2', from: 1, to: 2 },
    { id: '2-3', from: 2, to: 3 },
    { id: '3-4', from: 3, to: 4 },
  ]));

  const container = React.createRef();
  let networkInstance = null;

  // 创建数据包动画
  const createPacketAnimation = (fromNodeId, toNodeId) => {
    if (!networkInstance) return;

    // 获取节点坐标
    const fromNode = networkInstance.getPositions(fromNodeId)[fromNodeId];
    const toNode = networkInstance.getPositions(toNodeId)[toNodeId];
    const containerRect = container.current.getBoundingClientRect();

    // 创建数据包元素
    const packet = document.createElement('div');
    packet.style.position = 'absolute';
    packet.style.width = '20px';
    packet.style.height = '20px';
    packet.style.borderRadius = '50%';
    packet.style.backgroundColor = '#2196F3';
    packet.style.zIndex = 1000;
    packet.style.left = `${fromNode.x + containerRect.left - 10}px`;
    packet.style.top = `${fromNode.y + containerRect.top - 10}px`;
    document.body.appendChild(packet);

    // 动画参数
    const duration = 1500; // 动画时长(ms)
    const startTime = Date.now();

    // 动画帧函数
    const animate = () => {
      const elapsed = Date.now() - startTime;
      const progress = Math.min(elapsed / duration, 1);

      // 计算当前位置
      const currentX = fromNode.x + (toNode.x - fromNode.x) * progress;
      const currentY = fromNode.y + (toNode.y - fromNode.y) * progress;

      packet.style.left = `${currentX + containerRect.left - 10}px`;
      packet.style.top = `${currentY + containerRect.top - 10}px`;

      if (progress < 1) {
        requestAnimationFrame(animate);
      } else {
        // 动画结束,移除数据包
        document.body.removeChild(packet);
        // 继续下一段路径动画(示例:1->2->3->4)
        if (fromNodeId === 1 && toNodeId === 2) {
          createPacketAnimation(2, 3);
        } else if (fromNodeId === 2 && toNodeId === 3) {
          createPacketAnimation(3, 4);
        }
      }
    };

    requestAnimationFrame(animate);
  };

  useEffect(() => {
    const options = {
      nodes: {
        shape: 'circularImage',
        size: 60,
        borderWidth: 2,
        borderColor: '#333',
      },
      edges: {
        width: 2,
        color: '#888',
      },
      physics: {
        enabled: false, // 禁用物理引擎,固定节点位置
      },
    };

    const data = {
      nodes: nodes,
      edges: edges,
    };

    networkInstance = new Network(container.current, data, options);

    // 初始化后启动动画
    setTimeout(() => {
      createPacketAnimation(1, 2);
    }, 1000);

    return () => {
      networkInstance.destroy();
    };
  }, [nodes, edges]);

  return (
    <div>
      <div ref={container} style={{ width: '800px', height: '600px', border: '1px solid #eee' }} />
    </div>
  );
};

export default NetworkComponent;

内容的提问来源于stack exchange,提问作者universe_u

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:45:09