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+ < meta name ="description " content ="Skup podataka o punionicama električnih vozila na području Osijeka i Zagreba. Punionice su organzirane tako da imaju vezo roditelj-dijete između punionice i stanica za punjenje. Podaci ovog skupa dostupni su za preuzimanje u JSON i CSV formatu. ">
7+ < meta name ="author " content ="Borna Krušlin ">
8+ < meta name ="license " content ="Creative Commons Zero v1.0 Universal ">
9+ < meta name ="
contact information "
content ="
[email protected] "
> 10+ < title > DataTable</ title >
11+ < style >
12+ body {
13+ font-family : Arial, sans-serif;
14+ margin : 20px ;
15+ background-color : # f4f4f9 ;
16+ }
17+ h1 {
18+ color : # 333 ;
19+ text-align : center;
20+ }
21+ input , select , button {
22+ padding : 10px ;
23+ margin : 10px ;
24+ font-size : 16px ;
25+ }
26+ button {
27+ cursor : pointer;
28+ background-color : # 4CAF50 ;
29+ color : white;
30+ border : none;
31+ border-radius : 5px ;
32+ }
33+ button : hover {
34+ background-color : # 45a049 ;
35+ }
36+ table {
37+ width : 100% ;
38+ border-collapse : collapse;
39+ margin-top : 20px ;
40+ }
41+ th , td {
42+ border : 1px solid # ddd ;
43+ padding : 8px ;
44+ text-align : left;
45+ }
46+ th {
47+ background-color : # 4CAF50 ;
48+ color : white;
49+ }
50+ tr : nth-child (even) {
51+ background-color : # f2f2f2 ;
52+ }
53+ tr : hover {
54+ background-color : # ddd ;
55+ }
56+ .container {
57+ max-width : 1200px ;
58+ margin : auto;
59+ padding : 20px ;
60+ background-color : white;
61+ box-shadow : 0 0 10px rgba (0 , 0 , 0 , 0.1 );
62+ border-radius : 10px ;
63+ }
64+ </ style >
65+ </ head >
66+ < body >
67+ < h1 > Podaci u bazi podataka</ h1 >
68+
69+ <!-- Search Input Box and Column Selector -->
70+ < input type ="text " id ="search-input " placeholder ="Enter search term ">
71+ < select id ="column-select ">
72+ < option value =""> Svi stupci</ option >
73+ < option value ="id_punionice "> ID Punionice</ option >
74+ < option value ="naziv_punionice "> Naziv Punionice</ option >
75+ < option value ="adresa "> Adresa</ option >
76+ < option value ="geografska_sirina "> Geografska Sirina</ option >
77+ < option value ="geografska_duzina "> Geografska Duzina</ option >
78+ < option value ="vrsta_punjenja "> Vrsta Punjenja</ option >
79+ < option value ="broj_punjaca "> Broj Punjaca</ option >
80+ < option value ="snaga_punjenja "> Snaga Punjenja</ option >
81+ < option value ="cijena_po_kwh "> Cijena po kWh</ option >
82+ < option value ="otvorenje "> Otvorenje</ option >
83+ < option value ="zatvaranje "> Zatvaranje</ option >
84+ < option value ="id_stanice "> ID Stanice</ option >
85+ < option value ="id_punionice "> ID Punionice</ option >
86+ < option value ="tip_konektora "> Tip konektora</ option >
87+ < option value ="snaga_stanice "> Snaga Stanice</ option >
88+ < option value ="pruzatelj "> Pruzatelj</ option >
89+ </ select >
90+
91+ < button id ="download-json "> Preuzmi JSON</ button >
92+ < button id ="download-csv "> Preuzmi CSV</ button >
93+
94+ <!-- Table to display data -->
95+ < table border ="1 " id ="data-table ">
96+ < thead >
97+ < tr >
98+ < th > ID Punionice</ th >
99+ < th > Naziv Punionice</ th >
100+ < th > Adresa</ th >
101+ < th > Geografska Sirina</ th >
102+ < th > Geografska Duzina</ th >
103+ < th > Vrsta Punjenja</ th >
104+ < th > Broj Punjaca</ th >
105+ < th > Snaga Punjenja</ th >
106+ < th > Cijena po kWh</ th >
107+ < th > Otvorenje</ th >
108+ < th > Zatvaranje</ th >
109+ < th > ID Stanice</ th >
110+ < th > ID Punionice</ th >
111+ < th > Tip konektora</ th >
112+ < th > Snaga Stanice</ th >
113+ < th > Pruzatelj</ th >
114+ </ tr >
115+ </ thead >
116+ < tbody > </ tbody >
117+ </ table >
118+ < script >
119+ let allData = [ ] ; // Store all the data initially loaded from the server
120+ let filteredData = [ ] ; // Store the filtered data
121+
122+ // Function to fetch data from the server and populate the table
123+ async function fetchData ( ) {
124+ const searchTerm = document . getElementById ( 'search-input' ) . value ;
125+ const selectedColumn = document . getElementById ( 'column-select' ) . value ;
126+
127+ try {
128+ // Fetch the entire table if search term is not empty and column is empty
129+ const url = '/data' ;
130+ const response = await fetch ( url ) ;
131+ const data = await response . json ( ) ;
132+ console . log ( 'Data received from DB:' , data ) ; // Log the data received from the database
133+ allData = data ; // Save the fetched data to `allData`
134+
135+ displayTable ( data , searchTerm . toLowerCase ( ) , selectedColumn ) ;
136+
137+ } catch ( error ) {
138+ console . error ( 'Error fetching data:' , error ) ;
139+ }
140+ }
141+
142+ // Function to filter and display data in the table
143+ function displayTable ( data , searchTerm , selectedColumn ) {
144+ // Filter the data if search term exists
145+ filteredData = data . filter ( row => {
146+ if ( selectedColumn ) {
147+ // Search only in the selected column
148+ return row [ selectedColumn ] && row [ selectedColumn ] . toString ( ) . toLowerCase ( ) . includes ( searchTerm ) ;
149+ } else {
150+ // If no column is selected, search all columns in the row in order to find the search term
151+ // skip column if data is null
152+ for ( const key in row ) {
153+ if ( row [ key ] && row [ key ] . toString ( ) . toLowerCase ( ) . includes ( searchTerm ) ) {
154+ return true ;
155+ }
156+ }
157+ }
158+ } ) ;
159+
160+ // Populate the table with the filtered data
161+ const tableBody = document . getElementById ( 'data-table' ) . getElementsByTagName ( 'tbody' ) [ 0 ] ;
162+ tableBody . innerHTML = '' ; // Clear the existing table rows
163+
164+ filteredData . forEach ( row => {
165+ const tr = document . createElement ( 'tr' ) ;
166+ tr . innerHTML = `
167+ <td>${ row . id_punionice } </td>
168+ <td>${ row . naziv_punionice } </td>
169+ <td>${ row . adresa } </td>
170+ <td>${ row . geografska_sirina } </td>
171+ <td>${ row . geografska_duzina } </td>
172+ <td>${ row . vrsta_punjenja } </td>
173+ <td>${ row . broj_punjaca } </td>
174+ <td>${ row . snaga_punjenja } </td>
175+ <td>${ row . cijena_po_kwh } </td>
176+ <td>${ row . otvorenje } </td>
177+ <td>${ row . zatvaranje } </td>
178+ <td>${ row . id_stanice } </td>
179+ <td>${ row . id_punionice } </td>
180+ <td>${ row . tip_konektora } </td>
181+ <td>${ row . snaga_stanice } </td>
182+ <td>${ row . pruzatelj } </td>
183+ ` ;
184+ tableBody . appendChild ( tr ) ;
185+ } ) ;
186+ }
187+
188+ // Function to convert data to JSON and trigger download
189+ function downloadJSON ( data ) {
190+ const groupedData = data . reduce ( ( acc , row ) => {
191+ const { id_punionice, naziv_punionice, adresa, geografska_sirina, geografska_duzina, vrsta_punjenja, broj_punjaca, snaga_punjenja, cijena_po_kwh, otvorenje, zatvaranje, id_stanice, tip_konektora, snaga_stanice, pruzatelj } = row ;
192+ if ( ! acc [ id_punionice ] ) {
193+ acc [ id_punionice ] = {
194+ id_punionice,
195+ naziv_punionice,
196+ adresa,
197+ geografska_sirina,
198+ geografska_duzina,
199+ vrsta_punjenja,
200+ broj_punjaca,
201+ snaga_punjenja,
202+ cijena_po_kwh,
203+ otvorenje,
204+ zatvaranje,
205+ stanice : [ ]
206+ } ;
207+ }
208+ acc [ id_punionice ] . stanice . push ( { id_stanice, tip_konektora, snaga_stanice, pruzatelj } ) ;
209+ return acc ;
210+ } , { } ) ;
211+
212+ const json = JSON . stringify ( Object . values ( groupedData ) , null , 2 ) ;
213+ const blob = new Blob ( [ json ] , { type : 'application/json' } ) ;
214+ const url = URL . createObjectURL ( blob ) ;
215+ const a = document . createElement ( 'a' ) ;
216+ a . href = url ;
217+ a . download = 'data.json' ;
218+ a . click ( ) ;
219+ URL . revokeObjectURL ( url ) ;
220+ }
221+
222+ // Function to convert data to CSV and trigger download
223+ function downloadCSV ( data ) {
224+ const csvRows = [ ] ;
225+ const headers = Object . keys ( data [ 0 ] ) ;
226+ csvRows . push ( headers . join ( ',' ) ) ;
227+
228+ for ( const row of data ) {
229+ const values = headers . map ( header => {
230+ const escaped = ( '' + row [ header ] ) . replace ( / " / g, '\\"' ) ;
231+ return `"${ escaped } "` ;
232+ } ) ;
233+ csvRows . push ( values . join ( ',' ) ) ;
234+ }
235+
236+ const csv = csvRows . join ( '\n' ) ;
237+ const blob = new Blob ( [ csv ] , { type : 'text/csv' } ) ;
238+ const url = URL . createObjectURL ( blob ) ;
239+ const a = document . createElement ( 'a' ) ;
240+ a . href = url ;
241+ a . download = 'data.csv' ;
242+ a . click ( ) ;
243+ URL . revokeObjectURL ( url ) ;
244+ }
245+
246+ // Add event listener to the search input box to call fetchData dynamically
247+ document . getElementById ( 'search-input' ) . addEventListener ( 'keyup' , fetchData ) ;
248+
249+ // Add event listeners to the download buttons
250+ document . getElementById ( 'download-json' ) . addEventListener ( 'click' , ( ) => downloadJSON ( filteredData ) ) ;
251+ document . getElementById ( 'download-csv' ) . addEventListener ( 'click' , ( ) => downloadCSV ( filteredData ) ) ;
252+
253+ // Call fetchData when the DOM is fully loaded
254+ document . addEventListener ( 'DOMContentLoaded' , fetchData ) ;
255+ </ script >
256+
257+ </ body >
258+ </ html >
0 commit comments