npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@superlinearspace/supertopo

v0.0.1

Published

> 基于 Cytoscape.js 的拓扑图渲染组件

Readme

SuperTopo

基于 Cytoscape.js 的拓扑图渲染组件

一个轻量级的拓扑图库,同时支持 React/Next.js 和原生 HTML/JS。

功能特性

  • Clos 布局 - 自动为 Clos 拓扑网络计算最佳布局位置
  • Cytoscape.js 渲染 - 利用 Cytoscape.js 强大的可视化能力
  • TypeScript 支持 - 完整的类型定义
  • 性能优化 - 支持大规模拓扑图渲染
  • 双模式支持 - React 组件 + Vanilla JS(独立文件)
    • React 版本: 用于 Next.js/React 项目
    • Vanilla 版本: 用于原生 HTML/JS 项目(包含所有依赖,无需构建工具)

安装

pnpm add @repo/supertopo

使用方式

SuperTopo 提供两种使用方式:

方式 1: React/Next.js(推荐用于 React 项目)

import { SuperTopo } from "@repo/supertopo"

export default function Page() {
  const graphData = {
    nodes: [
      { data: { id: "spine0", label: "Spine 0", type: "spine", size: 40, color: "#3B82F6" } },
      { data: { id: "leaf0", label: "Leaf 0", type: "leaf", size: 35, color: "#0D9488" } },
      { data: { id: "server0", label: "Server 0", type: "server", size: 25, color: "#F97316" } },
    ],
    edges: [
      { data: { source: "spine0", target: "leaf0" } },
      { data: { source: "leaf0", target: "server0" } },
    ],
  }

  return (
    <div>
      <h1>Network Topology</h1>
      <SuperTopo 
        data={graphData}
        layout="clos"
        height={600}
      />
    </div>
  )
}

方式 2: Vanilla JS(用于原生 HTML/JS 项目)

步骤 1: 构建 Vanilla 版本

cd packages/supertopo
pnpm build

步骤 2: 复制生成的文件

cp dist/supertopo-vanilla.js /path/to/your/project/static/

步骤 3: 在 HTML 中使用

<!DOCTYPE html>
<html>
<head>
  <title>Network Topology</title>
  <script src="/static/supertopo-vanilla.js"></script>
  <style>
    #topology { width: 100%; height: 600px; border: 1px solid #ccc; }
  </style>
</head>
<body>
  <div id="topology"></div>
  <script>
    const topo = new SuperTopo({
      container: '#topology',
      nodes: [
        { id: 'spine0', label: 'Spine 0', type: 'spine', size: 40, color: '#3B82F6' },
        { id: 'leaf0', label: 'Leaf 0', type: 'leaf', size: 35, color: '#0D9488' },
        { id: 'server0', label: 'Server 0', type: 'server', size: 25, color: '#F97316' }
      ],
      edges: [
        { source: 'spine0', target: 'leaf0' },
        { source: 'leaf0', target: 'server0' }
      ],
      layout: 'clos',
      fit: true
    });
  </script>
</body>
</html>

Vanilla API 详情:

  • container - 容器选择器(如 #topology)或 DOM 元素
  • nodes - 节点数组(简化格式或完整格式)
  • edges - 边数组(简化格式或完整格式)
  • layout - 布局算法名称(clos, random, grid
  • layoutOptions - 布局选项
  • fit - 是否自动适应视图(默认 true)
  • events - 事件处理器

Vanilla JS 示例(在 FastAPI 中)

<!-- templates/topology.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Network Topology</title>
  <script src="/static/supertopo-vanilla.js"></script>
  <style>
    #topology { width: 100%; height: 600px; border: 1px solid #ddd; }
  </style>
</head>
<body>
  <h1>NUNet Topology</h1>
  <div id="topology"></div>
  <script>
    const topo = new SuperTopo({
      container: '#topology',
      nodes: {{ nodes|tojson|safe }},
      edges: {{ edges|tojson|safe }},
      layout: 'clos',
      layoutOptions: {
        suScope: {
          include: (node) => String(node.id).toLowerCase().includes('gpu')
        }
      },
      events: {
        click: (evt) => console.log('Clicked:', evt.target.id())
      },
      fit: true
    });
  </script>
</body>
</html>
# FastAPI router
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

router = APIRouter()
templates = Jinja2Templates(directory="app/templates")

@router.get("/", response_class=HTMLResponse)
async def topology_page(request: Request):
    # 假设这是从数据库获取的拓扑数据
    nodes = [
        {'id': 'spine0', 'label': 'Spine 0', 'type': 'spine', 'size': 40, 'color': '#3B82F6'},
        {'id': 'leaf0', 'label': 'Leaf 0', 'type': 'leaf', 'size': 35, 'color': '#0D9488'},
        {'id': 'server0', 'label': 'Server 0', 'type': 'server', 'size': 25, 'color': '#F97316'},
    ]
    edges = [
        {'source': 'spine0', 'target': 'leaf0'},
        {'source': 'leaf0', 'target': 'server0'},
    ]
    
    return templates.TemplateResponse("topology.html", {
        "request": request,
        "nodes": nodes,
        "edges": edges
    })

API 参考

React 版本 API

SuperTopo Props

| Prop | 类型 | 默认值 | 描述 | |------|------|---------|------| | data | GraphData | - | 图数据(节点和边) | | layout | string | "clos" | 布局算法名称 | | height | string \| number | "600px" | 画布高度 | | width | string \| number | "100%" | 画布宽度 | | layoutOptions | Record<string, unknown> | - | 布局选项 |

Vanilla 版本 API

构造函数选项

| 选项 | 类型 | 默认值 | 描述 | |------|------|---------|------| | container | string \| HTMLElement | - | 容器(必需) | | nodes | Array | [] | 节点数组(简化格式或完整格式) | | edges | Array | [] | 边数组(简化格式或完整格式) | | layout | string | - | 布局算法名称 | | layoutOptions | Object | - | 布局选项 | | fit | boolean | true | 是否自动适应视图 | | padding | number | 10 | 适应视图的内边距 | | events | Object | - | 事件处理器 |

实例方法

// 应用布局
topo.applyLayout('clos', options);

// 适应视图
topo.fit(padding);

// 获取节点数据
const nodeData = topo.getNode('spine0');

// 获取边数据
const edgeData = topo.getEdge('edge0');

// 设置节点属性
topo.setNodeAttribute('spine0', 'label', 'New Label');

// 销毁实例
topo.destroy();

图数据格式

interface NodeData {
  id: string | number
  label?: string
  type?: string
  size?: number
  color?: string
}

interface EdgeData {
  source: string | number
  target: string | number
  id?: string
  label?: string
}

interface TopoNode {
  group?: "nodes"
  data: NodeData
  position?: { x: number; y: number }
}

interface TopoEdge {
  group?: "edges"
  data: EdgeData
}

interface GraphData {
  nodes: TopoNode[]
  edges: TopoEdge[]
}

注意:在实际使用中,可以只传入 data 对象,Cytoscape 会自动将其转换为完整的元素定义。因此,为了简化使用,示例代码中直接使用了简化的格式。

简化格式(Vanilla JS 推荐):

{
  nodes: [
    { id: 'spine0', label: 'Spine 0', type: 'spine' },
    { id: 'leaf0', label: 'Leaf 0', type: 'leaf' },
  ],
  edges: [
    { source: 'spine0', target: 'leaf0' }
  ]
}

完整格式:

{
  nodes: [
    { data: { id: 'spine0', label: 'Spine 0', type: 'spine' } },
  ],
  edges: [
    { data: { source: 'spine0', target: 'leaf0' } }
  ]
}

布局选项

Clos 布局支持的选项:

| 选项 | 类型 | 默认值 | 描述 | |------|------|---------|------| | devicesPerRow | number | 8 | 每行最大设备数 | | horizontalSpacingFactor | number | 2.0 | SU 内横向间距倍数 | | spineToLeafSpacingFactor | number | 8.0 | Spine 到 Leaf 的间距倍数 | | suVerticalSpacingFactor | number | 4.0 | SU 内纵向间距倍数 | | suSpacingFactor | number | 2.0 | SU 之间间距倍数 | | spineCoverageFactor | number | 0.8 | Spine 覆盖宽度比例 | | scaleFactor | number | 0.5 | 整体缩放因子 | | suScope | SUScope | - | SU 范围配置 |

SU 范围配置 (suScope)

suScope 用于控制哪些服务器参与 SU 分组判断。回调函数接收 Cytoscape 节点对象(Vanilla 版本通过 node.id() 等方法访问)。

Vanilla JS 示例:

layoutOptions: {
  suScope: {
    // 只考虑满足条件的服务器参与分组
    include: (node) => String(node.id()).toLowerCase().includes('gpu'),
    
    // 排除满足条件的服务器
    exclude: (node) => node.data('type') === 'switch'
  }
}

常用方法:

  • node.id() - 获取节点ID
  • node.data('label') - 获取节点标签
  • node.data('type') - 获取节点类型
  • node.data('size') - 获取节点大小

节点类型

SuperTopo 通过节点的 type 属性自动识别节点类型:

  • spine - 脊柱交换机
  • leaf - 叶子交换机
  • 其他 - 服务器节点

示例

快速体验(独立 HTML 示例)

  1. 构建 Vanilla 版本:

    cd packages/supertopo
    pnpm build
  2. 在浏览器中打开独立示例:

    open examples/simple-standalone.html
    # 或在 Windows/Linux 中使用浏览器打开

这个示例包含:

  • 2 个 Spine 节点
  • 2 个 Leaf 节点
  • 4 个 Server 节点
  • 完整的 Clos 布局
  • 点击事件交互

FastAPI 集成示例

完整的 FastAPI 模板示例位于 examples/fastapi-topology.html,包含:

  • 完整的页面样式
  • 节点统计显示
  • 图例说明
  • 错误处理
  • 事件处理

开发

构建

# 开发模式(监听文件变化)
pnpm dev

# 生产构建
pnpm build

输出文件

构建后会在 dist/ 目录生成:

  • supertopo-vanilla.js - Vanilla 版本(包含所有依赖,可直接在浏览器中使用)
  • supertopo-vanilla.js.map - Source Map(用于调试)

许可证

MIT