UNPKG

ws-dottie

Version:

Your friendly TypeScript companion for Washington State transportation APIs - WSDOT and WSF data with smart caching and React Query integration

1,060 lines (905 loc) 41 kB
# Traffic APIs This guide covers all traffic-related APIs in WS-Dottie, providing comprehensive access to Washington State highway conditions, incidents, and traffic flow data. > **📚 Documentation Navigation**: [Documentation Index](../../INDEX.md) • [Getting Started](../../getting-started.md) • [API Guide](../api-guide.md) ## 🚗 Overview WS-Dottie provides access to seven traffic APIs that cover all aspects of Washington State highway information: | API | Description | Key Features | Update Frequency | |------|-------------|---------------|------------------| | **WSDOT Border Crossings** | Wait times and conditions at border crossings | Border planning, wait time monitoring, crossing status | Frequent (5-15m) | | **WSDOT Highway Alerts** | Real-time traffic incidents and construction | Incident tracking, construction updates, road closures | Real-time (5s) | | **WSDOT Highway Cameras** | Live traffic camera feeds | Visual monitoring, road conditions, traffic visualization | Static (daily) | | **WSDOT Mountain Pass Conditions** | Mountain pass status, restrictions, and road conditions | Pass conditions, travel restrictions, closure information | Frequent (15-30m) | | **WSDOT Toll Rates** | Real-time toll pricing for managed lanes | Cost calculation, route optimization, toll planning | Frequent (1-5m) | | **WSDOT Traffic Flow** | Current traffic speeds and congestion data | Flow monitoring, congestion analysis, speed data | Real-time (5s) | | **WSDOT Travel Times** | Estimated travel times between locations | Route planning, ETA calculation, delay tracking | Frequent (1-5m) | ## 🛃 WSDOT Border Crossings API ### API Overview The WSDOT Border Crossings API provides real-time information about border crossing wait times and conditions at Washington State crossings into Canada. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **border-crossing-data** | Real-time wait times for US-Canada border crossings | FREQUENT | ### Key Endpoints #### Border Crossings - **getBorderCrossings**: Returns current wait times for all border crossings - **Input**: No parameters required - **Output**: Array of border crossing information - **Key Fields**: - `BorderCrossingLocation`: Roadway location information (route, milepost, coordinates, direction), or null - `Direction`: Traffic direction (N, S, B, NB, SB), or null - `RoadName`: Highway designation (e.g., '005' for I-5), or null - `Description`: Human-readable location description, or null - `Latitude`: Latitude in decimal degrees - `Longitude`: Longitude in decimal degrees - `MilePost`: Milepost marker along the highway - `CrossingName`: Display code for the border crossing or lane (e.g., I5, I5Nexus, SR543TrucksFast), or null - `Time`: UTC datetime when the wait time observation was recorded (Date object) - `WaitTime`: Current estimated wait time in minutes (-1 if unavailable) ### Common Use Cases #### Border Crossing Monitor ```javascript import { useBorderCrossings } from 'ws-dottie/wsdot-border-crossings'; function BorderCrossingMonitor() { const { data: crossings, isLoading, error } = useBorderCrossings({ fetchMode: 'native', validate: false, }); // Group crossings by CrossingName prefix or RoadName if available // Note: The API doesn't provide CrossingType, so we'll filter by CrossingName patterns const passengerCrossings = crossings?.filter(c => c.CrossingName && !c.CrossingName.includes('Truck') ); const commercialCrossings = crossings?.filter(c => c.CrossingName && c.CrossingName.includes('Truck') ); const nexusCrossings = crossings?.filter(c => c.CrossingName && c.CrossingName.includes('Nexus') ); return ( <div> <h1>Washington Border Crossings</h1> {isLoading && <div>Loading border crossing data...</div>} {error && <div>Error loading border crossing data: {error.message}</div>} <div className="crossing-sections"> <div className="crossing-section"> <h2>Passenger Crossings</h2> {passengerCrossings?.map((crossing, index) => ( <div key={crossing.CrossingName || index} className="crossing-item"> <h3>{crossing.CrossingName || 'Unknown Crossing'}</h3> {crossing.BorderCrossingLocation?.Direction && ( <p>Direction: {crossing.BorderCrossingLocation.Direction}</p> )} {crossing.BorderCrossingLocation?.RoadName && ( <p>Route: {crossing.BorderCrossingLocation.RoadName}</p> )} <p>Current Wait: {crossing.WaitTime >= 0 ? `${crossing.WaitTime} minutes` : 'Not available'}</p> {/* Time is already a Date object (converted from .NET format) */} <p>Last Updated: {crossing.Time.toLocaleString()}</p> </div> ))} </div> <div className="crossing-section"> <h2>Commercial Crossings</h2> {commercialCrossings?.map((crossing, index) => ( <div key={crossing.CrossingName || index} className="crossing-item"> <h3>{crossing.CrossingName || 'Unknown Crossing'}</h3> {crossing.BorderCrossingLocation?.Direction && ( <p>Direction: {crossing.BorderCrossingLocation.Direction}</p> )} {crossing.BorderCrossingLocation?.RoadName && ( <p>Route: {crossing.BorderCrossingLocation.RoadName}</p> )} <p>Current Wait: {crossing.WaitTime >= 0 ? `${crossing.WaitTime} minutes` : 'Not available'}</p> {/* Time is already a Date object (converted from .NET format) */} <p>Last Updated: {crossing.Time.toLocaleString()}</p> </div> ))} </div> {nexusCrossings && nexusCrossings.length > 0 && ( <div className="crossing-section"> <h2>NEXUS Crossings</h2> {nexusCrossings.map((crossing, index) => ( <div key={crossing.CrossingName || index} className="crossing-item"> <h3>{crossing.CrossingName || 'Unknown Crossing'}</h3> {crossing.BorderCrossingLocation?.Direction && ( <p>Direction: {crossing.BorderCrossingLocation.Direction}</p> )} <p>Current Wait: {crossing.WaitTime >= 0 ? `${crossing.WaitTime} minutes` : 'Not available'}</p> <p>Last Updated: {crossing.Time.toLocaleString()}</p> </div> ))} </div> )} </div> </div> ); } ``` ## 🚨 WSDOT Highway Alerts API ### API Overview The WSDOT Highway Alerts API provides real-time information about traffic incidents, construction, and road conditions throughout Washington State. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **highwayAlerts** | Real-time traffic incidents and road conditions | FREQUENT | | **alertAreas** | Geographic areas for alert filtering | FREQUENT | | **event-categories** | Alert event categories and types | STATIC | ### Key Endpoints #### Highway Alerts - **getAlerts**: Returns all current highway alerts - **Input**: No parameters required - **Output**: Array of highway alert information - **Key Fields**: - `AlertID`: Unique alert identifier - `HeadlineDescription`: Brief description of the alert - `EventCategory`: Type of event (Accident, Construction, Weather, etc.) - `Priority`: Alert priority level (Low, Normal, High, Highest) - `StartTime`: When the alert began - `EndTime`: When the alert is expected to end - `StartRoadName`, `EndRoadName`: Affected road names - `StartMilepost`, `EndMilepost`: Affected milepost range - `County`: County where the alert is located - `Latitude`, `Longitude`: GPS coordinates - **getAlertById**: Returns a specific alert by ID - **Input**: `AlertID` (integer) - Unique alert identifier - **Output**: Single highway alert object with all fields above - **getAlertsByRegionId**: Returns alerts for a specific region - **Input**: `RegionID` (integer) - Region identifier - **Output**: Array of highway alerts for specified region - **getAlertsByMapArea**: Returns alerts for a specific geographic area - **Input**: `MapArea` (string) - Geographic area name - **Output**: Array of highway alerts for specified area - **searchAlerts**: Returns alerts matching search criteria - **Input**: - `StateRoute` (string) - State route number - `Region` (string) - Region name - `SearchTimeStart`, `SearchTimeEnd` (datetime) - Time range to search - `StartingMilepost`, `EndingMilepost` (number) - Milepost range - **Output**: Array of highway alerts matching search criteria ### Common Use Cases #### Traffic Alert Dashboard ```javascript import { useAlerts } from 'ws-dottie/wsdot-highway-alerts'; function TrafficAlertDashboard() { const { data: alerts, isLoading, error } = useAlerts(); // Group alerts by priority const highPriorityAlerts = alerts?.filter(alert => alert.Priority === 'High' || alert.Priority === 'Highest' ) || []; const normalAlerts = alerts?.filter(alert => alert.Priority === 'Normal' || alert.Priority === 'Low' ) || []; // Sort alerts by start time (most recent first) const sortedAlerts = [...(alerts || [])].sort((a, b) => new Date(b.StartTime) - new Date(a.StartTime) ); return ( <div> <h1>Washington Traffic Alerts</h1> {isLoading && <div>Loading alerts...</div>} {error && <div>Error loading alert data: {error.message}</div>} <div className="alert-summary"> <div className="alert-group"> <h2>High Priority Alerts ({highPriorityAlerts.length || 0})</h2> {highPriorityAlerts.map(alert => ( <div key={alert.AlertID} className="high-priority"> <h3>{alert.HeadlineDescription}</h3> <p>Category: {alert.EventCategory}</p> <p>Location: {alert.StartRoadName} to {alert.EndRoadName}</p> <p>Started: {new Date(alert.StartTime).toLocaleString()}</p> </div> ))} </div> <div className="alert-group"> <h2>Other Alerts ({normalAlerts.length || 0})</h2> {normalAlerts.map(alert => ( <div key={alert.AlertID} className="normal-priority"> <h3>{alert.HeadlineDescription}</h3> <p>Category: {alert.EventCategory}</p> <p>Location: {alert.StartRoadName} to {alert.EndRoadName}</p> <p>Started: {new Date(alert.StartTime).toLocaleString()}</p> </div> ))} </div> </div> <div className="alert-list"> <h2>All Alerts</h2> {sortedAlerts.map(alert => ( <div key={alert.AlertID} className={`alert-item ${alert.Priority.toLowerCase()}`}> <h3>{alert.HeadlineDescription}</h3> <p>Priority: {alert.Priority}</p> <p>Category: {alert.EventCategory}</p> <p>Location: {alert.StartRoadName} to {alert.EndRoadName}</p> <p>Started: {new Date(alert.StartTime).toLocaleString()}</p> {alert.EndTime && ( <p>Expected End: {new Date(alert.EndTime).toLocaleString()}</p> )} </div> ))} </div> </div> ); } ``` #### Regional Traffic Monitoring ```javascript import { useAlertsByMapArea } from 'ws-dottie/wsdot-highway-alerts'; function RegionalTrafficMonitor() { const [selectedRegion, setSelectedRegion] = useState('Seattle'); const { data: alerts, isLoading, error } = useAlertsByMapArea( selectedRegion ? { MapArea: selectedRegion } : null ); // Group alerts by category const accidents = alerts?.filter(alert => alert.EventCategory === 'Accident') || []; const construction = alerts?.filter(alert => alert.EventCategory === 'Construction') || []; const weather = alerts?.filter(alert => alert.EventCategory === 'Weather') || []; return ( <div> <h1>Regional Traffic Monitor</h1> {isLoading && <div>Loading alerts...</div>} {error && <div>Error loading alert data: {error.message}</div>} <div className="region-selector"> <label>Region: <select value={selectedRegion} onChange={e => setSelectedRegion(e.target.value)}> <option value="Seattle">Seattle</option> <option value="Spokane">Spokane</option> <option value="Vancouver">Vancouver</option> <option value="Tacoma">Tacoma</option> </select> </label> </div> <div className="regional-alerts"> <h2>{selectedRegion} Alerts ({alerts?.length || 0})</h2> <div className="alert-category"> <h3>Accidents ({accidents.length})</h3> {accidents.map(alert => ( <div key={alert.AlertID} className="alert-item accident"> <h4>{alert.HeadlineDescription}</h4> <p>Priority: {alert.Priority}</p> <p>Location: {alert.StartRoadName}</p> <p>Started: {new Date(alert.StartTime).toLocaleString()}</p> </div> ))} </div> <div className="alert-category"> <h3>Construction ({construction.length})</h3> {construction.map(alert => ( <div key={alert.AlertID} className="alert-item construction"> <h4>{alert.HeadlineDescription}</h4> <p>Priority: {alert.Priority}</p> <p>Location: {alert.StartRoadName}</p> <p>Started: {new Date(alert.StartTime).toLocaleString()}</p> </div> ))} </div> <div className="alert-category"> <h3>Weather ({weather.length})</h3> {weather.map(alert => ( <div key={alert.AlertID} className="alert-item weather"> <h4>{alert.HeadlineDescription}</h4> <p>Priority: {alert.Priority}</p> <p>Location: {alert.StartRoadName}</p> <p>Started: {new Date(alert.StartTime).toLocaleString()}</p> </div> ))} </div> </div> </div> ); } ``` ## 📷 WSDOT Highway Cameras API ### API Overview The WSDOT Highway Cameras API provides access to live traffic camera feeds throughout Washington State, allowing visual monitoring of current road conditions. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **cameras** | Live traffic camera feeds and metadata | STATIC | ### Key Endpoints #### Highway Cameras - **getHighwayCameras**: Returns all highway cameras - **Input**: No parameters required - **Output**: Array of camera information - **Key Fields**: - `CameraID`: Unique camera identifier - `Title`: Human-readable camera title - `RoadName`: Highway name where camera is located - `MilePost`: Milepost location - `Latitude`, `Longitude`: GPS coordinates - `ImageURL`: URL to current camera image - `Direction`: Camera direction (North, South, East, West) - `IsActive`: Whether camera is currently active - **searchHighwayCamerasByRouteAndMilepost**: Returns cameras for a specific route and milepost range - **Input**: - `StateRoute` (string) - State route number - `StartingMilepost`, `EndingMilepost` (number) - Milepost range - **Output**: Array of cameras matching search criteria - **getHighwayCameraByCameraId**: Returns a specific camera by ID - **Input**: `CameraID` (integer) - Unique camera identifier - **Output**: Single camera object with all fields above ### Common Use Cases #### Traffic Camera Viewer ```javascript import { useHighwayCameras, useSearchHighwayCamerasByRouteAndMilepost } from 'ws-dottie/wsdot-highway-cameras'; function TrafficCameraViewer() { const [selectedRoute, setSelectedRoute] = useState('I-5'); const { data: allCameras, isLoading: allLoading } = useHighwayCameras(); const { data: routeCameras, isLoading: routeLoading } = useSearchHighwayCamerasByRouteAndMilepost( selectedRoute ? { StateRoute: selectedRoute, StartingMilepost: 10, EndingMilepost: 20 } : null ); // Use route cameras if available, otherwise use all cameras const cameras = routeCameras || allCameras; const loading = routeLoading || allLoading; return ( <div> <h1>Washington Traffic Cameras</h1> {loading && <div>Loading cameras...</div>} <div className="camera-controls"> <label>Route: <select value={selectedRoute} onChange={e => setSelectedRoute(e.target.value)}> <option value="I-5">I-5</option> <option value="I-90">I-90</option> <option value="I-405">I-405</option> <option value="SR-520">SR-520</option> </select> </label> </div> <div className="camera-grid"> {cameras?.map(camera => ( <div key={camera.CameraID} className="camera-item"> <h3>{camera.Title}</h3> <p>Location: {camera.RoadName} - Milepost {camera.MilePost}</p> <p>Direction: {camera.Direction}</p> <div className="camera-image"> <img src={camera.ImageURL} alt={camera.Title} onError={() => console.error(`Failed to load camera ${camera.CameraID}`)} /> </div> </div> ))} </div> </div> ); } ``` ## 🏔️ WSDOT Mountain Pass Conditions API ### API Overview The WSDOT Mountain Pass Conditions API provides real-time information about mountain pass conditions throughout Washington State, including weather, road conditions, and travel restrictions. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **pass-conditions** | Mountain pass weather and road conditions | FREQUENT | ### Key Endpoints #### Mountain Pass Conditions - **getMountainPassConditions**: Returns conditions for all mountain passes - **Input**: No parameters required - **Output**: Array of mountain pass condition information - **Key Fields**: - `PassConditionID`: Unique pass identifier - `PassName`: Human-readable pass name - `Latitude`, `Longitude`: GPS coordinates - `ElevationInFeet`: Pass elevation in feet - `WeatherCondition`: Current weather condition - `TemperatureInFahrenheit`: Current temperature in Fahrenheit - `RestrictionOne`: Primary restriction status - `RestrictionTwo`: Secondary restriction status - `LastUpdated`: Timestamp of last update - **getMountainPassConditionById**: Returns conditions for a specific mountain pass - **Input**: `PassConditionID` (integer) - Unique pass identifier - **Output**: Single mountain pass condition object with all fields above ### Common Use Cases #### Mountain Pass Dashboard ```javascript import { useMountainPassConditions } from 'ws-dottie/wsdot-mountain-pass-conditions'; function MountainPassDashboard() { const { data: passes, isLoading, error } = useMountainPassConditions(); // Group passes by status const openPasses = passes?.filter(p => p.RestrictionOne === 'Open' || p.RestrictionOne === 'No Restrictions' ); const restrictedPasses = passes?.filter(p => p.RestrictionOne !== 'Open' && p.RestrictionOne !== 'No Restrictions' ); // Sort passes by elevation (highest first) const passesByElevation = [...(passes || [])].sort((a, b) => b.ElevationInFeet - a.ElevationInFeet ); return ( <div> <h1>Washington Mountain Passes</h1> {isLoading && <div>Loading mountain pass data...</div>} {error && <div>Error loading mountain pass data: {error.message}</div>} <div className="pass-status-summary"> <div className="pass-group"> <h2>Open Passes ({openPasses?.length || 0})</h2> {openPasses?.map(pass => ( <div key={pass.PassConditionID} className="pass-item open"> <h3>{pass.PassName}</h3> <p>Conditions: {pass.WeatherCondition}</p> <p>Temperature: {pass.TemperatureInFahrenheit}°F</p> <p>Elevation: {pass.ElevationInFeet} feet</p> </div> ))} </div> <div className="pass-group"> <h2>Restricted Passes ({restrictedPasses?.length || 0})</h2> {restrictedPasses?.map(pass => ( <div key={pass.PassConditionID} className="pass-item restricted"> <h3>{pass.PassName}</h3> <p>Restriction: {pass.RestrictionOne}</p> <p>Additional: {pass.RestrictionTwo}</p> <p>Conditions: {pass.WeatherCondition}</p> <p>Temperature: {pass.TemperatureInFahrenheit}°F</p> </div> ))} </div> </div> <div className="pass-details"> <h2>All Pass Conditions</h2> {passesByElevation?.map(pass => ( <div key={pass.PassConditionID} className="pass-details-item"> <h3>{pass.PassName}</h3> <p>Weather: {pass.WeatherCondition}</p> <p>Temperature: {pass.TemperatureInFahrenheit}°F</p> <p>Elevation: {pass.ElevationInFeet} feet</p> <p>Restriction 1: {pass.RestrictionOne}</p> <p>Restriction 2: {pass.RestrictionTwo}</p> <p>Last Updated: {new Date(pass.LastUpdated).toLocaleString()}</p> </div> ))} </div> </div> ); } ``` ## 💰 WSDOT Toll Rates API ### API Overview The WSDOT Toll Rates API provides real-time information about toll pricing for managed lanes throughout Washington State, helping travelers calculate costs and make informed routing decisions. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **toll-rates** | Real-time toll pricing for managed lanes | FREQUENT | ### Key Endpoints #### Toll Rates - **getTollRates**: Returns toll rates for all managed lanes - **Input**: No parameters required - **Output**: Array of toll rate information - **Key Fields**: - `TollRateID`: Unique toll rate identifier - `TripName`: Human-readable trip name - `StartLocationName`, `EndLocationName`: Start and end location names - `TollRate`: Current toll amount - `TimeOfDay`: Time period (Peak, Off-Peak) - `VehicleClass`: Vehicle type classification - `LastUpdated`: Timestamp of last update ### Common Use Cases #### Toll Calculator ```javascript import { useTollRates } from 'ws-dottie/wsdot-toll-rates'; function TollCalculator() { const [vehicleType, setVehicleType] = useState('2Axle'); const [trip, setTrip] = useState({ start: 'SR-167', end: 'SR-509' }); const { data: tollRates, isLoading, error } = useTollRates(); // Filter toll rates for selected trip const tripTollRates = tollRates?.filter(rate => rate.TripName.includes(trip.start) && rate.TripName.includes(trip.end) ) || []; // Find toll rate for selected vehicle type const findTollForVehicle = (rates, vehicleType) => { return rates?.find(rate => rate.VehicleClass === vehicleType); }; const currentToll = findTollForVehicle(tripTollRates, vehicleType); return ( <div> <h1>Toll Calculator</h1> {isLoading && <div>Loading toll rates...</div>} {error && <div>Error loading toll data: {error.message}</div>} <div className="toll-controls"> <div> <label>Vehicle Type: <select value={vehicleType} onChange={e => setVehicleType(e.target.value)}> <option value="2Axle">2-Axle Vehicle</option> <option value="3Axle">3-Axle Vehicle</option> <option value="Motorcycle">Motorcycle</option> </select> </label> </div> <div> <label>From: <select value={trip.start} onChange={e => setTrip({...trip, start: e.target.value})}> <option value="SR-167">SR-167</option> <option value="SR-509">SR-509</option> <option value="I-405">I-405 Express Lanes</option> </select> </label> <label>To: <select value={trip.end} onChange={e => setTrip({...trip, end: e.target.value})}> <option value="SR-509">SR-509</option> <option value="SR-167">SR-167</option> <option value="I-405">I-405 Express Lanes</option> </select> </label> </div> </div> <div className="toll-result"> <h2>Current Toll: ${currentToll?.TollRate || 'Not Available'}</h2> <p>Vehicle Type: {vehicleType}</p> <p>Route: {trip.start} to {trip.end}</p> {currentToll && ( <div> <p>Time of Day: {currentToll.TimeOfDay}</p> <p>Last Updated: {new Date(currentToll.LastUpdated).toLocaleString()}</p> </div> )} </div> </div> ); } ``` ## 🚦 WSDOT Traffic Flow API ### API Overview The WSDOT Traffic Flow API provides real-time information about traffic speeds and congestion throughout Washington State highways. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **flow-data** | Real-time traffic speed and congestion data | FREQUENT | ### Key Endpoints #### Traffic Flow - **getTrafficFlows**: Returns traffic flow data for all stations - **Input**: No parameters required - **Output**: Array of traffic flow information - **Key Fields**: - `FlowDataID`: Unique flow station identifier - `FlowStationLocation`: Description of station location - `Latitude`, `Longitude`: GPS coordinates - `CurrentSpeed`: Current traffic speed in mph - `FreeFlowSpeed`: Free flow speed in mph - `TimeStamp`: Timestamp of last update - `StationMilepost`: Milepost location - **getTrafficFlowById**: Returns traffic flow data for a specific station - **Input**: `FlowDataID` (integer) - Unique flow station identifier - **Output**: Single traffic flow object with all fields above ### Common Use Cases #### Traffic Flow Visualization ```javascript import { useTrafficFlows } from 'ws-dottie/wsdot-traffic-flow'; function TrafficFlowMap() { const { data: trafficFlows, isLoading, error } = useTrafficFlows(); // Process data for visualization const flowData = trafficFlows?.map(flow => ({ id: flow.FlowDataID, location: flow.FlowStationLocation, coordinates: [flow.Latitude, flow.Longitude], currentSpeed: flow.CurrentSpeed, freeFlowSpeed: flow.FreeFlowSpeed, congestion: flow.CurrentSpeed < flow.FreeFlowSpeed ? 'Congested' : 'Clear', speedRatio: flow.CurrentSpeed / flow.FreeFlowSpeed, timestamp: flow.TimeStamp })) || []; // Group flows by congestion level const congestionGroups = flowData.reduce((acc, flow) => { if (flow.congestion === 'Congested') acc.congested = [...(acc.congested || []), flow]; else acc.clear = [...(acc.clear || []), flow]; return acc; }, {}); return ( <div> <h1>Washington Traffic Flow</h1> {isLoading && <div>Loading traffic flow data...</div>} {error && <div>Error loading traffic flow data: {error.message}</div>} <div className="flow-summary"> <div className="flow-group"> <h3>Clear Flow ({congestionGroups.clear?.length || 0})</h3> <p>Average Speed: {calculateAverage(congestionGroups.clear, 'currentSpeed')?.toFixed(1)} mph</p> </div> <div className="flow-group"> <h3>Congested ({congestionGroups.congested?.length || 0})</h3> <p>Average Speed: {calculateAverage(congestionGroups.congested, 'currentSpeed')?.toFixed(1)} mph</p> </div> </div> <div className="traffic-map"> {/* Render map with traffic flow indicators */} {flowData.map(flow => ( <div key={flow.id} className={`traffic-indicator ${flow.congestion.toLowerCase()}`}> <h3>{flow.location}</h3> <p>Current Speed: {flow.currentSpeed} mph</p> <p>Free Flow Speed: {flow.freeFlowSpeed} mph</p> <p>Status: {flow.congestion}</p> <p>Speed Ratio: {(flow.speedRatio * 100).toFixed(1)}%</p> <p>Last Updated: {new Date(flow.timestamp).toLocaleTimeString()}</p> </div> ))} </div> </div> ); } // Helper function to calculate average values function calculateAverage(items, field) { if (!items || items.length === 0) return 0; const sum = items.reduce((acc, item) => acc + (item[field] || 0), 0); return sum / items.length; } ``` ## ⏱️ WSDOT Travel Times API ### API Overview The WSDOT Travel Times API provides estimated travel times between key locations throughout Washington State, helping travelers plan routes and estimate arrival times. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **travel-time-routes** | Travel time data for major corridors | STATIC | ### Key Endpoints #### Travel Times - **getTravelTimes**: Returns travel time data for all available routes - **Input**: No parameters required - **Output**: Array of travel time route information - **Key Fields**: - `TravelTimeID`: Unique route identifier - `Name`: Human-readable route name - `StartPointName`, `EndPointName`: Start and end location names - `CurrentTime`: Current travel time in minutes - `AverageTime`: Average travel time in minutes - `Distance`: Route distance in miles - `LastUpdated`: Timestamp of last update - **getTravelTimeById**: Returns travel time data for a specific route - **Input**: `TravelTimeID` (integer) - Unique route identifier - **Output**: Single travel time route object with all fields above ### Common Use Cases #### Route Comparison Tool ```javascript import { useTravelTimes } from 'ws-dottie/wsdot-travel-times'; function RouteComparison() { const { data: travelTimes, isLoading, error } = useTravelTimes(); // Group routes by common destinations const seattleRoutes = travelTimes?.filter(route => route.Name.includes('Seattle') || route.EndPointName.includes('Seattle') ) || []; const eastsideRoutes = travelTimes?.filter(route => route.Name.includes('Bellevue') || route.Name.includes('Redmond') || route.EndPointName.includes('Bellevue') || route.EndPointName.includes('Redmond') ) || []; // Sort routes by delay (longest first) const sortedRoutes = [...(travelTimes || [])].sort((a, b) => (b.CurrentTime - b.AverageTime) - (a.CurrentTime - a.AverageTime) ); return ( <div> <h1>Route Comparison</h1> {isLoading && <div>Loading travel times...</div>} {error && <div>Error loading travel time data: {error.message}</div>} <div className="route-comparison"> <div className="route-group"> <h2>Seattle Routes</h2> {seattleRoutes.map(route => ( <div key={route.TravelTimeID}> <h3>{route.Name}</h3> <p>From: {route.StartPointName}</p> <p>To: {route.EndPointName}</p> <p>Current Time: {route.CurrentTime} minutes</p> <p>Average Time: {route.AverageTime} minutes</p> <p>Delay: {route.CurrentTime - route.AverageTime > 0 ? '+' : ''}{Math.abs(route.CurrentTime - route.AverageTime)} minutes</p> <p>Distance: {route.Distance} miles</p> </div> ))} </div> <div className="route-group"> <h2>Eastside Routes</h2> {eastsideRoutes.map(route => ( <div key={route.TravelTimeID}> <h3>{route.Name}</h3> <p>From: {route.StartPointName}</p> <p>To: {route.EndPointName}</p> <p>Current Time: {route.CurrentTime} minutes</p> <p>Average Time: {route.AverageTime} minutes</p> <p>Delay: {route.CurrentTime - route.AverageTime > 0 ? '+' : ''}{Math.abs(route.CurrentTime - route.AverageTime)} minutes</p> <p>Distance: {route.Distance} miles</p> </div> ))} </div> </div> </div> ); } ``` ## 🔗 API Relationships Traffic APIs work together to provide comprehensive transportation information: ### Alerts + Mountain Pass Conditions Integration ```javascript import { useAlerts } from 'ws-dottie/wsdot-highway-alerts'; import { useMountainPassConditions } from 'ws-dottie/wsdot-mountain-pass-conditions'; function PassAwareTrafficDashboard() { const { data: alerts } = useAlerts(); const { data: passes } = useMountainPassConditions(); // Correlate alerts with mountain pass conditions const alertsWithPasses = alerts?.map(alert => { // Find nearby mountain passes (within 20 miles) const nearbyPasses = passes?.filter(p => { const distance = calculateDistance( alert.Latitude, alert.Longitude, p.Latitude, p.Longitude ); return distance <= 20; }); return { ...alert, nearbyPasses: nearbyPasses?.map(p => ({ name: p.PassName, restriction: p.RestrictionOne, conditions: p.WeatherCondition })) }; }) || []; return ( <div> <h1>Pass-Aware Traffic Dashboard</h1> <div className="traffic-alerts"> <h2>Current Incidents</h2> {alertsWithPasses.map(alert => ( <div key={alert.AlertID} className={`traffic-alert ${alert.Priority.toLowerCase()}`}> <h3>{alert.HeadlineDescription}</h3> <p>Priority: {alert.Priority}</p> <p>Location: {alert.StartRoadName} to {alert.EndRoadName}</p> {alert.nearbyPasses && alert.nearbyPasses.length > 0 && ( <div className="nearby-passes"> <h4>Nearby Mountain Passes:</h4> {alert.nearbyPasses.map((pass, index) => ( <div key={index} className="pass-info"> <p>{pass.name}: {pass.restriction} - {pass.conditions}</p> </div> ))} </div> )} </div> ))} </div> </div> ); } // Helper function to calculate distance between two points function calculateDistance(lat1, lon1, lat2, lon2) { const R = 3959; // Earth's radius in miles const dLat = (lat2 - lat1) * Math.PI / 180; const dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return R * c; } ``` ### Alerts + Traffic Flow Integration ```javascript import { useAlerts } from 'ws-dottie/wsdot-highway-alerts'; import { useTrafficFlows } from 'ws-dottie/wsdot-traffic-flow'; function TrafficDashboard() { const { data: alerts } = useAlerts(); const { data: flow } = useTrafficFlows(); // Correlate alerts with traffic flow data const alertsWithFlow = alerts?.map(alert => { // Find nearby flow stations (within 5 miles) const nearbyFlow = flow?.find(f => { const distance = calculateDistance( alert.Latitude, alert.Longitude, f.Latitude, f.Longitude ); return distance <= 5; }); return { ...alert, trafficSpeed: nearbyFlow?.CurrentSpeed, congestionLevel: nearbyFlow?.CurrentSpeed < nearbyFlow?.FreeFlowSpeed ? 'High' : 'Low' }; }) || []; return ( <div> <h1>Traffic Dashboard</h1> <div className="traffic-alerts"> <h2>Current Incidents</h2> {alertsWithFlow.map(alert => ( <div key={alert.AlertID} className={`traffic-alert ${alert.Priority.toLowerCase()}`}> <h3>{alert.HeadlineDescription}</h3> <p>Priority: {alert.Priority}</p> <p>Location: {alert.StartRoadName} to {alert.EndRoadName}</p> <p>Traffic Speed: {alert.trafficSpeed} mph</p> <p>Congestion: {alert.congestionLevel}</p> </div> ))} </div> </div> ); } // Helper function to calculate distance between two points function calculateDistance(lat1, lon1, lat2, lon2) { const R = 3959; // Earth's radius in miles const dLat = (lat2 - lat1) * Math.PI / 180; const dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return R * c; } ``` ### Travel Times + Toll Rates Integration ```javascript import { useTravelTimes } from 'ws-dottie/wsdot-travel-times'; import { useTollRates } from 'ws-dottie/wsdot-toll-rates'; function RouteOptimizer() { const { data: travelTimes } = useTravelTimes(); const { data: tollRates } = useTollRates(); // Calculate optimal route considering both time and cost const optimizedRoutes = travelTimes?.map(route => { // Find toll rate for this route const tollRate = tollRates?.find(t => t.TripName.includes(route.Name) || t.TripName.includes(route.StartPointName) || t.TripName.includes(route.EndPointName) ); // Calculate total cost (time + toll) const timeCost = route.CurrentTime * 0.5; // $0.50 per minute const tollCost = tollRate?.TollRate || 0; const totalCost = timeCost + tollCost; return { ...route, tollAmount: tollRate?.TollRate || 0, timeCost, totalCost }; }).sort((a, b) => a.totalCost - b.totalCost) || []; return ( <div> <h1>Route Optimizer</h1> <h2>Optimal Routes (by time + cost)</h2> {optimizedRoutes.map(route => ( <div key={route.TravelTimeID}> <h3>{route.Name}</h3> <p>From: {route.StartPointName}</p> <p>To: {route.EndPointName}</p> <p>Time: {route.CurrentTime} minutes</p> <p>Average: {route.AverageTime} minutes</p> <p>Delay: {route.CurrentTime - route.AverageTime > 0 ? '+' : ''}{Math.abs(route.CurrentTime - route.AverageTime)} minutes</p> <p>Toll: ${route.tollAmount}</p> <p>Time Cost: ${route.timeCost.toFixed(2)}</p> <p>Total Cost: ${route.totalCost.toFixed(2)}</p> </div> ))} </div> ); } ``` ## 📊 Performance Considerations ### Caching Strategies - **Highway Alerts**: `REALTIME_UPDATES` (5-second refresh) - **Traffic Flow**: `REALTIME_UPDATES` (5-second refresh) - **Travel Times**: `MINUTE_UPDATES` (1-minute refresh) - **Highway Cameras**: `DAILY_UPDATES` (daily refresh) - **Mountain Pass Conditions**: `FREQUENT_UPDATES` (15-30 minute refresh) - **Toll Rates**: `MINUTE_UPDATES` (1-minute refresh) - **Border Crossings**: `MINUTE_UPDATES` (5-15 minute refresh) ### Optimization Tips - **Real-time Data**: Use appropriate caching for alerts and flow data - **Camera Images**: Implement lazy loading for camera feeds - **Route Calculations**: Cache common route calculations - **Regional Filtering**: Use geographic filtering to reduce data volume - **Pass Monitoring**: Focus on passes relevant to travel routes ## 🔗 Detailed Documentation For detailed endpoint documentation, interactive examples, and schema definitions, see our generated documentation: - **[WSDOT Border Crossings HTML](../../../redoc/wsdot-border-crossings.html)** - Interactive border crossing documentation - **[WSDOT Highway Alerts HTML](../../../redoc/wsdot-highway-alerts.html)** - Interactive alerts documentation - **[WSDOT Highway Cameras HTML](../../../redoc/wsdot-highway-cameras.html)** - Interactive camera documentation - **[WSDOT Mountain Pass Conditions HTML](../../../redoc/wsdot-mountain-pass-conditions.html)** - Interactive pass conditions documentation - **[WSDOT Toll Rates HTML](../../../redoc/wsdot-toll-rates.html)** - Interactive toll documentation - **[WSDOT Traffic Flow HTML](../../../redoc/wsdot-traffic-flow.html)** - Interactive flow documentation - **[WSDOT Travel Times HTML](../../../redoc/wsdot-travel-times.html)** - Interactive travel times documentation ## 📚 Next Steps - **[TanStack Query Guide](../advanced/tanstack-query.md)** - React patterns with TanStack Query - **[Fetching Data Guide](../advanced/fetching-data.md)** - Server-side and client-side usage patterns - **[Performance Guide](../advanced/performance-guide.md)** - Performance optimization strategies - **[Error Handling Guide](../advanced/error-handling.md)** - Error recovery patterns