Grey

Larrain

Bratt

Grey
Larrain
Bratt

Park Finder Web App

Brief

  • Final project for DVC's Web and Mobile Design with JavaScript class
  • Develop a Web Application by combining at least two Web APIs
  • Our group chose to create an app to help dog owners find parks they could take their pets to

Beginning the Project: APIs

To find out what data would work with our chosen topic, we first looked through available Web APIs: different maps and different location data sources.

  • We chose Leaflet for its user-friendly documentation and versatility
  • I found an API from TomTom that allowed queries for locations classified as parks within a specific geographic range, so I created a basic code that allowed us to query for the term “dog park” within a specific area.

Connecting Geographic Data

In order to search for parks within a specific area, the API requires four different latitude & longitude points.

I found a JSON file from CountryStateCity that contained the latitude & longitude of (seemingly all) cities in the United States, which I downloaded and then extracted all the California places over into a separate JSON file. We decided that users could type in the city they wish to find parks near, and then scan the area around it.

To find the search area around the city, I wrote a JavaScript query to parse through city names for an exact location, and from there use an equation to find all four corners of the search area. Our search area looks for all parks within about 15 miles north, south, east and west from the location queried.

Calculating Search Area Points

let placeElem = document.getElementById("placeName");
    // placeholder city
    var placeName = "Alamo";

    // placeholder city data
    var placeLat = 37.85020000;
    var placeLon = -122.03218000;

    // creating a new object with the necessary info for querying
    var place = {
        name: placeName,
        nameUniversal: placeName.toUpperCase(),
        lat:placeLat,
        lon: placeLon,
        id: "ca111093",

        // equations for finding the new lat & long's
        top: function(lat) {
            return lat + 0.51;
        },
        left: function(lon) {
            return lon - 0.51;
        },
        btm: function(lat) {
            return lat - 0.51;
        },
        right: function(lon) {
            return lon + 0.51;
        }
    };

Then, I had to create a function that would connect the search results to a city.

Plugging in the City Data*

async function searchCities() { // compare search input to cities data
        try {
            let newPlace = await getSearch();
            if(errors.innerHTML !== "") {
                errors.innerHTML = "";
            };

            if(newPlace == "") {
                throw "Enter a place in California for new results";
            };

            if(newPlace == place.nameUniversal) {
                throw `“${newPlace}” results are already displayed below`;};

            let exists = false;
            // for loop to scan through cities
            for (let i = 0; i < caCitiesData.length; i++) {
                // labeling for clarity: as if wrote "forEach((caCity) =>)"
                let caCity = caCitiesData[i];
                // specifying the city data object
                let cityData = caCity.city;
                // if search name matches the city name
                if(newPlace == cityData.nameUniversal) {
                    exists = true;
                    // then replace old map place data with new place's data
                    place.name = cityData.name;
                    place.nameUniversal = cityData.nameUniversal;
                    place.lat = Number(cityData.lat);
                    place.lon = Number(cityData.lon);
                   place.id = cityData.id;
                    return place;
                };
            };
            if (exists == false) {
                throw `“${newPlace}” is not in the database`;
            };
        } catch(err) {
            errors.innerHTML = `Search Error: ${err}`;
        };
    };

Plotting the Results

Next came the hardest bit of code: iterating through the results to plot each of the dog parks on our map.

I went through step-by-step to make sure each new layer worked before I put it together into one function.

Creating plot points on the map*

async function filterParks() {
        try {
            // get park data from getParks f(x)
            let fullList = await getParks();
            // clear existing content
            list.innerHTML = "";
            // iterate through parks
            fullList.forEach((park) => {
                // filter to parks within limit range
                if(park.position.lon < place.right(place.lon)
                    && park.position.lon > place.left(place.lon)) {
                    if(park.position.lat > place.btm(place.lat)
                    && park.position.lat < place.top(place.lat)) {
                        // create a Park object for each park
                            var parkContent = new Park(
                                park.id,
                                park.position.lat,
                                park.position.lon,
                                park.poi.name,
                                park.address.freeformAddress
                            );
                            
                            // PLOT POINT for park
                                var parkMarker = L.marker(
                                    [park.position.lat,
                                        park.position.lon],
                                        {icon: mapIcon, title: park.poi.name, alt: "Marker"}).addTo(parksLayer)
                                        // create pop-up with basic info
                                    .bindPopup(
                                        `${park.poi.name}`,
                                        {maxWidth: 175})
                                    ;);

                            // add id for plot point
                            parkMarker.getElement().id = `m${park.id}`;
                            // change marker color
                            parkMarker.getElement().style.filter = "hue-rotate(160deg)"
                    };
                };
            });
        } catch(err) {
            console.log("Parks Filter Error:", err)
        };
    };

* For clarity, I have removed all HTML styling for the template literals from each extracted portion of code

Finished Web Application

After the class, I went back and almost entirely redesigned the layout to show myself what I could now do. I added lots of smoothed transitions with JavaScript that I couldn't have done before, and I made a full Web Application that I could feel proud of.