gauthamnairy commited on
Commit
ef388b3
·
verified ·
1 Parent(s): c93b11e

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +640 -0
index.html ADDED
@@ -0,0 +1,640 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Terrain Analysis Explorer</title>
7
+
8
+ <!-- Esri ArcGIS Maps SDK for JavaScript -->
9
+ <link rel="stylesheet" href="https://js.arcgis.com/4.28/esri/themes/dark/main.css">
10
+ <script src="https://js.arcgis.com/4.28/"></script>
11
+
12
+ <style>
13
+ * {
14
+ margin: 0;
15
+ padding: 0;
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ body {
20
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
21
+ background: #1a1a1a;
22
+ color: #ffffff;
23
+ overflow: hidden;
24
+ }
25
+
26
+ .app-container {
27
+ display: flex;
28
+ height: 100vh;
29
+ width: 100vw;
30
+ }
31
+
32
+ /* Left Panel Styling */
33
+ .left-panel {
34
+ width: 350px;
35
+ background: linear-gradient(135deg, #2c2c2c 0%, #1a1a1a 100%);
36
+ padding: 20px;
37
+ display: flex;
38
+ flex-direction: column;
39
+ box-shadow: 2px 0 15px rgba(0, 0, 0, 0.3);
40
+ border-right: 1px solid #333;
41
+ }
42
+
43
+ .app-header {
44
+ margin-bottom: 30px;
45
+ }
46
+
47
+ .app-title {
48
+ font-size: 24px;
49
+ font-weight: 600;
50
+ color: #00d4ff;
51
+ margin-bottom: 8px;
52
+ background: linear-gradient(45deg, #00d4ff, #0099cc);
53
+ background-clip: text;
54
+ -webkit-background-clip: text;
55
+ -moz-background-clip: text;
56
+ -webkit-text-fill-color: transparent;
57
+ }
58
+
59
+ .app-subtitle {
60
+ font-size: 14px;
61
+ color: #aaa;
62
+ font-weight: 300;
63
+ }
64
+
65
+ /* Input Section */
66
+ .input-section {
67
+ margin-bottom: 30px;
68
+ }
69
+
70
+ .input-label {
71
+ display: block;
72
+ font-size: 14px;
73
+ font-weight: 500;
74
+ color: #ddd;
75
+ margin-bottom: 10px;
76
+ }
77
+
78
+ .location-input {
79
+ width: 100%;
80
+ padding: 12px 16px;
81
+ font-size: 14px;
82
+ background: rgba(255, 255, 255, 0.1);
83
+ border: 1px solid #444;
84
+ border-radius: 8px;
85
+ color: #fff;
86
+ transition: all 0.3s ease;
87
+ backdrop-filter: blur(10px);
88
+ }
89
+
90
+ .location-input:focus {
91
+ outline: none;
92
+ border-color: #00d4ff;
93
+ box-shadow: 0 0 10px rgba(0, 212, 255, 0.3);
94
+ background: rgba(255, 255, 255, 0.15);
95
+ }
96
+
97
+ .location-input::placeholder {
98
+ color: #888;
99
+ }
100
+
101
+ .analyze-btn {
102
+ width: 100%;
103
+ padding: 12px;
104
+ margin-top: 15px;
105
+ background: linear-gradient(135deg, #00d4ff 0%, #0099cc 100%);
106
+ color: white;
107
+ border: none;
108
+ border-radius: 8px;
109
+ font-size: 14px;
110
+ font-weight: 600;
111
+ cursor: pointer;
112
+ transition: all 0.3s ease;
113
+ text-transform: uppercase;
114
+ letter-spacing: 0.5px;
115
+ }
116
+
117
+ .analyze-btn:hover {
118
+ transform: translateY(-2px);
119
+ box-shadow: 0 5px 15px rgba(0, 212, 255, 0.4);
120
+ }
121
+
122
+ .analyze-btn:disabled {
123
+ background: #555;
124
+ cursor: not-allowed;
125
+ transform: none;
126
+ box-shadow: none;
127
+ }
128
+
129
+ /* Results Section */
130
+ .results-section {
131
+ flex-grow: 1;
132
+ }
133
+
134
+ .results-title {
135
+ font-size: 18px;
136
+ font-weight: 600;
137
+ color: #fff;
138
+ margin-bottom: 20px;
139
+ padding-bottom: 10px;
140
+ border-bottom: 1px solid #333;
141
+ }
142
+
143
+ .result-item {
144
+ background: rgba(255, 255, 255, 0.05);
145
+ padding: 15px;
146
+ margin-bottom: 15px;
147
+ border-radius: 8px;
148
+ border-left: 4px solid #00d4ff;
149
+ backdrop-filter: blur(10px);
150
+ transition: all 0.3s ease;
151
+ }
152
+
153
+ .result-item:hover {
154
+ background: rgba(255, 255, 255, 0.08);
155
+ transform: translateX(5px);
156
+ }
157
+
158
+ .result-label {
159
+ font-size: 12px;
160
+ color: #aaa;
161
+ text-transform: uppercase;
162
+ letter-spacing: 0.5px;
163
+ margin-bottom: 5px;
164
+ }
165
+
166
+ .result-value {
167
+ font-size: 16px;
168
+ font-weight: 600;
169
+ color: #fff;
170
+ }
171
+
172
+ .coordinates {
173
+ font-family: 'Courier New', monospace;
174
+ font-size: 14px;
175
+ }
176
+
177
+ /* Map Container */
178
+ .map-container {
179
+ flex-grow: 1;
180
+ position: relative;
181
+ }
182
+
183
+ #mapView {
184
+ width: 100%;
185
+ height: 100%;
186
+ }
187
+
188
+ /* Loading Animation */
189
+ .loading {
190
+ display: none;
191
+ align-items: center;
192
+ justify-content: center;
193
+ gap: 10px;
194
+ color: #00d4ff;
195
+ }
196
+
197
+ .loading.active {
198
+ display: flex;
199
+ }
200
+
201
+ .spinner {
202
+ width: 20px;
203
+ height: 20px;
204
+ border: 2px solid #333;
205
+ border-top: 2px solid #00d4ff;
206
+ border-radius: 50%;
207
+ animation: spin 1s linear infinite;
208
+ }
209
+
210
+ @keyframes spin {
211
+ 0% { transform: rotate(0deg); }
212
+ 100% { transform: rotate(360deg); }
213
+ }
214
+
215
+ /* Error/Status Messages */
216
+ .message {
217
+ padding: 10px 15px;
218
+ margin: 15px 0;
219
+ border-radius: 6px;
220
+ font-size: 14px;
221
+ display: none;
222
+ }
223
+
224
+ .message.error {
225
+ background: rgba(255, 99, 99, 0.2);
226
+ border: 1px solid #ff6363;
227
+ color: #ff6363;
228
+ }
229
+
230
+ .message.success {
231
+ background: rgba(99, 255, 99, 0.2);
232
+ border: 1px solid #63ff63;
233
+ color: #63ff63;
234
+ }
235
+
236
+ .message.show {
237
+ display: block;
238
+ }
239
+
240
+ /* Helper Text */
241
+ .helper-text {
242
+ font-size: 12px;
243
+ color: #888;
244
+ margin-top: 10px;
245
+ line-height: 1.4;
246
+ }
247
+
248
+ /* Responsive Design */
249
+ @media (max-width: 768px) {
250
+ .app-container {
251
+ flex-direction: column;
252
+ }
253
+
254
+ .left-panel {
255
+ width: 100%;
256
+ height: auto;
257
+ max-height: 40vh;
258
+ overflow-y: auto;
259
+ }
260
+
261
+ .map-container {
262
+ height: 60vh;
263
+ }
264
+ }
265
+
266
+ /* Custom Scrollbar */
267
+ .left-panel::-webkit-scrollbar {
268
+ width: 6px;
269
+ }
270
+
271
+ .left-panel::-webkit-scrollbar-track {
272
+ background: rgba(255, 255, 255, 0.1);
273
+ border-radius: 3px;
274
+ }
275
+
276
+ .left-panel::-webkit-scrollbar-thumb {
277
+ background: #00d4ff;
278
+ border-radius: 3px;
279
+ }
280
+
281
+ .left-panel::-webkit-scrollbar-thumb:hover {
282
+ background: #0099cc;
283
+ }
284
+ </style>
285
+ </head>
286
+ <body>
287
+ <div class="app-container">
288
+ <!-- Left Panel for Input and Results -->
289
+ <div class="left-panel">
290
+ <div class="app-header">
291
+ <h1 class="app-title">Terrain Explorer</h1>
292
+ <p class="app-subtitle">Analyze elevation and land cover data worldwide</p>
293
+ </div>
294
+
295
+ <!-- Input Section -->
296
+ <div class="input-section">
297
+ <label class="input-label" for="locationInput">Enter Coordinates or Place Name</label>
298
+ <input
299
+ type="text"
300
+ id="locationInput"
301
+ class="location-input"
302
+ placeholder="e.g., 40.7128, -74.0060 or New York City"
303
+ >
304
+ <div class="helper-text">
305
+ Supported formats:<br>
306
+ • Decimal: 40.7128, -74.0060<br>
307
+ • DMS: 40°42'46"N 74°0'21"W<br>
308
+ • Place names: New York City
309
+ </div>
310
+ <button id="analyzeBtn" class="analyze-btn">Analyze Location</button>
311
+ </div>
312
+
313
+ <!-- Loading Indicator -->
314
+ <div id="loadingIndicator" class="loading">
315
+ <div class="spinner"></div>
316
+ <span>Analyzing terrain...</span>
317
+ </div>
318
+
319
+ <!-- Status Messages -->
320
+ <div id="statusMessage" class="message"></div>
321
+
322
+ <!-- Results Section -->
323
+ <div class="results-section">
324
+ <h2 class="results-title">Analysis Results</h2>
325
+
326
+ <div class="result-item">
327
+ <div class="result-label">Coordinates</div>
328
+ <div id="coordinatesResult" class="result-value coordinates">
329
+ Click "Analyze Location" to get started
330
+ </div>
331
+ </div>
332
+
333
+ <div class="result-item">
334
+ <div class="result-label">Elevation</div>
335
+ <div id="elevationResult" class="result-value">
336
+ --
337
+ </div>
338
+ </div>
339
+
340
+ <div class="result-item">
341
+ <div class="result-label">Terrain Type</div>
342
+ <div id="terrainResult" class="result-value">
343
+ --
344
+ </div>
345
+ </div>
346
+ </div>
347
+ </div>
348
+
349
+ <!-- Map Container -->
350
+ <div class="map-container">
351
+ <div id="mapView"></div>
352
+ </div>
353
+ </div>
354
+
355
+ <script>
356
+ // Global variables
357
+ let map, view, currentMarker;
358
+ const API_BASE_URL = window.location.origin;
359
+
360
+ // Initialize the map when the page loads
361
+ require([
362
+ "esri/Map",
363
+ "esri/views/MapView",
364
+ "esri/Graphic",
365
+ "esri/geometry/Point",
366
+ "esri/symbols/SimpleMarkerSymbol",
367
+ "esri/layers/ImageryTileLayer"
368
+ ], function(Map, MapView, Graphic, Point, SimpleMarkerSymbol, ImageryTileLayer) {
369
+
370
+ // Create imagery layer (satellite view)
371
+ const imageryLayer = new ImageryTileLayer({
372
+ url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
373
+ title: "World Imagery"
374
+ });
375
+
376
+ // Create the map with satellite imagery
377
+ map = new Map({
378
+ basemap: "satellite",
379
+ layers: [imageryLayer]
380
+ });
381
+
382
+ // Create the map view
383
+ view = new MapView({
384
+ container: "mapView",
385
+ map: map,
386
+ center: [0, 20], // Longitude, Latitude
387
+ zoom: 2,
388
+ ui: {
389
+ components: ["zoom", "compass"]
390
+ }
391
+ });
392
+
393
+ // Set up event listeners after map is loaded
394
+ view.when(() => {
395
+ console.log("Map loaded successfully");
396
+ setupEventListeners();
397
+ });
398
+
399
+ // Handle map click events to get coordinates
400
+ view.on("click", function(event) {
401
+ const lat = event.mapPoint.latitude;
402
+ const lon = event.mapPoint.longitude;
403
+
404
+ // Update input field with clicked coordinates
405
+ document.getElementById('locationInput').value = `${lat.toFixed(6)}, ${lon.toFixed(6)}`;
406
+
407
+ // Automatically analyze the clicked location
408
+ analyzeLocation();
409
+ });
410
+ });
411
+
412
+ function setupEventListeners() {
413
+ const analyzeBtn = document.getElementById('analyzeBtn');
414
+ const locationInput = document.getElementById('locationInput');
415
+
416
+ // Set up button click handler
417
+ analyzeBtn.addEventListener('click', analyzeLocation);
418
+
419
+ // Set up Enter key handler for input field
420
+ locationInput.addEventListener('keypress', function(event) {
421
+ if (event.key === 'Enter') {
422
+ analyzeLocation();
423
+ }
424
+ });
425
+ }
426
+
427
+ async function analyzeLocation() {
428
+ const locationInput = document.getElementById('locationInput');
429
+ const inputValue = locationInput.value.trim();
430
+
431
+ if (!inputValue) {
432
+ showMessage('Please enter a location or coordinates', 'error');
433
+ return;
434
+ }
435
+
436
+ // Show loading state
437
+ setLoadingState(true);
438
+ clearMessage();
439
+
440
+ try {
441
+ // Make API request to backend
442
+ const response = await fetch(`${API_BASE_URL}/api/analyze`, {
443
+ method: 'POST',
444
+ headers: {
445
+ 'Content-Type': 'application/json',
446
+ },
447
+ body: JSON.stringify({
448
+ input: inputValue
449
+ })
450
+ });
451
+
452
+ if (!response.ok) {
453
+ const errorData = await response.json();
454
+ throw new Error(errorData.detail || 'Failed to analyze location');
455
+ }
456
+
457
+ const data = await response.json();
458
+
459
+ // Update results display
460
+ updateResults(data);
461
+
462
+ // Update map with marker
463
+ updateMapMarker(data.latitude, data.longitude);
464
+
465
+ // Show success message
466
+ showMessage('Analysis completed successfully!', 'success');
467
+
468
+ } catch (error) {
469
+ console.error('Error analyzing location:', error);
470
+ showMessage(`Error: ${error.message}`, 'error');
471
+ } finally {
472
+ setLoadingState(false);
473
+ }
474
+ }
475
+
476
+ function updateResults(data) {
477
+ // Update coordinates display
478
+ const coordsElement = document.getElementById('coordinatesResult');
479
+ coordsElement.textContent = `${data.latitude.toFixed(6)}, ${data.longitude.toFixed(6)}`;
480
+
481
+ // Update elevation display
482
+ const elevationElement = document.getElementById('elevationResult');
483
+ const elevationValue = data.elevation !== null ? `${data.elevation.toFixed(1)} m` : 'No data available';
484
+ elevationElement.textContent = elevationValue;
485
+
486
+ // Update terrain type display
487
+ const terrainElement = document.getElementById('terrainResult');
488
+ terrainElement.textContent = data.terrain_type || 'Unknown';
489
+ }
490
+
491
+ function updateMapMarker(latitude, longitude) {
492
+ require([
493
+ "esri/Graphic",
494
+ "esri/geometry/Point",
495
+ "esri/symbols/SimpleMarkerSymbol"
496
+ ], function(Graphic, Point, SimpleMarkerSymbol) {
497
+
498
+ // Remove existing marker if present
499
+ if (currentMarker) {
500
+ view.graphics.remove(currentMarker);
501
+ }
502
+
503
+ // Create new marker
504
+ const point = new Point({
505
+ longitude: longitude,
506
+ latitude: latitude
507
+ });
508
+
509
+ const markerSymbol = new SimpleMarkerSymbol({
510
+ color: [0, 212, 255],
511
+ size: 12,
512
+ outline: {
513
+ color: [255, 255, 255],
514
+ width: 2
515
+ }
516
+ });
517
+
518
+ currentMarker = new Graphic({
519
+ geometry: point,
520
+ symbol: markerSymbol
521
+ });
522
+
523
+ // Add marker to map
524
+ view.graphics.add(currentMarker);
525
+
526
+ // Center map on the marker
527
+ view.goTo({
528
+ center: [longitude, latitude],
529
+ zoom: 10
530
+ }, {
531
+ duration: 2000
532
+ });
533
+ });
534
+ }
535
+
536
+ function setLoadingState(isLoading) {
537
+ const loadingIndicator = document.getElementById('loadingIndicator');
538
+ const analyzeBtn = document.getElementById('analyzeBtn');
539
+
540
+ if (isLoading) {
541
+ loadingIndicator.classList.add('active');
542
+ analyzeBtn.disabled = true;
543
+ analyzeBtn.textContent = 'Analyzing...';
544
+ } else {
545
+ loadingIndicator.classList.remove('active');
546
+ analyzeBtn.disabled = false;
547
+ analyzeBtn.textContent = 'Analyze Location';
548
+ }
549
+ }
550
+
551
+ function showMessage(message, type) {
552
+ const messageElement = document.getElementById('statusMessage');
553
+ messageElement.textContent = message;
554
+ messageElement.className = `message ${type} show`;
555
+
556
+ // Auto-hide success messages after 3 seconds
557
+ if (type === 'success') {
558
+ setTimeout(() => {
559
+ clearMessage();
560
+ }, 3000);
561
+ }
562
+ }
563
+
564
+ function clearMessage() {
565
+ const messageElement = document.getElementById('statusMessage');
566
+ messageElement.className = 'message';
567
+ }
568
+
569
+ // Example locations for demonstration
570
+ const exampleLocations = [
571
+ { name: 'Mount Everest', coords: '27.9881, 86.9250' },
572
+ { name: 'Death Valley', coords: '36.5323, -117.0143' },
573
+ { name: 'Amazon Rainforest', coords: '-3.4653, -62.2159' },
574
+ { name: 'Sahara Desert', coords: '23.8859, 11.0167' },
575
+ { name: 'New York City', coords: '40.7128, -74.0060' }
576
+ ];
577
+
578
+ // Add some sample locations to help users get started
579
+ function addExampleLocations() {
580
+ const inputSection = document.querySelector('.input-section');
581
+ const examplesDiv = document.createElement('div');
582
+ examplesDiv.className = 'examples-section';
583
+ examplesDiv.innerHTML = `
584
+ <div class="helper-text" style="margin-top: 20px; margin-bottom: 10px;">
585
+ <strong>Try these examples:</strong>
586
+ </div>
587
+ `;
588
+
589
+ exampleLocations.forEach(location => {
590
+ const exampleBtn = document.createElement('button');
591
+ exampleBtn.className = 'example-btn';
592
+ exampleBtn.textContent = location.name;
593
+ exampleBtn.style.cssText = `
594
+ display: inline-block;
595
+ margin: 2px 5px 2px 0;
596
+ padding: 4px 8px;
597
+ background: rgba(0, 212, 255, 0.2);
598
+ border: 1px solid rgba(0, 212, 255, 0.5);
599
+ border-radius: 4px;
600
+ color: #00d4ff;
601
+ font-size: 11px;
602
+ cursor: pointer;
603
+ transition: all 0.3s ease;
604
+ `;
605
+
606
+ exampleBtn.addEventListener('click', () => {
607
+ document.getElementById('locationInput').value = location.coords;
608
+ analyzeLocation();
609
+ });
610
+
611
+ exampleBtn.addEventListener('mouseenter', () => {
612
+ exampleBtn.style.background = 'rgba(0, 212, 255, 0.3)';
613
+ });
614
+
615
+ exampleBtn.addEventListener('mouseleave', () => {
616
+ exampleBtn.style.background = 'rgba(0, 212, 255, 0.2)';
617
+ });
618
+
619
+ examplesDiv.appendChild(exampleBtn);
620
+ });
621
+
622
+ inputSection.appendChild(examplesDiv);
623
+ }
624
+
625
+ // Initialize example locations when page loads
626
+ document.addEventListener('DOMContentLoaded', () => {
627
+ addExampleLocations();
628
+ });
629
+
630
+ // Handle window resize to maintain map responsiveness
631
+ window.addEventListener('resize', () => {
632
+ if (view) {
633
+ view.when(() => {
634
+ view.resize();
635
+ });
636
+ }
637
+ });
638
+ </script>
639
+ </body>
640
+ </html>