Skip to content

Commit 50259b7

Browse files
committed
Deployed 8b48156 with MkDocs version: 1.5.3
1 parent d3b6fc0 commit 50259b7

File tree

6 files changed

+1025
-58
lines changed

6 files changed

+1025
-58
lines changed

assets/js/cwe_sunburst.js

Lines changed: 154 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,51 @@ async function loadData() {
3838
.sum(d=>(!d.children||!d.children.length)?1:0)
3939
.sort((a,b)=>b.value-a.value)
4040
);
41+
42+
// Ensure minimum segment size for visibility
43+
root.descendants().forEach(d => {
44+
// Ensure each segment has a minimum angular width
45+
if (d.x1 - d.x0 < 0.01 && d !== root) {
46+
// If segment is too small, set a minimum size of 0.01 radians
47+
// This may slightly distort the proportions but improves visibility
48+
const midpoint = (d.x0 + d.x1) / 2;
49+
d.x0 = midpoint - 0.005;
50+
d.x1 = midpoint + 0.005;
51+
}
52+
});
4153

54+
// Increase minimum padding between segments
4255
const arc = d3.arc()
4356
.startAngle(d=>d.x0).endAngle(d=>d.x1)
44-
.padAngle(d=>Math.min((d.x1-d.x0)/2,0.005)).padRadius(radius/2)
57+
.padAngle(d=>Math.min((d.x1-d.x0)/2,0.003)).padRadius(radius/2)
4558
.innerRadius(d=>Math.max(innerRadius,d.y0*radius))
4659
.outerRadius(d=>Math.max(d.y0*radius,d.y1*radius-1));
4760

48-
// draw slices
61+
// draw slices with improved visibility
4962
g.selectAll("path")
5063
.data(root.descendants().slice(1))
5164
.join("path")
5265
.attr("fill", color)
5366
.attr("d", arc)
5467
.style("cursor", "pointer")
55-
.on("mouseover", showInfo)
68+
.style("opacity", 1) // Full opacity for better visibility
69+
.style("stroke", "#fff")
70+
.style("stroke-width", "0.5px") // Slightly thicker borders
71+
.on("mouseover", (event, d) => {
72+
// Highlight on hover
73+
d3.select(event.currentTarget)
74+
.style("opacity", 0.8)
75+
.style("stroke-width", "1px");
76+
showInfo(event, d);
77+
})
78+
.on("mouseout", (event) => {
79+
// Restore normal appearance
80+
d3.select(event.currentTarget)
81+
.style("opacity", 1)
82+
.style("stroke-width", "0.5px");
83+
})
5684
.on("click", (event, d) => {
57-
// build the URL you want—here well link to the MITRE CWE page:
85+
// build the URL you want—here we'll link to the MITRE CWE page:
5886
const idNum = d.data.id?.split("CWE-")[1];
5987
if (idNum) {
6088
window.open(
@@ -64,45 +92,120 @@ async function loadData() {
6492
}
6593
});
6694

67-
// draw labels
95+
// Add clickable center label for CWE-1000
96+
g.append("a")
97+
.attr("href", "https://cwe.mitre.org/data/definitions/1000.html")
98+
.attr("target", "_blank") // Open in new tab
99+
.append("text")
100+
.attr("text-anchor", "middle")
101+
.attr("font-size", "12px")
102+
.attr("font-weight", "bold")
103+
.attr("fill", "#0066cc") // Use link color
104+
.attr("cursor", "pointer") // Show pointer cursor on hover
105+
.text("CWE-1000")
106+
.append("title")
107+
.text("Click to open CWE-1000: Research Concepts");
108+
109+
// draw labels with more intelligent spacing
68110
g.append("g")
69111
.attr("pointer-events","none")
70112
.attr("text-anchor","middle")
71113
.selectAll("text")
72114
.data(root.descendants().slice(1))
73115
.join("text")
74-
.attr("transform", d => {
116+
.attr("transform", (d, i) => {
117+
// Calculate arc width to determine space available
118+
const arcWidth = (d.x1 - d.x0);
119+
const arcLength = arcWidth * ((d.y0 + d.y1)/2 * radius);
120+
121+
// For very small segments, position text at different radius points
122+
// For segments with siblings, stagger the radius
123+
let radiusFactor = 1.0;
124+
125+
// If segment is larger, position text in the middle
126+
if (arcLength > 30) {
127+
// Plenty of room, use middle position
128+
radiusFactor = 1.0;
129+
} else if (d.parent && d.parent.children.length > 4) {
130+
// For crowded areas with many siblings, stagger by position within parent
131+
const siblingIndex = d.parent.children.indexOf(d);
132+
// Use modulo 3 to create three different radius positions
133+
if (siblingIndex % 3 === 0) radiusFactor = 0.85; // Inner position
134+
else if (siblingIndex % 3 === 1) radiusFactor = 1.0; // Middle position
135+
else radiusFactor = 1.15; // Outer position
136+
}
137+
75138
const angle = (d.x0 + d.x1)/2 * 180/Math.PI;
76-
const radiusFactor = 1.12;
77139
const y = (d.y0 + d.y1)/2 * radius * radiusFactor;
140+
78141
return `rotate(${angle-90}) translate(${y},0) rotate(${angle<180?0:180})`;
79142
})
80-
.attr("font-size", "3px")
143+
// Fixed modest font size
144+
.attr("font-size", "5px")
145+
// Improve text readability with stronger outline
146+
.attr("stroke", "#fff")
147+
.attr("stroke-width", "0.3px")
148+
.attr("font-weight", "bold")
149+
// Only show CWE IDs, not names
81150
.text(d => d.data.id
82151
? d.data.id.split(':')[0]
83-
: (d.data.name||"").substring(0,30)
152+
: ""
84153
)
85-
.on("mouseover click", showInfo);
154+
// Always display text, regardless of segment size
155+
.style("display", "inline")
156+
.append("title") // Add tooltip with full name on hover
157+
.text(d => d.data.id && d.data.name ? `${d.data.id}: ${d.data.name}` : (d.data.name || ""));
86158

87-
// info‐panel
88-
function showInfo(_,d) {
159+
// info‐panel with children list
160+
function showInfo(event, d) {
89161
const bc = d.ancestors().reverse()
90-
.map(a=>a.data.id||a.data.name||"Root").join(" > ");
162+
.map(a => a.data.id || a.data.name || "Root").join(" > ");
163+
91164
let html = `<div class="breadcrumb">${bc}</div>`;
92-
if(d.data.id) html += `
165+
if (d.data.id) html += `
93166
<div class="cwe-id">
94167
<a href="https://cwe.mitre.org/data/definitions/${d.data.id.split('-')[1]}.html" target="_blank">
95168
${d.data.id}
96169
</a>
97170
</div>`;
98-
if(d.data.name) html += `<div class="cwe-name">${d.data.name}</div>`;
99-
if(d.data.abstraction)
171+
if (d.data.name) html += `<div class="cwe-name">${d.data.name}</div>`;
172+
if (d.data.abstraction)
100173
html += `<div class="cwe-abstraction">Abstraction: ${d.data.abstraction}</div>`;
174+
175+
// Add children count
101176
html += `<div class="children-count">${
102177
d.children
103178
? `Children: ${d.children.length}`
104179
: 'Leaf node'
105180
}</div>`;
181+
182+
// Always add the complete children list if there are any children
183+
if (d.children && d.children.length > 0) {
184+
html += `<div class="children-list"><h4>Child nodes:</h4><ul>`;
185+
186+
// Sort children alphabetically by ID
187+
const sortedChildren = [...d.children].sort((a, b) => {
188+
const aId = a.data.id || "";
189+
const bId = b.data.id || "";
190+
return aId.localeCompare(bId);
191+
});
192+
193+
// Add each child to the list with its ID and name
194+
sortedChildren.forEach(child => {
195+
if (child.data.id) {
196+
const idNum = child.data.id.split('-')[1];
197+
html += `<li>
198+
<a href="https://cwe.mitre.org/data/definitions/${idNum}.html" target="_blank">${child.data.id}</a>:
199+
${child.data.name || ""}
200+
</li>`;
201+
} else {
202+
html += `<li>${child.data.name || ""}</li>`;
203+
}
204+
});
205+
206+
html += `</ul></div>`;
207+
}
208+
106209
d3.select(".node-info").html(html);
107210
}
108211

@@ -116,7 +219,40 @@ async function loadData() {
116219

117220
// initial
118221
showInfo(null, root);
222+
223+
// Add CSS without scrollbars
224+
const styleElement = document.createElement('style');
225+
styleElement.textContent = `
226+
.children-list {
227+
margin-top: 15px;
228+
border: 1px solid #eee;
229+
padding: 15px;
230+
background: #f9f9f9;
231+
border-radius: 4px;
232+
}
233+
.children-list h4 {
234+
margin-top: 0;
235+
margin-bottom: 10px;
236+
color: #333;
237+
}
238+
.children-list ul {
239+
margin: 0;
240+
padding-left: 20px;
241+
}
242+
.children-list li {
243+
margin-bottom: 5px;
244+
font-size: 14px;
245+
line-height: 1.4;
246+
}
247+
.children-list a {
248+
color: #0066cc;
249+
text-decoration: none;
250+
}
251+
.children-list a:hover {
252+
text-decoration: underline;
253+
}
254+
`;
255+
document.head.appendChild(styleElement);
119256
}
120257

121-
loadData();
122-
258+
loadData();

0 commit comments

Comments
 (0)