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
Markdown
# 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