Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[Perf] Axis tick labels are keyed by value, so relative ticks on a rolling window recreate every label

Open
#195 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
Half a day
Newbie friendliness
45/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
d3, typescript

Research direction

The label key is built in scene.ts around line 1882 and written to data-ts-key in svg-renderer.ts, then matched by reconcile.ts around lines 344-345. Start by running the repro in packages/charts-core/test-repro/10-rolling-windows.test.ts to see the 4 new label nodes. Done means that test passes with a tick-index key, and that the default 'value' behaviour and the existing tests still pass.

Written by the indexing model from the issue text.

Description

Version: @tanstack/charts 1.1.0 (57774e1).

Problem

A rolling line chart (path: { update: 'rolling' }) with x ticks relative to the newest sample (ticks.values: "now - 30 s", "now - 20 s", ...) gets new tick values every step. Tick labels are keyed by value, so every label node is removed and re-created each step.

With default "nice" ticks the values persist, so this only shows with relative or per-step tick values.

Why
Repro

Save as packages/charts-core/src/repro.test.ts, run pnpm vitest run packages/charts-core/src/repro.test.ts.

import { expect, it, vi } from 'vitest'
import { scaleLinear, scaleUtc } from 'd3-scale'
import { lineY } from './line'
import { motion } from './motion'
import { createChartScene, defineChart } from './scene'

const T0 = Date.UTC(2026, 0, 1)
const scene = (start: number) => {
  const rows = Array.from({ length: 40 }, (_, i) => ({
    id: `r${start + i}`, time: new Date(T0 + (start + i) * 1000), value: 50 + 20 * Math.sin(i / 2),
  }))
  const end = rows[39]!.time.getTime()
  return createChartScene(defineChart({
    motion: { path: { update: 'rolling', x: 'shift' }, transition: { type: 'tween', duration: 100 } },
    marks: [lineY(rows, { id: 's', x: 'time', y: 'value', key: 'id' })],
    scales: {
      x: {
        scale: scaleUtc().domain([rows[2]!.time, rows[39]!.time]),
        axis: { ticks: { values: [30, 20, 10, 0].map((s) => new Date(end - s * 1000)) } },
      },
      y: { scale: scaleLinear().domain([0, 100]) },
    },
    clip: true,
  }), { width: 300, height: 200 })
}

it('x tick label nodes are reused across a one-step rolling update', () => {
  vi.spyOn(window, 'requestAnimationFrame').mockImplementation(() => 1)
  const container = document.createElement('div')
  const surface = motion({ initial: false }).mount(container, () => {})
  const labels = () => [...container.querySelectorAll('text[data-ts-key^="x-tick-label:"]')]
  surface.render(scene(0), { ariaLabel: 'rolling' })
  const before = labels()
  surface.render(scene(1), { ariaLabel: 'rolling' })
  expect(labels().filter((node) => !before.includes(node))).toHaveLength(0)
})

Output: AssertionError: expected [ SVGElement{ …(2) }, …(3) ] to have a length of +0 but got 4. Without values the same test passes.

Proposed

tickLabels.key: 'value' | 'index' (default 'value'), switching the key at scene.ts:1882 to the tick index, so a fixed set of label nodes is reused and only text and position update.

Downstream measurement (bklit migration, Chrome, 10 s rolling line with relative x ticks): custom x labels keyed by slot index cut element additions from about 500 to 1.

Dominant language
TypeScript
Stars
819
Forks
49
Avg merge
12h 9m
Merged PRs (30d)
6

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from TanStack/charts

All issues in TanStack/charts

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.