feat(archives): players-over-time chart (replaces player engagement)#448
Merged
Conversation
…catter) Replace the per-event Player Engagement scatter with a per-war player-count line that hooks into the existing /archives faction toggle: - global → total-players line (brand primary) + dots for every event - a faction → that faction's line (faction-colored) + only its events' dots Event dots sit on the line at each event's start day with a type · region · faction · outcome tooltip. No legend (the toggle labels it). - getCampaign: additive `playerTimeseries` field (per-bucket players from h1_statistic via new groupStatisticByBucket); [] for pre-telemetry seasons. - buildPlayerLine.mjs: pure, unit-tested line+dots builder. - PlayersOverTimeChart.jsx (+ Loader), wired into ArchivesClient's faction section; removed PlayerEngagementChart + buildEngagementSeries (+ scatter). - Hides for historical seasons with no player timeseries. Verified: lint, typecheck, test:unit (1514), build; DevTools across all toggle states + hide-when-empty on a telemetry-less season. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The x-axis plotted the integer day, so multiple intra-day buckets collapsed
onto one column and the line drew vertical stacks instead of a real time
series. Use continuous (fractional) day-into-war anchored to war_start, and
switch the line from monotone to linear so sharp changes read as honest cliffs
rather than smoothed curves.
- buildPlayerLine: `warStart` param; fractional `dayInto` x for points + dots
- PlayersOverTimeChart: declares `warStart`, line type="linear"
- ArchivesClient: passes `warStart={data?.war_start}`
- tests: fractional-x dot, intra-day-distinct-x regression, warStart anchor
Verified: lint, typecheck, test:unit (1516), build; DevTools on S157 — x is
strictly increasing, no vertical collapse.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Show a tick for every day (D0…D<last>) instead of the ~5 auto-thinned ticks, and anchor the axis 0-based to war_start so the day labels match Conquest Progress for side-by-side reading. The line stays time-proportional (continuous fractional x); only the tick set and base changed. - buildPlayerLine: 0-based dayInto (drop the +1) - PlayersOverTimeChart: explicit ticks=[0..lastDay], domain=[0, lastDay] - tests updated to the 0-based convention Verified: lint, typecheck, test:unit (1516), build; DevTools S157 shows D0…D40.
Two fixes for the players-over-time chart and its comparability with Conquest Progress (FactionHealthChart): 1. Tooltip was stuck on one event regardless of cursor. It read the dots Scatter (a separate data array from the line), whose payload doesn't follow the active index. Rewrote it to read the LINE series + active `label` — showing "Day N · M players" at the hovered point, with the event details appended when an event sits on that day. 2. Conquest Progress used a category x-axis (one slot per snapshot, not time-proportional, duplicate day labels). Gave it the same continuous, 0-based, time-proportional day axis as players-over-time, and a SHARED day-domain (warDayMax, passed to both) so the two charts line up day-for-day. - FactionHealthChart: fractional 0-based day, type=number XAxis, all-day ticks, warStart + domainMax props; ChartTooltip rounds the day. - PlayersOverTimeChart: PlayerTooltip reads line+label+event; domainMax prop. - ArchivesClient: computes warDayMax, passes warStart+domainMax to both charts. - Tests: FactionHealthChart intra-day fractional-day regression. Verified: lint, typecheck, test:unit, build; DevTools — both axes D0-based, time-proportional, shared [0,44] domain; tooltip reads the hovered line point.
…cursor The players-over-time tooltip froze past the first few days. The <Scatter> held its OWN short data array (~25-78 dots) inside a ComposedChart whose single activeTooltipIndex sweeps the ~600-point line; past the scatter's indices recharts clamped the index and froze the tooltip. Conquest Progress never broke because all its series share one data array. Render events as <ReferenceDot> markers (non-data decorators) instead of a Scatter, so the Line is the SOLE tooltip data source — like Conquest. The tooltip now reports the player count (+ event) at every hovered day. Root cause + fix from a four-way debate (Opus/Sonnet/Codex/Gemini): unanimous on the cause, 3/4 on ReferenceDots over Gemini's unified-data merge. Verified: lint, typecheck, test:unit, build; DevTools differential sweep — Players now tracks D6/186 → D28/168 → D34/166, identical behaviour to Conquest.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the per-event Player Engagement scatter with a per-war player-count line over time, with war events mapped onto it — as discussed.
Behavior (hooks into the existing faction toggle)
type · region · faction · outcomeImplementation
getCampaign: additiveplayerTimeseriesfield (per-bucket player counts fromh1_statisticvia a newgroupStatisticByBucket, mirroringgroupStatusByBucket);[]for pre-telemetry seasons. Verified additive — no existing consumer changes.buildPlayerLine.mjs: pure, unit-tested builder (line points + event dots, faction-driven).PlayersOverTimeChart.jsx(+…Loader), wired intoArchivesClient's faction section.PlayerEngagementChart.jsx,PlayerEngagementChartLoader.jsx,buildEngagementSeries.mjs(+ test).Verification
✅ lint (0 err) · typecheck · test:unit (1514) · build — node 24.
✅ DevTools, live (Chrome MCP), all confirmed:
#e8822a, dots filter 25→1, faction-coloredArchivesClient.jsx; merge-order may want a glance.🤖 Generated with Claude Code