Skip to content

feat(quill-charts): monotone curve and axis-flush line strokes - #67989

Merged
sampennington merged 4 commits into
masterfrom
sam/quill-charts-line-stroke
Jul 3, 2026
Merged

feat(quill-charts): monotone curve and axis-flush line strokes#67989
sampennington merged 4 commits into
masterfrom
sam/quill-charts-line-stroke

Conversation

@sampennington

Copy link
Copy Markdown
Contributor

Problem

Part 1 of the quill charts style refresh (split from #67982 for reviewability). Line charts can only draw straight segments, and a stroke whose first point sits at the plot edge (or whose value hugs zero) straddles any axis line drawn there — half the stroke bleeds past the axis into the gutter.

Changes

Library-only, opt-in, default-off — nothing renders differently unless a host passes the new options.

  • curve: 'monotone' — monotone-cubic (Fritsch–Carlson) line/area smoothing that passes through every point and never overshoots a peak; a shortened control arm (1/4 vs the standard 1/3) keeps the bend gentle. Hand-rolled rather than d3-shape because the arm length isn't expressible with curveMonotoneX. The default linear path keeps the existing zero-allocation streaming moveTo/lineTo.
  • yFloor draw-time clamp + a left-edge clip on the shared line/area layer, so charts that draw axis lines (part 2) can rest baseline-hugging strokes on the x-axis and end the first point's stroke at the y-axis. Scales, ticks, tooltips, and hit-testing stay at true positions — only the drawn stroke is adjusted.

How did you test this code?

  • New unit tests: bezier emission per point pair, no-overshoot invariant at a peak, subpath splitting at gaps, yFloor clamping (linear + smooth), area edge smoothing
  • Full charts jest suite: 59 suites / 1528 tests pass
  • Manual visual review in the local app across trends/SQL line and area charts

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Docs update

The charts AGENTS.md gains the option docs in part 2 (#67982) where the axis-line style that uses them lands.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Built with Claude Code with the human directing the visuals against the live app. This split is one of four stacked PRs replacing the original monolithic #67982 after review. Incorporates sp-ship review findings: the linear path keeps streaming (no per-draw allocation), and a scale-inset approach to the axis-flush problem was tried and rejected because it moved ticks/crosshair off the axis.

🤖 Generated with Claude Code

Opt-in, default-off line rendering options:

- curve: 'monotone' — monotone-cubic (Fritsch-Carlson) line/area
  smoothing that passes through every point without overshooting;
  a shortened control arm keeps the bend gentle. The linear default
  keeps the zero-allocation streaming path.
- yFloor draw-time clamp and a left-edge clip so charts that draw axis
  lines can rest baseline-hugging strokes on the x-axis and end the
  first point's stroke at the y-axis instead of straddling either.
  Scales, ticks, and hit-testing stay at true positions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff (1)

  1. packages/quill/packages/charts/src/core/canvas-renderer.ts, line 76-88 (link)

    P2 Straight-line kink on the final segment when smooth and stroke.partial are both active

    drawFractionalTailDash draws the solid portion via tracePath (which correctly dispatches to traceSmoothPath), then appends ctx.lineTo(splitX, splitY) and a moveTo/lineTo dashed tail. Both the connection from the last smooth node to the split pixel and the dashed segment are straight lines. For any series with a stroke.partial fraction (e.g., live/real-time charts showing a partially-complete period), enabling curve: 'monotone' produces a visible kink: every segment except the last curves, and the last reverts to a straight chord.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "feat(quill-charts): monotone curve and a..." | Re-trigger Greptile

Comment thread packages/quill/packages/charts/src/core/canvas-renderer.ts

@sampennington sampennington left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 sp-ship · 🚫 Blockers

The monotone-cubic smoothing and axis-flush stroke math are correct and single-pass (division-by-zero guarded, NaN gaps split into subpaths, curveReverse geometrically retraces curveForward, yFloor is a pure draw-time clamp that leaves scales/ticks untouched). Three things block: two test bodies use for…of loops with assertions inside (branching logic in tests), and the new clipLeftEdge/withVerticalClip left-clip branch ships with no test at all — a regression there would pass silently. Non-blocking themes worth a look: hot-path allocation churn in the smooth draw path at the 1k×100k ceiling, a couple of untested/edge geometry cases (endpoint overshoot, area bottom edge not clamped to yFloor), and housekeeping — the new curve option isn't documented in the charts guide and has no story, the hand-rolled monotone math duplicates d3-shape's curveMonotoneX (justified by the shortened arm, worth a tighter comment), and withVerticalClip/fillAreaPath growing positional params (with an undefined placeholder at the call site) would read better as options objects.

Comment thread packages/quill/packages/charts/src/core/canvas-renderer.test.ts Outdated
Comment thread packages/quill/packages/charts/src/core/canvas-renderer.test.ts Outdated
Comment thread packages/quill/packages/charts/src/core/canvas-renderer.ts
Comment thread packages/quill/packages/charts/src/core/canvas-renderer.ts
Comment thread packages/quill/packages/charts/src/core/canvas-renderer.ts
Comment thread packages/quill/packages/charts/src/core/canvas-renderer.ts
Comment thread packages/quill/packages/charts/src/core/canvas-renderer.ts
Replace nested for-of loops with expect inside the bezier overshoot and
yFloor clamping tests with aggregate min/max assertions. Add a
drawLineSeriesLayer test asserting ctx.rect args for clipLeftEdge true/false.

Generated-By: PostHog Code
Task-Id: 7d472e91-eb72-439a-be92-ab33652875d8
@sampennington sampennington added the stamphog Request AI approval (no full review) label Jul 2, 2026
Addresses two Greptile review findings on the monotone-curve change:

- drawFractionalTailDash now splits the final monotone bezier at the
  fraction via de Casteljau, so a smooth line with a stroke.partial tail
  keeps the tail on the curve instead of reverting to a straight chord.
- The monotone-curve helpers (monotoneTangents/Segments, curveForward,
  curveReverse) take a Point[] so fillAreaPath passes top/bottom
  directly, dropping the four per-call throwaway arrays in the smooth
  area draw loop. traceSmoothPath shares the new collectSmoothRuns.

Generated-By: PostHog Code
Task-Id: 66eb1ef6-d0d9-4bb5-ad24-cdb2914e0c0f

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR has an active in-progress review signal (👀 from hex-security-app[bot]) alongside its thumbs-up — an in-flight review always blocks auto-approval regardless of other positive signals.

@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Jul 2, 2026
@sampennington sampennington added the stamphog Request AI approval (no full review) label Jul 2, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All three blocking review comments (loop-with-assertion test smell x2, missing clipLeftEdge test coverage) are visibly fixed in the current diff with matching test code, remaining feedback is acknowledged follow-up/perf suggestions (not blockers), the new curve/clipLeftEdge behavior is opt-in and defaults preserve existing rendering, and an independent bot reviewer (greptile) thumbed-up the PR with no outstanding unresolved concerns.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core rendering math (monotone-cubic curves, axis-flush clamping/clipping) is carefully guarded (NaN gaps, div-by-zero, unreachable edge cases documented) and now has solid test coverage, including the previously-flagged missing clipLeftEdge test and the loop-with-assertion test smells — both were fixed in a later commit per the resolved review threads, which the current diff confirms. An independent bot reviewer (greptile-apps) commented and reacted 👍 on the PR with its one flagged concern acknowledged as an out-of-scope follow-up; a security bot also 👍'd. Remaining review threads are non-blocking documentation/perf follow-ups, explicitly deferred.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🔺 Bundle size

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 81.55 MiB · 🔺 +3.3 KiB (+0.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 25.38 MiB 🔺 +2.9 KiB (+0.0%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

Frontend typechecking failed: the clipLeftEdge test annotated its
resolveYScale helper as ReturnType<typeof scaleLinear>, which resolves
against d3's overloaded signature to a broader type than the
drawLineSeriesLayer option expects (ScaleLinear<number, number> |
ScaleLogarithmic<number, number>). Annotate it with the concrete
ScaleLinear<number, number> so the call site typechecks.

Generated-By: PostHog Code
Task-Id: 66eb1ef6-d0d9-4bb5-ad24-cdb2914e0c0f
@stamphog

stamphog Bot commented Jul 2, 2026

Copy link
Copy Markdown

Retaining stamphog approval — delta since last review classified as trivial_paths.

@sampennington
sampennington merged commit 5c0c696 into master Jul 3, 2026
192 checks passed
@sampennington
sampennington deleted the sam/quill-charts-line-stroke branch July 3, 2026 05:57
@deployment-status-posthog

deployment-status-posthog Bot commented Jul 3, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-07-03 06:25 UTC Run
prod-us ✅ Deployed 2026-07-03 06:39 UTC Run
prod-eu ✅ Deployed 2026-07-03 06:39 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant