@cocorof/graphier 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # Graphier
2
+
3
+ High-performance 3D/2D graph renderer for React — powered by Three.js and d3-force-3d.
4
+
5
+ ![License](https://img.shields.io/badge/license-MIT-blue)
6
+
7
+ ## Features
8
+
9
+ - **2 GPU draw calls** — InstancedMesh (nodes) + LineSegments (edges) for maximum performance
10
+ - **Web Worker layout** — Force-directed simulation off the main thread (d3-force-3d)
11
+ - **Custom GLSL shaders** — Fresnel rim glow + subsurface scatter on every node
12
+ - **Post-processing** — UnrealBloomPass glow with adaptive resolution
13
+ - **Auto-adaptive** — Layout, LOD, bloom, and fog scale automatically with graph size
14
+ - **360 keyboard camera** — Full spherical rotation with quaternion-based controls, no gimbal lock
15
+ - **Incremental updates** — `appendData()` adds nodes/links without full rebuild
16
+ - **Position preservation** — Existing node positions survive data changes
17
+ - **Theme system** — 3 built-in presets (celestial, neon, minimal) + fully customizable
18
+ - **Node Detail Panel** — Modal with navigation history, connections list, and 3D subgraph
19
+ - **2D Subgraph View** — Lightweight canvas-based neighborhood renderer
20
+ - **Graph Analysis** — Tree-shakeable analytics module (`graphier/analysis`), zero Three.js dependency
21
+ - **TypeScript** — Full type safety with exported types
22
+ - **Dual ESM/CJS** — Works in all bundler configurations
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ npm install graphier three react react-dom
28
+ ```
29
+
30
+ **Peer dependencies:** `react >= 18`, `react-dom >= 18`, `three >= 0.150`
31
+
32
+ ## Quick Start
33
+
34
+ ```tsx
35
+ import { NetworkGraph3D } from "graphier";
36
+
37
+ const data = {
38
+ nodes: [
39
+ { id: "alice", type: "person", label: "Alice", val: 10 },
40
+ { id: "bob", type: "person", label: "Bob", val: 5 },
41
+ { id: "project-x", type: "repo", label: "Project X", val: 20 },
42
+ ],
43
+ links: [
44
+ { source: "alice", target: "project-x", type: "owns" },
45
+ { source: "bob", target: "project-x", type: "contributes" },
46
+ { source: "alice", target: "bob", type: "follows" },
47
+ ],
48
+ };
49
+
50
+ export default function App() {
51
+ return (
52
+ <div style={{ width: "100vw", height: "100vh" }}>
53
+ <NetworkGraph3D data={data} />
54
+ </div>
55
+ );
56
+ }
57
+ ```
58
+
59
+ ## Ref API
60
+
61
+ ```tsx
62
+ const graphRef = useRef<NetworkGraph3DRef>(null);
63
+
64
+ graphRef.current?.focusNode("alice", 1200);
65
+ graphRef.current?.zoomToFit(800, 100);
66
+ graphRef.current?.zoomIn();
67
+ graphRef.current?.zoomOut();
68
+ graphRef.current?.appendData(newNodes, newLinks);
69
+ graphRef.current?.screenshot();
70
+ ```
71
+
72
+ ## Theme & Style
73
+
74
+ ```tsx
75
+ <NetworkGraph3D
76
+ data={data}
77
+ theme="celestial" // or "neon", "minimal", or a ThemeConfig object
78
+ style={{
79
+ bloomStrength: 0.7,
80
+ fogDensity: 0.0004,
81
+ nodeMinSize: 2,
82
+ nodeMaxSize: 18,
83
+ showLabels: true,
84
+ maxLabels: 200,
85
+ }}
86
+ />
87
+ ```
88
+
89
+ ## Analysis Module
90
+
91
+ ```tsx
92
+ import { analyzeGraph } from "graphier/analysis";
93
+
94
+ const stats = analyzeGraph(data);
95
+ // stats.nodeCount, stats.density, stats.avgDegree, stats.topByDegree(10), ...
96
+ ```
97
+
98
+ ## Keyboard Controls
99
+
100
+ | Key | Action |
101
+ |-----|--------|
102
+ | `Z` / `X` | Zoom in / out |
103
+ | Arrow keys | 360 camera rotation |
104
+ | `Escape` | Deselect |
105
+
106
+ ## Documentation
107
+
108
+ - [USAGE.md](./USAGE.md) — Full English documentation
109
+ - [USAGE.ko.md](./USAGE.ko.md) — 한국어 문서
110
+
111
+ ## Next.js / SSR
112
+
113
+ ```tsx
114
+ // app/page.tsx
115
+ "use client";
116
+ import dynamic from "next/dynamic";
117
+ const GraphView = dynamic(() => import("./GraphView"), { ssr: false });
118
+ ```
119
+
120
+ ```js
121
+ // next.config.js
122
+ const nextConfig = { transpilePackages: ["graphier"] };
123
+ ```
124
+
125
+ ## Architecture
126
+
127
+ ```
128
+ NetworkGraph3D
129
+ ├── InstancedMesh (all nodes → 1 draw call)
130
+ ├── LineSegments (all edges → 1 draw call)
131
+ ├── Web Worker (d3-force-3d layout, off main thread)
132
+ ├── UnrealBloomPass (post-processing glow)
133
+ ├── Sprite labels (distance-culled, texture-cached)
134
+ └── Keyboard controls (quaternion-based 360 rotation)
135
+ ```
136
+
137
+ ## License
138
+
139
+ MIT
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ function computeDegreeMap(data) {
4
+ const degree = {};
5
+ for (const n of data.nodes) degree[n.id] = 0;
6
+ for (const l of data.links) {
7
+ const s = typeof l.source === "object" ? l.source.id : l.source;
8
+ const t = typeof l.target === "object" ? l.target.id : l.target;
9
+ if (degree[s] !== void 0) degree[s]++;
10
+ if (degree[t] !== void 0) degree[t]++;
11
+ }
12
+ return degree;
13
+ }
14
+ function computeDegreeStats(degreeMap) {
15
+ const values = Object.values(degreeMap);
16
+ if (values.length === 0) {
17
+ return { min: 0, max: 0, avg: 0, total: 0 };
18
+ }
19
+ const total = values.reduce((a, b) => a + b, 0);
20
+ return {
21
+ min: Math.min(...values),
22
+ max: Math.max(...values),
23
+ avg: total / values.length,
24
+ total
25
+ };
26
+ }
27
+ function topByDegree(nodes, degreeMap, n) {
28
+ return nodes.map((node) => ({ ...node, degree: degreeMap[node.id] ?? 0 })).sort((a, b) => b.degree - a.degree).slice(0, n);
29
+ }
30
+ function computeDensity(nodeCount, linkCount) {
31
+ if (nodeCount <= 1) return 0;
32
+ return 2 * linkCount / (nodeCount * (nodeCount - 1));
33
+ }
34
+ function computeLinkTypeBreakdown(links) {
35
+ const counts = {};
36
+ for (const l of links) {
37
+ const type = l.type ?? "default";
38
+ counts[type] = (counts[type] ?? 0) + 1;
39
+ }
40
+ return counts;
41
+ }
42
+ function computeNodeLinkCounts(data, linkTypes) {
43
+ const counts = /* @__PURE__ */ new Map();
44
+ for (const n of data.nodes) counts.set(n.id, 0);
45
+ const typeSet = new Set(linkTypes);
46
+ for (const l of data.links) {
47
+ if (!typeSet.has(l.type ?? "default")) continue;
48
+ const s = typeof l.source === "object" ? l.source.id : l.source;
49
+ const t = typeof l.target === "object" ? l.target.id : l.target;
50
+ if (counts.has(s)) counts.set(s, counts.get(s) + 1);
51
+ if (counts.has(t)) counts.set(t, counts.get(t) + 1);
52
+ }
53
+ return counts;
54
+ }
55
+ function findHubs(nodes, degreeMap, minDegree) {
56
+ return nodes.map((n) => ({ ...n, degree: degreeMap[n.id] ?? 0 })).filter((n) => n.degree >= minDegree).sort((a, b) => b.degree - a.degree);
57
+ }
58
+ function groupByType(nodes) {
59
+ const groups = {};
60
+ for (const n of nodes) {
61
+ const type = n.type ?? "default";
62
+ groups[type] = (groups[type] ?? 0) + 1;
63
+ }
64
+ return groups;
65
+ }
66
+ function buildAdjacencyMap(links) {
67
+ const adj = /* @__PURE__ */ new Map();
68
+ for (const l of links) {
69
+ const s = typeof l.source === "object" ? l.source.id : l.source;
70
+ const t = typeof l.target === "object" ? l.target.id : l.target;
71
+ if (!adj.has(s)) adj.set(s, []);
72
+ if (!adj.has(t)) adj.set(t, []);
73
+ adj.get(s).push(t);
74
+ adj.get(t).push(s);
75
+ }
76
+ return adj;
77
+ }
78
+ function getNeighbors(adjacencyMap, rootId, maxHops) {
79
+ const visited = /* @__PURE__ */ new Map();
80
+ visited.set(rootId, 0);
81
+ const queue = [rootId];
82
+ while (queue.length > 0) {
83
+ const current = queue.shift();
84
+ const dist = visited.get(current);
85
+ if (dist >= maxHops) continue;
86
+ for (const nb of adjacencyMap.get(current) ?? []) {
87
+ if (!visited.has(nb)) {
88
+ visited.set(nb, dist + 1);
89
+ queue.push(nb);
90
+ }
91
+ }
92
+ }
93
+ return visited;
94
+ }
95
+ function analyzeGraph(data) {
96
+ const degreeMap = computeDegreeMap(data);
97
+ const degreeStats = computeDegreeStats(degreeMap);
98
+ const density = computeDensity(data.nodes.length, data.links.length);
99
+ const nodesByType = groupByType(data.nodes);
100
+ const linksByType = computeLinkTypeBreakdown(data.links);
101
+ return {
102
+ nodeCount: data.nodes.length,
103
+ linkCount: data.links.length,
104
+ density,
105
+ avgDegree: degreeStats.avg,
106
+ maxDegree: degreeStats.max,
107
+ minDegree: degreeStats.min,
108
+ totalDegree: degreeStats.total,
109
+ degreeMap,
110
+ nodesByType,
111
+ linksByType,
112
+ topByDegree: (n) => topByDegree(data.nodes, degreeMap, n)
113
+ };
114
+ }
115
+ exports.analyzeGraph = analyzeGraph;
116
+ exports.buildAdjacencyMap = buildAdjacencyMap;
117
+ exports.computeDegreeMap = computeDegreeMap;
118
+ exports.computeDegreeStats = computeDegreeStats;
119
+ exports.computeDensity = computeDensity;
120
+ exports.computeLinkTypeBreakdown = computeLinkTypeBreakdown;
121
+ exports.computeNodeLinkCounts = computeNodeLinkCounts;
122
+ exports.findHubs = findHubs;
123
+ exports.getNeighbors = getNeighbors;
124
+ exports.groupByType = groupByType;
125
+ exports.topByDegree = topByDegree;
126
+ //# sourceMappingURL=analysis.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.cjs","sources":["../src/analysis/degree.ts","../src/analysis/density.ts","../src/analysis/centrality.ts","../src/analysis/adjacency.ts","../src/analysis/index.ts"],"sourcesContent":["/**\n * Degree computation: degree map, distribution stats.\n */\nimport type { GraphData, GraphNode } from \"../types\";\n\nexport interface DegreeMap {\n [nodeId: string]: number;\n}\n\n/** Compute degree for every node */\nexport function computeDegreeMap(data: GraphData): DegreeMap {\n const degree: DegreeMap = {};\n for (const n of data.nodes) degree[n.id] = 0;\n for (const l of data.links) {\n const s = typeof l.source === \"object\" ? (l.source as any).id : l.source;\n const t = typeof l.target === \"object\" ? (l.target as any).id : l.target;\n if (degree[s] !== undefined) degree[s]++;\n if (degree[t] !== undefined) degree[t]++;\n }\n return degree;\n}\n\nexport interface DegreeStats {\n min: number;\n max: number;\n avg: number;\n total: number;\n}\n\n/** Compute degree distribution statistics */\nexport function computeDegreeStats(degreeMap: DegreeMap): DegreeStats {\n const values = Object.values(degreeMap);\n if (values.length === 0) {\n return { min: 0, max: 0, avg: 0, total: 0 };\n }\n const total = values.reduce((a, b) => a + b, 0);\n return {\n min: Math.min(...values),\n max: Math.max(...values),\n avg: total / values.length,\n total,\n };\n}\n\n/** Get top N nodes by degree */\nexport function topByDegree(\n nodes: GraphNode[],\n degreeMap: DegreeMap,\n n: number\n): Array<GraphNode & { degree: number }> {\n return nodes\n .map((node) => ({ ...node, degree: degreeMap[node.id] ?? 0 }))\n .sort((a, b) => b.degree - a.degree)\n .slice(0, n);\n}\n","/**\n * Network density computation.\n */\n\n/** Compute graph density: 2|E| / (|N| * (|N| - 1)) for undirected graphs */\nexport function computeDensity(nodeCount: number, linkCount: number): number {\n if (nodeCount <= 1) return 0;\n return (2 * linkCount) / (nodeCount * (nodeCount - 1));\n}\n","/**\n * Centrality and hub detection.\n */\nimport type { GraphData, GraphNode, GraphLink } from \"../types\";\nimport { computeDegreeMap, type DegreeMap } from \"./degree\";\n\nexport interface LinkTypeBreakdown {\n [linkType: string]: number;\n}\n\n/** Count links by type */\nexport function computeLinkTypeBreakdown(links: GraphLink[]): LinkTypeBreakdown {\n const counts: LinkTypeBreakdown = {};\n for (const l of links) {\n const type = l.type ?? \"default\";\n counts[type] = (counts[type] ?? 0) + 1;\n }\n return counts;\n}\n\n/** Count how many links of specific types each node has */\nexport function computeNodeLinkCounts(\n data: GraphData,\n linkTypes: string[]\n): Map<string, number> {\n const counts = new Map<string, number>();\n for (const n of data.nodes) counts.set(n.id, 0);\n\n const typeSet = new Set(linkTypes);\n for (const l of data.links) {\n if (!typeSet.has(l.type ?? \"default\")) continue;\n const s = typeof l.source === \"object\" ? (l.source as any).id : l.source;\n const t = typeof l.target === \"object\" ? (l.target as any).id : l.target;\n if (counts.has(s)) counts.set(s, counts.get(s)! + 1);\n if (counts.has(t)) counts.set(t, counts.get(t)! + 1);\n }\n return counts;\n}\n\n/**\n * Find hub nodes — nodes with degree above a threshold.\n * Returns nodes sorted by degree descending.\n */\nexport function findHubs(\n nodes: GraphNode[],\n degreeMap: DegreeMap,\n minDegree: number\n): Array<GraphNode & { degree: number }> {\n return nodes\n .map((n) => ({ ...n, degree: degreeMap[n.id] ?? 0 }))\n .filter((n) => n.degree >= minDegree)\n .sort((a, b) => b.degree - a.degree);\n}\n\n/** Group nodes by type with counts */\nexport function groupByType(\n nodes: GraphNode[]\n): Record<string, number> {\n const groups: Record<string, number> = {};\n for (const n of nodes) {\n const type = n.type ?? \"default\";\n groups[type] = (groups[type] ?? 0) + 1;\n }\n return groups;\n}\n","/**\n * Adjacency list construction and N-hop neighbor search.\n */\nimport type { GraphLink } from \"../types\";\n\n/** Build an adjacency map from a list of links */\nexport function buildAdjacencyMap(\n links: GraphLink[]\n): Map<string, string[]> {\n const adj = new Map<string, string[]>();\n for (const l of links) {\n const s = typeof l.source === \"object\" ? (l.source as any).id : l.source;\n const t = typeof l.target === \"object\" ? (l.target as any).id : l.target;\n if (!adj.has(s)) adj.set(s, []);\n if (!adj.has(t)) adj.set(t, []);\n adj.get(s)!.push(t);\n adj.get(t)!.push(s);\n }\n return adj;\n}\n\n/**\n * Find all nodes within N hops of a root node.\n * Returns a Map of node ID → hop distance.\n */\nexport function getNeighbors(\n adjacencyMap: Map<string, string[]>,\n rootId: string,\n maxHops: number\n): Map<string, number> {\n const visited = new Map<string, number>();\n visited.set(rootId, 0);\n const queue = [rootId];\n while (queue.length > 0) {\n const current = queue.shift()!;\n const dist = visited.get(current)!;\n if (dist >= maxHops) continue;\n for (const nb of adjacencyMap.get(current) ?? []) {\n if (!visited.has(nb)) {\n visited.set(nb, dist + 1);\n queue.push(nb);\n }\n }\n }\n return visited;\n}\n","/**\n * Graph analysis module — tree-shakeable, no Three.js dependency.\n *\n * Usage:\n * import { analyzeGraph, buildAdjacencyMap } from 'graphier/analysis';\n */\nimport type { GraphData, GraphNode } from \"../types\";\nimport { computeDegreeMap, computeDegreeStats, topByDegree } from \"./degree\";\nimport { computeDensity } from \"./density\";\nimport {\n computeLinkTypeBreakdown,\n groupByType,\n} from \"./centrality\";\nimport { buildAdjacencyMap, getNeighbors } from \"./adjacency\";\n\nexport interface GraphAnalytics {\n nodeCount: number;\n linkCount: number;\n density: number;\n avgDegree: number;\n maxDegree: number;\n minDegree: number;\n totalDegree: number;\n degreeMap: Record<string, number>;\n nodesByType: Record<string, number>;\n linksByType: Record<string, number>;\n /** Get top N nodes by degree */\n topByDegree(n: number): Array<GraphNode & { degree: number }>;\n}\n\n/**\n * Analyze a graph and return comprehensive statistics.\n *\n * @example\n * ```ts\n * const stats = analyzeGraph(data);\n * console.log(`Density: ${stats.density}`);\n * console.log(`Top hubs:`, stats.topByDegree(10));\n * ```\n */\nexport function analyzeGraph(data: GraphData): GraphAnalytics {\n const degreeMap = computeDegreeMap(data);\n const degreeStats = computeDegreeStats(degreeMap);\n const density = computeDensity(data.nodes.length, data.links.length);\n const nodesByType = groupByType(data.nodes);\n const linksByType = computeLinkTypeBreakdown(data.links);\n\n return {\n nodeCount: data.nodes.length,\n linkCount: data.links.length,\n density,\n avgDegree: degreeStats.avg,\n maxDegree: degreeStats.max,\n minDegree: degreeStats.min,\n totalDegree: degreeStats.total,\n degreeMap,\n nodesByType,\n linksByType,\n topByDegree: (n: number) => topByDegree(data.nodes, degreeMap, n),\n };\n}\n\n// Re-export individual utilities\nexport { buildAdjacencyMap, getNeighbors } from \"./adjacency\";\nexport { computeDegreeMap, computeDegreeStats, topByDegree } from \"./degree\";\nexport { computeDensity } from \"./density\";\nexport {\n computeLinkTypeBreakdown,\n computeNodeLinkCounts,\n findHubs,\n groupByType,\n} from \"./centrality\";\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Analyze a graph and return comprehensive statistics.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * const stats = analyzeGraph(data);
7
+ * console.log(`Density: ${stats.density}`);
8
+ * console.log(`Top hubs:`, stats.topByDegree(10));
9
+ * ```
10
+ */
11
+ export declare function analyzeGraph(data: GraphData): GraphAnalytics;
12
+
13
+ /** Build an adjacency map from a list of links */
14
+ export declare function buildAdjacencyMap(links: GraphLink[]): Map<string, string[]>;
15
+
16
+ /** Compute degree for every node */
17
+ export declare function computeDegreeMap(data: GraphData): DegreeMap;
18
+
19
+ /** Compute degree distribution statistics */
20
+ export declare function computeDegreeStats(degreeMap: DegreeMap): DegreeStats;
21
+
22
+ /**
23
+ * Network density computation.
24
+ */
25
+ /** Compute graph density: 2|E| / (|N| * (|N| - 1)) for undirected graphs */
26
+ export declare function computeDensity(nodeCount: number, linkCount: number): number;
27
+
28
+ /** Count links by type */
29
+ export declare function computeLinkTypeBreakdown(links: GraphLink[]): LinkTypeBreakdown;
30
+
31
+ /** Count how many links of specific types each node has */
32
+ export declare function computeNodeLinkCounts(data: GraphData, linkTypes: string[]): Map<string, number>;
33
+
34
+ declare interface DegreeMap {
35
+ [nodeId: string]: number;
36
+ }
37
+
38
+ declare interface DegreeStats {
39
+ min: number;
40
+ max: number;
41
+ avg: number;
42
+ total: number;
43
+ }
44
+
45
+ /**
46
+ * Find hub nodes — nodes with degree above a threshold.
47
+ * Returns nodes sorted by degree descending.
48
+ */
49
+ export declare function findHubs(nodes: GraphNode[], degreeMap: DegreeMap, minDegree: number): Array<GraphNode & {
50
+ degree: number;
51
+ }>;
52
+
53
+ /**
54
+ * Find all nodes within N hops of a root node.
55
+ * Returns a Map of node ID → hop distance.
56
+ */
57
+ export declare function getNeighbors(adjacencyMap: Map<string, string[]>, rootId: string, maxHops: number): Map<string, number>;
58
+
59
+ export declare interface GraphAnalytics {
60
+ nodeCount: number;
61
+ linkCount: number;
62
+ density: number;
63
+ avgDegree: number;
64
+ maxDegree: number;
65
+ minDegree: number;
66
+ totalDegree: number;
67
+ degreeMap: Record<string, number>;
68
+ nodesByType: Record<string, number>;
69
+ linksByType: Record<string, number>;
70
+ /** Get top N nodes by degree */
71
+ topByDegree(n: number): Array<GraphNode & {
72
+ degree: number;
73
+ }>;
74
+ }
75
+
76
+ declare interface GraphData {
77
+ nodes: GraphNode[];
78
+ links: GraphLink[];
79
+ }
80
+
81
+ declare interface GraphLink {
82
+ /** Source node id */
83
+ source: string;
84
+ /** Target node id */
85
+ target: string;
86
+ /** Relationship type — maps to theme colors (e.g. "follows", "owns") */
87
+ type?: string;
88
+ /** Edge weight (default: 1) */
89
+ weight?: number;
90
+ /** User-defined extra data */
91
+ [key: string]: unknown;
92
+ }
93
+
94
+ /**
95
+ * Core graph data types — domain-agnostic.
96
+ * Users provide any `type` string ("person", "server", "repo", etc.)
97
+ * and the theme system maps them to colors automatically.
98
+ */
99
+ declare interface GraphNode {
100
+ /** Unique identifier */
101
+ id: string;
102
+ /** Node category — maps to theme colors (e.g. "person", "repo") */
103
+ type?: string;
104
+ /** Display label (falls back to id) */
105
+ label?: string;
106
+ /** Size weight — higher values render larger (default: 1) */
107
+ val?: number;
108
+ /** Grouping key for color auto-assignment (alternative to type) */
109
+ group?: string;
110
+ /** User-defined extra data (accessible in callbacks) */
111
+ [key: string]: unknown;
112
+ }
113
+
114
+ /** Group nodes by type with counts */
115
+ export declare function groupByType(nodes: GraphNode[]): Record<string, number>;
116
+
117
+ declare interface LinkTypeBreakdown {
118
+ [linkType: string]: number;
119
+ }
120
+
121
+ /** Get top N nodes by degree */
122
+ export declare function topByDegree(nodes: GraphNode[], degreeMap: DegreeMap, n: number): Array<GraphNode & {
123
+ degree: number;
124
+ }>;
125
+
126
+ export { }
@@ -0,0 +1,126 @@
1
+ function computeDegreeMap(data) {
2
+ const degree = {};
3
+ for (const n of data.nodes) degree[n.id] = 0;
4
+ for (const l of data.links) {
5
+ const s = typeof l.source === "object" ? l.source.id : l.source;
6
+ const t = typeof l.target === "object" ? l.target.id : l.target;
7
+ if (degree[s] !== void 0) degree[s]++;
8
+ if (degree[t] !== void 0) degree[t]++;
9
+ }
10
+ return degree;
11
+ }
12
+ function computeDegreeStats(degreeMap) {
13
+ const values = Object.values(degreeMap);
14
+ if (values.length === 0) {
15
+ return { min: 0, max: 0, avg: 0, total: 0 };
16
+ }
17
+ const total = values.reduce((a, b) => a + b, 0);
18
+ return {
19
+ min: Math.min(...values),
20
+ max: Math.max(...values),
21
+ avg: total / values.length,
22
+ total
23
+ };
24
+ }
25
+ function topByDegree(nodes, degreeMap, n) {
26
+ return nodes.map((node) => ({ ...node, degree: degreeMap[node.id] ?? 0 })).sort((a, b) => b.degree - a.degree).slice(0, n);
27
+ }
28
+ function computeDensity(nodeCount, linkCount) {
29
+ if (nodeCount <= 1) return 0;
30
+ return 2 * linkCount / (nodeCount * (nodeCount - 1));
31
+ }
32
+ function computeLinkTypeBreakdown(links) {
33
+ const counts = {};
34
+ for (const l of links) {
35
+ const type = l.type ?? "default";
36
+ counts[type] = (counts[type] ?? 0) + 1;
37
+ }
38
+ return counts;
39
+ }
40
+ function computeNodeLinkCounts(data, linkTypes) {
41
+ const counts = /* @__PURE__ */ new Map();
42
+ for (const n of data.nodes) counts.set(n.id, 0);
43
+ const typeSet = new Set(linkTypes);
44
+ for (const l of data.links) {
45
+ if (!typeSet.has(l.type ?? "default")) continue;
46
+ const s = typeof l.source === "object" ? l.source.id : l.source;
47
+ const t = typeof l.target === "object" ? l.target.id : l.target;
48
+ if (counts.has(s)) counts.set(s, counts.get(s) + 1);
49
+ if (counts.has(t)) counts.set(t, counts.get(t) + 1);
50
+ }
51
+ return counts;
52
+ }
53
+ function findHubs(nodes, degreeMap, minDegree) {
54
+ return nodes.map((n) => ({ ...n, degree: degreeMap[n.id] ?? 0 })).filter((n) => n.degree >= minDegree).sort((a, b) => b.degree - a.degree);
55
+ }
56
+ function groupByType(nodes) {
57
+ const groups = {};
58
+ for (const n of nodes) {
59
+ const type = n.type ?? "default";
60
+ groups[type] = (groups[type] ?? 0) + 1;
61
+ }
62
+ return groups;
63
+ }
64
+ function buildAdjacencyMap(links) {
65
+ const adj = /* @__PURE__ */ new Map();
66
+ for (const l of links) {
67
+ const s = typeof l.source === "object" ? l.source.id : l.source;
68
+ const t = typeof l.target === "object" ? l.target.id : l.target;
69
+ if (!adj.has(s)) adj.set(s, []);
70
+ if (!adj.has(t)) adj.set(t, []);
71
+ adj.get(s).push(t);
72
+ adj.get(t).push(s);
73
+ }
74
+ return adj;
75
+ }
76
+ function getNeighbors(adjacencyMap, rootId, maxHops) {
77
+ const visited = /* @__PURE__ */ new Map();
78
+ visited.set(rootId, 0);
79
+ const queue = [rootId];
80
+ while (queue.length > 0) {
81
+ const current = queue.shift();
82
+ const dist = visited.get(current);
83
+ if (dist >= maxHops) continue;
84
+ for (const nb of adjacencyMap.get(current) ?? []) {
85
+ if (!visited.has(nb)) {
86
+ visited.set(nb, dist + 1);
87
+ queue.push(nb);
88
+ }
89
+ }
90
+ }
91
+ return visited;
92
+ }
93
+ function analyzeGraph(data) {
94
+ const degreeMap = computeDegreeMap(data);
95
+ const degreeStats = computeDegreeStats(degreeMap);
96
+ const density = computeDensity(data.nodes.length, data.links.length);
97
+ const nodesByType = groupByType(data.nodes);
98
+ const linksByType = computeLinkTypeBreakdown(data.links);
99
+ return {
100
+ nodeCount: data.nodes.length,
101
+ linkCount: data.links.length,
102
+ density,
103
+ avgDegree: degreeStats.avg,
104
+ maxDegree: degreeStats.max,
105
+ minDegree: degreeStats.min,
106
+ totalDegree: degreeStats.total,
107
+ degreeMap,
108
+ nodesByType,
109
+ linksByType,
110
+ topByDegree: (n) => topByDegree(data.nodes, degreeMap, n)
111
+ };
112
+ }
113
+ export {
114
+ analyzeGraph,
115
+ buildAdjacencyMap,
116
+ computeDegreeMap,
117
+ computeDegreeStats,
118
+ computeDensity,
119
+ computeLinkTypeBreakdown,
120
+ computeNodeLinkCounts,
121
+ findHubs,
122
+ getNeighbors,
123
+ groupByType,
124
+ topByDegree
125
+ };
126
+ //# sourceMappingURL=analysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.js","sources":["../src/analysis/degree.ts","../src/analysis/density.ts","../src/analysis/centrality.ts","../src/analysis/adjacency.ts","../src/analysis/index.ts"],"sourcesContent":["/**\n * Degree computation: degree map, distribution stats.\n */\nimport type { GraphData, GraphNode } from \"../types\";\n\nexport interface DegreeMap {\n [nodeId: string]: number;\n}\n\n/** Compute degree for every node */\nexport function computeDegreeMap(data: GraphData): DegreeMap {\n const degree: DegreeMap = {};\n for (const n of data.nodes) degree[n.id] = 0;\n for (const l of data.links) {\n const s = typeof l.source === \"object\" ? (l.source as any).id : l.source;\n const t = typeof l.target === \"object\" ? (l.target as any).id : l.target;\n if (degree[s] !== undefined) degree[s]++;\n if (degree[t] !== undefined) degree[t]++;\n }\n return degree;\n}\n\nexport interface DegreeStats {\n min: number;\n max: number;\n avg: number;\n total: number;\n}\n\n/** Compute degree distribution statistics */\nexport function computeDegreeStats(degreeMap: DegreeMap): DegreeStats {\n const values = Object.values(degreeMap);\n if (values.length === 0) {\n return { min: 0, max: 0, avg: 0, total: 0 };\n }\n const total = values.reduce((a, b) => a + b, 0);\n return {\n min: Math.min(...values),\n max: Math.max(...values),\n avg: total / values.length,\n total,\n };\n}\n\n/** Get top N nodes by degree */\nexport function topByDegree(\n nodes: GraphNode[],\n degreeMap: DegreeMap,\n n: number\n): Array<GraphNode & { degree: number }> {\n return nodes\n .map((node) => ({ ...node, degree: degreeMap[node.id] ?? 0 }))\n .sort((a, b) => b.degree - a.degree)\n .slice(0, n);\n}\n","/**\n * Network density computation.\n */\n\n/** Compute graph density: 2|E| / (|N| * (|N| - 1)) for undirected graphs */\nexport function computeDensity(nodeCount: number, linkCount: number): number {\n if (nodeCount <= 1) return 0;\n return (2 * linkCount) / (nodeCount * (nodeCount - 1));\n}\n","/**\n * Centrality and hub detection.\n */\nimport type { GraphData, GraphNode, GraphLink } from \"../types\";\nimport { computeDegreeMap, type DegreeMap } from \"./degree\";\n\nexport interface LinkTypeBreakdown {\n [linkType: string]: number;\n}\n\n/** Count links by type */\nexport function computeLinkTypeBreakdown(links: GraphLink[]): LinkTypeBreakdown {\n const counts: LinkTypeBreakdown = {};\n for (const l of links) {\n const type = l.type ?? \"default\";\n counts[type] = (counts[type] ?? 0) + 1;\n }\n return counts;\n}\n\n/** Count how many links of specific types each node has */\nexport function computeNodeLinkCounts(\n data: GraphData,\n linkTypes: string[]\n): Map<string, number> {\n const counts = new Map<string, number>();\n for (const n of data.nodes) counts.set(n.id, 0);\n\n const typeSet = new Set(linkTypes);\n for (const l of data.links) {\n if (!typeSet.has(l.type ?? \"default\")) continue;\n const s = typeof l.source === \"object\" ? (l.source as any).id : l.source;\n const t = typeof l.target === \"object\" ? (l.target as any).id : l.target;\n if (counts.has(s)) counts.set(s, counts.get(s)! + 1);\n if (counts.has(t)) counts.set(t, counts.get(t)! + 1);\n }\n return counts;\n}\n\n/**\n * Find hub nodes — nodes with degree above a threshold.\n * Returns nodes sorted by degree descending.\n */\nexport function findHubs(\n nodes: GraphNode[],\n degreeMap: DegreeMap,\n minDegree: number\n): Array<GraphNode & { degree: number }> {\n return nodes\n .map((n) => ({ ...n, degree: degreeMap[n.id] ?? 0 }))\n .filter((n) => n.degree >= minDegree)\n .sort((a, b) => b.degree - a.degree);\n}\n\n/** Group nodes by type with counts */\nexport function groupByType(\n nodes: GraphNode[]\n): Record<string, number> {\n const groups: Record<string, number> = {};\n for (const n of nodes) {\n const type = n.type ?? \"default\";\n groups[type] = (groups[type] ?? 0) + 1;\n }\n return groups;\n}\n","/**\n * Adjacency list construction and N-hop neighbor search.\n */\nimport type { GraphLink } from \"../types\";\n\n/** Build an adjacency map from a list of links */\nexport function buildAdjacencyMap(\n links: GraphLink[]\n): Map<string, string[]> {\n const adj = new Map<string, string[]>();\n for (const l of links) {\n const s = typeof l.source === \"object\" ? (l.source as any).id : l.source;\n const t = typeof l.target === \"object\" ? (l.target as any).id : l.target;\n if (!adj.has(s)) adj.set(s, []);\n if (!adj.has(t)) adj.set(t, []);\n adj.get(s)!.push(t);\n adj.get(t)!.push(s);\n }\n return adj;\n}\n\n/**\n * Find all nodes within N hops of a root node.\n * Returns a Map of node ID → hop distance.\n */\nexport function getNeighbors(\n adjacencyMap: Map<string, string[]>,\n rootId: string,\n maxHops: number\n): Map<string, number> {\n const visited = new Map<string, number>();\n visited.set(rootId, 0);\n const queue = [rootId];\n while (queue.length > 0) {\n const current = queue.shift()!;\n const dist = visited.get(current)!;\n if (dist >= maxHops) continue;\n for (const nb of adjacencyMap.get(current) ?? []) {\n if (!visited.has(nb)) {\n visited.set(nb, dist + 1);\n queue.push(nb);\n }\n }\n }\n return visited;\n}\n","/**\n * Graph analysis module — tree-shakeable, no Three.js dependency.\n *\n * Usage:\n * import { analyzeGraph, buildAdjacencyMap } from 'graphier/analysis';\n */\nimport type { GraphData, GraphNode } from \"../types\";\nimport { computeDegreeMap, computeDegreeStats, topByDegree } from \"./degree\";\nimport { computeDensity } from \"./density\";\nimport {\n computeLinkTypeBreakdown,\n groupByType,\n} from \"./centrality\";\nimport { buildAdjacencyMap, getNeighbors } from \"./adjacency\";\n\nexport interface GraphAnalytics {\n nodeCount: number;\n linkCount: number;\n density: number;\n avgDegree: number;\n maxDegree: number;\n minDegree: number;\n totalDegree: number;\n degreeMap: Record<string, number>;\n nodesByType: Record<string, number>;\n linksByType: Record<string, number>;\n /** Get top N nodes by degree */\n topByDegree(n: number): Array<GraphNode & { degree: number }>;\n}\n\n/**\n * Analyze a graph and return comprehensive statistics.\n *\n * @example\n * ```ts\n * const stats = analyzeGraph(data);\n * console.log(`Density: ${stats.density}`);\n * console.log(`Top hubs:`, stats.topByDegree(10));\n * ```\n */\nexport function analyzeGraph(data: GraphData): GraphAnalytics {\n const degreeMap = computeDegreeMap(data);\n const degreeStats = computeDegreeStats(degreeMap);\n const density = computeDensity(data.nodes.length, data.links.length);\n const nodesByType = groupByType(data.nodes);\n const linksByType = computeLinkTypeBreakdown(data.links);\n\n return {\n nodeCount: data.nodes.length,\n linkCount: data.links.length,\n density,\n avgDegree: degreeStats.avg,\n maxDegree: degreeStats.max,\n minDegree: degreeStats.min,\n totalDegree: degreeStats.total,\n degreeMap,\n nodesByType,\n linksByType,\n topByDegree: (n: number) => topByDegree(data.nodes, degreeMap, n),\n };\n}\n\n// Re-export individual utilities\nexport { buildAdjacencyMap, getNeighbors } from \"./adjacency\";\nexport { computeDegreeMap, computeDegreeStats, topByDegree } from \"./degree\";\nexport { computeDensity } from \"./density\";\nexport {\n computeLinkTypeBreakdown,\n computeNodeLinkCounts,\n findHubs,\n groupByType,\n} from \"./centrality\";\n"],"names":[],"mappings":"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"}