ojasrohatgi commited on
Commit
90239ec
Β·
verified Β·
1 Parent(s): c031958

Upload index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +422 -0
templates/index.html ADDED
@@ -0,0 +1,422 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-theme="light">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Deforestation Detection Tool</title>
7
+
8
+ <!-- Leaflet CSS & JS -->
9
+ <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
10
+ <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
11
+
12
+ <!-- Leaflet Geocoder Plugin -->
13
+ <link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" />
14
+ <script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
15
+
16
+ <!-- Leaflet Draw -->
17
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
18
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
19
+
20
+ <!-- Google Fonts -->
21
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
22
+
23
+ <style>
24
+ :root {
25
+ --bg: #f9f9f9;
26
+ --text: #2c3e50;
27
+ --map-border: #2c3e50;
28
+ --box-bg: #ffffff;
29
+ --button-hover: #27ae60;
30
+ --loader-ring: #f3f3f3;
31
+ --loader-spin: #2ecc71;
32
+ --gain: #41a8ff;
33
+ --loss: #ff4c4c;
34
+ --retain: #3ecf4e;
35
+ --neutral: #ffffff;
36
+ }
37
+
38
+ [data-theme='dark'] {
39
+ --bg: #1f1f1f;
40
+ --text: #f0f0f0;
41
+ --map-border: #444;
42
+ --box-bg: #2b2b2b;
43
+ --button-bg: #27ae60;
44
+ --button-hover: #219150;
45
+ --loader-ring: #444;
46
+ --loader-spin: #27ae60;
47
+ --border-light: #555;
48
+ }
49
+
50
+ html, body {
51
+ margin: 0;
52
+ font-family: 'Inter', sans-serif;
53
+ background-color: var(--bg);
54
+ color: var(--text);
55
+ transition: background 0.3s, color 0.3s;
56
+ }
57
+
58
+ h2 {
59
+ text-align: center;
60
+ margin: 20px 0 10px;
61
+ }
62
+
63
+ .header {
64
+ display: flex;
65
+ justify-content: space-between;
66
+ align-items: center;
67
+ padding: 10px 30px;
68
+ background: var(--box-bg);
69
+ color: var(--text);
70
+ box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 25px 0px;
71
+ position: sticky;
72
+ top: 0;
73
+ z-index: 999;
74
+ }
75
+
76
+ #themeToggle {
77
+ background: var(--box-bg);
78
+ color: var(--text);
79
+ border: 1px solid #ccc;
80
+ padding: 8px 14px;
81
+ font-size: 14px;
82
+ border-radius: 6px;
83
+ cursor: pointer;
84
+ box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
85
+ transition: background 0.3s ease, color 0.3s ease;
86
+ }
87
+
88
+ #themeToggle:hover {
89
+ background: var(--button-hover);
90
+ color: white;
91
+ }
92
+
93
+ #map {
94
+ height: 75vh;
95
+ width: 90%;
96
+ margin: 0 auto;
97
+ border: 3px solid var(--map-border);
98
+ border-radius: 12px;
99
+ transition: border 0.3s;
100
+ z-index: 0;
101
+ }
102
+
103
+ .controls {
104
+ max-width: 600px;
105
+ margin: 30px auto;
106
+ background: var(--box-bg);
107
+ padding: 20px;
108
+ border-radius: 12px;
109
+ box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
110
+ text-align: center;
111
+ }
112
+
113
+ .controls label {
114
+ font-weight: 600;
115
+ margin: 0 10px;
116
+ }
117
+
118
+ .controls input {
119
+ padding: 6px 10px;
120
+ border-radius: 6px;
121
+ border: 1px solid #ccc;
122
+ width: 80px;
123
+ text-align: center;
124
+ background: var(--bg);
125
+ color: var(--text);
126
+ }
127
+
128
+ .controls button {
129
+ margin-top: 15px;
130
+ padding: 10px 20px;
131
+ background-color: #2ecc71;
132
+ color: white;
133
+ font-size: 16px;
134
+ border: none;
135
+ border-radius: 12px;
136
+ cursor: pointer;
137
+ transition:
138
+ box-shadow 0.2s ease,
139
+ transform 0.1s ease,
140
+ background-color 0.2s ease;
141
+ }
142
+
143
+ .controls button:hover {
144
+ box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
145
+ }
146
+
147
+ .controls button:active {
148
+ box-shadow:
149
+ rgba(0, 0, 0, 0.2) 0px 10px 20px inset,
150
+ rgba(0, 0, 0, 0.25) 0px 6px 12px inset;
151
+ transform: scale(0.97); /* nice tactile press effect */
152
+ }
153
+
154
+ #loader {
155
+ margin: 15px auto;
156
+ border: 6px solid var(--loader-ring);
157
+ border-top: 6px solid var(--loader-spin);
158
+ border-radius: 50%;
159
+ background: white;
160
+ width: 40px;
161
+ height: 40px;
162
+ animation: spin 0.8s linear infinite;
163
+ display: none;
164
+ }
165
+
166
+ #resultImage {
167
+ margin: 0 auto;
168
+ padding: 10px;
169
+ border-radius: 12px;
170
+ display: none;
171
+ object-fit: contain;
172
+ background: white;
173
+ box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
174
+ }
175
+
176
+ #legend {
177
+ position: fixed;
178
+ bottom: 20px;
179
+ left: 20px;
180
+ background: var(--box-bg);
181
+ padding: 12px 15px;
182
+ border-radius: 8px;
183
+ box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
184
+ font-size: 14px;
185
+ z-index: 999;
186
+ cursor: pointer;
187
+ display: none;
188
+ }
189
+
190
+ #legend h4 {
191
+ margin: 0 0 6px;
192
+ font-size: 15px;
193
+ }
194
+
195
+ #legend div {
196
+ display: flex;
197
+ align-items: center;
198
+ margin-bottom: 4px;
199
+ }
200
+
201
+ #legend span {
202
+ width: 18px;
203
+ height: 18px;
204
+ display: inline-block;
205
+ margin-right: 8px;
206
+ border-radius: 3px;
207
+ border: 1px solid #ccc;
208
+ }
209
+
210
+ #result {
211
+ text-align: center;
212
+ margin-bottom: 40px;
213
+ display: none;
214
+ }
215
+
216
+ @keyframes spin {
217
+ 0% { transform: rotate(0deg); }
218
+ 100% { transform: rotate(360deg); }
219
+ }
220
+
221
+ @media (max-width: 600px) {
222
+ .controls label, .controls input {
223
+ display: block;
224
+ margin: 10px auto;
225
+ }
226
+ }
227
+
228
+ [data-theme='dark'] {
229
+ --bg: #1a1a1a;
230
+ --text: #f0f0f0;
231
+ --map-border: #555;
232
+ --box-bg: #242424;
233
+ --button-bg: #2ecc71;
234
+ --button-hover: #27ae60;
235
+ --loader-ring: #444;
236
+ --loader-spin: #2ecc71;
237
+ }
238
+
239
+ /* Apply consistent border to all containers in dark */
240
+ [data-theme='dark'] .controls,
241
+ [data-theme='dark'] .header,
242
+ [data-theme='dark'] #legend {
243
+ border: 1px solid var(--border-light);
244
+ box-shadow: rgba(255, 255, 255, 0.2) 0px 7px 29px 0px;
245
+ backdrop-filter: blur(6px);
246
+ }
247
+
248
+ [data-theme='dark'] #loader {
249
+ background: black;
250
+ }
251
+
252
+ [data-theme='dark'] #resultImage {
253
+ box-shadow: rgba(255, 255, 255, 0.35) 0px 5px 15px;
254
+ }
255
+
256
+ [data-theme='dark'] .controls button:hover {
257
+ box-shadow: rgba(255, 255, 255, 0.35) 0px 5px 15px;
258
+ }
259
+
260
+ [data-theme='dark'] .controls button:active {
261
+ box-shadow:
262
+ rgba(0, 0, 0, 0.2) 0px 10px 20px inset,
263
+ rgba(0, 0, 0, 0.25) 0px 6px 12px inset;
264
+ transform: scale(0.97); /* nice tactile press effect */
265
+ }
266
+ </style>
267
+ </head>
268
+ <body>
269
+
270
+ <div class="header">
271
+ <h2>🌍 Deforestation Detection Tool</h2>
272
+ <button id="themeToggle">πŸŒ™ Dark Mode</button>
273
+ </div>
274
+
275
+ <div id="map"></div>
276
+
277
+ <div class="controls">
278
+ <label>Start Year:
279
+ <input type="number" id="startYear" value="2013" min="2000" max="2024">
280
+ </label>
281
+ <label>End Year:
282
+ <input type="number" id="endYear" value="2024" min="2000" max="2024">
283
+ </label>
284
+ <br />
285
+ <button onclick="submitSelection()">πŸ” Analyze Deforestation</button>
286
+ <div id="loader"></div>
287
+ </div>
288
+
289
+ <div id="result">
290
+ <p id="resultText" style="font-size: 18px; display: none;"></p>
291
+ <img id="resultImage" />
292
+ </div>
293
+
294
+ <div id="legend" onclick="toggleLegendDetails()">
295
+ <h4>πŸ—ΊοΈ Legend </h4>
296
+ <div id="legend-details" style="display:none;">
297
+ <div><span style="background: var(--loss);"></span> Vegetation Lost</div>
298
+ <div><span style="background: var(--retain);"></span> Vegetation Retained</div>
299
+ <div><span style="background: var(--gain)";></span> Vegetation Gained</div>
300
+ <div><span style="background: var(--neutral); border: 1px solid #aaa;"></span> No Vegetation</div>
301
+ </div>
302
+ </div>
303
+
304
+ <script>
305
+ const map = L.map('map').setView([20, 0], 2);
306
+
307
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
308
+ attribution: '&copy; OpenStreetMap contributors'
309
+ }).addTo(map);
310
+
311
+ L.Control.geocoder({
312
+ defaultMarkGeocode: true
313
+ }).addTo(map);
314
+
315
+ const drawnItems = new L.FeatureGroup();
316
+ map.addLayer(drawnItems);
317
+
318
+ new L.Control.Draw({
319
+ draw: {
320
+ rectangle: true,
321
+ polyline: false,
322
+ polygon: false,
323
+ marker: false,
324
+ circle: false,
325
+ circlemarker: false
326
+ },
327
+ edit: { featureGroup: drawnItems }
328
+ }).addTo(map);
329
+
330
+ let selectedBounds = null;
331
+
332
+ map.on('draw:created', function (e) {
333
+ drawnItems.clearLayers();
334
+ let layer = e.layer;
335
+ drawnItems.addLayer(layer);
336
+ selectedBounds = layer.getBounds();
337
+ });
338
+
339
+ // πŸ”„ Update bounds after edit
340
+ map.on('draw:edited', function (e) {
341
+ e.layers.eachLayer(function (layer) {
342
+ selectedBounds = layer.getBounds();
343
+ });
344
+ });
345
+
346
+
347
+ function toggleLegendDetails() {
348
+ const details = document.getElementById("legend-details");
349
+ details.style.display = details.style.display === "none" ? "block" : "none";
350
+ }
351
+
352
+ function submitSelection() {
353
+ if (!selectedBounds) {
354
+ alert("Please draw a rectangle on the map first.");
355
+ return;
356
+ }
357
+
358
+ const data = {
359
+ lat_min: selectedBounds.getSouth(),
360
+ lat_max: selectedBounds.getNorth(),
361
+ lon_min: selectedBounds.getWest(),
362
+ lon_max: selectedBounds.getEast(),
363
+ start_year: parseInt(document.getElementById('startYear').value),
364
+ end_year: parseInt(document.getElementById('endYear').value)
365
+ };
366
+
367
+ const loader = document.getElementById('loader');
368
+ const resultBox = document.getElementById('result');
369
+ const resultText = document.getElementById('resultText');
370
+ const resultImage = document.getElementById('resultImage');
371
+
372
+ loader.style.display = 'block';
373
+ resultBox.style.display = 'none';
374
+
375
+ setTimeout(() => {
376
+ loader.scrollIntoView({ behavior: 'smooth' });
377
+ }, 100);
378
+
379
+ fetch('/predict', {
380
+ method: 'POST',
381
+ headers: { 'Content-Type': 'application/json' },
382
+ body: JSON.stringify(data)
383
+ })
384
+ .then(res => res.json())
385
+ .then(response => {
386
+ loader.style.display = 'none';
387
+
388
+ resultImage.src = `data:image/png;base64,${response.image_base64}`;
389
+ resultImage.style.display = 'block';
390
+
391
+ resultText.innerHTML = `
392
+ 🌿 Vegetation lost: <strong>${response.percent_deforested}%</strong><br>
393
+ 🌱 Vegetation gained: <strong>${response.percent_regrowth}%</strong>
394
+ `;
395
+ resultText.style.display = 'block';
396
+ resultBox.style.display = 'block';
397
+
398
+ // βœ… Show legend now
399
+ document.getElementById("legend").style.display = "block";
400
+
401
+ setTimeout(() => {
402
+ resultBox.scrollIntoView({ behavior: 'smooth' });
403
+ }, 100);
404
+ })
405
+ .catch(err => {
406
+ loader.style.display = 'none';
407
+ console.error(err);
408
+ alert("❌ Failed to fetch results.");
409
+ });
410
+ }
411
+
412
+ const themeToggle = document.getElementById("themeToggle");
413
+ themeToggle.onclick = () => {
414
+ const html = document.documentElement;
415
+ const current = html.getAttribute("data-theme");
416
+ const next = current === "light" ? "dark" : "light";
417
+ html.setAttribute("data-theme", next);
418
+ themeToggle.textContent = next === "dark" ? "β˜€οΈ Light Mode" : "πŸŒ™ Dark Mode";
419
+ };
420
+ </script>
421
+ </body>
422
+ </html>