AdityaAdaki commited on
Commit
cf1f925
·
1 Parent(s): 75dc612

Fix css js

Browse files
static/css/style.css ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* General Styles */
2
+ body {
3
+ background-color: #f8f9fa;
4
+ color: #333;
5
+ font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
6
+ }
7
+
8
+ .container {
9
+ max-width: 1000px;
10
+ }
11
+
12
+ /* Header Styles */
13
+ h1 {
14
+ color: #2c3e50;
15
+ font-weight: 600;
16
+ margin-bottom: 2rem;
17
+ position: relative;
18
+ padding-bottom: 1rem;
19
+ }
20
+
21
+ h1:after {
22
+ content: '';
23
+ position: absolute;
24
+ bottom: 0;
25
+ left: 50%;
26
+ transform: translateX(-50%);
27
+ width: 100px;
28
+ height: 4px;
29
+ background: linear-gradient(to right, #007bff, #00d2ff);
30
+ border-radius: 2px;
31
+ }
32
+
33
+ /* Card Styles */
34
+ .card {
35
+ border: none;
36
+ border-radius: 12px;
37
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
38
+ transition: transform 0.2s, box-shadow 0.2s;
39
+ margin-bottom: 2rem;
40
+ }
41
+
42
+ .card:hover {
43
+ transform: translateY(-5px);
44
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
45
+ }
46
+
47
+ .card-body {
48
+ padding: 2rem;
49
+ }
50
+
51
+ /* Form Styles */
52
+ .form-control {
53
+ border-radius: 8px;
54
+ padding: 0.75rem 1rem;
55
+ border: 2px solid #e9ecef;
56
+ transition: border-color 0.2s;
57
+ }
58
+
59
+ .form-control:focus {
60
+ border-color: #007bff;
61
+ box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.15);
62
+ }
63
+
64
+ /* Button Styles */
65
+ .btn {
66
+ padding: 0.75rem 1.5rem;
67
+ border-radius: 8px;
68
+ font-weight: 500;
69
+ transition: all 0.2s;
70
+ }
71
+
72
+ .btn-primary {
73
+ background: linear-gradient(45deg, #007bff, #00d2ff);
74
+ border: none;
75
+ }
76
+
77
+ .btn-primary:hover {
78
+ background: linear-gradient(45deg, #0056b3, #00a6cc);
79
+ transform: translateY(-2px);
80
+ }
81
+
82
+ .btn-success {
83
+ background: linear-gradient(45deg, #28a745, #20c997);
84
+ border: none;
85
+ }
86
+
87
+ .btn-success:hover {
88
+ background: linear-gradient(45deg, #218838, #1aa179);
89
+ transform: translateY(-2px);
90
+ }
91
+
92
+ /* Map Container Styles */
93
+ #map {
94
+ width: 100% !important;
95
+ height: 500px !important;
96
+ border-radius: 12px;
97
+ overflow: hidden;
98
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
99
+ }
100
+
101
+ #map iframe {
102
+ width: 100% !important;
103
+ height: 500px !important;
104
+ }
105
+
106
+ /* Screenshot Styles */
107
+ #capturedImage {
108
+ max-width: 100%;
109
+ border-radius: 12px;
110
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
111
+ }
112
+
113
+ /* Analysis Page Styles */
114
+ .analysis-container {
115
+ background: white;
116
+ border-radius: 12px;
117
+ padding: 2rem;
118
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
119
+ }
120
+
121
+ .image-container {
122
+ margin-bottom: 2rem;
123
+ }
124
+
125
+ .image-container img {
126
+ border-radius: 12px;
127
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
128
+ }
129
+
130
+ .results-container {
131
+ background: #f8f9fa;
132
+ padding: 2rem;
133
+ border-radius: 12px;
134
+ }
135
+
136
+ .results-list li {
137
+ background: white;
138
+ padding: 1rem;
139
+ margin-bottom: 1rem;
140
+ border-radius: 8px;
141
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
142
+ }
143
+
144
+ .progress {
145
+ height: 12px;
146
+ border-radius: 6px;
147
+ background-color: #e9ecef;
148
+ }
149
+
150
+ .progress-bar {
151
+ background: linear-gradient(45deg, #007bff, #00d2ff);
152
+ border-radius: 6px;
153
+ }
154
+
155
+ .percentage {
156
+ font-weight: 600;
157
+ color: #007bff;
158
+ }
159
+
160
+ /* Loading States */
161
+ .btn:disabled {
162
+ opacity: 0.8;
163
+ cursor: wait;
164
+ }
165
+
166
+ /* Alert Styles */
167
+ .alert {
168
+ border-radius: 8px;
169
+ border: none;
170
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
171
+ }
172
+
173
+ .alert-info {
174
+ background: linear-gradient(45deg, #17a2b8, #20c997);
175
+ color: white;
176
+ }
177
+
178
+ /* Responsive Adjustments */
179
+ @media (max-width: 768px) {
180
+ .card-body {
181
+ padding: 1.5rem;
182
+ }
183
+
184
+ #map, #map iframe {
185
+ height: 400px !important;
186
+ }
187
+
188
+ .btn {
189
+ width: 100%;
190
+ margin-bottom: 0.5rem;
191
+ }
192
+ }
193
+
194
+ /* Analysis Layout Styles */
195
+ .analysis-container {
196
+ background: white;
197
+ border-radius: 12px;
198
+ padding: 2rem;
199
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
200
+ }
201
+
202
+ .section-title {
203
+ font-size: 1.5rem;
204
+ color: #2c3e50;
205
+ margin-bottom: 1.5rem;
206
+ padding-bottom: 1rem;
207
+ border-bottom: 2px solid #e9ecef;
208
+ }
209
+
210
+ /* Image Section Styles */
211
+ .image-section {
212
+ height: 100%;
213
+ display: flex;
214
+ flex-direction: column;
215
+ }
216
+
217
+ .image-wrapper {
218
+ flex-grow: 1;
219
+ background: #f8f9fa;
220
+ border-radius: 12px;
221
+ padding: 1rem;
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: center;
225
+ }
226
+
227
+ .analyzed-image {
228
+ max-width: 100%;
229
+ height: auto;
230
+ border-radius: 8px;
231
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
232
+ }
233
+
234
+ /* Results Section Styles */
235
+ .results-section {
236
+ height: 100%;
237
+ display: flex;
238
+ flex-direction: column;
239
+ }
240
+
241
+ .results-list-wrapper {
242
+ flex-grow: 1;
243
+ background: #f8f9fa;
244
+ border-radius: 12px;
245
+ padding: 1.5rem;
246
+ max-height: 600px;
247
+ overflow-y: auto;
248
+ }
249
+
250
+ .results-list {
251
+ list-style: none;
252
+ padding: 0;
253
+ margin: 0;
254
+ }
255
+
256
+ .results-list li {
257
+ background: white;
258
+ padding: 1rem;
259
+ margin-bottom: 1rem;
260
+ border-radius: 8px;
261
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
262
+ }
263
+
264
+ .results-list li:last-child {
265
+ margin-bottom: 0;
266
+ }
267
+
268
+ .element-header {
269
+ display: flex;
270
+ justify-content: space-between;
271
+ align-items: center;
272
+ margin-bottom: 0.5rem;
273
+ }
274
+
275
+ .class-name {
276
+ font-weight: 600;
277
+ color: #2c3e50;
278
+ }
279
+
280
+ .percentage {
281
+ font-weight: 600;
282
+ color: #007bff;
283
+ background: rgba(0, 123, 255, 0.1);
284
+ padding: 0.25rem 0.75rem;
285
+ border-radius: 20px;
286
+ }
287
+
288
+ .progress {
289
+ height: 8px;
290
+ border-radius: 4px;
291
+ background-color: #e9ecef;
292
+ margin-top: 0.5rem;
293
+ }
294
+
295
+ .progress-bar {
296
+ background: linear-gradient(45deg, #007bff, #00d2ff);
297
+ border-radius: 4px;
298
+ }
299
+
300
+ /* Scrollbar Styles */
301
+ .results-list-wrapper::-webkit-scrollbar {
302
+ width: 8px;
303
+ }
304
+
305
+ .results-list-wrapper::-webkit-scrollbar-track {
306
+ background: #f1f1f1;
307
+ border-radius: 4px;
308
+ }
309
+
310
+ .results-list-wrapper::-webkit-scrollbar-thumb {
311
+ background: #888;
312
+ border-radius: 4px;
313
+ }
314
+
315
+ .results-list-wrapper::-webkit-scrollbar-thumb:hover {
316
+ background: #555;
317
+ }
318
+
319
+ /* Alert Styles Update */
320
+ .alert-info {
321
+ background: linear-gradient(45deg, #17a2b8, #20c997);
322
+ color: white;
323
+ border: none;
324
+ padding: 1rem;
325
+ }
326
+
327
+ /* Responsive Adjustments */
328
+ @media (max-width: 992px) {
329
+ .image-section {
330
+ margin-bottom: 2rem;
331
+ }
332
+
333
+ .results-list-wrapper {
334
+ max-height: 400px;
335
+ }
336
+ }
337
+
338
+ /* Masks Section Styles */
339
+ .masks-section {
340
+ margin-top: 2rem;
341
+ padding: 2rem;
342
+ background: white;
343
+ border-radius: 12px;
344
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
345
+ }
346
+
347
+ .masks-grid {
348
+ display: grid;
349
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
350
+ gap: 1.5rem;
351
+ margin-top: 1.5rem;
352
+ }
353
+
354
+ .mask-item {
355
+ background: #f8f9fa;
356
+ padding: 1rem;
357
+ border-radius: 8px;
358
+ }
359
+
360
+ .mask-wrapper {
361
+ background: white;
362
+ padding: 0.5rem;
363
+ border-radius: 8px;
364
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
365
+ }
366
+
367
+ .mask-image {
368
+ width: 100%;
369
+ height: auto;
370
+ border-radius: 4px;
371
+ }
372
+
373
+ .mask-item h4 {
374
+ margin: 0 0 1rem 0;
375
+ color: #2c3e50;
376
+ text-align: center;
377
+ }
378
+
379
+ /* Add these new styles */
380
+ .feature-item {
381
+ background: white;
382
+ padding: 1.25rem;
383
+ border-radius: 10px;
384
+ margin-bottom: 1rem;
385
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
386
+ transition: transform 0.2s;
387
+ }
388
+
389
+ .feature-item:hover {
390
+ transform: translateY(-2px);
391
+ }
392
+
393
+ .feature-header {
394
+ display: flex;
395
+ justify-content: space-between;
396
+ align-items: center;
397
+ margin-bottom: 0.75rem;
398
+ }
399
+
400
+ .feature-name {
401
+ font-weight: 600;
402
+ color: #2c3e50;
403
+ }
404
+
405
+ .feature-percentage {
406
+ background: #f8f9fa;
407
+ padding: 0.25rem 0.75rem;
408
+ border-radius: 20px;
409
+ font-weight: 600;
410
+ color: #2c3e50;
411
+ }
412
+
413
+ .progress {
414
+ height: 8px;
415
+ background-color: #f8f9fa;
416
+ border-radius: 4px;
417
+ }
418
+
419
+ /* Feature-specific progress bar colors */
420
+ .feature-vegetation { background-color: #28a745; }
421
+ .feature-water { background-color: #007bff; }
422
+ .feature-building { background-color: #6c757d; }
423
+ .feature-terrain { background-color: #8B4513; }
424
+ .feature-other { background-color: #adb5bd; }
425
+
426
+ .masks-grid {
427
+ display: grid;
428
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
429
+ gap: 1.5rem;
430
+ }
431
+
432
+ .mask-title {
433
+ font-size: 1.1rem;
434
+ color: #2c3e50;
435
+ margin-bottom: 1rem;
436
+ text-align: center;
437
+ }
438
+
439
+ .image-wrapper {
440
+ background: #f8f9fa;
441
+ padding: 1rem;
442
+ border-radius: 10px;
443
+ margin-top: 1rem;
444
+ }
445
+
446
+ .analyzed-image {
447
+ width: 100%;
448
+ height: auto;
449
+ border-radius: 6px;
450
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
451
+ }
452
+
453
+ /* Responsive adjustments */
454
+ @media (max-width: 768px) {
455
+ .masks-grid {
456
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
457
+ }
458
+ }
static/css/styles.css ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #map {
2
+ position: relative;
3
+ width: 100%;
4
+ height: 500px;
5
+ overflow: hidden;
6
+ }
7
+
8
+ .draw-button {
9
+ position: absolute;
10
+ top: 10px;
11
+ right: 10px;
12
+ z-index: 1000;
13
+ padding: 8px 16px;
14
+ background-color: #fff;
15
+ border: 2px solid #ccc;
16
+ border-radius: 4px;
17
+ cursor: pointer;
18
+ }
19
+
20
+ .draw-button:hover {
21
+ background-color: #f0f0f0;
22
+ }
23
+
24
+ /* Make sure the SVG overlay is visible and blocks map interaction during drawing */
25
+ svg {
26
+ position: absolute;
27
+ top: 0;
28
+ left: 0;
29
+ width: 100%;
30
+ height: 100%;
31
+ z-index: 1000;
32
+ }
33
+
34
+ /* Style for the polygon being drawn */
35
+ polygon {
36
+ fill: rgba(255, 0, 0, 0.2);
37
+ stroke: red;
38
+ stroke-width: 2;
39
+ }
40
+
41
+ /* Style for the map container during drawing */
42
+ #map.drawing-mode iframe {
43
+ pointer-events: none;
44
+ }
static/js/main.js ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let polygonDraw = null;
2
+ let currentMap = null;
3
+
4
+ $(document).ready(function() {
5
+ // Location search form submission
6
+ $('#locationForm').on('submit', function(e) {
7
+ e.preventDefault();
8
+
9
+ $.ajax({
10
+ url: '/search_location',
11
+ method: 'POST',
12
+ data: {
13
+ location: $('#location').val()
14
+ },
15
+ success: function(response) {
16
+ $('#mapContainer').removeClass('d-none');
17
+ loadMap(response.lat, response.lon);
18
+ },
19
+ error: function(xhr) {
20
+ alert('Error: ' + (xhr.responseJSON ? xhr.responseJSON.error : 'Location not found'));
21
+ }
22
+ });
23
+ });
24
+
25
+ // File upload form submission
26
+ $('#uploadForm').on('submit', function(e) {
27
+ e.preventDefault();
28
+
29
+ const formData = new FormData();
30
+ const fileInput = $('#imageUpload')[0];
31
+
32
+ if (fileInput.files.length === 0) {
33
+ alert('Please select a file to upload');
34
+ return;
35
+ }
36
+
37
+ formData.append('file', fileInput.files[0]);
38
+
39
+ $.ajax({
40
+ url: '/upload',
41
+ method: 'POST',
42
+ data: formData,
43
+ processData: false,
44
+ contentType: false,
45
+ success: function(response) {
46
+ window.location.href = `/analyze?image=${encodeURIComponent(response.filepath)}`;
47
+ },
48
+ error: function(xhr) {
49
+ alert('Error uploading file: ' + (xhr.responseJSON ? xhr.responseJSON.error : 'Upload failed'));
50
+ }
51
+ });
52
+ });
53
+
54
+ // Screenshot capture button click
55
+ $('#captureBtn').on('click', function() {
56
+ if (!polygonDraw) {
57
+ // Initialize polygon drawing if not already initialized
58
+ const mapContainer = document.getElementById('map');
59
+ mapContainer.classList.add('drawing-mode');
60
+ polygonDraw = new PolygonDraw(mapContainer);
61
+ polygonDraw.startDrawing();
62
+ $(this).text('Complete Drawing (Press Enter)');
63
+ } else if (polygonDraw.isDrawing) {
64
+ const points = polygonDraw.completePolygon();
65
+ const mapContainer = document.getElementById('map');
66
+ mapContainer.classList.remove('drawing-mode');
67
+ if (points.length >= 3) {
68
+ captureWithPolygon(points);
69
+ }
70
+ $(this).text('Capture Screenshot');
71
+ } else {
72
+ const mapContainer = document.getElementById('map');
73
+ mapContainer.classList.add('drawing-mode');
74
+ polygonDraw.startDrawing();
75
+ $(this).text('Complete Drawing (Press Enter)');
76
+ }
77
+ });
78
+
79
+ // Analyze button click
80
+ $('#analyzeBtn').on('click', function() {
81
+ const screenshotPath = $('#capturedImage').attr('src');
82
+ if (screenshotPath) {
83
+ window.location.href = `/analyze?image=${encodeURIComponent(screenshotPath)}`;
84
+ }
85
+ });
86
+
87
+ // Add keyboard event listener for Enter key
88
+ document.addEventListener('keydown', function(event) {
89
+ if (event.key === 'Enter' && polygonDraw && polygonDraw.isDrawing) {
90
+ const points = polygonDraw.completePolygon();
91
+ const mapContainer = document.getElementById('map');
92
+ mapContainer.classList.remove('drawing-mode');
93
+ if (points.length >= 3) {
94
+ captureWithPolygon(points);
95
+ }
96
+ $('#captureBtn').text('Capture Screenshot');
97
+ }
98
+ });
99
+ });
100
+
101
+ function loadMap(lat, lon) {
102
+ const mapDiv = document.getElementById('map');
103
+ mapDiv.innerHTML = ''; // Clear any existing content
104
+
105
+ // Create a new map instance
106
+ currentMap = L.map('map', {
107
+ center: [lat, lon],
108
+ zoom: 20,
109
+ maxZoom: 18,
110
+ preferCanvas: true
111
+ });
112
+
113
+ // Add the satellite tile layer
114
+ L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
115
+ attribution: 'Esri',
116
+ maxZoom: 20,
117
+ tileSize: 256
118
+ }).addTo(currentMap);
119
+
120
+ // Wait for the map to load completely
121
+ currentMap.whenReady(() => {
122
+ currentMap.invalidateSize();
123
+ currentMap.setView([lat, lon], 20);
124
+ });
125
+ }
126
+
127
+ function captureWithPolygon(points) {
128
+ const mapContainer = document.getElementById('map');
129
+
130
+ // Get the current map state
131
+ const center = currentMap.getCenter();
132
+ const bounds = currentMap.getBounds();
133
+ const zoom = currentMap.getZoom();
134
+
135
+ const data = {
136
+ width: mapContainer.offsetWidth,
137
+ height: mapContainer.offsetHeight,
138
+ polygon: points,
139
+ mapState: {
140
+ center: {
141
+ lat: center.lat,
142
+ lng: center.lng
143
+ },
144
+ bounds: {
145
+ north: bounds.getNorth(),
146
+ south: bounds.getSouth(),
147
+ east: bounds.getEast(),
148
+ west: bounds.getWest()
149
+ },
150
+ zoom: zoom
151
+ }
152
+ };
153
+
154
+ // Log the map state for debugging
155
+ console.log('Capturing map state:', data.mapState);
156
+
157
+ fetch('/capture_screenshot', {
158
+ method: 'POST',
159
+ headers: {
160
+ 'Content-Type': 'application/json'
161
+ },
162
+ body: JSON.stringify(data)
163
+ })
164
+ .then(response => response.json())
165
+ .then(data => {
166
+ if (data.success) {
167
+ $('#screenshotGallery').removeClass('d-none');
168
+ const imagePath = data.cutout_path || data.screenshot_path;
169
+ const imageUrl = imagePath + '?t=' + new Date().getTime();
170
+ $('#capturedImage').attr('src', imageUrl);
171
+ } else {
172
+ alert('Error capturing screenshot');
173
+ }
174
+ })
175
+ .catch(error => {
176
+ console.error('Error:', error);
177
+ alert('Error capturing screenshot');
178
+ });
179
+ }
static/js/polygon-draw.js ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class PolygonDraw {
2
+ constructor(container) {
3
+ this.container = container;
4
+ this.points = [];
5
+ this.isDrawing = false;
6
+ this.svg = null;
7
+ this.polygon = null;
8
+ this.setupSVG();
9
+ }
10
+
11
+ setupSVG() {
12
+ // Create SVG overlay
13
+ this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
14
+ this.svg.style.position = 'absolute';
15
+ this.svg.style.top = '0';
16
+ this.svg.style.left = '0';
17
+ this.svg.style.width = '100%';
18
+ this.svg.style.height = '100%';
19
+ this.svg.style.pointerEvents = 'all';
20
+ this.svg.style.zIndex = '1000';
21
+
22
+ // Create polygon element
23
+ this.polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
24
+ this.polygon.setAttribute('fill', 'rgba(255, 0, 0, 0.2)');
25
+ this.polygon.setAttribute('stroke', 'red');
26
+ this.polygon.setAttribute('stroke-width', '2');
27
+ this.svg.appendChild(this.polygon);
28
+
29
+ // Add SVG to container
30
+ this.container.appendChild(this.svg);
31
+ }
32
+
33
+ startDrawing() {
34
+ this.isDrawing = true;
35
+ this.points = [];
36
+ this.updatePolygon();
37
+
38
+ // Add click listener to container
39
+ this.container.style.cursor = 'crosshair';
40
+ this.clickHandler = this.handleClick.bind(this);
41
+ this.moveHandler = this.handleMouseMove.bind(this);
42
+
43
+ // Find and disable the iframe
44
+ const mapFrame = this.container.querySelector('iframe');
45
+ if (mapFrame) {
46
+ mapFrame.style.pointerEvents = 'none';
47
+ }
48
+
49
+ this.svg.addEventListener('click', this.clickHandler);
50
+ this.svg.addEventListener('mousemove', this.moveHandler);
51
+ }
52
+
53
+ handleClick(event) {
54
+ event.preventDefault();
55
+ event.stopPropagation();
56
+
57
+ const rect = this.container.getBoundingClientRect();
58
+ const x = event.clientX - rect.left;
59
+ const y = event.clientY - rect.top;
60
+
61
+ this.points.push({ x, y });
62
+ this.updatePolygon();
63
+ }
64
+
65
+ handleMouseMove(event) {
66
+ if (this.points.length > 0) {
67
+ event.preventDefault();
68
+ event.stopPropagation();
69
+
70
+ const rect = this.container.getBoundingClientRect();
71
+ const x = event.clientX - rect.left;
72
+ const y = event.clientY - rect.top;
73
+
74
+ this.updatePolygon([...this.points, { x, y }]);
75
+ }
76
+ }
77
+
78
+ updatePolygon(points = this.points) {
79
+ if (points.length > 0) {
80
+ const pointsString = points.map(p => `${p.x},${p.y}`).join(' ');
81
+ this.polygon.setAttribute('points', pointsString);
82
+ } else {
83
+ this.polygon.setAttribute('points', '');
84
+ }
85
+ }
86
+
87
+ completePolygon() {
88
+ this.isDrawing = false;
89
+ this.container.style.cursor = 'default';
90
+ this.svg.removeEventListener('click', this.clickHandler);
91
+ this.svg.removeEventListener('mousemove', this.moveHandler);
92
+
93
+ // Re-enable the iframe
94
+ const mapFrame = this.container.querySelector('iframe');
95
+ if (mapFrame) {
96
+ mapFrame.style.pointerEvents = 'auto';
97
+ }
98
+
99
+ const points = [...this.points];
100
+ this.points = [];
101
+ this.updatePolygon();
102
+ return points;
103
+ }
104
+
105
+ cleanup() {
106
+ if (this.svg && this.svg.parentNode) {
107
+ this.svg.parentNode.removeChild(this.svg);
108
+ }
109
+ }
110
+ }
templates/index.html CHANGED
@@ -1,99 +1,35 @@
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>Satellite Image Analyzer</title>
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
9
- <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
10
- <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
11
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
 
 
12
  </head>
13
  <body>
14
- <div class="container py-5">
15
- <h1 class="text-center">Satellite Image Analyzer</h1>
16
 
17
- <div class="row justify-content-center">
18
- <div class="col-lg-10">
19
- <div class="card mb-4">
20
- <div class="card-body">
21
- <form id="locationForm" class="mb-3">
22
- <div class="form-group">
23
- <label for="location" class="form-label">
24
- <i class="fas fa-search-location me-2"></i>Enter Location
25
- </label>
26
- <input type="text"
27
- class="form-control form-control-lg"
28
- id="location"
29
- name="location"
30
- placeholder="Enter an address or location name"
31
- required>
32
- </div>
33
- <button type="submit" class="btn btn-primary mt-3">
34
- <i class="fas fa-map-marked-alt me-2"></i>Search Location
35
- </button>
36
- </form>
37
- </div>
38
- </div>
39
-
40
- <div class="card mb-4">
41
- <div class="card-body">
42
- <h5 class="card-title">
43
- <i class="fas fa-upload me-2"></i>Or Upload an Image
44
- </h5>
45
- <form id="uploadForm" class="mb-3">
46
- <div class="form-group">
47
- <input type="file"
48
- class="form-control"
49
- id="imageUpload"
50
- accept=".jpg,.jpeg,.png,.tif,.tiff"
51
- required>
52
- </div>
53
- <button type="submit" class="btn btn-primary mt-3">
54
- <i class="fas fa-upload me-2"></i>Upload and Analyze
55
- </button>
56
- </form>
57
- </div>
58
- </div>
59
-
60
- <div id="mapContainer" class="card mb-4 d-none">
61
- <div class="card-body">
62
- <div id="map"></div>
63
- <div class="mt-4 d-flex justify-content-between align-items-center flex-wrap">
64
- <button id="captureBtn" class="btn btn-success">
65
- <i class="fas fa-camera me-2"></i>Capture Screenshot
66
- </button>
67
- <small class="text-muted">
68
- <i class="fas fa-info-circle me-2"></i>Use map controls to adjust the view
69
- </small>
70
- </div>
71
- </div>
72
- </div>
73
 
74
- <div id="screenshotGallery" class="card d-none">
75
- <div class="card-body">
76
- <h5 class="card-title">
77
- <i class="fas fa-image me-2"></i>Captured Image
78
- </h5>
79
- <div id="screenshotContainer" class="text-center">
80
- <img id="capturedImage" class="img-fluid" alt="Captured map">
81
- <div class="mt-4">
82
- <a id="analyzeBtn" class="btn btn-primary">
83
- <i class="fas fa-chart-bar me-2"></i>Analyze Image
84
- </a>
85
- </div>
86
- </div>
87
- </div>
88
- </div>
89
  </div>
 
 
90
  </div>
 
 
91
  </div>
92
 
93
- <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
94
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
95
- <script src="{{ url_for('static', filename='js/polygon-draw.js') }}"></script>
96
- <script src="{{ url_for('static', filename='js/main.js') }}"></script>
97
- <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
98
  </body>
99
  </html>
 
1
  <!DOCTYPE html>
2
+ <html>
3
  <head>
4
+ <title>Map Screenshot Tool</title>
 
 
 
 
 
 
5
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
6
+ <link rel="stylesheet" href="/static/css/styles.css" />
7
+ <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
8
  </head>
9
  <body>
10
+ <div class="container">
11
+ <h1>Map Screenshot Tool</h1>
12
 
13
+ <div class="controls">
14
+ <input type="text" id="location-input" placeholder="Enter location...">
15
+ <button onclick="searchLocation()">Search</button>
16
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ <div id="map-container">
19
+ <div id="map"></div>
20
+
21
+ <div class="drawing-controls">
22
+ <button id="polygon-toggle" onclick="togglePolygonDraw()">Start Drawing</button>
23
+ <button id="clear-polygon" onclick="clearPolygon()">Clear Drawing</button>
 
 
 
 
 
 
 
 
 
24
  </div>
25
+
26
+ <button onclick="captureScreenshot()">Capture Screenshot</button>
27
  </div>
28
+
29
+ <div id="screenshot-result" class="results"></div>
30
  </div>
31
 
32
+ <script src="/static/js/main.js"></script>
33
+ <script src="/static/js/polygon-draw.js"></script>
 
 
 
34
  </body>
35
  </html>