Compare commits
No commits in common. "d688bff8134973ccec875c8bd1f4a7c5442eb2a3" and "76a187bbb6d8b4e440dc7fe3d7a68332f187a6f3" have entirely different histories.
d688bff813
...
76a187bbb6
|
@ -1,4 +1,7 @@
|
||||||
require('regenerator-runtime/runtime');
|
require('regenerator-runtime/runtime');
|
||||||
|
|
||||||
const {createMap} = require('./map');
|
const {createMap} = require('./map');
|
||||||
|
|
||||||
|
require('../tam/simulation');
|
||||||
|
|
||||||
createMap(/* map = */ 'map');
|
createMap(/* map = */ 'map');
|
||||||
|
|
|
@ -21,7 +21,6 @@ const color = require('color');
|
||||||
const mapboxToken = `pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\
|
const mapboxToken = `pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\
|
||||||
h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw`;
|
h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw`;
|
||||||
|
|
||||||
const simulation = require('../tam/simulation');
|
|
||||||
const network = require('../tam/network.json');
|
const network = require('../tam/network.json');
|
||||||
|
|
||||||
const getRouteColors = routes =>
|
const getRouteColors = routes =>
|
||||||
|
@ -40,7 +39,7 @@ const getRouteColors = routes =>
|
||||||
return ['#FFFFFF'];
|
return ['#FFFFFF'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeDataSources = () =>
|
const makeDataSources = async () =>
|
||||||
{
|
{
|
||||||
const segmentsSource = new VectorSource();
|
const segmentsSource = new VectorSource();
|
||||||
const stopsSource = new VectorSource();
|
const stopsSource = new VectorSource();
|
||||||
|
@ -102,7 +101,7 @@ const stopsStyle = feature => new Style({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const createMap = target =>
|
const createMap = async (target) =>
|
||||||
{
|
{
|
||||||
// Map background
|
// Map background
|
||||||
const backgroundSource = new XYZSource({
|
const backgroundSource = new XYZSource({
|
||||||
|
@ -117,8 +116,8 @@ const createMap = target =>
|
||||||
source: backgroundSource,
|
source: backgroundSource,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Static data overlay
|
// Data overlay
|
||||||
const {segmentsSource, stopsSource} = makeDataSources();
|
const {segmentsSource, stopsSource} = await makeDataSources();
|
||||||
|
|
||||||
const segmentsBorderLayer = new VectorLayer({
|
const segmentsBorderLayer = new VectorLayer({
|
||||||
source: segmentsSource,
|
source: segmentsSource,
|
||||||
|
@ -145,63 +144,6 @@ const createMap = target =>
|
||||||
updateWhileAnimating: true,
|
updateWhileAnimating: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Dynamic data overlay
|
|
||||||
const coursesSource = new VectorSource();
|
|
||||||
|
|
||||||
const onFrame = courses =>
|
|
||||||
{
|
|
||||||
// Remove stale courses
|
|
||||||
for (let feature of coursesSource.getFeatures())
|
|
||||||
{
|
|
||||||
if (!(feature.getId() in courses))
|
|
||||||
{
|
|
||||||
coursesSource.removeFeature(feature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new courses or update existing courses
|
|
||||||
const newFeatures = [];
|
|
||||||
|
|
||||||
for (let [courseId, course] of Object.entries(courses))
|
|
||||||
{
|
|
||||||
if ('position' in course)
|
|
||||||
{
|
|
||||||
const feature = coursesSource.getFeatureById(courseId);
|
|
||||||
const coords = proj.fromLonLat([
|
|
||||||
course.position.lon,
|
|
||||||
course.position.lat
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (feature === null)
|
|
||||||
{
|
|
||||||
const feature = new Feature({
|
|
||||||
colors: ['#FF0000'],
|
|
||||||
geometry: new Point(coords)
|
|
||||||
});
|
|
||||||
|
|
||||||
feature.setId(courseId);
|
|
||||||
newFeatures.push(feature);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
feature.getGeometry().setCoordinates(coords);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coursesSource.addFeatures(newFeatures);
|
|
||||||
};
|
|
||||||
|
|
||||||
simulation.run(onFrame);
|
|
||||||
|
|
||||||
const coursesLayer = new VectorLayer({
|
|
||||||
source: coursesSource,
|
|
||||||
style: stopsStyle,
|
|
||||||
|
|
||||||
updateWhileInteracting: true,
|
|
||||||
updateWhileAnimating: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Setup map
|
// Setup map
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
target,
|
target,
|
||||||
|
@ -210,7 +152,6 @@ const createMap = target =>
|
||||||
segmentsBorderLayer,
|
segmentsBorderLayer,
|
||||||
segmentsInnerLayer,
|
segmentsInnerLayer,
|
||||||
stopsLayer,
|
stopsLayer,
|
||||||
coursesLayer,
|
|
||||||
],
|
],
|
||||||
view: new View({
|
view: new View({
|
||||||
center: proj.fromLonLat([3.88, 43.605]),
|
center: proj.fromLonLat([3.88, 43.605]),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
const tam = require('./sources/tam');
|
const tam = require('./sources/tam');
|
||||||
const util = require('../util');
|
const util = require('../util');
|
||||||
const network = require('./network.json');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparison function between two stop passings.
|
* Comparison function between two stop passings.
|
||||||
|
@ -58,28 +57,6 @@ const getCourses = () => new Promise((res, rej) =>
|
||||||
|
|
||||||
if (!util.isObject(entry))
|
if (!util.isObject(entry))
|
||||||
{
|
{
|
||||||
// Filter courses to only keep those referring to known data
|
|
||||||
for (let courseId of Object.keys(courses))
|
|
||||||
{
|
|
||||||
const course = courses[courseId];
|
|
||||||
|
|
||||||
if (!(course.line in network.lines))
|
|
||||||
{
|
|
||||||
delete courses[courseId];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (let passing of course.nextPassings)
|
|
||||||
{
|
|
||||||
if (!(passing.stopId in network.stops))
|
|
||||||
{
|
|
||||||
delete courses[courseId];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of courses information stream. Sort next stops by increasing
|
// End of courses information stream. Sort next stops by increasing
|
||||||
// arrival time in each course then save result in memory cache
|
// arrival time in each course then save result in memory cache
|
||||||
for (let course of Object.values(courses))
|
for (let course of Object.values(courses))
|
||||||
|
|
|
@ -71,6 +71,12 @@ const updateFromTam = async (courses) =>
|
||||||
|
|
||||||
for (let [id, course] of Object.entries(currentCourses))
|
for (let [id, course] of Object.entries(currentCourses))
|
||||||
{
|
{
|
||||||
|
// Only track selected lines
|
||||||
|
if (!['1', '2', '3', '4'].includes(course.line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Find out the next stop, ignoring the ones that are in the past
|
// Find out the next stop, ignoring the ones that are in the past
|
||||||
let nextStop = null;
|
let nextStop = null;
|
||||||
let arrivalTime = null;
|
let arrivalTime = null;
|
||||||
|
@ -149,7 +155,6 @@ const updatePositions = (courses, time) =>
|
||||||
{
|
{
|
||||||
if (course.state === 'moving')
|
if (course.state === 'moving')
|
||||||
{
|
{
|
||||||
// Increase the travelled distance respective to the current speed
|
|
||||||
const delta = course.speed * time;
|
const delta = course.speed * time;
|
||||||
|
|
||||||
const segment = getCurrentSegment(course);
|
const segment = getCurrentSegment(course);
|
||||||
|
@ -163,66 +168,20 @@ const updatePositions = (courses, time) =>
|
||||||
{
|
{
|
||||||
course.traveledDistance += delta;
|
course.traveledDistance += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recompute updated position
|
|
||||||
const departureStop = network.stops[course.departureStop];
|
|
||||||
const arrivalStop = network.stops[course.arrivalStop];
|
|
||||||
const nextNodeIndex = segment.points.findIndex(
|
|
||||||
({distance}) => distance >= course.traveledDistance);
|
|
||||||
|
|
||||||
if (nextNodeIndex === 0)
|
|
||||||
{
|
|
||||||
course.position = {
|
|
||||||
lat: departureStop.lat,
|
|
||||||
lon: departureStop.lon
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (nextNodeIndex === -1)
|
|
||||||
{
|
|
||||||
course.position = {
|
|
||||||
lat: arrivalStop.lat,
|
|
||||||
lon: arrivalStop.lon
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const previousNode = segment.points[nextNodeIndex - 1];
|
|
||||||
const nextNode = segment.points[nextNodeIndex];
|
|
||||||
|
|
||||||
const curLength = course.traveledDistance
|
|
||||||
- previousNode.distance;
|
|
||||||
const totalLength = nextNode.distance
|
|
||||||
- previousNode.distance;
|
|
||||||
const progression = curLength / totalLength;
|
|
||||||
|
|
||||||
course.position = {
|
|
||||||
lat: progression * nextNode.lat
|
|
||||||
+ (1 - progression) * previousNode.lat,
|
|
||||||
lon: progression * nextNode.lon
|
|
||||||
+ (1 - progression) * previousNode.lon,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const currentStop = network.stops[course.currentStop];
|
|
||||||
course.position = {
|
|
||||||
lat: currentStop.lat,
|
|
||||||
lon: currentStop.lon,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const run = callback =>
|
|
||||||
{
|
|
||||||
const courses = {};
|
const courses = {};
|
||||||
let lastFrame = null;
|
let lastFrame = null;
|
||||||
let lastUpdate = null;
|
let lastUpdate = null;
|
||||||
|
|
||||||
const loop = () =>
|
const loop = now =>
|
||||||
{
|
{
|
||||||
const now = Date.now();
|
const time = lastFrame === null ? 0 : now - lastFrame;
|
||||||
|
|
||||||
|
lastFrame = now;
|
||||||
|
updatePositions(courses, time);
|
||||||
|
|
||||||
if (lastUpdate === null || lastUpdate + 5000 <= now)
|
if (lastUpdate === null || lastUpdate + 5000 <= now)
|
||||||
{
|
{
|
||||||
|
@ -230,15 +189,7 @@ const run = callback =>
|
||||||
updateFromTam(courses);
|
updateFromTam(courses);
|
||||||
}
|
}
|
||||||
|
|
||||||
const time = lastFrame === null ? 0 : now - lastFrame;
|
requestAnimationFrame(loop);
|
||||||
lastFrame = now;
|
|
||||||
updatePositions(courses, time);
|
|
||||||
|
|
||||||
callback(courses);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const interval = setInterval(loop, 24);
|
requestAnimationFrame(loop);
|
||||||
return () => clearInterval(interval);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.run = run;
|
|
||||||
|
|
Loading…
Reference in New Issue