Converting the trip geometry of a GTFS file to a polygon to display on a React Map

43 Views Asked by At

I am developing a React application that involves gathering nearby transit routes from a pinpointed location. I am using Mapbox, and I have my own GTFS database with each trip having its own shape. Currently, this is how my application looks like:

Screenshot of app

I want to display the shape of the routes on the map when they are a part of the nearby routes array, something like this:

Ideal output of the app

How should I approach this?

Currently, here is my code:

App.js

// packages
import React, { useState, useEffect } from 'react';
import { Map, NavigationControl, Marker } from 'react-map-gl';
import { useLazyQuery } from '@apollo/client';
import { NEARBY_ROUTES } from './graphql/Queries';
import Popup from 'reactjs-popup';
// -----------------------------

// Main Website

const App = () => {

  // initial settings
  const [settings, setsettings] = useState({
    touchZoom: false,
    doubleClickZoom: false
    });
  
  // ---------------- Nearby routes function -------------------------

  const [latitude, setLatitude] = useState("")
  const [longitude, setLongitude] = useState("")
  const [showPopup, setShowPopup] = useState(false);
  const [noRoutes, setNoRoutes] = useState(false);
  const [getNearbyRoutes, { error, data }] = useLazyQuery(NEARBY_ROUTES, {variables: {lat: latitude, lon: longitude}});

  if (error) return <p>Error: {error.message}</p>;

  const allRoutes = data?.stopsByRadius?.edges?.flatMap((edge) => edge?.node?.stop?.routes) || []; // all of the routes

  const uniqueRoutesSet = new Set();

  // Filter out duplicates using the 'longName' property as the identifier
  const routes = allRoutes.filter((route) => {
    if (!uniqueRoutesSet.has(route.longName)) {
      uniqueRoutesSet.add(route.longName);
      return true;
    }
    return false;
  });

  console.log(routes);

  async function handleClick(event) { // on double click
    const coords = event.lngLat; // gets the coordinates of clicked location
    setLongitude(coords.lng);
    setLatitude(coords.lat);
    await getNearbyRoutes() // requests query
    console.log(coords);

    if (routes.length <= 0)
      setNoRoutes(true);
    else
      setNoRoutes(false);

    setShowPopup(true);
  }
  
  // -----------------------------------------------------------
  return (
    <>
    <Map
      {...settings}
      style={{ width: window.innerWidth, height: window.innerHeight }}
      initialViewState={{
        longitude: 121.04042520880047,
        latitude: 14.649743779882588,
        zoom: 14
      }}
      mapboxAccessToken="pk.eyJ1IjoiYWNlZG9taW5nbyIsImEiOiJjbGpvOTB3ZjMwMWFiM2dxbDc5cjU0Y2FvIn0.aJC6z1-KjLBiG15MUfzO4Q"
      mapStyle="mapbox://styles/mapbox/light-v11"
      onDblClick={handleClick}
    >
      <NavigationControl showCompass={false} />
      <Marker latitude={latitude} longitude={longitude}></Marker>
    </Map>
  
    {/* Popup that displays the nearby routes */}
    <Popup
      open={showPopup}
      onClose={() => setShowPopup(false)}
      position="bottom left"
      contentStyle={{
        background: 'white',
        width: '400px',
        padding: '20px',
        borderRadius: '4px',
        boxShadow: '0 0 10px rgba(0, 0, 0, 0.3)',
        textAlign: 'left',
        position: 'fixed',
        left: '20px',
        bottom: '20px'
      }}
    >
      <div>
        <h1>Nearby Routes:</h1>
        { noRoutes ? (
            <p>There are no nearby routes.</p>
            ) : (
              <ul>
              {routes.map((route) => (
                <li key={route.gtfsId}>{route.longName}</li>
              ))}
              </ul> 
            )
        }
      </div>
    </Popup> 
    </>
  );
}

export default App

This is my NEARBY_ROUTES query:

query nearbyRoutes($lat: Float!, $lon: Float!) {
  stopsByRadius(lat: $lat, lon: $lon, radius: 500) {
    edges {
      node {
        stop {
          routes {
            ...routes
          }
        }
      }
    }
  }
}

fragment routes on Route {
  longName
  gtfsId
  trips {
    tripGeometry {
      points
    }
  }
}

And its expected output should be something like this:

 "data": {
    "stopsByRadius": {
      "edges": [
        {
          "node": {
            "stop": {
              "routes": [
                {
                  "longName": "SM North - UP",
                  "gtfsId": "1:LTFRB_PUJ0010",
                  "trips": [
                    {
                      "tripGeometry": {
                        "points": "akmxAuzuaV`CuQ??xAuK??bBoMPc@D???xES??tAGbFa@~@Q??nHmAt@U??xEwAHE??hIkDHI??|FoE??PMjF{FvBwC??vByCjCyF??hAaCR_AmEo@??kMiB??oEo@eFu@??eG}@wCg@ViAVaBMsCm@uBAA??_CqC_C}@mBSeDD_Dp@_ACc@K??WG}B_EO_@??oBuEUaBUeB??}@kHKeN???AKuQ??C}B?oIfDuA??^QIyR??CoK??G_P"
                      }
                    }
                  ]
                }
0

There are 0 best solutions below