const MAPS_API_KEY = ''; // Put your API Key for Maps SDK here
const LS_API_KEY = ''; // Put your API Key for Location Selection APIs here
const MAPS_URL = `https://maps.googleapis.com/maps/api/js?key=${
MAPS_API_KEY}&libraries=places,geometry&callback=initMap`;
const LS_BASE_URL = 'https://locationselection.googleapis.com/v1beta';
const API_URL_PUPS_FOR_PLACE =
`${LS_BASE_URL}:findPickupPointsForPlace?key=${LS_API_KEY}`;
const API_URL_PUPS_FOR_LOCATION =
`${LS_BASE_URL}:findPickupPointsForLocation?key=${LS_API_KEY}`;
const API_URL_NEARBY_PLACES =
`${LS_BASE_URL}:findNearbyPlaces?key=${LS_API_KEY}`;
const FORM_ID_PUPS_FOR_LOCATION = 'form-pups-for-location';
const FORM_ID_PUPS_FOR_PLACE = 'form-pups-for-place';
const FORM_ID_NEARBY_PLACES = 'form-nearby-places';
const FORM_TO_API_URL_MAP = {
[FORM_ID_PUPS_FOR_LOCATION]: API_URL_PUPS_FOR_LOCATION,
[FORM_ID_PUPS_FOR_PLACE]: API_URL_PUPS_FOR_PLACE,
[FORM_ID_NEARBY_PLACES]: API_URL_NEARBY_PLACES,
};
const RED_PIN = 'http://maps.google.com/mapfiles/ms/icons/red-dot.png';
const GREEN_PIN = 'http://maps.google.com/mapfiles/ms/icons/green-dot.png';
const BLUE_PIN = 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png';
const DEFAULT_ZOOM_LEVEL = 18;
// codepoint from https://fonts.google.com/icons
const SEARCH_LOCATION_MARKER = '\ue7f2';
const GOOGLEPLEX = {
lat: 37.422001,
lng: -122.084061
};
let map;
let polyLines = [];
let polygons = [];
let mapMarkers = [];
let entranceMarkers = [];
function loadMap() {
const script = document.createElement('script');
script.src = MAPS_URL;
document.body.appendChild(script);
}
function initMap() {
map = new google.maps.Map(
document.getElementById('map'),
{center: GOOGLEPLEX, zoom: DEFAULT_ZOOM_LEVEL});
}
function setupForm() {
const form = document.getElementsByTagName('form')[0];
form.addEventListener('submit', onFormSubmit);
}
function onFormSubmit(evt) {
evt.preventDefault();
evt.stopPropagation();
const formData = new FormData(evt.target);
fetchAPIResults(formData);
}
function transformFormData(fd) {
let transformedFd = {
localizationPreferences: {},
};
const formId = document.getElementsByTagName('form')[0].id;
if (formId === FORM_ID_PUPS_FOR_LOCATION ||
formId === FORM_ID_PUPS_FOR_PLACE) {
transformedFd = {localizationPreferences: {}, travelModes: []};
}
const addSearchLocation = () => {
if (transformedFd.searchLocation == null) {
transformedFd.searchLocation = {};
}
};
const addDestination = () => {
if (transformedFd.destination == null) {
transformedFd.destination = {};
}
};
fd.forEach((value, key) => {
switch (key) {
case 'travelModes':
transformedFd.travelModes.push(value);
break;
case 'languageCode':
transformedFd.localizationPreferences[key] = value;
break;
case 'regionCode':
transformedFd.localizationPreferences[key] = value;
break;
case 'searchLocation-latitude':
if (value) {
addSearchLocation();
transformedFd.searchLocation['latitude'] = value;
}
break;
case 'searchLocation-longitude':
if (value) {
addSearchLocation();
transformedFd.searchLocation['longitude'] = value;
}
break;
case 'destination-latitude':
if (value) {
addDestination();
transformedFd.destination['latitude'] = value;
}
break;
case 'destination-longitude':
if (value) {
addDestination();
transformedFd.destination['longitude'] = value;
}
break;
default:
transformedFd[key] = value;
break;
}
});
const json = JSON.stringify(transformedFd, undefined, 2);
return json;
}
async function fetchAPIResults(fd) {
const formId = document.getElementsByTagName('form')[0].id;
const url = FORM_TO_API_URL_MAP[formId];
const transformedFd = transformFormData(fd);
const response = await fetch(url, {method: 'POST', body: transformedFd});
const result = await response.json();
// Display JSON
displayAPIResults(result);
// Update map
let searchLocation = {};
if (JSON.parse(transformedFd).searchLocation) {
searchLocation = {
lat: Number(JSON.parse(transformedFd).searchLocation.latitude),
lng: Number(JSON.parse(transformedFd).searchLocation.longitude),
};
}
switch (formId) {
case FORM_ID_PUPS_FOR_PLACE:
markPickupPointsForPlace(result);
break;
case FORM_ID_PUPS_FOR_LOCATION:
markPickupPointsForLocation(result, searchLocation);
break;
case FORM_ID_NEARBY_PLACES:
markNearbyPlaces(result, searchLocation);
break;
default:
break;
}
}
function displayAPIResults(data) {
const output = document.getElementById('output');
output.textContent = JSON.stringify(data, undefined, 2);
}
function markNearbyPlaces(data, searchLocation) {
if (data.error) {
resetMap();
return;
}
const places = [];
for (const placeResult of data.placeResults) {
places.push(placeResult.place);
}
resetMap(searchLocation);
markPlaces(places, searchLocation);
for (const place of places) {
markEntrances(place.associatedCompounds, place);
}
markSearchLocation(searchLocation, '');
for (const place of places) {
mapPolygons(place.associatedCompounds);
}
}
function markPickupPointsForPlace(data) {
if (data.error) {
resetMap();
return;
}
const place = data.placeResult.place;
const pickupPoints = data.pickupPointResults;
const searchLocation = {
lat: place.geometry.location.latitude,
lng: place.geometry.location.longitude
};
resetMap(searchLocation);
markPickupPoints(place, pickupPoints, searchLocation);
markEntrances(place.associatedCompounds, place);
markSearchLocation(searchLocation, place.displayName);
createPolyLinesOneToMany(searchLocation, pickupPoints);
mapPolygons(place.associatedCompounds);
}
function markPickupPointsForLocation(data, searchLocation) {
if (data.error) {
resetMap();
return;
}
const placeIdToPlace = {};
// A dict, and the key is placeId(str)s and the value is a list of pups.
const placePickupPoints = {};
data.placeResults.forEach(result => {
placeIdToPlace[result.place.placeId] = result.place;
placePickupPoints[result.place.placeId] = [];
});
data.placePickupPointResults.forEach(result => {
placePickupPoints[result.associatedPlaceId].push(result.pickupPointResult);
})
resetMap(searchLocation);
for (const placeId in placePickupPoints) {
const place = placeIdToPlace[placeId];
const pups = placePickupPoints[placeId];
markEntrances(place.associatedCompounds, place);
markPickupPoints(place, pups, searchLocation);
createPolyLinesOneToMany(searchLocation, pups);
mapPolygons(place.associatedCompounds);
}
// update the marker rank to global order
for (let i = 0; i < mapMarkers.length; i++) {
mapMarkers[i].label = String(i);
}
markSearchLocation(searchLocation, '');
}
function markPlaces(places, searchLocation) {
for (const place of places) {
const placeLocation = place.geometry.location;
const infoWindow =
new google.maps.InfoWindow({content: createInfoWindow(place, null)});
const marker = new google.maps.Marker({
position: toLatLngLiteral(placeLocation),
animation: google.maps.Animation.DROP,
map: map,
});
marker.addListener('click', () => {
infoWindow.open(map, marker);
});
map.addListener('click', () => {
infoWindow.close();
});
mapMarkers.push(marker);
}
}
function markEntrances(compounds, place) {
if (!compounds) {
return;
}
for (const compound of compounds) {
if (!compound.entrances) {
continue;
}
for (const entrance of compound.entrances) {
const entranceMarker = new google.maps.Marker({
position: toLatLngLiteral(entrance.location),
icon: {
url: BLUE_PIN,
},
animation: google.maps.Animation.DROP,
map: map,
});
const infoWindow =
new google.maps.InfoWindow({content: createInfoWindow(place, null)});
entranceMarker.addListener('click', () => {
infoWindow.open(map, entranceMarker);
});
map.addListener('click', () => {
infoWindow.close();
});
entranceMarkers.push(entranceMarker);
}
}
}
function mapPolygons(many) {
if (!many) {
return;
}
for (const toPoint of many) {
const data = toPoint.geometry.displayBoundary;
if (data == null || data.coordinates == null) {
continue;
}
const value = data.coordinates;
const polyArray = JSON.parse(JSON.stringify(value))[0];
const usedColors = [];
const finalLatLngs = [];
let color = '';
for (let i = 0; i < polyArray.length; ++i) {
if (polyArray[i] != null && polyArray[i].length > 0) {
color = getColor(usedColors);
usedColors.push(color);
if (isArrLatLng(polyArray[i])) {
finalLatLngs.push({lat: polyArray[i][1], lng: polyArray[i][0]});
}
}
}
const poly = new google.maps.Polygon({
strokeColor: color,
strokeOpacity: 0.2,
strokeWeight: 5,
fillColor: color,
fillOpacity: 0.1,
paths: finalLatLngs,
map: map,
});
polygons.push(poly);
}
}
function getColor(usedColors) {
let color = generateStrokeColor();
while (usedColors.includes(color)) {
color = generateStrokeColor();
}
return color;
}
function generateStrokeColor() {
return Math.floor(Math.random() * 16777215).toString(16);
}
function isArrLatLng(currArr) {
if (!currArr || currArr.length !== 2) {
return false;
}
return ((typeof currArr[0]) === 'number') &&
((typeof currArr[1]) === 'number');
}
function toLatLngLiteral(latlng) {
return {lat: latlng.latitude, lng: latlng.longitude};
}
function pickupHasRestrictions(pickupPointData) {
let hasRestrictions = false;
const travelDetails = pickupPointData.travelDetails;
for (let i = 0; i < travelDetails.length; i++) {
if (travelDetails[i].trafficRestriction !== 'NO_RESTRICTION') {
hasRestrictions = true;
}
}
return hasRestrictions;
}
function markPickupPoints(place, pickupPoints, searchLocation) {
for (let i = 0; i < pickupPoints.length; i++) {
const pickupPointData = pickupPoints[i];
const pickupPoint = pickupPoints[i].pickupPoint;
const pupIcon =
pickupHasRestrictions(pickupPointData) ? RED_PIN : GREEN_PIN;
const contentString = createInfoWindow(place, pickupPoint);
const pupInfoWindow = new google.maps.InfoWindow({content: contentString});
const marker = new google.maps.Marker({
position: toLatLngLiteral(pickupPoint.location),
label: {
text: String(i),
fontWeight: 'bold',
fontSize: '20px',
color: '#000'
},
animation: google.maps.Animation.DROP,
map,
icon: {
url: pupIcon,
anchor: new google.maps.Point(14, 43),
labelOrigin: new google.maps.Point(-5, 5)
},
});
marker.addListener('click', () => {
pupInfoWindow.open(map, marker);
});
map.addListener('click', () => {
pupInfoWindow.close();
});
mapMarkers.push(marker);
}
}
function createInfoWindow(place, pickupPoint) {
let result = [];
const addResult = (value, key, map) =>
result.push(`<p><span class="info-label">${key}:</span> ${value}</p>`);
const formatAddress = (address) => address.lines.join(',');
const placeFieldMap = new Map();
if (place !== null) {
placeFieldMap.set('Place', '');
placeFieldMap.set('Name', place.displayName);
placeFieldMap.set('Place ID', place.placeId);
placeFieldMap.set('Address', formatAddress(place.address.formattedAddress));
}
const pickupPointFieldMap = new Map();
if (pickupPoint !== null) {
pickupPointFieldMap.set('Pickup point', '');
pickupPointFieldMap.set('Name', pickupPoint.displayName);
}
placeFieldMap.forEach(addResult);
result.push('<hr/>');
pickupPointFieldMap.forEach(addResult);
return result.join('');
}
function markSearchLocation(location, label) {
const infoWindow =
new google.maps.InfoWindow({content: `<p><b>Name: </b>${label}</p>`});
const marker = new google.maps.Marker({
position: location,
map,
label: {
text: SEARCH_LOCATION_MARKER,
fontFamily: 'Material Icons',
color: '#ffffff',
fontSize: '18px',
fontWeight: 'bold',
},
});
marker.addListener('click', () => {
infoWindow.open(map, marker);
});
map.addListener('click', () => {
infoWindow.close();
});
mapMarkers.push(marker);
}
function createPolyLinesOneToMany(one, many) {
const lineSymbol = {
path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
};
for (const toPoint of many) {
const line = new google.maps.Polyline({
path: [one, toLatLngLiteral(toPoint.pickupPoint.location)],
icons: [
{
icon: lineSymbol,
offset: '100%',
},
],
map: map,
});
polyLines.push(line);
}
}
/******* Reset the map ******/
function deleteMarkers() {
for (const mapMarker of mapMarkers) {
mapMarker.setMap(null);
}
mapMarkers = [];
}
function deletePolyLines() {
for (const polyLine of polyLines) {
polyLine.setMap(null);
}
polyLines = [];
}
function deleteEntranceMarkers() {
for (const entranceMarker of entranceMarkers) {
entranceMarker.setMap(null);
}
entranceMarkers = [];
}
function clearPolygons() {
for (let i = 0; i < polygons.length; i++) {
polygons[i].setMap(null);
}
polygons = [];
}
function resetMap(searchLocation) {
if (searchLocation) {
map.setCenter(searchLocation);
} else {
map.setCenter(GOOGLEPLEX);
}
map.setZoom(DEFAULT_ZOOM_LEVEL);
deleteMarkers();
deletePolyLines();
deleteEntranceMarkers();
clearPolygons();
}
// Initiate map & set form event handlers
loadMap();
setupForm();
לפני שמשתמשים ב-Location Selection API כדי לחפש נקודות איסוף לנסיעה, צריך לפעול לפי ההוראות לשילוב עם ספריית הלקוח.
שירות בחירת המיקום מספק שלושה ממשקי API לבחירת מיקום האיסוף וההחזרה: FindNearbyPlaces, FindPickupPointsForPlace ו-FindPickupPointsForLocation.
אפשר להשתמש ב-FindNearbyPlaces כדי לאתר מקומות בקרבת מקום לחיפוש או למיקום המכשיר. המקומות מדורגים לפי הקרבה למיקום ולפי החשיבות שלהם לשיתוף נסיעות. FindNearbyPlaces מחזירה רשימה של מקומות שאפשר להציג כדי לאפשר למשתמש לבחור את האפשרות הטובה ביותר. אחרי שבוחרים מקום, משתמשים ב-FindPickupPointsForPlace כדי לאחזר נקודות איסוף למקום שנבחר.
אפשר להשתמש ב-FindPickupPointsForLocation כדי לאחזר מקומות ונקודות איסוף משויכות בקרבת המיקום של החיפוש או המכשיר באותה קריאת RPC.
כל נקודת איסוף משויכת למקום. נקודות האיסוף מדורגות לפי הקרבה למיקום ולפי מידת הבולטות שלהן לשיתוף נסיעות. חשוב לזכור שנקודות איסוף של כמה מקומות מוצגות יחד. FindPickupPointsForLocation משלב בין FindNearbyPlaces לבין FindPickupPointsForPlace. לדוגמה, נניח שהבקשה היא למצוא מיקום ליד המקומות P1, P2 ו-P3. אם נקודת האיסוף הכי טובה T1 משויכת למקום P2, ונקודת האיסוף הבאה הכי טובה משויכת למקום P1, התוצאות יוצגו בסדר הבא: [T1:P2, T2:P1, ...].
אם אתם מעדיפים להציג למשתמש מקומות לפני שהוא בוחר נקודות איסוף, או להציג מקומות סמוכים על ידי גרירת סיכה, אתם יכולים להשתמש בקריאת ה-RPC הבאה:
FindNearbyPlacesRequest find_nearby_places_request =
FindNearbyPlacesRequest.newBuilder()
.setLocalizationPreferences(LocalizationPreferences.newBuilder()
// Language used for localizing text such as name or address.
.setLanguageCode("en")
.setRegionCode("US")
.build())
// Rider's location or location of dragged pin.
.setSearchLocation(LatLng.newBuilder().setLatitude(37.365647).setLongitude(-121.925356))
// Number of places requested.
.setMaxResults(3)
.build();
FindNearbyPlacesResponse findNearbyPlacesResponse =
locationSelectionBetaClient.findNearbyPlaces(find_nearby_places_request);
הקריאה לשירות מרוחק (RPC) מחזירה רשימה מדורגת של תשובות לגבי מקומות שעומדות בקריטריונים של הקלט, מסודרות לפי שילוב של קרבה ובולטות. אתם יכולים לאפשר לנוסע לבחור מקום או להשתמש בתוצאה הראשונה ולהמשיך לבחירת נקודת האיסוף. לכל תגובה של מקום יש מזהה ייחודי place_id שאפשר להשתמש בו בבקשת FindPickupPointsForPlaceRequest כדי לאחזר נקודות איסוף. מידע נוסף זמין במאמר חיפוש לפי מזהה מקום.
FindPickupPointsForLocationRequest FindPickupPointsForLocationRequest =
FindPickupPointsForLocationRequest.newBuilder()
// Language used for localizing text such as name and address.
.setLocalizationPreferences(LocalizationPreferences.newBuilder().setRegionCode("US").setLanguageCode("en"))
// The search location of the rider or the dropped pin.
.setSearchLocation(LatLng.newBuilder().setLatitude(-23.482049).setLongitude(-46.602135))
// The max results returned.
.setMaxResults(5)
// List of travel modes. At least one of the travel modes must be supported by the pickup points.
.addTravelModes(TravelMode.DRIVING)
// Specifies the sorting order of matching pickup points.
.setOrderBy(PickupPointOrder.DISTANCE_FROM_SEARCH_LOCATION)
.build();
FindPickupPointsForLocationResponse FindPickupPointsForLocationResponse =
locationSelectionService.FindPickupPointsForLocation(
RpcClientContext.create(), FindPickupPointsForLocationRequest);
הקריאה לשירות מרוחק (RPC) מחזירה רשימה מדורגת של נקודות איסוף שעומדות בקריטריונים של הקלט, מסודרת לפי שילוב של קרבה ובולטות. קריאת ה-RPC הזו
משלבת בין FindNearbyPlaces לבין FindPickupPointsForPlaceRequest ואפשר להשתמש בה במקום לשלב בין שתי הקריאות האחרות.
חיפוש לפי מזהה מקום
אפשר לקבל place_id באמצעות FindNearbyPlaces או באמצעות שירות ההשלמה האוטומטית של Places API. לאחר מכן, משתמשים בקריאת ה-RPC הבאה כדי לספק נקודות איסוף אופטימליות למקום שצוין:
FindPickupPointsForPlaceRequest findPickupPointsForPlaceRequest =
FindPickupPointsForPlaceRequest.newBuilder()
// Language used for localizing text such as name and address.
.setLocalizationPreferences(LocalizationPreferences.newBuilder().setRegionCode("US").setLanguageCode("en"))
// Place ID of the place for which pickup points are being fetched;
// for example, Hilton Hotel, Downtown San Jose.
.setPlaceId("ChIJwTUa-q_Mj4ARff4yludGH-M")
// List of travel modes. At least one of the travel modes must be supported by the pickup points.
.addTravelModes(TravelMode.DRIVING)
// Rider's location or location of dragged pin.
// It is recommended to use the same location that was used in `FindNearbyPlaces` for better quality.
.setSearchLocation(LatLng.newBuilder().setLatitude(37.329472).setLongitude(-121.890449))
.setOrderBy(PickupPointOrder.DISTANCE_FROM_SEARCH_LOCATION)
.setMaxResults(5)
.build();
FindPickupPointsForPlaceResponse findPickupPointsForPlaceResponse =
locationSelectionBetaClient.findPickupPointsForPlace(findPickupPointsForPlaceRequest);
FindPickupPointsForPlace מחזירה את PickupPointResponses עם קווי הרוחב והאורך של הנקודות שבהן אפשר לאסוף את הנוסע.
אופטימיזציה של איסופים למספר נסיעות
בנסיעות משותפות או בנסיעות רצופות, FindPickupPointsForPlace תומך בהזמנת נקודות איסוף לפי DRIVING_ETA_FROM_PICKUP_POINT_TO_DESTINATION. כך תוכלו להחזיר נקודת איסוף לנסיעה הבאה שעברה אופטימיזציה עם מסלול הנסיעה הנוכחי של הנהג.
דוגמה
FindPickupPointsForPlaceRequest findPickupPointsForPlaceRequest =
FindPickupPointsForPlaceRequest.newBuilder()
// Language used for localizing text such as name and address.
.setLocalizationPreferences(LocalizationPreferences.newBuilder().setRegionCode("US").setLanguageCode("en"))
// Place ID of the place for which pickup points are being fetched;
// for example, Hilton Hotel, Downtown San Jose.
.setPlaceId("ChIJwTUa-q_Mj4ARff4yludGH-M")
// List of travel modes. At least one of the travel modes must be supported by the pickup points.
.addTravelModes(TravelMode.DRIVING)
// Second rider's location or location of dragged pin.
.setSearchLocation(LatLng.newBuilder().setLatitude(37.329472).setLongitude(-121.890449))
// Location of the driver's next drop off after picking up the second
// rider. Note, it is not necessarily the second rider's destination.
.setDestination(LatLng.newBuilder().setLatitude(37.329472).setLongitude(-121.890449))
.setOrderBy(PickupPointOrder.DRIVING_ETA_FROM_PICKUP_POINT_TO_DESTINATION)
.setComputeDrivingEta(true)
.setMaxResults(5)
.build();
FindPickupPointsForPlaceResponse findPickupPointsForPlaceResponse =
locationSelectionBetaClient.findPickupPointsForPlace(findPickupPointsForPlaceRequest);
הצגת קווי המתאר של הבניין, הכניסות והיציאות
בהודעת התגובה של פרוטוקול המקום, השדה associatedCompounds מציין את המתחמים שמשויכים למקום. ההודעה המורכבת
כוללת שלושה סוגי מידע:
סוג התרכובת – אחת מארבע אפשרויות
compoundBuilding – בניין עצמאי יחיד, כמו קניון או סופרמרקט.
compoundSection – מתחם בתוך מתחם גדול יותר, כמו חנות בודדת בקניון.
compoundGrounds – כל מה שמשויך ל-compoundBuilding, כמו קניון, החניון שלו וכל בניין אחר שנמצא בתוך החניון הזה.
unrecognized – ערך ברירת המחדל
גיאומטריה – הקואורדינטות של הפוליגון המתווה, שמאוחסנות במבנה GeoJSON בשדה displayBoundary. הקואורדינטות האלה משמשות ליצירת המתאר של החלק, הבניין או השטח.
כניסות – קואורדינטות קו הרוחב וקו האורך של כל הכניסות
והיציאות שמופיעות במיקום.
הפונקציה Location Selection מחזירה כל סוג מורכב שמשויך למיקום החיפוש. אם מיקום החיפוש הוא בחנות מסוימת בקניון, התכונה 'בחירת מיקום' תחזיר:
* את החנות הספציפית, את הכניסות והיציאות שלה ואת המתאר שלה
* את הבניין המורכב (הקניון), את הכניסות והיציאות שלו ואת המתאר שלו
* את השטח המורכב (הקניון + החניון), את הכניסות והיציאות שלו ואת המתאר של כל השטח
בתמונה הזו מוצגים כל שלושת הסוגים המורכבים שמוחזרים.
תמונה שמציגה כמה מיקומים בתוך שדה תעופה, עם הגבול של בניין בתוך שדה התעופה ועם הגבול של שדה התעופה וכל השטחים שקשורים אליו.
[[["התוכן קל להבנה","easyToUnderstand","thumb-up"],["התוכן עזר לי לפתור בעיה","solvedMyProblem","thumb-up"],["סיבה אחרת","otherUp","thumb-up"]],[["חסרים לי מידע או פרטים","missingTheInformationINeed","thumb-down"],["התוכן מורכב מדי או עם יותר מדי שלבים","tooComplicatedTooManySteps","thumb-down"],["התוכן לא עדכני","outOfDate","thumb-down"],["בעיה בתרגום","translationIssue","thumb-down"],["בעיה בדוגמאות/בקוד","samplesCodeIssue","thumb-down"],["סיבה אחרת","otherDown","thumb-down"]],["עדכון אחרון: 2025-10-23 (שעון UTC)."],[],["This application uses Google Maps and Location Selection APIs to display location data. Users input details like `placeId`, language/region codes, and coordinates to find pickup points. The form data is transformed into JSON and sent to the APIs. Results are displayed both as raw JSON and visually on a map. The map shows markers for places, pickup points, entrances, and polylines connecting locations and polygons for compound boundaries. Users can interact with markers to view info windows. It uses javascript functions for each action in order to process and display the results.\n"]]