| name | transit-3d-realtime |
| version | 1.0.0 |
| description | Visualización 3D de tránsito urbano en tiempo real — patrón inspirado en Mini Tokyo 3D. Mapa 3D de transporte público con trenes/metros/buses animados, tracking de vehículos, y datos GTFS-realtime. |
| tags | ["transit","3d","gtfs","realtime","threejs","visualization","transport"] |
Tránsito 3D en Tiempo Real
Resumen
Patrón para construir visualizaciones 3D de sistemas de transporte público en tiempo real. Inspirado en Mini Tokyo 3D (⭐4.1K) — mapa 3D de Tokyo que muestra trenes, aviones y estaciones en movimiento real.
Cuándo usar
- Visor 3D de red de metro/autobús con vehículos animados en tiempo real
- Dashboard de movilidad urbana con tracking GPS de flota
- Visualización de datos GTFS-realtime en 3D
- Mapa interactivo de tránsito con route search y playback
Arquitectura
GTFS estático (rutas, paradas, horarios)
+ GTFS-realtime (posiciones de vehículos, delays)
+ Datos geoespaciales (GeoJSON de líneas)
↓
Three.js scene
├── Terreno 3D (tiles o plano con elevación)
├── Líneas de ruta (TubeGeometry extruded)
├── Estaciones (sprites o meshes)
├── Vehículos (meshes animados con interpolation)
└── UI overlay (panel de búsqueda, info, controles)
↓
Loop de animación
├── Update posiciones de vehículos (fetch cada 3-10s)
├── Interpolate entre posiciones (smooth movement)
├── Camera tracking (follow vehicle)
└── LOD: simplificar lejanos, detallar cercanos
Patrón Mini Tokyo 3D
const railways = await loadGTFS('railways.json');
const stations = await loadGTFS('stations.json');
const vehicles = await fetchRealtime();
railways.forEach(rail => {
const points = rail.coordinates.map(c => latLngTo3D(c[1], c[0]));
const curve = new THREE.CatmullRomCurve3(points);
const geometry = new THREE.TubeGeometry(curve, 64, 2, 8, false);
const mesh = new THREE.Mesh(geometry, lineMaterial);
scene.add(mesh);
});
stations.forEach(st => {
const pos = latLngTo3D(st.lng, st.lat);
const geom = new THREE.SphereGeometry(3, 16, 16);
const mesh = new THREE.Mesh(geom, stationMaterial);
mesh.position.copy(pos);
mesh.userData = { name: st.name, lines: st.lines };
scene.add(mesh);
});
function updateVehicles(realtimeData) {
realtimeData.forEach(v => {
let mesh = vehicleMeshes.get(v.id);
if (!mesh) {
mesh = new THREE.Mesh(trainGeometry, trainMaterial);
vehicleMeshes.set(v.id, mesh);
scene.add(mesh);
}
const target = latLngTo3D(v.longitude, v.latitude);
mesh.userData.target = target;
mesh.userData.bearing = v.bearing;
});
}
function animate() {
requestAnimationFrame(animate);
const lerpFactor = 0.05;
vehicleMeshes.forEach(mesh => {
if (mesh.userData.target) {
mesh.position.lerp(mesh.userData.target, lerpFactor);
mesh.rotation.y = THREE.MathUtils.lerp(
mesh.rotation.y, mesh.userData.bearing, lerpFactor
);
}
});
renderer.render(scene, camera);
}
setInterval(() => fetchRealtime().then(updateVehicles), 5000);
Controles interactivos (patrón Mini Tokyo)
| Acción | Función |
|---|
| Drag | Pan del mapa |
| Wheel | Zoom in/out |
| Right-click drag | Tilt + rotate |
| Shift + drag | Box zoom |
| Click vehículo | Tracking mode |
| Click estación | Info panel |
| Hover | Tooltip info |
| Playback button | Modo replay temporal |
| Layer button | Toggle capas (trenes, buses, etc.) |
GTFS-realtime integration
async function fetchRealtime() {
const response = await fetch('https://api.transportes.gob.es/gtfs-rt/vehicles');
const data = await response.json();
return data.entity.map(e => ({
id: e.vehicle.vehicle.id,
latitude: e.vehicle.position.latitude,
longitude: e.vehicle.position.longitude,
bearing: e.vehicle.position.bearing,
speed: e.vehicle.position.speed,
trip_id: e.vehicle.trip.tripId,
route_id: e.vehicle.trip.routeId
}));
}
Pitfalls
- Interpolación de posiciones: NO actualizar posición directamente del fetch. Usar
lerp() para smooth movement entre updates.
- Rate limiting GTFS-realtime: Fetch cada 3-10s, no más frecuente. Cachear última posición.
- Coordenadas: Convertir lat/lng a coordenadas 3D del scene. Usar proyección adecuada (WebMercator o local tangent plane).
- LOD de vehículos: Si hay >500 vehículos, usar instanced meshes o sprites para lejanos.
- Underground mode: Las líneas de metro deben poder ocultarse/visualizarse. Toggle de capa.
- Eco mode: Reducir framerate (30fps) para ahorrar batería en mobile.
- i18n: Cargar nombres de estaciones en múltiples idiomas desde dictionary JSON.
Referencias
Hecho con ❤️ por David Antizar