1- // Data
1+ // Data
22let data = [
33 { gender : 'Female' , 'Physical Activity' : 2.43 , 'Study Time' : 4.49 , 'Screen Time' : 6.44 , 'Sleep' : 7.31 } ,
4- { gender : 'Male' , 'Physical Activity' : 3.05 , 'Study Time' : 4.58 , 'Screen Time' : 8.5 , 'Sleep' : 7.14 }
5- ] ;
4+ { gender : 'Male' , 'Physical Activity' : 3.05 , 'Study Time' : 4.58 , 'Screen Time' : 8.5 , 'Sleep' : 7.14 }
5+ ] ;
6+
7+ const keys = [ 'Physical Activity' , 'Study Time' , 'Screen Time' , 'Sleep' ] ;
8+ const colors = [ '#dbdb8d' , '#aec7e8' , '#ff9896' , '#ffbb78' ] ;
9+
10+ let width = 600 ,
11+ height = 400 ;
12+
13+ let margin = { top : 50 , bottom : 60 , left : 60 , right : 160 } ;
14+
15+ let svg = d3 . select ( 'body' )
16+ . append ( 'svg' )
17+ . attr ( 'width' , width )
18+ . attr ( 'height' , height ) ;
619
7- const keys = [ 'Physical Activity' , 'Study Time' , 'Screen Time' , 'Sleep' ] ;
8- const colors = [ '#dbdb8d' , '#aec7e8' , '#ff9896' , '#ffbb78' ] ;
9- let width = 600 ,
10- height = 400 ;
11- let margin = { top : 50 , bottom : 60 , left : 60 , right : 160 } ;
12- let svg = d3 . select ( '#chart' )
13- . append ( 'svg' )
14- . attr ( 'width' , width )
15- . attr ( 'height' , height ) ;
16- let stack = d3 . stack ( ) . keys ( keys ) ;
17- let series = stack ( data ) ;
18- let maxVal = d3 . max ( series , s => d3 . max ( s , d => d [ 1 ] ) ) ;
19- let yScale = d3 . scaleLinear ( )
20+ let tooltip = d3 . select ( 'body' )
21+ . append ( 'div' )
22+ . style ( 'position' , 'absolute' )
23+ . style ( 'background' , 'rgba(0,0,0,0.75)' )
24+ . style ( 'color' , '#fff' )
25+ . style ( 'padding' , '8px 12px' )
26+ . style ( 'font-size' , '13px' )
27+ . style ( 'pointer-events' , 'none' )
28+ . style ( 'opacity' , 0 ) ;
29+
30+ let stack = d3 . stack ( ) . keys ( keys ) ;
31+ let series = stack ( data ) ;
32+
33+ let maxVal = d3 . max ( series , s => d3 . max ( s , d => d [ 1 ] ) ) ;
34+
35+ let yScale = d3 . scaleLinear ( )
2036 . domain ( [ 0 , Math . ceil ( maxVal ) ] )
2137 . range ( [ height - margin . bottom , margin . top ] ) ;
22- let xScale = d3 . scaleBand ( )
38+
39+ let xScale = d3 . scaleBand ( )
2340 . domain ( data . map ( d => d . gender ) )
2441 . range ( [ margin . left , width - margin . right ] )
2542 . padding ( 0.35 ) ;
2643
27- let yAxis = svg . append ( 'g' )
44+ let yAxis = svg . append ( 'g' )
2845 . call ( d3 . axisLeft ( yScale ) . ticks ( 6 ) )
2946 . attr ( 'transform' , `translate(${ margin . left } , 0)` ) ;
30- let xAxis = svg . append ( 'g' )
47+
48+ let xAxis = svg . append ( 'g' )
3149 . call ( d3 . axisBottom ( xScale ) . tickSize ( 0 ) )
3250 . attr ( 'transform' , `translate(0, ${ height - margin . bottom } )` ) ;
33-
34- // Input axis labels
35- svg . append ( 'text' )
51+
52+ // Input axis labels
53+ svg . append ( 'text' )
3654 . attr ( 'x' , - ( height / 2 ) )
3755 . attr ( 'y' , 18 )
3856 . attr ( 'transform' , 'rotate(-90)' )
3957 . attr ( 'text-anchor' , 'middle' )
4058 . text ( 'Average hours per day' ) ;
41- svg . append ( 'text' )
59+
60+ svg . append ( 'text' )
4261 . attr ( 'x' , margin . left + ( width - margin . left - margin . right ) / 2 )
4362 . attr ( 'y' , height - 10 )
4463 . attr ( 'text-anchor' , 'middle' )
45- . text ( 'Gender' ) ;
46- let groups = svg . selectAll ( 'g.series' )
64+ . text ( 'Sex' ) ;
65+
66+ let groups = svg . selectAll ( 'g.series' )
4767 . data ( series )
4868 . enter ( )
4969 . append ( 'g' )
5070 . attr ( 'class' , 'series' )
5171 . attr ( 'fill' , ( d , i ) => colors [ i ] ) ;
52- groups . selectAll ( 'rect' )
72+
73+ groups . selectAll ( 'rect' )
5374 . data ( d => d )
5475 . enter ( )
5576 . append ( 'rect' )
56- . attr ( 'x' , d => xScale ( d . data . gender ) )
57- . attr ( 'y' , d => yScale ( d [ 1 ] ) )
58- . attr ( 'width' , xScale . bandwidth ( ) )
59- . attr ( 'height' , d => yScale ( d [ 0 ] ) - yScale ( d [ 1 ] ) ) ;
77+ . attr ( 'x' , d => xScale ( d . data . gender ) )
78+ . attr ( 'y' , d => yScale ( d [ 1 ] ) )
79+ . attr ( 'width' , xScale . bandwidth ( ) )
80+ . attr ( 'height' , d => yScale ( d [ 0 ] ) - yScale ( d [ 1 ] ) )
81+ . style ( 'cursor' , 'pointer' )
82+ . on ( 'mouseover' , function ( event , d ) {
83+ const key = d3 . select ( this . parentNode ) . datum ( ) . key ;
84+ const rawVal = d . data [ key ] ;
85+ const total = keys . reduce ( ( sum , k ) => sum + d . data [ k ] , 0 ) ;
86+ const pct = ( ( rawVal / total ) * 100 ) . toFixed ( 1 ) ;
87+
88+ tooltip
89+ . style ( 'opacity' , 1 )
90+ . html ( `
91+ <strong>${ d . data . gender } </strong><br/>
92+ <span style="color:#ccc">${ key } </span><br/>
93+ ${ rawVal . toFixed ( 2 ) } hrs | ${ pct } %
94+ ` ) ;
6095
61- // Create the legend
62- let legend = svg . append ( 'g' )
96+ d3 . select ( this ) . style ( 'filter' , 'brightness(1.2)' ) ;
97+ } )
98+ . on ( 'mousemove' , function ( event ) {
99+ tooltip
100+ . style ( 'left' , ( event . pageX + 14 ) + 'px' )
101+ . style ( 'top' , ( event . pageY - 36 ) + 'px' ) ;
102+ } )
103+ . on ( 'mouseout' , function ( ) {
104+ tooltip . style ( 'opacity' , 0 ) ;
105+ d3 . select ( this ) . style ( 'filter' , null ) ;
106+ } ) ;
107+
108+ // Create the legend
109+ let legend = svg . append ( 'g' )
63110 . attr ( 'transform' , `translate(${ width - margin . right + 16 } , ${ margin . top } )` ) ;
64- keys . forEach ( ( key , i ) => {
111+
112+ keys . forEach ( ( key , i ) => {
65113 let row = legend . append ( 'g' ) . attr ( 'transform' , `translate(0, ${ i * 24 } )` ) ;
66114 row . append ( 'rect' ) . attr ( 'width' , 12 ) . attr ( 'height' , 12 ) . attr ( 'fill' , colors [ i ] ) ;
67115 row . append ( 'text' ) . attr ( 'x' , 18 ) . attr ( 'y' , 10 ) . style ( 'font-size' , '12px' ) . text ( key ) ;
68- } )
116+ } ) ;
0 commit comments