Skip to content

Commit 04be5f5

Browse files
authored
The nodes of the graph change color based on the number of CVEs (#111)
1 parent bba645a commit 04be5f5

File tree

2 files changed

+56
-9
lines changed

2 files changed

+56
-9
lines changed

components/DependencyGraph.tsx

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface GraphDependency {
1111
interface DependencyNode extends d3.SimulationNodeDatum {
1212
id: string;
1313
color: string;
14+
cve_count: number;
1415
}
1516

1617
interface DependencyLink extends d3.SimulationLinkDatum<DependencyNode> {
@@ -60,11 +61,11 @@ const DependencyGraph: React.FC = () => {
6061
svg.append('defs').append('marker')
6162
.attr('id', 'arrowhead')
6263
.attr('viewBox', '0 -5 10 10')
63-
.attr('refX', 17)
64+
.attr('refX', 8)
6465
.attr('refY', 0)
6566
.attr('orient', 'auto')
66-
.attr('markerWidth', 3)
67-
.attr('markerHeight', 3)
67+
.attr('markerWidth', 6)
68+
.attr('markerHeight', 6)
6869
.append('path')
6970
.attr('d', 'M 0,-5 L 10,0 L 0,5')
7071
.attr('fill', '#333')
@@ -77,7 +78,21 @@ const DependencyGraph: React.FC = () => {
7778
const nodeId = `${dep.name_and_version}`;
7879
let node = nodesMap.get(nodeId);
7980
if (!node) {
80-
node = { id: nodeId, color: parent ? '#5c6470' : '#32e0c4' };
81+
const getColorByCveCount = (count: number) => {
82+
if (count === 0) return '#2ecc71'; // 绿色
83+
if (count >= 10) return '#8b0000'; // 深红色
84+
if (count >= 6) return '#e74c3c'; // 红色
85+
if (count >= 3) return '#e67e22'; // 橙色
86+
if (count >= 1) return '#f1c40f'; // 黄色
87+
return '#2ecc71'; // 默认绿色
88+
};
89+
90+
const nodeColor = !parent ? '#32e0c4' : getColorByCveCount(dep.cve_count);
91+
node = {
92+
id: nodeId,
93+
color: nodeColor,
94+
cve_count: dep.cve_count
95+
};
8196
nodesMap.set(nodeId, node);
8297
}
8398
if (parent) {
@@ -96,7 +111,7 @@ const DependencyGraph: React.FC = () => {
96111
.force('link', d3.forceLink<DependencyNode, DependencyLink>(links).id(d => d.id).distance(80))
97112
.force('charge', d3.forceManyBody().strength(-300))
98113
.force('center', d3.forceCenter(width / 2, height / 2))
99-
.force('collide', d3.forceCollide().radius(10));
114+
.force('collide', d3.forceCollide().radius(15));
100115

101116
const g = svg.append('g');
102117

@@ -106,13 +121,25 @@ const DependencyGraph: React.FC = () => {
106121
.enter().append('line')
107122
.attr('stroke-width', 1.5)
108123
.attr('stroke', '#333')
109-
.attr('marker-end', 'url(#arrowhead)');
124+
.attr('marker-end', 'url(#arrowhead)')
125+
.attr('x2', function (d) {
126+
const dx = (d.target as DependencyNode).x! - (d.source as DependencyNode).x!;
127+
const dy = (d.target as DependencyNode).y! - (d.source as DependencyNode).y!;
128+
const dist = Math.sqrt(dx * dx + dy * dy);
129+
return dist === 0 ? 0 : (d.target as DependencyNode).x! - (dx * 15 / dist);
130+
})
131+
.attr('y2', function (d) {
132+
const dx = (d.target as DependencyNode).x! - (d.source as DependencyNode).x!;
133+
const dy = (d.target as DependencyNode).y! - (d.source as DependencyNode).y!;
134+
const dist = Math.sqrt(dx * dx + dy * dy);
135+
return dist === 0 ? 0 : (d.target as DependencyNode).y! - (dy * 15 / dist);
136+
});
110137

111138
const node = g.append('g')
112139
.selectAll('circle')
113140
.data(nodes)
114141
.enter().append('circle')
115-
.attr('r', 5)
142+
.attr('r', 8)
116143
.attr('fill', d => d.color)
117144
.attr('stroke', '#333')
118145
.attr('stroke-width', 1.5)
@@ -144,8 +171,18 @@ const DependencyGraph: React.FC = () => {
144171
link
145172
.attr('x1', d => (d.source as DependencyNode).x!)
146173
.attr('y1', d => (d.source as DependencyNode).y!)
147-
.attr('x2', d => (d.target as DependencyNode).x!)
148-
.attr('y2', d => (d.target as DependencyNode).y!);
174+
.attr('x2', function (d) {
175+
const dx = (d.target as DependencyNode).x! - (d.source as DependencyNode).x!;
176+
const dy = (d.target as DependencyNode).y! - (d.source as DependencyNode).y!;
177+
const dist = Math.sqrt(dx * dx + dy * dy);
178+
return dist === 0 ? 0 : (d.target as DependencyNode).x! - (dx * 15 / dist);
179+
})
180+
.attr('y2', function (d) {
181+
const dx = (d.target as DependencyNode).x! - (d.source as DependencyNode).x!;
182+
const dy = (d.target as DependencyNode).y! - (d.source as DependencyNode).y!;
183+
const dist = Math.sqrt(dx * dx + dy * dy);
184+
return dist === 0 ? 0 : (d.target as DependencyNode).y! - (dy * 15 / dist);
185+
});
149186

150187
node
151188
.attr('cx', d => d.x!)

next.config.mjs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,14 @@
44
export default {
55
output: "standalone",
66
reactStrictMode: true,
7+
// async redirects() {
8+
// return [
9+
// {
10+
// source: '/',
11+
12+
// destination: '/hompage',
13+
// permanent: false,
14+
// },
15+
// ];
16+
// },
717
};

0 commit comments

Comments
 (0)