Google 标记数组错误 - 选择了错误的标记元素

Google Markers array bug - selecting the wrong marker element

我制作了一个 API 用于在地图上获取电动汽车充电点并创建路线。

如果车辆容量不足以完成行程,路线应自动添加充电点。

我获取了一个 Json 并创建了一个 Marker 对象数组。这很好用。

然后我将它传递给一个循环,该循环应该将所有标记拼接得离起点太远而无法到达,然后另一个循环选择最接近目的地的标记。

出于某种我不明白的原因,虽然数组似乎已被正确修剪,但结果是一个标记就在目的地旁边,完全超出起点的范围。

我正在使用 Google 中的以下库:方向、地理编码、地图 Javascript...

我希望有人能帮助我,因为我完全被困在这里。

编辑(进一步解释:

该程序旨在在行程超过车辆容量(即 220 公里)时添加一个充电中途停留点。 所有符合条件的中途停留点都显示在地图上并推入一个数组(作为标记对象)。 该函数首先拼接所有超过 220 公里的中途停留点。从数组中,然后在另一个循环中,我选择了离目的地最近的中途停留地。 但是,如果您仔细观察路线,您会发现充电中途停留点(B 点)实际上是 550 公里。从出发和 2 公里。从到达。 这个Marker应该已经拼接好了,不在数组里了

function selectMarkerClosestToDestination(vehicle) {
   //Selecting the closest marker to destination as long as it is not out of the vehicle capacity range
   //CURRENTLY BUGGED
   let waypoints = chargingPointsMarkers;

   for (let x = waypoints.length -1; x > 0; x--) {
       if(calculateDistance(waypoints[x], start) > (vehicle.status*vehicle.consumption)){
           console.log(calculateDistance(waypoints[x], start))
           console.log(vehicle.status*vehicle.consumption)
           waypoints.splice(x, 1)
           console.log(waypoints)
       }
   }

   console.log(waypoints)

   for (let x = waypoints.length - 1; x > 0; x--) {
       if (calculateDistance(waypoints[x], end) > (calculateDistance(waypoints[x-1], end))) {
           waypoints.splice(x, 1);
       } else {
           waypoints.splice(x - 1, 1);
       }
   }
   console.log(waypoints)
   return waypoints[0];
}

function calculateDistance(p1, p2) {
   //Uses the Google geometry library to calculate distance between two Markers
   let a = p1.getPosition();
   let b = p2.getPosition();

   let distance = (google.maps.geometry.spherical.computeDistanceBetween(a, b) / 1000).toFixed(2);
   return distance;
}

这是完整代码(代码片段):

let map;
let mapCenter = { lat: 59.428, lng: 24.76};
let start;
let end;
let chargingPointsMarkers = [];
let markerArray = [];
let stopoverMarkers = []
let vehicle1 = {capacity: 33, status: 33, consumption: 6.6666} //1KW = 6.6666 Km; Capacity in KM = status*consumption;

function initMap(listener) {
   //Create the map, the DirectionsService, the DirectionsRenderer and an eventListener for the GO button
   //If I chose to implement a detailed steps display it would also be created here
   const directionsService = new google.maps.DirectionsService();

   const mapOptions = {
       center: mapCenter,
       zoom: 7,
   }
   map = new google.maps.Map(document.getElementById("map"), mapOptions);

   const directionsRenderer = new google.maps.DirectionsRenderer({map: map});

   //const stepDisplay = new google.maps.InfoWindow();

   const geocoder = new google.maps.Geocoder();
   document.getElementById("submit").addEventListener("click", () => {
       launcher(geocoder, directionsRenderer, directionsService);
   });
}


async function launcher(geocoder, directionsRenderer, directionsService){
   //the method is used to be launched by the eventListener
   //it sets up the start and end points, fetches the EV markers and launches the route calculation process though a callback function
   resetMarkers();
   const startEndPointsArray =  await setupRoutingProcess(geocoder);
   await callbackHandler(startEndPointsArray,directionsRenderer,
       directionsService, calculateAndDisplayRoute);
}

function setMapOnAll(map){
   // Sets the map on all markers in the array.
   for (let i = 0; i < markerArray.length; i++) {
       markerArray[i].setMap(map);
   }
}

function clearMarkers() {
   // Removes the markers from the map, but keeps them in the array.
   setMapOnAll(null);
}

function resetMarkers(){
   // Pushes all visible markers to a same array,
   // launches the different reset processes and
   // deletes all markers in the arrays by removing references to them.
   for (let i = 0; i < chargingPointsMarkers.length; i++) {
       markerArray.push(chargingPointsMarkers[i])
   }
   chargingPointsMarkers = [];

   for (let j = 0; j < stopoverMarkers.length; j++) {
           markerArray.push(stopoverMarkers[j])
   }
   stopoverMarkers = [];

   clearMarkers();

   markerArray = []
}

async function setupRoutingProcess(geocoder){
   //launches the setGeocodeAddress method for both start and end points and stores them in an array
   start = await setGeocodeAddress(geocoder, map, "start");
   end = await setGeocodeAddress(geocoder, map, "end");
   let startEndPointsArray = [start];
   startEndPointsArray.push(end);
   return startEndPointsArray;

}

async function setGeocodeAddress(geocoder, resultsMap, elementId) {
   //Retrieve the addresses (strings) from the html text boxes and uses Geocoder to Google Markers objects.
   //it pushes those markers in an array later used to delete the markers on the map
   const address = document.getElementById(elementId).value;
   return new Promise(resolve => geocoder.geocode({address: address},
       (results, status) => {
           if (status === "OK") {
               resultsMap.setCenter(results[0].geometry.location);
               const marker = new google.maps.Marker({
                   map: resultsMap,
                   position: results[0].geometry.location,
                   title: elementId,
               });
               resolve(marker)
               markerArray.push(marker);
           } else {
               alert("Trip Route finder was not successful for the following reason: " + status);
           }
       }));
}

async function callbackHandler (startEndPointsArray,
                               directionsRenderer,
                               directionsService,
                               calculateAndDisplayRoute){
   //
   let jsonChargingPoints = await setChargingStationsMarkers(startEndPointsArray, directionsRenderer,
       directionsService, calculateAndDisplayRoute);


   await createChargerPointMarkers(jsonChargingPoints)

   calculateAndDisplayRoute(
       directionsRenderer,
       directionsService,
       jsonChargingPoints
   );
}

async function setChargingStationsMarkers(startEndPointsArray, directionsRenderer,
                                         directionsService, calculateAndDisplayRoute) {
   //Creates an encoded polyline to be passed as an Url argument to limit the results
   //fetches the EV Charging Points as Json response
   const polyline = await createPolyline(startEndPointsArray);
   const baseUrl = 'https://api.openchargemap.io/v3/poi/?output=json&maxresults=200&includecomments=true';
   const queryUrl = baseUrl + '&polyline=' + polyline + '&distance=50';
   let data  = await fetch(queryUrl)
       .then((response) => response.json())
       .then((data) => {return data})
   return data;
}

async function createPolyline(startEndPointsArray){
   //Creates a polyline and encodes it
   try {
       position = startEndPointsArray[0].getPosition();
       position2 = startEndPointsArray[1].getPosition();
       const initialPath = [position, position2];
       const poly = new google.maps.Polyline({
           path: initialPath,
           strokeColor: '#ff0000',
           strokeOpacity: 0.00001,
           strokeWeight: 0,
       });

       const path = poly.getPath();
       const encodedPath = await google.maps.geometry.encoding.encodePath(path);
       return encodedPath;
   }catch (error){
       throw error ('Failed to create polyline');
   }
}

function createChargerPointMarkers(jsonChargingPoints) {
   //Loop through the Json response and launch the PlaceMarkers function
   for (let x = 0; x < jsonChargingPoints.length; x++) {
       const LatLng = new google.maps.LatLng(parseFloat(jsonChargingPoints[x].AddressInfo.Latitude), parseFloat(jsonChargingPoints[x].AddressInfo.Longitude));
       placeMarker(LatLng);
   }
}

function placeMarker(location) {
   //Convert the Json response elements to Google Markers, places them on the Map and pushes them to an array.
   let marker = new google.maps.Marker({
       position: location,
       map,
       draggable: false,
   });
   chargingPointsMarkers.push(marker)
}

async function calculateAndDisplayRoute(
   directionsRenderer,
   directionsService,
   jsonChargingPoints,
   stepDisplay,
   map) {

   if (!compareVehicleCapacityToDistance(vehicle1, start)) {
       setChargeCheckpoint(vehicle1)
   }

   directionsService.route(setRequest(),
       function (result, status) {
           if (status === "OK") {
               directionsRenderer.setDirections(result);
               // showSteps(result, markerArray, stepDisplay, map);
           } else {
               window.alert("Directions request failed due to " + status);
           }
       });
}

function setRequest(){
   //prepares the request sent to the Directions service
   let stopovers = [];
   for (let x = 0; x < stopoverMarkers.length; x++){
       let latLng = stopoverMarkers[x].getPosition();
       let waypoint = {
           location: latLng,
           stopover: true
       };
       stopovers.push(waypoint)
   }

   const request = {
       origin: start.getPosition(),
       destination: end.getPosition(),
       waypoints: stopovers,
       travelMode: google.maps.TravelMode.DRIVING,
       unitSystem: google.maps.UnitSystem.METRIC
   };
   return request;
}

function compareVehicleCapacityToDistance(vehicle, p1){
   //Checks if the distance to destination is greater than the vehicle capacity
   if (calculateDistance(p1, end) > (vehicle.status*vehicle.consumption)){
       return false
   }return true;
}

function setChargeCheckpoint(vehicle){
   //launches the function selecting the closest marker to destination
   //Setting a marker of the selected marker on the map (might be redundant)
   //Pushes it to markerArray for later deletion (might be redundant)
   //Pushes it to stopoverMarkers to be used by the Directions service to setup a route
   let waypoint = selectMarkerClosestToDestination(vehicle);
   const waypointLocation = waypoint.getPosition();
   const marker = new google.maps.Marker({
       position: waypointLocation,
       stopover: true,
       draggable: false,
       title: "EV charging stopover"
   });
   markerArray.push(marker)
   stopoverMarkers.push(marker)
}



function selectMarkerClosestToDestination(vehicle) {
   //Selecting the closest marker to destination as long as it is not out of the vehicle capacity range
   //CURRENTLY BUGGED
   let waypoints = chargingPointsMarkers;

   for (let x = waypoints.length -1; x > 0; x--) {
       if(calculateDistance(waypoints[x], start) > (vehicle.status*vehicle.consumption)){
           console.log(calculateDistance(waypoints[x], start))
           console.log(vehicle.status*vehicle.consumption)
           waypoints.splice(x, 1)
           console.log(waypoints)
       }
   }

   console.log(waypoints)

   for (let x = waypoints.length - 1; x > 0; x--) {
       if (calculateDistance(waypoints[x], end) > (calculateDistance(waypoints[x-1], end))) {
           waypoints.splice(x, 1);
       } else {
           waypoints.splice(x - 1, 1);
       }
   }
   console.log(waypoints)
   return waypoints[0];
}

function calculateDistance(p1, p2) {
   //Uses the Google geometry library to calculate distance between two Markers
   let a = p1.getPosition();
   let b = p2.getPosition();

   let distance = (google.maps.geometry.spherical.computeDistanceBetween(a, b) / 1000).toFixed(2);
   return distance;
}

function showSteps(directionResult, stepDisplay, map) {
   // For each step, place a marker, and add the text to the marker's infowindow.
   // Also attach the marker to an array so we can keep track of it and remove it
   // when calculating new routes.
   //NOT CURRENTLY IMPLEMENTED/USED
   const myRoute = directionResult.routes[0].legs[0];

   for (let i = 0; i < myRoute.steps.length; i++) {
       const marker = (markerArray[i] =
           markerArray[i] || new google.maps.Marker());
       marker.setMap(map);
       marker.setPosition(myRoute.steps[i].start_location);
       attachInstructionText(
           stepDisplay,
           marker,
           myRoute.steps[i].instructions,
           map
       );
   }
}

function attachInstructionText(stepDisplay, marker, text, map) {
   google.maps.event.addListener(marker, "click", () => {
       // Open an info window when the marker is clicked on, containing the text
       // of the step.
       //NOT CURRENTLY IMPLEMENTED/USED
       stepDisplay.setContent(text);
       stepDisplay.open(map, marker);
   });
}
/* Always set the map height explicitly to define the size of the div
      * element that contains the map. */
#map {
   height: 100%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
   height: 100%;
   margin: 0;
   padding: 0;
}

#floating-panel {
   position: absolute;
   top: 10px;
   left: 25%;
   z-index: 5;
   background-color: #fff;
   padding: 5px;
   border: 1px solid #999;
   text-align: center;
   font-family: "Roboto", "sans-serif";
   line-height: 30px;
   padding-left: 10px;
}

#warnings-panel {
   width: 100%;
   height: 10%;
   text-align: center;
}
<!DOCTYPE html>
<html>
<head>
   <title>EV Trip Route Finder</title>
   <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
   <script
           src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=&v=weekly"
           defer
   ></script>
   <!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="floating-panel" >
   <b>Start: </b>
   <input id="start" type="text" value="Tallinn">
   <b>End: </b>
   <input id="end" type="text" value="Vilnius">
   <input id="submit" type="button" value="GO" />
</div>
<div id="map"></div>
&nbsp;
<div id="warnings-panel"></div>
</body>
</html>

您的代码中只有一个小错误,即在您的 for 循环中您排除了 waypoints 超出车辆容量的内容。

基本上,您正在执行以下操作,如您所见,它不会输出您期望的内容:

const a = [1, 2, 3, 4, 5];

for (let i = a.length - 1; i > 0; i--) {
  console.log(a[i])
}

相反,您想使用 i >= 0 遍历数组中的所有元素:

const a = [1, 2, 3, 4, 5];

for (let i = a.length - 1; i >= 0; i--) {
  console.log(a[i])
}

更改这个语句似乎可以解决问题,因为您没有遍历整个数组,因此您在第一个循环中从开始处的 528 公里处留下了 1 个元素,最终将成为您 select 在第二个循环中(在 selectMarkerClosestToDestination() 函数中)。

let map;
let mapCenter = { lat: 59.428, lng: 24.76};
let start;
let end;
let chargingPointsMarkers = [];
let markerArray = [];
let stopoverMarkers = []
let vehicle1 = {capacity: 33, status: 33, consumption: 6.6666} //1KW = 6.6666 Km; Capacity in KM = status*consumption;

function initMap(listener) {
   //Create the map, the DirectionsService, the DirectionsRenderer and an eventListener for the GO button
   //If I chose to implement a detailed steps display it would also be created here
   const directionsService = new google.maps.DirectionsService();

   const mapOptions = {
       center: mapCenter,
       zoom: 7,
   }
   map = new google.maps.Map(document.getElementById("map"), mapOptions);

   const directionsRenderer = new google.maps.DirectionsRenderer({map: map});

   //const stepDisplay = new google.maps.InfoWindow();

   const geocoder = new google.maps.Geocoder();
   document.getElementById("submit").addEventListener("click", () => {
       launcher(geocoder, directionsRenderer, directionsService);
   });
}


async function launcher(geocoder, directionsRenderer, directionsService){
   //the method is used to be launched by the eventListener
   //it sets up the start and end points, fetches the EV markers and launches the route calculation process though a callback function
   resetMarkers();
   const startEndPointsArray =  await setupRoutingProcess(geocoder);
   await callbackHandler(startEndPointsArray,directionsRenderer,
       directionsService, calculateAndDisplayRoute);
}

function setMapOnAll(map){
   // Sets the map on all markers in the array.
   for (let i = 0; i < markerArray.length; i++) {
       markerArray[i].setMap(map);
   }
}

function clearMarkers() {
   // Removes the markers from the map, but keeps them in the array.
   setMapOnAll(null);
}

function resetMarkers(){
   // Pushes all visible markers to a same array,
   // launches the different reset processes and
   // deletes all markers in the arrays by removing references to them.
   for (let i = 0; i < chargingPointsMarkers.length; i++) {
       markerArray.push(chargingPointsMarkers[i])
   }
   chargingPointsMarkers = [];

   for (let j = 0; j < stopoverMarkers.length; j++) {
           markerArray.push(stopoverMarkers[j])
   }
   stopoverMarkers = [];

   clearMarkers();

   markerArray = []
}

async function setupRoutingProcess(geocoder){
   //launches the setGeocodeAddress method for both start and end points and stores them in an array
   start = await setGeocodeAddress(geocoder, map, "start");
   end = await setGeocodeAddress(geocoder, map, "end");
   let startEndPointsArray = [start];
   startEndPointsArray.push(end);
   return startEndPointsArray;

}

async function setGeocodeAddress(geocoder, resultsMap, elementId) {
   //Retrieve the addresses (strings) from the html text boxes and uses Geocoder to Google Markers objects.
   //it pushes those markers in an array later used to delete the markers on the map
   const address = document.getElementById(elementId).value;
   return new Promise(resolve => geocoder.geocode({address: address},
       (results, status) => {
           if (status === "OK") {
               resultsMap.setCenter(results[0].geometry.location);
               const marker = new google.maps.Marker({
                   map: resultsMap,
                   position: results[0].geometry.location,
                   title: elementId,
               });
               resolve(marker)
               markerArray.push(marker);
           } else {
               alert("Trip Route finder was not successful for the following reason: " + status);
           }
       }));
}

async function callbackHandler (startEndPointsArray,
                               directionsRenderer,
                               directionsService,
                               calculateAndDisplayRoute){
   //
   let jsonChargingPoints = await setChargingStationsMarkers(startEndPointsArray, directionsRenderer,
       directionsService, calculateAndDisplayRoute);


   await createChargerPointMarkers(jsonChargingPoints)

   calculateAndDisplayRoute(
       directionsRenderer,
       directionsService,
       jsonChargingPoints
   );
}

async function setChargingStationsMarkers(startEndPointsArray, directionsRenderer,
                                         directionsService, calculateAndDisplayRoute) {
   //Creates an encoded polyline to be passed as an Url argument to limit the results
   //fetches the EV Charging Points as Json response
   const polyline = await createPolyline(startEndPointsArray);
   const baseUrl = 'https://api.openchargemap.io/v3/poi/?output=json&maxresults=200&includecomments=true';
   const queryUrl = baseUrl + '&polyline=' + polyline + '&distance=50';
   let data  = await fetch(queryUrl)
       .then((response) => response.json())
       .then((data) => {return data})
   return data;
}

async function createPolyline(startEndPointsArray){
   //Creates a polyline and encodes it
   try {
       position = startEndPointsArray[0].getPosition();
       position2 = startEndPointsArray[1].getPosition();
       const initialPath = [position, position2];
       const poly = new google.maps.Polyline({
           path: initialPath,
           strokeColor: '#ff0000',
           strokeOpacity: 0.00001,
           strokeWeight: 0,
       });

       const path = poly.getPath();
       const encodedPath = await google.maps.geometry.encoding.encodePath(path);
       return encodedPath;
   }catch (error){
       throw error ('Failed to create polyline');
   }
}

function createChargerPointMarkers(jsonChargingPoints) {
   //Loop through the Json response and launch the PlaceMarkers function
   for (let x = 0; x < jsonChargingPoints.length; x++) {
       const LatLng = new google.maps.LatLng(parseFloat(jsonChargingPoints[x].AddressInfo.Latitude), parseFloat(jsonChargingPoints[x].AddressInfo.Longitude));
       placeMarker(LatLng);
   }
}

function placeMarker(location) {
   //Convert the Json response elements to Google Markers, places them on the Map and pushes them to an array.
   let marker = new google.maps.Marker({
       position: location,
       map,
       draggable: false,
   });
   chargingPointsMarkers.push(marker)
}

async function calculateAndDisplayRoute(
   directionsRenderer,
   directionsService,
   jsonChargingPoints,
   stepDisplay,
   map) {

   if (!compareVehicleCapacityToDistance(vehicle1, start)) {
       setChargeCheckpoint(vehicle1)
   }

   directionsService.route(setRequest(),
       function (result, status) {
           if (status === "OK") {
               directionsRenderer.setDirections(result);
               // showSteps(result, markerArray, stepDisplay, map);
           } else {
               window.alert("Directions request failed due to " + status);
           }
       });
}

function setRequest(){
   //prepares the request sent to the Directions service
   let stopovers = [];
   for (let x = 0; x < stopoverMarkers.length; x++){
       let latLng = stopoverMarkers[x].getPosition();
       let waypoint = {
           location: latLng,
           stopover: true
       };
       stopovers.push(waypoint)
   }

   const request = {
       origin: start.getPosition(),
       destination: end.getPosition(),
       waypoints: stopovers,
       travelMode: google.maps.TravelMode.DRIVING,
       unitSystem: google.maps.UnitSystem.METRIC
   };
   return request;
}

function compareVehicleCapacityToDistance(vehicle, p1){
   //Checks if the distance to destination is greater than the vehicle capacity
   if (calculateDistance(p1, end) > (vehicle.status*vehicle.consumption)){
       return false
   }return true;
}

function setChargeCheckpoint(vehicle){
   //launches the function selecting the closest marker to destination
   //Setting a marker of the selected marker on the map (might be redundant)
   //Pushes it to markerArray for later deletion (might be redundant)
   //Pushes it to stopoverMarkers to be used by the Directions service to setup a route
   let waypoint = selectMarkerClosestToDestination(vehicle);
   const waypointLocation = waypoint.getPosition();
   const marker = new google.maps.Marker({
       position: waypointLocation,
       stopover: true,
       draggable: false,
       title: "EV charging stopover"
   });
   markerArray.push(marker)
   stopoverMarkers.push(marker)
}



function selectMarkerClosestToDestination(vehicle) {
   //Selecting the closest marker to destination as long as it is not out of the vehicle capacity range
   //CURRENTLY BUGGED
   let waypoints = chargingPointsMarkers;

   for (let x = waypoints.length -1; x >= 0; x--) {
       if(calculateDistance(waypoints[x], start) > (vehicle.status*vehicle.consumption)){
           console.log(calculateDistance(waypoints[x], start))
           console.log(vehicle.status*vehicle.consumption)
           waypoints.splice(x, 1)
           console.log(waypoints)
       }
   }

   console.log(waypoints)

   for (let x = waypoints.length - 1; x > 0; x--) {
       if (calculateDistance(waypoints[x], end) > (calculateDistance(waypoints[x-1], end))) {
           waypoints.splice(x, 1);
       } else {
           waypoints.splice(x - 1, 1);
       }
   }
   console.log(waypoints)
   return waypoints[0];
}

function calculateDistance(p1, p2) {
   //Uses the Google geometry library to calculate distance between two Markers
   let a = p1.getPosition();
   let b = p2.getPosition();

   let distance = (google.maps.geometry.spherical.computeDistanceBetween(a, b) / 1000).toFixed(2);
   return distance;
}

function showSteps(directionResult, stepDisplay, map) {
   // For each step, place a marker, and add the text to the marker's infowindow.
   // Also attach the marker to an array so we can keep track of it and remove it
   // when calculating new routes.
   //NOT CURRENTLY IMPLEMENTED/USED
   const myRoute = directionResult.routes[0].legs[0];

   for (let i = 0; i < myRoute.steps.length; i++) {
       const marker = (markerArray[i] =
           markerArray[i] || new google.maps.Marker());
       marker.setMap(map);
       marker.setPosition(myRoute.steps[i].start_location);
       attachInstructionText(
           stepDisplay,
           marker,
           myRoute.steps[i].instructions,
           map
       );
   }
}

function attachInstructionText(stepDisplay, marker, text, map) {
   google.maps.event.addListener(marker, "click", () => {
       // Open an info window when the marker is clicked on, containing the text
       // of the step.
       //NOT CURRENTLY IMPLEMENTED/USED
       stepDisplay.setContent(text);
       stepDisplay.open(map, marker);
   });
}
/* Always set the map height explicitly to define the size of the div
      * element that contains the map. */
#map {
   height: 100%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
   height: 100%;
   margin: 0;
   padding: 0;
}

#floating-panel {
   position: absolute;
   top: 10px;
   left: 25%;
   z-index: 5;
   background-color: #fff;
   padding: 5px;
   border: 1px solid #999;
   text-align: center;
   font-family: "Roboto", "sans-serif";
   line-height: 30px;
   padding-left: 10px;
}

#warnings-panel {
   width: 100%;
   height: 10%;
   text-align: center;
}
<!DOCTYPE html>
<html>
<head>
   <title>EV Trip Route Finder</title>
   <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
   <script
           src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=&v=weekly"
           defer
   ></script>
   <!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="floating-panel" >
   <b>Start: </b>
   <input id="start" type="text" value="Tallinn">
   <b>End: </b>
   <input id="end" type="text" value="Vilnius">
   <input id="submit" type="button" value="GO" />
</div>
<div id="map"></div>
&nbsp;
<div id="warnings-panel"></div>
</body>
</html>