0
\$\begingroup\$

I am quite new to Javascript. For a school project we wrote a website that displays the user's location on a google map alongside with some objects such as vehicles or passengers. I rewrote my code to include async...await syntax after learning about them. But I still do not know if the code is any good, or if it could be improved. I hoped you guys would have an answer. Here is the code:

const myID = 'Wkevc4Sj';
const myIcon = 'images/marker.png';
const passIcon = 'images/passenger.png';
const carIcon = 'images/car.png';
const weinerIcon = 'images/weinermobile.png';
const has = Object.prototype.hasOwnProperty;

var infowindow = {};
var directionsService = {};
var directionsDisplay = {};
var userLocation = {};
var weinerExists = false;

async function run() {
  try {
    let map = await initMap();
    renderMap(map);
    let userMarker = addUserMarker(map);

    let request = getRide();
    let response = await request;
    let ride = await response.json();
    console.log(ride);
    let userType = has.call(ride, "vehicles") ? "passenger" : "vehicle";

    populateMap(userType, ride, map, userMarker);
  } catch (e)
  {
    alert (e);
  }
}

// getLocation is a promise that resolves with the location that uses navigator
const getLocation = new Promise(function(resolve, reject) {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(resolve, reject);
  } else {
    reject('Browser does not support geolocation');
  }
});

// initMap() when called initializes the map element on the body using
//    the user's location
async function initMap() {
  var position = await getLocation;
  userLocation = {
    lat: position.coords.latitude,
    lng: position.coords.longitude
  };
  return new google.maps.Map(document.getElementById('map'), {
    center: userLocation,
    zoom: 16,
    disableDefaultUI: true
  });
}

// renderMap(map) when given a google.maps.map object,
//    adds direction service and an infoWindow to the map.
//    also adds a marker on the current position of the user.
function renderMap(map) {
  infowindow = new google.maps.InfoWindow();
  directionsService = new google.maps.DirectionsService();
  directionsDisplay = new google.maps.DirectionsRenderer();

  directionsDisplay.setMap(map);
  directionsDisplay.setOptions({
    suppressMarkers: true
  });
}

// getRide() returns a promise that resolves with a JSON object returned from the
//    ride API
async function getRide() {
  const url = 'https://hans-moleman.herokuapp.com/rides';
  const params = `username=${myID}&lat=${userLocation.lat}&lng=${userLocation.lng}`;

  return fetch(url, {
    method: 'POST',
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: params,
  });
}

// addUserMarker(map) adds a user marker to the provided map
function addUserMarker(map) {
  const content = `<p><strong>Your Location:</strong><br /> Lat = ${precise(userLocation.lat, 4)} Lng = ${precise(userLocation.lng, 4)}`;
  let userMarker = newMarker(userLocation, myIcon, content, map);
  google.maps.event.addListener(userMarker, 'click', function() {
    infowindow.setContent(this.content);
    infowindow.open(map, this);
  });
  return userMarker;
}

// newMarker(position, icon, content, map) returns a new marker with the
//    arguments as marker properties.
function newMarker(position, icon, content, map) {
  return new google.maps.Marker({
    position: position,
    icon: icon,
    content: content,
    map: map
  });
}

// newMarkerwListener(position, icon, content, map) returns a new marker with
//    arguments as marker properties and a popup click listener added.
function newMarkerwListener(position, icon, content, map) {
  let marker = newMarker(position, icon, content, map);
  google.maps.event.addListener(marker, 'click', function() {
    infowindow.setContent(this.content);
    infowindow.open(map, this);
  });

  return marker;
}

// populateMap(userType, ride, map, marker) given the type of the user,
//  ride API response JSON object, a google map and a user marker,
//  populates the map with the objects of the ride and modifies the
//  marker to represent the nearest object
function populateMap(userType, ride, map, marker) {
  const elemArray = ride[userType == "passenger" ? "vehicles" : "passengers"];
  let nearest = elemArray[0];
  let weinerMobile = {};

  for (var i = 0; i < elemArray.length; i++) {
    let elem = elemArray[i];
    let nearestDistance = distanceTo(userLocation, nearest);
    let distance = distanceTo(userLocation, elem);

    let content = `<p><strong>Name: </strong> ${elem.username}<br />${distance} miles away from you`;
    let icon = userType == "vehicle" ? passIcon : carIcon;

    if (elem.username == "WEINERMOBILE") {
      icon = weinerIcon;
      weinerExists = true;
      weinerMobile = elem;
    }
    newMarkerwListener(elem, icon, content, map);
    nearest = nearestDistance < distance ? nearest : elem;
  }

  if (!(nearest === undefined)) {
    marker.content += `<br /><strong>Nearest: ${nearest.username}</strong><br />${distanceTo(userLocation, nearest)} miles away from you`;
  }

  if (weinerExists) {
    marker.content += `<br /><strong>Weinermobile:</strong><br />${distanceTo(userLocation, weinerMobile)} miles away`;
  } else {
    marker.content += "<br />The Weinermobile is nowhere to be seen";
  }

}

/* HELPER FUNCTIONS */
function precise(x, y) {
  return Number.parseFloat(x).toPrecision(y);
}

function findDistFromTo(from, to) {
  var vLatLng = new google.maps.LatLng(
    parseFloat(from.lat),
    parseFloat(from.lng)
  );
  var cLatLng = new google.maps.LatLng(
    parseFloat(to.lat),
    parseFloat(to.lng)
  );
  return google.maps.geometry.spherical.computeDistanceBetween(
    cLatLng,
    vLatLng
  );
}

function toMiles(meters) {
  return meters * 0.000621371192;
}

function distanceTo(from, to) {
  return precise(toMiles(findDistFromTo(from, to)), 4);
}

Thanks in advance.

\$\endgroup\$
1
\$\begingroup\$

My observations:

  1. Use let instead of var. You are already using let in some places, but a few need to be converted. For those that do not know the difference, let is one of the new features in ES2015 (ES6) and it respects block scopes in the same way as other programming languages.
  2. ~~
  3. I would use file scope constants for the strings "passenger" and "vehicle". Makes it easier in the future to do refactors. For example, at the top of the file const PASSENGER = 'passenger'
  4. Change this if (!(nearest === undefined)) to if (!!nearest), what you care about is if its a truthy value. The specificity of "not undefined" would allow other falsy values like 0, null, NaN, '', "", ````
  5. If file scope constant were to be used and all the possible values are known, you could test for those specifically. Instead of if (!!nearest) you could if ([PASSENGER, VEHICLE].includes(nearest))
\$\endgroup\$
  • \$\begingroup\$ Thank you for the suggestions \$\endgroup\$ – Armanc Keser Mar 19 at 18:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.