جستجوی نقاط وانت سواری با استفاده از انتخاب مکان (بتا)

        <html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Location Selection Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  </head>
  <body>
  <h1>Location Selection Demo - FindPickupPointsForPlace</h1>
  <div class="container">
    <section class="form-container">
      <form id="form-pups-for-place" name="location-selection">
        <label class="form-label" for="placeId">Place ID</label>
        <input type="text" id="placeId" name="placeId" value="ChIJwTUa-q_Mj4ARff4yludGH-M" />

        <label class="form-label" for="languageCode">Language Code</label>
        <input type="text" id="languageCode" name="languageCode" value="en-US" />

        <label class="form-label" for="regionCode">Region Code</label>
        <input type="text" id="regionCode" name="regionCode" value="US" />

        <label class="form-label" for="searchLocation-latitude">Search Location - Latitude</label>
        <input type="text" id="searchLocation-latitude" name="searchLocation-latitude" value="37.329472" />

        <label class="form-label" for="searchLocation-longitude">Search Location - Longitude</label>
        <input type="text" id="searchLocation-longitude" name="searchLocation-longitude" value="-121.890449" />

        <label class="form-label" for="orderBy">Order By</label>
        <select id="orderBy" name="orderBy">
          <option value="DISTANCE_FROM_SEARCH_LOCATION" selected>DISTANCE_FROM_SEARCH_LOCATION</option>
          <option value="WALKING_ETA_FROM_SEARCH_LOCATION">WALKING_ETA_FROM_SEARCH_LOCATION</option>
          <option value="DRIVING_ETA_FROM_PICKUP_POINT_TO_DESTINATION">DRIVING_ETA_FROM_PICKUP_POINT_TO_DESTINATION</option>
        </select>

        <label class="form-label" for="destination-latitude">Destination - Latitude</label>
        <input type="text" id="destination-latitude" name="destination-latitude" value="" />

        <label class="form-label" for="destination-longitude">Destination - Longitude</label>
        <input type="text" id="destination-longitude" name="destination-longitude" value="" />

        <label class="form-label" for="maxResults">Max Results</label>
        <input type="number" id="maxResults" name="maxResults" min="1" value="5" step="1" />

        <fieldset>
          <legend>Travel Modes</legend>
          <div>
            <input type="checkbox" id="walking" name="travelModes" value="WALKING" checked>
            <label for="walking" class="form-checkbox-label">WALKING</label>
          </div>
          <div>
            <input type="checkbox" id="driving" name="travelModes" value="DRIVING" checked>
            <label for="driving" class="form-checkbox-label">DRIVING</label>
          </div>
          <div>
            <input type="checkbox" id="twoWheeler" name="travelModes" value="TWO_WHEELER">
            <label for="twoWheeler" class="form-checkbox-label">TWO_WHEELER</label>
          </div>
        </fieldset>

        <label class="form-label" for="computeWalkingEta">Compute Walking ETA</label>
        <select id="computeWalkingEta" name="computeWalkingEta" class="boolean">
          <option value="true">true</option>
          <option value="false" selected>false</option>
        </select>

        <label class="form-label" for="computeDrivingEta">Compute Driving ETA</label>
        <select id="computeDrivingEta" name="computeDrivingEta" class="boolean">
          <option value="true">true</option>
          <option value="false" selected>false</option>
        </select>

        <input class="submit-button" type="submit" value="Call" />
      </form>
    </section>
    <section>
      <div id="map" class="map"></div>
    </section>
  </div>
  <section class="output-container">
    <h2>Response</h2>
    <pre id="output"></pre>
  </section>
  </body>
  </html>
    
        body {
    font-family: 'Google Sans';
}

.container {
    display: grid;
    grid-template-columns: 30% 1fr;
    grid-template-rows: 100%;
    grid-column-gap: 20px;
    grid-row-gap: 0px;
}

h1 {
    font-size: 24px;
    margin-top: 20px;
    margin-bottom: 20px;
    font-weight: bold;
}

h2 {
    font-size: 18px;
    font-weight: bold;
}

h1,
.form-container,
.output-container {
    margin-left: 20px;
}

.map,
.output-container {
    margin-right: 20px;
}

.form-container {
    border: 1px solid black;
    padding: 20px;
}

.map {
    border: 1px solid black;
    min-height: 800px;
}

.output-container {
    margin-top: 20px;
}

#output {
    border: 1px solid red;
    font-family: 'Google Sans';
    min-height: 150px;
}


label:not(.form-checkbox-label), legend {
    overflow-wrap: break-word;
    font-weight: bold;
}

input:not([type="checkbox"]), select, fieldset {
    font-family: 'Google Sans';
    width: 100%;
    padding: 5px 5px;
    margin: 0 0 20px 0;
    display: inline-block;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-sizing: border-box;
}


input[type="submit"] {
    min-width: 150px;
    background-color: green; /* Blue */
    border: none;
    color: white;
    padding: 15px 15px;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    border-radius: 20px;
    width: 50%;
}

input[type="submit"]:hover {
    background-color: darkseagreen;
}

input[type="submit"]:active {
    background-color: darkseagreen;
    box-shadow: 0 5px #666;
    transform: translateY(4px);
}

.info-label {
    font-weight: bold;
}

    
        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();


    
        <html lang="en">
<head>
  <meta charset="utf-8">
  <title>Location Selection Demo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<h1>Location Selection Demo - FindPickupPointsForLocation</h1>
<div class="container">
  <section class="form-container">
    <form id="form-pups-for-location" name="location-selection">

      <label class="form-label" for="languageCode">Language Code</label>
      <input type="text" id="languageCode" name="languageCode" value="en-US" />

      <label class="form-label" for="regionCode">Region Code</label>
      <input type="text" id="regionCode" name="regionCode" value="US" />

      <label class="form-label" for="searchLocation-latitude">Search Location - Latitude</label>
      <input type="text" id="searchLocation-latitude" name="searchLocation-latitude" value="-23.482049" />

      <label class="form-label" for="searchLocation-longitude">Search Location - Longitude</label>
      <input type="text" id="searchLocation-longitude" name="searchLocation-longitude" value="-46.602135" />

      <label class="form-label" for="orderBy">Order By</label>
      <select id="orderBy" name="orderBy">
        <option value="DISTANCE_FROM_SEARCH_LOCATION" selected>DISTANCE_FROM_SEARCH_LOCATION</option>
        <option value="WALKING_ETA_FROM_SEARCH_LOCATION">WALKING_ETA_FROM_SEARCH_LOCATION</option>
        <option value="DRIVING_ETA_FROM_PICKUP_POINT_TO_DESTINATION">DRIVING_ETA_FROM_PICKUP_POINT_TO_DESTINATION</option>
      </select>

      <label class="form-label" for="destination-latitude">Destination - Latitude</label>
      <input type="text" id="destination-latitude" name="destination-latitude" value="" />

      <label class="form-label" for="destination-longitude">Destination - Longitude</label>
      <input type="text" id="destination-longitude" name="destination-longitude" value="" />

      <label class="form-label" for="maxResults">Max Results</label>
      <input type="number" id="maxResults" name="maxResults" min="1" value="5" step="1" />

      <fieldset>
        <legend>Travel Modes</legend>
        <div>
          <input type="checkbox" id="walking" name="travelModes" value="WALKING" checked>
          <label for="walking" class="form-checkbox-label">WALKING</label>
        </div>
        <div>
          <input type="checkbox" id="driving" name="travelModes" value="DRIVING" checked>
          <label for="driving" class="form-checkbox-label">DRIVING</label>
        </div>
        <div>
          <input type="checkbox" id="twoWheeler" name="travelModes" value="TWO_WHEELER">
          <label for="twoWheeler" class="form-checkbox-label">TWO_WHEELER</label>
        </div>
      </fieldset>

      <label class="form-label" for="computeWalkingEta">Compute Walking ETA</label>
      <select id="computeWalkingEta" name="computeWalkingEta" class="boolean">
        <option value="true">true</option>
        <option value="false" selected>false</option>
      </select>

      <label class="form-label" for="computeDrivingEta">Compute Driving ETA</label>
      <select id="computeDrivingEta" name="computeDrivingEta" class="boolean">
        <option value="true">true</option>
        <option value="false" selected>false</option>
      </select>

      <input class="submit-button" type="submit" value="Call" />
    </form>
  </section>
  <section>
    <div id="map" class="map"></div>
  </section>
</div>
<section class="output-container">
  <h2>Response</h2>
  <pre id="output"></pre>
</section>
</body>
</html>
    
        body {
    font-family: 'Google Sans';
}

.container {
    display: grid;
    grid-template-columns: 30% 1fr;
    grid-template-rows: 100%;
    grid-column-gap: 20px;
    grid-row-gap: 0px;
}

h1 {
    font-size: 24px;
    margin-top: 20px;
    margin-bottom: 20px;
    font-weight: bold;
}

h2 {
    font-size: 18px;
    font-weight: bold;
}

h1,
.form-container,
.output-container {
    margin-left: 20px;
}

.map,
.output-container {
    margin-right: 20px;
}

.form-container {
    border: 1px solid black;
    padding: 20px;
}

.map {
    border: 1px solid black;
    min-height: 800px;
}

.output-container {
    margin-top: 20px;
}

#output {
    border: 1px solid red;
    font-family: 'Google Sans';
    min-height: 150px;
}


label:not(.form-checkbox-label), legend {
    overflow-wrap: break-word;
    font-weight: bold;
}

input:not([type="checkbox"]), select, fieldset {
    font-family: 'Google Sans';
    width: 100%;
    padding: 5px 5px;
    margin: 0 0 20px 0;
    display: inline-block;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-sizing: border-box;
}


input[type="submit"] {
    min-width: 150px;
    background-color: green; /* Blue */
    border: none;
    color: white;
    padding: 15px 15px;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    border-radius: 20px;
    width: 50%;
}

input[type="submit"]:hover {
    background-color: darkseagreen;
}

input[type="submit"]:active {
    background-color: darkseagreen;
    box-shadow: 0 5px #666;
    transform: translateY(4px);
}

.info-label {
    font-weight: bold;
}

    
        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();


    
        <html lang="en">
<head>
  <meta charset="utf-8">
  <title>Location Selection Demo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<h1>Location Selection Demo - FindNearbyPlaces</h1>
<div class="container">
  <section class="form-container">
    <form id="form-nearby-places" name="location-selection">
      <label class="form-label" for="languageCode">Language Code</label>
      <input type="text" id="languageCode" name="languageCode" value="en-US" />

      <label class="form-label" for="regionCode">Region Code</label>
      <input type="text" id="regionCode" name="regionCode" value="US" />

      <label class="form-label" for="searchLocation-latitude">Search Location - Latitude</label>
      <input type="text" id="searchLocation-latitude" name="searchLocation-latitude" value="37.365647" />

      <label class="form-label" for="searchLocation-longitude">Search Location - Longitude</label>
      <input type="text" id="searchLocation-longitude" name="searchLocation-longitude" value="-121.925356" />

      <label class="form-label" for="maxResults">Max Results</label>
      <input type="number" id="maxResults" name="maxResults" min="1" value="5" step="1" />
      <input class="submit-button" type="submit" value="Call" />
    </form>
  </section>
  <section>
    <div id="map" class="map"></div>
  </section>
</div>
<section class="output-container">
  <h2>Response</h2>
  <pre id="output"></pre>
</section>
</body>
</html>
    
        body {
    font-family: 'Google Sans';
}

.container {
    display: grid;
    grid-template-columns: 30% 1fr;
    grid-template-rows: 100%;
    grid-column-gap: 20px;
    grid-row-gap: 0px;
}

h1 {
    font-size: 24px;
    margin-top: 20px;
    margin-bottom: 20px;
    font-weight: bold;
}

h2 {
    font-size: 18px;
    font-weight: bold;
}

h1,
.form-container,
.output-container {
    margin-left: 20px;
}

.map,
.output-container {
    margin-right: 20px;
}

.form-container {
    border: 1px solid black;
    padding: 20px;
}

.map {
    border: 1px solid black;
    min-height: 800px;
}

.output-container {
    margin-top: 20px;
}

#output {
    border: 1px solid red;
    font-family: 'Google Sans';
    min-height: 150px;
}


label:not(.form-checkbox-label), legend {
    overflow-wrap: break-word;
    font-weight: bold;
}

input:not([type="checkbox"]), select, fieldset {
    font-family: 'Google Sans';
    width: 100%;
    padding: 5px 5px;
    margin: 0 0 20px 0;
    display: inline-block;
    border: 1px solid #ccc;
    border-radius: 8px;
    box-sizing: border-box;
}


input[type="submit"] {
    min-width: 150px;
    background-color: green; /* Blue */
    border: none;
    color: white;
    padding: 15px 15px;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    border-radius: 20px;
    width: 50%;
}

input[type="submit"]:hover {
    background-color: darkseagreen;
}

input[type="submit"]:active {
    background-color: darkseagreen;
    box-shadow: 0 5px #666;
    transform: translateY(4px);
}

.info-label {
    font-weight: bold;
}

    
        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 برای جستجوی نقاط وانت سواری، دستورالعمل‌های اینجا را دنبال کنید تا با کتابخانه مشتری یکپارچه شوید.

سرویس Location Selection سه 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 را ترکیب می کند و می تواند به جای ترکیب دو تماس دیگر استفاده شود.

جستجو بر اساس شناسه مکان

می توانید با استفاده از FindNearbyPlaces یا با استفاده از سرویس تکمیل خودکار Places API یک place_id دریافت کنید. سپس از فراخوانی 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 را با lat/lngs برای نقاطی که می‌توان سوار را سوار کرد، برمی‌گرداند.

بهینه سازی پیکاپ ها برای سفرهای متعدد

برای سواری مشترک یا پشت سر هم، 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: * فروشگاه خاص، ورودی ها و خروجی های آن، و طرح کلی فروشگاه * ساختمان مرکب (مرکز خرید)، ورودی ها و خروجی های آن، و طرح کلی را برمی گرداند. مرکز خرید * محوطه مرکب (مرکز خرید + پارکینگ)، ورودی و خروجی آنها و طرح کلی کل محوطه

این تصویر هر سه نوع ترکیب را نشان می دهد که برگردانده شده اند.

این تصویر چندین مکان را در داخل یک فرودگاه نشان می‌دهد که هم مرز یک ساختمان در داخل فرودگاه و هم مرز فرودگاه و همه محوطه‌های مرتبط با آن است.