AdityaAdaki commited on
Commit
af11331
·
1 Parent(s): b0b8a40
Files changed (3) hide show
  1. static/js/main.js +159 -43
  2. static/js/polygon-draw.js +101 -61
  3. templates/index.html +54 -12
static/js/main.js CHANGED
@@ -1,60 +1,176 @@
1
- function searchLocation() {
2
- const location = document.getElementById('location').value;
3
-
4
- fetch('/search_location', {
5
- method: 'POST',
6
- headers: {
7
- 'Content-Type': 'application/x-www-form-urlencoded',
8
- },
9
- body: `location=${encodeURIComponent(location)}`
10
- })
11
- .then(response => response.json())
12
- .then(data => {
13
- if (data.error) {
14
- alert(data.error);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  return;
16
  }
17
- // Update map with location data
18
- map.setView([data.lat, data.lon], 20);
19
- })
20
- .catch(error => {
21
- console.error('Error:', error);
22
- alert('Error searching location');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  });
24
  }
25
 
26
- function captureScreenshot() {
27
- const bounds = map.getBounds();
28
- const center = map.getCenter();
 
 
 
 
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  fetch('/capture_screenshot', {
31
  method: 'POST',
32
  headers: {
33
- 'Content-Type': 'application/json',
34
  },
35
- body: JSON.stringify({
36
- width: map.getContainer().clientWidth,
37
- height: map.getContainer().clientHeight,
38
- mapState: {
39
- center: center,
40
- zoom: map.getZoom(),
41
- bounds: {
42
- north: bounds.getNorth(),
43
- south: bounds.getSouth(),
44
- east: bounds.getEast(),
45
- west: bounds.getWest()
46
- }
47
- },
48
- polygon: drawnPolygon
49
- })
50
  })
51
  .then(response => response.json())
52
  .then(data => {
53
- if (data.error) {
54
- alert(data.error);
55
- return;
 
 
 
 
56
  }
57
- window.location.href = `/analyze?image=${data.cutout_path || data.screenshot_path}`;
58
  })
59
  .catch(error => {
60
  console.error('Error:', error);
 
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);
static/js/polygon-draw.js CHANGED
@@ -1,70 +1,110 @@
1
- let drawnPolygon = [];
2
- let drawing = false;
3
- let drawingCanvas;
4
- let ctx;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- document.addEventListener('DOMContentLoaded', function() {
7
- drawingCanvas = document.getElementById('drawing-canvas');
8
- ctx = drawingCanvas.getContext('2d');
9
-
10
- // Setup canvas size
11
- function resizeCanvas() {
12
- drawingCanvas.width = map.getContainer().clientWidth;
13
- drawingCanvas.height = map.getContainer().clientHeight;
 
 
 
 
 
 
 
 
 
 
14
  }
15
-
16
- resizeCanvas();
17
- window.addEventListener('resize', resizeCanvas);
18
-
19
- // Setup map click handler
20
- map.on('click', function(e) {
21
- if (!drawing) return;
22
- addPoint(e);
23
- });
24
- });
25
 
26
- function startDrawing() {
27
- drawing = true;
28
- drawnPolygon = [];
29
- clearCanvas();
30
- document.getElementById('map').style.cursor = 'crosshair';
31
- }
 
 
 
 
 
32
 
33
- function stopDrawing() {
34
- if (drawnPolygon.length > 2) {
35
- // Close the polygon
36
- addPoint({ containerPoint: drawnPolygon[0] });
 
 
 
 
 
 
 
37
  }
38
- drawing = false;
39
- document.getElementById('map').style.cursor = '';
40
- }
41
 
42
- function clearCanvas() {
43
- ctx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height);
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
- function addPoint(e) {
47
- const point = {
48
- x: e.containerPoint.x,
49
- y: e.containerPoint.y
50
- };
51
-
52
- drawnPolygon.push(point);
53
-
54
- // Draw point
55
- ctx.fillStyle = 'red';
56
- ctx.beginPath();
57
- ctx.arc(point.x, point.y, 3, 0, 2 * Math.PI);
58
- ctx.fill();
59
-
60
- // Draw line
61
- if (drawnPolygon.length > 1) {
62
- const prev = drawnPolygon[drawnPolygon.length - 2];
63
- ctx.beginPath();
64
- ctx.moveTo(prev.x, prev.y);
65
- ctx.lineTo(point.x, point.y);
66
- ctx.strokeStyle = 'red';
67
- ctx.lineWidth = 2;
68
- ctx.stroke();
69
  }
70
  }
 
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
@@ -19,21 +19,63 @@
19
  <button onclick="searchLocation()">Search</button>
20
  </div>
21
 
22
- <div id="map-container">
23
- <div id="map"></div>
24
-
25
- <div class="drawing-controls">
26
- <button id="polygon-toggle" onclick="togglePolygonDraw()">Start Drawing</button>
27
- <button id="clear-polygon" onclick="clearPolygon()">Clear Drawing</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  </div>
29
-
30
- <button onclick="captureScreenshot()">Capture Screenshot</button>
31
  </div>
32
-
33
- <div id="screenshot-result" class="results"></div>
34
  </div>
35
 
36
- <script src="/static/js/main.js"></script>
37
- <script src="/static/js/polygon-draw.js"></script>
 
 
 
38
  </body>
39
  </html>
 
19
  <button onclick="searchLocation()">Search</button>
20
  </div>
21
 
22
+ <div class="card mb-4">
23
+ <div class="card-body">
24
+ <h5 class="card-title">
25
+ <i class="fas fa-upload me-2"></i>Or Upload an Image
26
+ </h5>
27
+ <form id="uploadForm" class="mb-3">
28
+ <div class="form-group">
29
+ <input type="file"
30
+ class="form-control"
31
+ id="imageUpload"
32
+ accept=".jpg,.jpeg,.png,.tif,.tiff"
33
+ required>
34
+ </div>
35
+ <button type="submit" class="btn btn-primary mt-3">
36
+ <i class="fas fa-upload me-2"></i>Upload and Analyze
37
+ </button>
38
+ </form>
39
+ </div>
40
+ </div>
41
+
42
+ <div id="mapContainer" class="card mb-4 d-none">
43
+ <div class="card-body">
44
+ <div id="map"></div>
45
+ <div class="mt-4 d-flex justify-content-between align-items-center flex-wrap">
46
+ <button id="captureBtn" class="btn btn-success">
47
+ <i class="fas fa-camera me-2"></i>Capture Screenshot
48
+ </button>
49
+ <small class="text-muted">
50
+ <i class="fas fa-info-circle me-2"></i>Use map controls to adjust the view
51
+ </small>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <div id="screenshotGallery" class="card d-none">
57
+ <div class="card-body">
58
+ <h5 class="card-title">
59
+ <i class="fas fa-image me-2"></i>Captured Image
60
+ </h5>
61
+ <div id="screenshotContainer" class="text-center">
62
+ <img id="capturedImage" class="img-fluid" alt="Captured map">
63
+ <div class="mt-4">
64
+ <a id="analyzeBtn" class="btn btn-primary">
65
+ <i class="fas fa-chart-bar me-2"></i>Analyze Image
66
+ </a>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </div>
71
  </div>
 
 
72
  </div>
 
 
73
  </div>
74
 
75
+ <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
76
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
77
+ <script src="{{ url_for('static', filename='js/polygon-draw.js') }}"></script>
78
+ <script src="{{ url_for('static', filename='js/main.js') }}"></script>
79
+ <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
80
  </body>
81
  </html>