Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display node locations prior to click #140

Merged
merged 10 commits into from
Jul 26, 2024
8 changes: 4 additions & 4 deletions backend/app/get_closest_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
SQL = '''
SELECT
cg_nodes.node_id::int,
ST_AsGeoJSON(cg_nodes.geom) AS geom,
ST_AsGeoJSON(cg_nodes.geom, 5) AS geom,
cg_nodes.geom::geography <-> ST_MakePoint(%(longitude)s, %(latitude)s)::geography AS distance,
array_agg(DISTINCT InitCap(streets.st_name)) FILTER (WHERE streets.st_name IS NOT NULL) AS street_names
FROM congestion.network_nodes AS cg_nodes
Expand All @@ -16,16 +16,16 @@
cg_nodes.node_id,
cg_nodes.geom
ORDER BY distance
LIMIT 3;
LIMIT 20;
'''

def get_closest_nodes(longitude, latitude):
def get_nodes_within(meters,longitude, latitude):
with getConnection() as connection:
with connection.cursor() as cursor:
cursor.execute(SQL, {"latitude": latitude, "longitude": longitude})
candidate_nodes = []
for node_id, geojson, distance, street_names in cursor.fetchall():
if distance < 50: # meters
if distance <= meters:
candidate_nodes.append( {
'node_id': node_id,
'street_names': street_names,
Expand Down
11 changes: 6 additions & 5 deletions backend/app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from flask import jsonify
from app import app
from app.db import getConnection
from app.get_closest_nodes import get_closest_nodes
from app.get_closest_nodes import get_nodes_within
from app.get_node import get_node
from app.get_travel_time import get_travel_time

Expand All @@ -17,14 +17,15 @@ def index():
})

# test URL /closest-node/-79.3400/43.6610
@app.route('/closest-node/<longitude>/<latitude>', methods=['GET'])
def closest_node(longitude,latitude):
@app.route('/nodes-within/<meters>/<longitude>/<latitude>', methods=['GET'])
def closest_node(meters,longitude,latitude):
try:
longitude = float(longitude)
latitude = float(latitude)
meters = float(meters)
except:
return jsonify({'error': "Longitude and latitude must be decimal numbers!"})
return jsonify(get_closest_nodes(longitude,latitude))
return jsonify({'error': "all inputs must be decimal numbers"})
return jsonify(get_nodes_within(meters,longitude,latitude))

# test URL /node/30357505
@app.route('/node/<node_id>', methods=['GET'])
Expand Down
47 changes: 43 additions & 4 deletions frontend/src/Map/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Polyline,
LayerGroup
} from 'react-leaflet'
import { useContext } from 'react'
import { useContext, useState } from 'react'
import { DataContext } from '../Layout'
import { useMapEvent } from 'react-leaflet/hooks'
import { domain } from '../domain.js'
Expand All @@ -15,11 +15,17 @@ import 'leaflet/dist/leaflet.css'

const initialMapCenter = { lat: 43.65344, lng: -79.38400 }

export default function Map() {
export default function CartoMap(){
return (
<MapContainer center={initialMapCenter} zoom={15} style={{height:'100vh'}}>
<MapContainer
center={initialMapCenter}
zoom={15}
style={{height:'100vh'}}
doubleClickZoom={false}
>
<TileLayer url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'/>
<DataLayer/>
<NodeLayer/>
</MapContainer>
)
}
Expand All @@ -29,7 +35,7 @@ function DataLayer(){
const activeCorridor = data.activeCorridor
useMapEvent('click', (event) => { // add an intersection
if( activeCorridor?.intersections?.length < 2 ){
fetch(`${domain}/closest-node/${event.latlng.lng}/${event.latlng.lat}`)
fetch(`${domain}/nodes-within/50/${event.latlng.lng}/${event.latlng.lat}`)
.then( resp => resp.json() )
.then( node => {
const data = node[0]
Expand Down Expand Up @@ -76,4 +82,37 @@ function DataLayer(){
</LayerGroup>
)
} )
}

function NodeLayer(){
// briefly shows locations of nearby clickable nodes on double-click
const [ nodes, setNodes ] = useState( new Map() )
useMapEvent('dblclick', (event) => {
fetch(`${domain}/nodes-within/1000/${event.latlng.lng}/${event.latlng.lat}`)
.then( resp => resp.json() )
.then( intersections => {
setNodes( n => { // add intersections
intersections.forEach( i => n.set(i.node_id,i) )
return new Map(n)
} )
setTimeout( // remove them
() => setNodes( n => {
intersections.forEach( i => n.delete(i.node_id) )
return new Map(n)
} ),
5000
)
} )
} )
return (
<LayerGroup>
{[...nodes.values()].map( (node,i) => (
<CircleMarker key={i}
center={{lat: node.geometry.coordinates[1], lng: node.geometry.coordinates[0]}}
radius={5}
pathOptions={{color:'grey'}}
/>
) ) }
</LayerGroup>
)
}
Loading