1
+ <!DOCTYPE html>
2
+ < html lang ="en ">
3
+ < head >
4
+ < meta charset ="UTF-8 ">
5
+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6
+ < title > Optimized Homeless Data Visualization</ title >
7
+ < script src ="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.2/echarts.min.js "> </ script >
8
+ < style >
9
+ body {
10
+ font-family : 'Segoe UI' , Tahoma, Geneva, Verdana, sans-serif;
11
+ margin : 0 ;
12
+ padding : 20px ;
13
+ background-color : # f0f2f5 ;
14
+ color : # 333 ;
15
+ }
16
+ # main-container {
17
+ position : relative;
18
+ background-color : white;
19
+ border-radius : 12px ;
20
+ box-shadow : 0 4px 15px rgba (0 , 0 , 0 , 0.1 );
21
+ padding : 20px ;
22
+ margin-bottom : 20px ;
23
+ }
24
+ # chart {
25
+ height : 600px ;
26
+ width : 100% ;
27
+ margin-top : 60px ; /* Add space for controls */
28
+ }
29
+ # controls {
30
+ display : flex;
31
+ justify-content : flex-start;
32
+ align-items : center;
33
+ padding : 10px ;
34
+ background-color : # f8f9fa ;
35
+ border-bottom : 1px solid # e9ecef ;
36
+ position : absolute;
37
+ top : 0 ;
38
+ left : 0 ;
39
+ right : 0 ;
40
+ z-index : 10 ;
41
+ }
42
+ .control-group {
43
+ margin-right : 20px ;
44
+ }
45
+ select , button {
46
+ padding : 6px 12px ;
47
+ font-size : 14px ;
48
+ border : 1px solid # ced4da ;
49
+ border-radius : 4px ;
50
+ background-color : white;
51
+ color : # 495057 ;
52
+ cursor : pointer;
53
+ transition : all 0.3s ease;
54
+ }
55
+ select : hover , button : hover {
56
+ border-color : # 80bdff ;
57
+ box-shadow : 0 0 0 0.2rem rgba (0 , 123 , 255 , .25 );
58
+ }
59
+ h1 {
60
+ text-align : center;
61
+ color : # 1a3a5c ;
62
+ margin-bottom : 20px ;
63
+ font-size : 28px ;
64
+ font-weight : 700 ;
65
+ }
66
+ label {
67
+ margin-right : 5px ;
68
+ font-weight : 500 ;
69
+ }
70
+ </ style >
71
+ </ head >
72
+ < body >
73
+ < h1 > Homeless Population Data by City</ h1 >
74
+ < div id ="main-container ">
75
+ < div id ="controls ">
76
+ < div class ="control-group ">
77
+ < label for ="year "> Year:</ label >
78
+ < select id ="year "> </ select >
79
+ </ div >
80
+ < div class ="control-group ">
81
+ < label for ="topN "> Top N CoCs:</ label >
82
+ < select id ="topN ">
83
+ < option value ="10 "> 10</ option >
84
+ < option value ="15 " selected > 15</ option >
85
+ < option value ="20 "> 20</ option >
86
+ </ select >
87
+ </ div >
88
+ < button id ="toggleView "> Toggle View</ button >
89
+ </ div >
90
+ < div id ="chart "> </ div >
91
+ </ div >
92
+ < script >
93
+ // INSERT_DATA_HERE
94
+
95
+ var myChart = echarts . init ( document . getElementById ( 'chart' ) ) ;
96
+ var years = [ ...new Set ( data . map ( item => item . Year ) ) ] . sort ( ( a , b ) => a - b ) ;
97
+ var yearSelector = document . getElementById ( 'year' ) ;
98
+ var topNSelector = document . getElementById ( 'topN' ) ;
99
+ var toggleViewButton = document . getElementById ( 'toggleView' ) ;
100
+ var isHorizontal = false ;
101
+
102
+ years . forEach ( year => {
103
+ var option = document . createElement ( 'option' ) ;
104
+ option . value = year ;
105
+ option . textContent = year ;
106
+ yearSelector . appendChild ( option ) ;
107
+ } ) ;
108
+ yearSelector . value = years [ years . length - 1 ] ;
109
+
110
+ function formatNumber ( num ) {
111
+ if ( num >= 1000000 ) {
112
+ return ( num / 1000000 ) . toFixed ( 1 ) + 'M' ;
113
+ } else if ( num >= 1000 ) {
114
+ return ( num / 1000 ) . toFixed ( 1 ) + 'K' ;
115
+ }
116
+ return num . toString ( ) ;
117
+ }
118
+
119
+ function truncateLabel ( str , maxLength ) {
120
+ if ( str . length > maxLength ) {
121
+ return str . substr ( 0 , maxLength - 3 ) + '...' ;
122
+ }
123
+ return str ;
124
+ }
125
+
126
+ function updateChart ( ) {
127
+ var year = yearSelector . value ;
128
+ var topN = parseInt ( topNSelector . value ) ;
129
+ var yearData = data . filter ( item => item . Year == year ) ;
130
+ yearData . sort ( ( a , b ) => b . Overall_Homeless - a . Overall_Homeless ) ;
131
+ var topCoCNames = yearData . slice ( 0 , topN ) . map ( item => item [ 'CoC Name' ] ) ;
132
+
133
+ var seriesData = [ 'Overall_Homeless' , 'Sheltered' , 'Unsheltered' ] . map ( type => ( {
134
+ name : type . replace ( '_' , ' ' ) ,
135
+ type : 'bar' ,
136
+ data : topCoCNames . map ( name => yearData . find ( item => item [ 'CoC Name' ] === name ) [ type ] || 0 )
137
+ } ) ) ;
138
+
139
+ var option = {
140
+ title : {
141
+ text : `Top ${ topN } CoCs by Homeless Population Types in ${ year } ` ,
142
+ left : 'center' ,
143
+ top : '20px' ,
144
+ textStyle : {
145
+ fontSize : 20 ,
146
+ fontWeight : 'bold' ,
147
+ color : '#1a3a5c'
148
+ }
149
+ } ,
150
+ tooltip : {
151
+ trigger : 'axis' ,
152
+ axisPointer : { type : 'shadow' }
153
+ } ,
154
+ legend : {
155
+ data : [ 'Overall Homeless' , 'Sheltered' , 'Unsheltered' ] ,
156
+ top : '50px' ,
157
+ textStyle : { fontSize : 12 }
158
+ } ,
159
+ grid : {
160
+ left : '3%' ,
161
+ right : '4%' ,
162
+ bottom : isHorizontal ? '3%' : '15%' ,
163
+ top : '100px' ,
164
+ containLabel : true
165
+ } ,
166
+ xAxis : {
167
+ type : isHorizontal ? 'value' : 'category' ,
168
+ data : isHorizontal ? null : topCoCNames ,
169
+ axisLabel : {
170
+ interval : 0 ,
171
+ rotate : isHorizontal ? 0 : 45 ,
172
+ fontSize : 12 ,
173
+ fontWeight : 'bold' ,
174
+ color : '#555' ,
175
+ formatter : function ( value ) {
176
+ return isHorizontal ? formatNumber ( value ) : truncateLabel ( value , 20 ) ;
177
+ }
178
+ } ,
179
+ axisLine : {
180
+ lineStyle : {
181
+ color : '#999'
182
+ }
183
+ }
184
+ } ,
185
+ yAxis : {
186
+ type : isHorizontal ? 'category' : 'value' ,
187
+ data : isHorizontal ? topCoCNames : null ,
188
+ axisLabel : {
189
+ fontSize : 12 ,
190
+ formatter : function ( value ) {
191
+ return isHorizontal ? truncateLabel ( value , 20 ) : formatNumber ( value ) ;
192
+ }
193
+ } ,
194
+ axisLine : {
195
+ lineStyle : {
196
+ color : '#999'
197
+ }
198
+ }
199
+ } ,
200
+ series : seriesData
201
+ } ;
202
+
203
+ myChart . setOption ( option ) ;
204
+ }
205
+
206
+ yearSelector . addEventListener ( 'change' , updateChart ) ;
207
+ topNSelector . addEventListener ( 'change' , updateChart ) ;
208
+ toggleViewButton . addEventListener ( 'click' , function ( ) {
209
+ isHorizontal = ! isHorizontal ;
210
+ updateChart ( ) ;
211
+ } ) ;
212
+
213
+ updateChart ( ) ;
214
+
215
+ window . addEventListener ( 'resize' , function ( ) {
216
+ myChart . resize ( ) ;
217
+ } ) ;
218
+ </ script >
219
+ </ body >
220
+ </ html >
0 commit comments