mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(traffic): stop a few matched roads reading as "no matches"
The live flow status derived its wording from the rounded coverage percent, so 1 matched dot among 300 rounded to 0% and read "SIMULATED ... (no matches)", and 1 simulated dot among 300 rounded to 100% and dropped "Unmatched: simulated". Coverage now stays within 1-99% whenever both matched and simulated dots are shown.
This commit is contained in:
1 parent
a4d3701c3c
commit
c6f437ed52
3 files changed
+38
-5
No files matched your search
Vendored
+13
-2
@@ -259,7 +259,8 @@ export function createControls({ state: layerState, services, parts, source }) {
|
||||
* `error` carries this instant's health, so a live-configured layer whose
|
||||
* flow feed went down reads DEGRADED with the reason instead of a stale
|
||||
* LIVE coverage number. `flowCoveragePct` is shown dots on matched roads /
|
||||
* all shown dots (0–100 int), excluding closures; `tilesFetched` counts flow-tile requests
|
||||
* all shown dots (0–100 int, kept within 1–99 while both kinds are shown),
|
||||
* excluding closures; `tilesFetched` counts flow-tile requests
|
||||
* issued to the proxy this session (decode-cache hits excluded).
|
||||
* @returns {{count:number, lastUpdate:number|null, loading:boolean,
|
||||
* mode:'live'|'sim', error:string|null, flowCoveragePct:number,
|
||||
@@ -304,8 +305,18 @@ export function createControls({ state: layerState, services, parts, source }) {
|
||||
Boolean(layerState._heightPending);
|
||||
const { free, slow, jam, sim } = layerState._bucketCounts;
|
||||
const matched = free + slow + jam;
|
||||
// The label reads 0 as "no matches" and 100 as nothing simulated, so
|
||||
// rounding must not reach either while both kinds of dot are shown.
|
||||
const flowCoveragePct =
|
||||
matched + sim > 0 ? Math.round((100 * matched) / (matched + sim)) : 0;
|
||||
matched + sim > 0
|
||||
? Math.min(
|
||||
sim > 0 ? 99 : 100,
|
||||
Math.max(
|
||||
matched > 0 ? 1 : 0,
|
||||
Math.round((100 * matched) / (matched + sim)),
|
||||
),
|
||||
)
|
||||
: 0;
|
||||
const feed = parts.model.trafficFeedPresentation({
|
||||
liveMode: layerState._liveMode,
|
||||
fetching: loading,
|
||||
|
||||
@@ -516,6 +516,26 @@ test('late closures hide and stop dots; coverage counts shown matched dots, and
|
||||
assert.equal(controls.getStats().flowCoveragePct, 80);
|
||||
});
|
||||
|
||||
test('coverage never rounds to "no matches" or full coverage while both kinds of dot are shown', async () => {
|
||||
const { state, controls } = await matchingContext(async () => []);
|
||||
state._bucketCounts = { free: 1, slow: 0, jam: 0, sim: 300 };
|
||||
assert.equal(controls.getStats().flowCoveragePct, 1);
|
||||
assert.equal(
|
||||
controls.getStats().loadingLabel,
|
||||
'LIVE · Roads: OpenStreetMap · Flow: TomTom · 1% cov · Unmatched: simulated',
|
||||
);
|
||||
state._bucketCounts = { free: 300, slow: 0, jam: 0, sim: 1 };
|
||||
assert.equal(controls.getStats().flowCoveragePct, 99);
|
||||
assert.equal(
|
||||
controls.getStats().loadingLabel,
|
||||
'LIVE · Roads: OpenStreetMap · Flow: TomTom · 99% cov · Unmatched: simulated',
|
||||
);
|
||||
state._bucketCounts = { free: 300, slow: 0, jam: 0, sim: 0 };
|
||||
assert.equal(controls.getStats().flowCoveragePct, 100);
|
||||
state._bucketCounts = { free: 0, slow: 0, jam: 0, sim: 300 };
|
||||
assert.equal(controls.getStats().flowCoveragePct, 0);
|
||||
});
|
||||
|
||||
test('refresh failure removes cached matches and reports simulated flow', async () => {
|
||||
const { flow, state, model, controls } = await matchingContext(async () => {
|
||||
throw new Error('HTTP 429');
|
||||
|
||||
Reference in new issue
Block a user