@@ -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 we’ ll 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