{"spec_id":"network-force-directed","library":"echarts","language":"javascript","code":"// anyplot.ai\n// network-force-directed: Force-Directed Graph\n// Library: echarts 5.5.1 | JavaScript 22.23.1\n// Quality: 83/100 | Created: 2026-07-01\n//# anyplot-orientation: square\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Software module dependency network — 30 nodes, 4 communities\nconst categoryDefs = [\n  { name: \"Frontend\" },\n  { name: \"Backend\" },\n  { name: \"Data Layer\" },\n  { name: \"Infrastructure\" },\n];\n\nconst rawNodes = [\n  { id: \"App\",        label: \"App\",        cat: 0 },\n  { id: \"Router\",     label: \"Router\",     cat: 0 },\n  { id: \"Pages\",      label: \"Pages\",      cat: 0 },\n  { id: \"Components\", label: \"Components\", cat: 0 },\n  { id: \"Store\",      label: \"Store\",      cat: 0 },\n  { id: \"Styles\",     label: \"Styles\",     cat: 0 },\n  { id: \"Assets\",     label: \"Assets\",     cat: 0 },\n  { id: \"API\",        label: \"API\",        cat: 1 },\n  { id: \"Auth\",       label: \"Auth\",       cat: 1 },\n  { id: \"Users\",      label: \"Users\",      cat: 1 },\n  { id: \"Products\",   label: \"Products\",   cat: 1 },\n  { id: \"Orders\",     label: \"Orders\",     cat: 1 },\n  { id: \"Search\",     label: \"Search\",     cat: 1 },\n  { id: \"Cache\",      label: \"Cache\",      cat: 1 },\n  { id: \"Config\",     label: \"Config\",     cat: 1 },\n  { id: \"Database\",   label: \"Database\",   cat: 2 },\n  { id: \"Analytics\",  label: \"Analytics\",  cat: 2 },\n  { id: \"Reports\",    label: \"Reports\",    cat: 2 },\n  { id: \"ETL\",        label: \"ETL\",        cat: 2 },\n  { id: \"DataStore\",  label: \"DataStore\",  cat: 2 },\n  { id: \"Queue\",      label: \"Queue\",      cat: 2 },\n  { id: \"Metrics\",    label: \"Metrics\",    cat: 2 },\n  { id: \"CICD\",       label: \"CI/CD\",      cat: 3 },\n  { id: \"Deploy\",     label: \"Deploy\",     cat: 3 },\n  { id: \"Monitor\",    label: \"Monitor\",    cat: 3 },\n  { id: \"Logging\",    label: \"Logging\",    cat: 3 },\n  { id: \"Docker\",     label: \"Docker\",     cat: 3 },\n  { id: \"K8s\",        label: \"K8s\",        cat: 3 },\n  { id: \"Registry\",   label: \"Registry\",   cat: 3 },\n  { id: \"Gateway\",    label: \"Gateway\",    cat: 3 },\n];\n\nconst edgePairs = [\n  // Frontend internal\n  [\"App\", \"Router\"], [\"App\", \"Pages\"], [\"App\", \"Components\"], [\"App\", \"Store\"],\n  [\"Pages\", \"Components\"], [\"Pages\", \"Styles\"], [\"Components\", \"Styles\"], [\"Components\", \"Assets\"],\n  // Backend internal\n  [\"API\", \"Auth\"], [\"API\", \"Users\"], [\"API\", \"Products\"], [\"API\", \"Orders\"],\n  [\"API\", \"Search\"], [\"Auth\", \"Users\"], [\"Auth\", \"Config\"],\n  [\"Users\", \"Cache\"], [\"Products\", \"Cache\"],\n  // Data Layer internal\n  [\"Database\", \"Analytics\"], [\"Database\", \"DataStore\"], [\"Analytics\", \"Reports\"],\n  [\"ETL\", \"Database\"], [\"ETL\", \"DataStore\"], [\"Queue\", \"ETL\"],\n  [\"Metrics\", \"Analytics\"], [\"DataStore\", \"Reports\"],\n  // Infrastructure internal\n  [\"K8s\", \"Docker\"], [\"K8s\", \"Deploy\"], [\"CICD\", \"Docker\"], [\"CICD\", \"Registry\"],\n  [\"Deploy\", \"Monitor\"], [\"Deploy\", \"K8s\"], [\"Monitor\", \"Logging\"],\n  [\"Gateway\", \"Monitor\"], [\"Gateway\", \"K8s\"], [\"Registry\", \"Docker\"],\n  // Cross-community\n  [\"App\", \"API\"],\n  [\"API\", \"Database\"], [\"API\", \"Cache\"], [\"Auth\", \"Database\"], [\"Orders\", \"Queue\"],\n  [\"CICD\", \"API\"], [\"Gateway\", \"API\"],\n  [\"Monitor\", \"Metrics\"], [\"Logging\", \"DataStore\"],\n];\n\n// Compute degree for proportional node sizing\nconst degree = {};\nrawNodes.forEach(function(n) { degree[n.id] = 0; });\nedgePairs.forEach(function(pair) {\n  degree[pair[0]] = (degree[pair[0]] || 0) + 1;\n  degree[pair[1]] = (degree[pair[1]] || 0) + 1;\n});\n\nconst nodes = rawNodes.map(function(n) {\n  const d = degree[n.id];\n  const isHub = n.id === \"API\";\n  return {\n    name: n.id,\n    value: d,\n    category: n.cat,\n    symbolSize: Math.max(14, 10 + d * 4),\n    label: { formatter: n.label },\n    itemStyle: isHub ? { borderWidth: 4, borderColor: t.ink } : undefined,\n  };\n});\n\n// Cross-community edges styled slightly wider/more opaque to guide the eye\nconst crossEdges = new Set([\n  \"App->API\", \"API->Database\", \"API->Cache\", \"Auth->Database\",\n  \"Orders->Queue\", \"CICD->API\", \"Gateway->API\", \"Monitor->Metrics\", \"Logging->DataStore\",\n]);\n\nconst links = edgePairs.map(function(pair) {\n  const result = { source: pair[0], target: pair[1] };\n  if (crossEdges.has(pair[0] + \"->\" + pair[1])) {\n    result.lineStyle = { width: 2.5, opacity: 0.75 };\n  }\n  return result;\n});\n\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"network-force-directed · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 24,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: \"bold\" },\n  },\n  legend: {\n    data: categoryDefs.map(function(c) { return c.name; }),\n    top: 70,\n    left: \"center\",\n    orient: \"horizontal\",\n    textStyle: { color: t.inkSoft, fontSize: 13 },\n    icon: \"circle\",\n    itemWidth: 10,\n    itemHeight: 10,\n    itemGap: 28,\n  },\n  series: [\n    {\n      type: \"graph\",\n      layout: \"force\",\n      data: nodes,\n      links: links,\n      categories: categoryDefs,\n      roam: false,\n      label: {\n        show: true,\n        position: \"right\",\n        fontSize: 12,\n        color: t.inkSoft,\n      },\n      labelLayout: { hideOverlap: true },\n      lineStyle: {\n        width: 1.5,\n        opacity: 0.55,\n        color: \"source\",\n        curveness: 0,\n      },\n      itemStyle: {\n        borderColor: t.pageBg,\n        borderWidth: 2,\n      },\n      emphasis: { scale: false },\n      force: {\n        repulsion: 500,\n        gravity: 0.3,\n        edgeLength: [80, 200],\n        layoutAnimation: false,\n      },\n    },\n  ],\n});\n"}