374 lines
12 KiB
JavaScript
374 lines
12 KiB
JavaScript
/*
|
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
|
* Click nbfs://nbhost/SystemFileSystem/Templates/Other/javascript.js to edit this template
|
|
*/
|
|
|
|
|
|
|
|
mapboxgl.accessToken = 'pk.eyJ1IjoiZXhhbXBsZXMiLCJhIjoiY2p0MG01MXRqMW45cjQzb2R6b2ptc3J4MSJ9.zA2W0IkI0c6KaAhJfk9bWg';
|
|
|
|
/**
|
|
* Add the map to the page
|
|
*/
|
|
const map = new mapboxgl.Map({
|
|
container: 'map',
|
|
style: 'mapbox://styles/mapbox/light-v10',
|
|
center: [-77.034084142948, 38.909671288923],
|
|
zoom: 13,
|
|
scrollZoom: false
|
|
});
|
|
|
|
const stores = {
|
|
'type': 'FeatureCollection',
|
|
'features': [
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.034084142948, 38.909671288923]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(202) 234-7336',
|
|
'phone': '2022347336',
|
|
'address': '1471 P St NW',
|
|
'city': 'Washington DC',
|
|
'country': 'United States',
|
|
'crossStreet': 'at 15th St NW',
|
|
'postalCode': '20005',
|
|
'state': 'D.C.'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.049766, 38.900772]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(202) 507-8357',
|
|
'phone': '2025078357',
|
|
'address': '2221 I St NW',
|
|
'city': 'Washington DC',
|
|
'country': 'United States',
|
|
'crossStreet': 'at 22nd St NW',
|
|
'postalCode': '20037',
|
|
'state': 'D.C.'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.043929, 38.910525]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(202) 387-9338',
|
|
'phone': '2023879338',
|
|
'address': '1512 Connecticut Ave NW',
|
|
'city': 'Washington DC',
|
|
'country': 'United States',
|
|
'crossStreet': 'at Dupont Circle',
|
|
'postalCode': '20036',
|
|
'state': 'D.C.'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.0672, 38.90516896]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(202) 337-9338',
|
|
'phone': '2023379338',
|
|
'address': '3333 M St NW',
|
|
'city': 'Washington DC',
|
|
'country': 'United States',
|
|
'crossStreet': 'at 34th St NW',
|
|
'postalCode': '20007',
|
|
'state': 'D.C.'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.002583742142, 38.887041080933]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(202) 547-9338',
|
|
'phone': '2025479338',
|
|
'address': '221 Pennsylvania Ave SE',
|
|
'city': 'Washington DC',
|
|
'country': 'United States',
|
|
'crossStreet': 'btwn 2nd & 3rd Sts. SE',
|
|
'postalCode': '20003',
|
|
'state': 'D.C.'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-76.933492720127, 38.99225245786]
|
|
},
|
|
'properties': {
|
|
'address': '8204 Baltimore Ave',
|
|
'city': 'College Park',
|
|
'country': 'United States',
|
|
'postalCode': '20740',
|
|
'state': 'MD'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.097083330154, 38.980979]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(301) 654-7336',
|
|
'phone': '3016547336',
|
|
'address': '4831 Bethesda Ave',
|
|
'cc': 'US',
|
|
'city': 'Bethesda',
|
|
'country': 'United States',
|
|
'postalCode': '20814',
|
|
'state': 'MD'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.359425054188, 38.958058116661]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(571) 203-0082',
|
|
'phone': '5712030082',
|
|
'address': '11935 Democracy Dr',
|
|
'city': 'Reston',
|
|
'country': 'United States',
|
|
'crossStreet': 'btw Explorer & Library',
|
|
'postalCode': '20190',
|
|
'state': 'VA'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.10853099823, 38.880100922392]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(703) 522-2016',
|
|
'phone': '7035222016',
|
|
'address': '4075 Wilson Blvd',
|
|
'city': 'Arlington',
|
|
'country': 'United States',
|
|
'crossStreet': 'at N Randolph St.',
|
|
'postalCode': '22203',
|
|
'state': 'VA'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-75.28784, 40.008008]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(610) 642-9400',
|
|
'phone': '6106429400',
|
|
'address': '68 Coulter Ave',
|
|
'city': 'Ardmore',
|
|
'country': 'United States',
|
|
'postalCode': '19003',
|
|
'state': 'PA'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-75.20121216774, 39.954030175164]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(215) 386-1365',
|
|
'phone': '2153861365',
|
|
'address': '3925 Walnut St',
|
|
'city': 'Philadelphia',
|
|
'country': 'United States',
|
|
'postalCode': '19104',
|
|
'state': 'PA'
|
|
}
|
|
},
|
|
{
|
|
'type': 'Feature',
|
|
'geometry': {
|
|
'type': 'Point',
|
|
'coordinates': [-77.043959498405, 38.903883387232]
|
|
},
|
|
'properties': {
|
|
'phoneFormatted': '(202) 331-3355',
|
|
'phone': '2023313355',
|
|
'address': '1901 L St. NW',
|
|
'city': 'Washington DC',
|
|
'country': 'United States',
|
|
'crossStreet': 'at 19th St',
|
|
'postalCode': '20036',
|
|
'state': 'D.C.'
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
/**
|
|
* Assign a unique id to each store. You'll use this `id`
|
|
* later to associate each point on the map with a listing
|
|
* in the sidebar.
|
|
*/
|
|
stores.features.forEach((store, i) => {
|
|
store.properties.id = i;
|
|
});
|
|
|
|
/**
|
|
* Wait until the map loads to make changes to the map.
|
|
*/
|
|
map.on('load', () => {
|
|
/* Add the data to your map as a layer */
|
|
map.addLayer({
|
|
'id': 'locations',
|
|
'type': 'circle',
|
|
/* Add a GeoJSON source containing place coordinates and information. */
|
|
'source': {
|
|
'type': 'geojson',
|
|
'data': stores
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Add things to the page:
|
|
* - The location listings on the side of the page
|
|
*/
|
|
buildLocationList(stores);
|
|
});
|
|
|
|
/**
|
|
* Listen to the map and when it is clicked, do three things:
|
|
* 1. Query the map to determine if a feature in the
|
|
* "locations" layer exists at that point.
|
|
* 2. If yes, then:
|
|
* a. Fly to the point
|
|
* b. Close all other popups and display popup for clicked store
|
|
* c. Highlight listing in sidebar (and remove highlight for all other listings)
|
|
**/
|
|
map.on('click', (event) => {
|
|
/* Query the map to determine if a feature in the "locations" layer exists at that point. */
|
|
const features = map.queryRenderedFeatures(event.point, {
|
|
layers: ['locations']
|
|
});
|
|
|
|
/* If it does not exist, return */
|
|
if (!features.length) return;
|
|
const clickedPoint = features[0];
|
|
|
|
/* Fly to the point */
|
|
flyToStore(clickedPoint);
|
|
|
|
/* Close all other popups and display popup for clicked store */
|
|
createPopUp(clickedPoint);
|
|
|
|
/* Highlight listing in sidebar (and remove highlight for all other listings) */
|
|
const activeItem = document.getElementsByClassName('active');
|
|
if (activeItem[0]) {
|
|
activeItem[0].classList.remove('active');
|
|
}
|
|
const listing = document.getElementById(
|
|
`listing-${clickedPoint.properties.id}`
|
|
);
|
|
listing.classList.add('active');
|
|
});
|
|
|
|
/**
|
|
* Add a listing for each store to the sidebar.
|
|
**/
|
|
function buildLocationList(stores) {
|
|
for (const store of stores.features) {
|
|
/* Add a new listing section to the sidebar. */
|
|
const listings = document.getElementById('listings');
|
|
const listing = listings.appendChild(document.createElement('div'));
|
|
/* Assign a unique `id` to the listing. */
|
|
listing.id = `listing-${store.properties.id}`;
|
|
/* Assign the `item` class to each listing for styling. */
|
|
listing.className = 'item';
|
|
|
|
/* Add the link to the individual listing created above. */
|
|
const link = listing.appendChild(document.createElement('a'));
|
|
link.href = '#';
|
|
link.className = 'title';
|
|
link.id = `link-${store.properties.id}`;
|
|
link.innerHTML = `${store.properties.address}`;
|
|
|
|
/* Add details to the individual listing. */
|
|
const details = listing.appendChild(document.createElement('div'));
|
|
details.innerHTML = `${store.properties.city}`;
|
|
if (store.properties.phone) {
|
|
details.innerHTML += ` · ${store.properties.phoneFormatted}`;
|
|
}
|
|
if (store.properties.distance) {
|
|
const roundedDistance =
|
|
Math.round(store.properties.distance * 100) / 100;
|
|
details.innerHTML += `<div><strong>${roundedDistance} miles away</strong></div>`;
|
|
}
|
|
|
|
/**
|
|
* Listen to the element and when it is clicked, do four things:
|
|
* 1. Update the `currentFeature` to the store associated with the clicked link
|
|
* 2. Fly to the point
|
|
* 3. Close all other popups and display popup for clicked store
|
|
* 4. Highlight listing in sidebar (and remove highlight for all other listings)
|
|
**/
|
|
link.addEventListener('click', function () {
|
|
for (const feature of stores.features) {
|
|
if (this.id === `link-${feature.properties.id}`) {
|
|
flyToStore(feature);
|
|
createPopUp(feature);
|
|
}
|
|
}
|
|
const activeItem = document.getElementsByClassName('active');
|
|
if (activeItem[0]) {
|
|
activeItem[0].classList.remove('active');
|
|
}
|
|
this.parentNode.classList.add('active');
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Use Mapbox GL JS's `flyTo` to move the camera smoothly
|
|
* a given center point.
|
|
**/
|
|
function flyToStore(currentFeature) {
|
|
map.flyTo({
|
|
center: currentFeature.geometry.coordinates,
|
|
zoom: 15
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create a Mapbox GL JS `Popup`.
|
|
**/
|
|
function createPopUp(currentFeature) {
|
|
const popUps = document.getElementsByClassName('mapboxgl-popup');
|
|
if (popUps[0]) popUps[0].remove();
|
|
|
|
const popup = new mapboxgl.Popup({ closeOnClick: false })
|
|
.setLngLat(currentFeature.geometry.coordinates)
|
|
.setHTML(
|
|
`<h3>Sweetgreen</h3><h4>${currentFeature.properties.address}</h4>`
|
|
)
|
|
.addTo(map);
|
|
}
|
|
|