feat(cartesian): treat all-Date x values as a time scale - #683
Open
denniske wants to merge 1 commit into
Open
Conversation
When every xKey value is a Date, the x axis becomes a time scale: points are positioned by elapsed time rather than by index, ticks land on calendar boundaries, and formatXLabel receives a Date. Dates are positioned as epoch timestamps on the existing linear scale, which is equivalent to a d3 time scale for positioning, so scale construction is unchanged. Only tick generation and label formatting need to know the values are dates. Mixed arrays, empty arrays and Invalid Dates fall back to the existing numerical/categorical handling, so charts that don't use dates are unaffected. Closes FormidableLabs#384 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@denniske is attempting to deploy a commit to the Nearform Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: ce3815a The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
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.
Description
Disclaimer: Created with Claude Code Opus 5. Tested manually on my app.
Adds time scale support to the Cartesian x axis, as requested in #384.
When every
xKeyvalue is aDate, the axis is treated as a time scale:formatXLabelreceives aDateDetection is deliberately strict: mixed arrays, empty arrays,
Invalid Date, date-like strings and raw timestamps all keep their existing numerical/categorical behavior, so charts that don't use dates are unaffected.Implementation notes
Dates are positioned as epoch timestamps on the existing linear scale. A d3 time scale and a linear scale over timestamps produce identical positions — they differ only in tick placement and formatting. So
makeScaleis untouched, andisDateDataimpliesisNumericalData, letting dates reuse the whole numeric path (domain, bounds, zoom, press handling) unchanged.Only two places need to know the values are dates:
getXAxisTicksborrowsscaleTimeto pick calendar-aware boundaries from the scale's domain, then maps back to timestamps so every downstream consumer stays numeric. Without this, a linear scale over timestamps produces ticks at values like1756000000000.isNumericalData ? tick : ix[tick]pattern becomesisDateData ? new Date(tick) : …, soformatXLabelgets a realDate.d3-scalealready exportsscaleTimeand is an existing dependency, so no new dependencies are added.Two smaller changes fall out of this:
InputFieldTypegainsDate. Without it,InputFields<T>filteredDate-typed keys out entirely, soxKeycouldn't be typed to a date column.formatXLabelusestoLocaleDateString()forDatevalues, rather thanString(date)'s"Mon Jan 01 2024 00:00:00 GMT+0100 (…)".Scope / limitations
isDateData: false. TherexKeydrives the category axis, so a time scale doesn't apply the same way; this keeps horizontal layout semantics unchanged.tickValuesstill acceptsnumber[], notDate[]. Explicit tick values continue to take precedence over generated date ticks. Widening it means touchingdownsampleTicks/getDomainFromTicks, which currently throw on non-numbers — there's an existing TODO there about string/date support. Happy to add it here or in a follow-up, whichever you prefer.Type of Change
How Has This Been Tested?
yarn check:codepasses (lint, typecheck, 274 unit tests + 3 headless).22 new tests across three files:
lib/src/utils/isDateData.test.ts— detection, includingInvalid Date, empty and mixed arrayslib/src/cartesian/utils/getXAxisTicks.test.ts— ticks are calendar-aligned, stay inside the domain, remain numeric, and yield to explicittickValueslib/src/cartesian/utils/transformInputData.test.ts— end to end: detection, timestamp positioning,ixpreserving the originalDateobjects, chronological sorting with y values reordered to match, and that date-like strings/timestamps are not treated as datesThe load-bearing one asserts proportional spacing: for points at Jan 1, Jan 2 and Jan 11 across a 500px window, the middle point lands at
50(10% of the span) rather than the categorical250. That's what distinguishes a real time scale from evenly spaced categories.Also verified on a physical device (iOS): a new
Date Axisexample screen renders one chart with deliberately irregular gaps (Jan 1–3, then Jan 13 and Jan 20) and one spanning twelve months with noformatXLabel.Checklist
Happy to add website documentation in this PR or a follow-up — let me know which you'd prefer.