-
Notifications
You must be signed in to change notification settings - Fork 0
/
map-with-cards.html
321 lines (282 loc) · 10.3 KB
/
map-with-cards.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
<!DOCTYPE html>
<html>
<head>
<title>Map with Cards - Mapbox GL JS</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://api.mapbox.com/mapbox-gl-js/v1.3.1/mapbox-gl.css" rel="stylesheet">
<style>
@import url('https://fonts.googleapis.com/css2?family=Avenir:wght@400;700&display=swap');
body {
font-family: 'Avenir', sans-serif;
background-color: white; /* Set the background color to white */
}
#container {
display: flex;
}
#cardsContainer {
max-height: 600px;
overflow-y: auto;
width: 300px;
padding: 10px;
}
#map {
flex-grow: 1;
height: 600px;
position: relative; /* Ensure the info pane is positioned relative to the map */
}
.card {
cursor: pointer;
padding: 10px;
border: 1px solid #ccc;
margin: 5px;
}
.card-selected {
background-color: #f0f0f0; /* Light grey background */
}
.marker-selected {
background-color: orange; /* Orange marker */
}
#infoPane {
position: absolute;
top: 10px;
left: 10px;
width: 33%; /* One-third the width of the map */
height: 70%;
overflow-y: auto;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px;
box-sizing: border-box;
display: none; /* Initially hidden */
z-index: 1; /* Ensure it's above the map */
}
.popup-image {
width: 100%;
height: auto;
max-height: 200px; /* Limit the height of the image */
object-fit: cover; /* Ensure the aspect ratio of the image is preserved */
}
.popup-title {
font-size: 18px;
font-weight: bold;
}
.popup-address {
font-style: italic;
}
.property-name {
font-weight: bold;
font-size: 14px;
}
.address {
font-style: italic;
font-size: 10px;
}
.details {
font-size: 10px;
}
.dropdown {
position: relative;
display: inline-block;
width: 100%;
}
.dropdown-button {
width: 100%;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
width: 100%;
}
.dropdown-option {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
width: 100%;
}
.dropdown-option:hover {
background-color: #f1f1f1;
}
.dropdown.open .dropdown-content {
display: block;
}
</style>
</head>
<body>
<div id="container">
<div id="cardsContainer"></div>
<div id="map">
<!-- Add the info pane inside the map container -->
<div id="infoPane"></div>
</div>
</div>
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.3.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.3.1/mapbox-gl.css' rel='stylesheet' />
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
<script>
// Set your Mapbox access token here
mapboxgl.accessToken = 'pk.eyJ1IjoiYnJ5YW5qYWNvYnMiLCJhIjoiY2xoNHpxN3l0MDluMzNsczJzbHpieWIxayJ9.EFX6EwOCHvgKW1Gb_ALMRA';
// Initialize the map
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/bryanjacobs/clh4znlb501c601qjdq3jeowe',
center: [-74.0060, 40.7128],
zoom: 13
});
// Create an empty bounds object
var bounds = new mapboxgl.LngLatBounds();
// Define the getLocationCategory function and the locationContainers object
function getLocationCategory(address) {
if (address.includes(', CA')) {
return 'California';
} else if (address.includes(', HI')) {
return 'Hawaii';
} else {
return 'Other';
}
}
var locationContainers = {};
// Parse the CSV file
Papa.parse('data.csv', {
download: true,
header: true,
complete: function(results) {
var data = results.data;
var cardsContainer = document.getElementById('cardsContainer');
// Create a variable to store the current popup
var currentPopup = null;
// Create variables to store the selected card and marker
var selectedCard = null;
var selectedMarker = null;
data.forEach(function(row) {
// Extract the city and state from the address
var addressParts = row.Address.split(',');
var city = addressParts[1].trim().replace(/"/g, ''); // Extract the city after the second comma, remove double quotes, and trim any leading/trailing spaces
var state = addressParts[2].trim();
// Generate a unique key for the location container
var locationContainerKey = state + '-' + city;
// Create a new location container if it doesn't exist
if (!locationContainers[locationContainerKey]) {
var locationContainer = document.createElement('div');
locationContainer.id = locationContainerKey.replace(/\s+/g, '').toLowerCase();
locationContainer.innerHTML = '<h2>' + state + ' - ' + city + '</h2>';
// Append the new location container to the cards container
cardsContainer.appendChild(locationContainer);
// Store the new location container
locationContainers[locationContainerKey] = {
container: locationContainer,
cities: {}
};
}
// Store the city within the state container
var stateContainer = locationContainers[locationContainerKey];
if (!stateContainer.cities[city]) {
stateContainer.cities[city] = [];
}
// Add the current property to the city list
stateContainer.cities[city].push(row);
// Create card
var card = document.createElement('div');
card.className = 'card';
card.dataset.lat = row.Latitude;
card.dataset.lng = row.Longitude;
card.innerHTML = `<div class="property-name">${row['Property Name']}</div> <div class="address">${row.Address}</div> <div class="details">${row['Total Sqft']} sqft, Built in ${row.Built}</div>`;
// Append the card to the appropriate location container
stateContainer.container.appendChild(card);
// Create marker
var marker = new mapboxgl.Marker()
.setLngLat([row.Longitude, row.Latitude])
.addTo(map);
// Add click event listener to the card
card.addEventListener('click', function() {
// If the card is already selected, deselect it and hide the info pane
if (card.classList.contains('card-selected')) {
card.classList.remove('card-selected');
document.getElementById('infoPane').style.display = 'none';
marker.getElement().classList.remove('marker-selected');
return;
}
// Remove the "card-selected" class from the previously selected card
if (selectedCard) {
selectedCard.classList.remove('card-selected');
}
// Add the "card-selected" class to the clicked card
card.classList.add('card-selected');
selectedCard = card;
// Close any existing popup
if (currentPopup) {
currentPopup.remove();
}
// Update the content of the info pane
var infoPane = document.getElementById('infoPane');
infoPane.innerHTML = `
<div class="popup-content">
<img class="popup-image" src="https://via.placeholder.com/200" alt="Placeholder Image">
<h2 class="popup-title">${row['Property Name']}</h2>
<div class="popup-address">${row.Address}</div>
<div>${row['Total Sqft']} sqft</div>
<div>Built in ${row.Built}</div>
</div>
`;
// Show the info pane
infoPane.style.display = 'block';
// Deselect the previously selected marker if it exists
if (selectedMarker) {
selectedMarker.getElement().classList.remove('marker-selected');
}
// Select the corresponding marker
marker.getElement().classList.add('marker-selected');
selectedMarker = marker;
var lat = parseFloat(card.dataset.lat);
var lng = parseFloat(card.dataset.lng);
// Fly to the selected location
map.flyTo({
center: [lng, lat],
zoom: 15,
essential: true
});
});
// Add click event listener to the marker
marker.getElement().addEventListener('click', function(e) {
// Stop the event propagation so that the 'click' event on the map won't be triggered
e.stopPropagation();
// Trigger the click event on the corresponding card
card.click();
});
// Extend the bounds to include the current point
bounds.extend([row.Longitude, row.Latitude]);
}); // End of forEach
// Fit the map to the bounds of all markers
map.fitBounds(bounds, { padding: 90, maxZoom: 14 }); // Adjust maxZoom if needed
}
});
// Handle dropdown menu clicks
var dropdownButtons = document.querySelectorAll('.dropdown-button');
dropdownButtons.forEach(function(button) {
button.addEventListener('click', function() {
var dropdown = button.parentElement;
dropdown.classList.toggle('open');
});
});
// Close dropdown menus when clicking outside
window.addEventListener('click', function(event) {
dropdownButtons.forEach(function(button) {
if (!button.contains(event.target)) {
button.parentElement.classList.remove('open');
}
});
});
// Prevent dropdown menu from closing when clicking inside
var dropdownContents = document.querySelectorAll('.dropdown-content');
dropdownContents.forEach(function(content) {
content.addEventListener('click', function(event) {
event.stopPropagation();
});
});
</script>
</body>
</html>