[Perf] Axis tick labels are keyed by value, so relative ticks on a rolling window recreate every label
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- Medio día
- Aptitud para principiantes
- 45/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- d3, typescript
- Área
- data-visualization
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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
- Label key is the tick value:
scene.ts:1882. - The renderer writes it to
data-ts-key(svg-renderer.ts:192) and the reconciler matches nodes by it (reconcile.ts:344-345). No match means remove and re-create. - No
tickLabelsoption changes the key (types.ts:391-405).
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.
- Lenguaje dominante
- TypeScript
- Estrellas
- 842
- Forks
- 53
- Merge medio
- 4 h 40 min
- PR fusionados (30 d)
- 16
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de TanStack/charts
-
[Bug] Focus guides: `url(#id)` paints ignore `idPrefix`Posiblemente ocupada @getdownandcode la tomó hace 8 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
TanStack/charts#211 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
[Bug] Printed charts keep their screen width: resize redraw waits for an animation framePosiblemente ocupada @piecyk la tomó hace 7 días. Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 25/100
Los mantenedores suelen responder en 1 día
-
[Feature] Readable outside labels for crowded pie and donut chartsPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
TanStack/charts#227 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 42/100
TanStack/charts#216 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 4/5 3-5 días Aptitud para principiantes 57/100
Los mantenedores suelen responder en 1 día
Todos los issues de TanStack/charts
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
endora-commerce/endora-commerce#397 ·
Los mantenedores suelen responder en 1 día
-
level/task
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
wazuh/wazuh-dashboard-plugins#9472 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 63/100
Los mantenedores suelen responder en 1 día
-
ready-for-agent
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
xavxyz/bei-shan-lin-shui#57 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
opennextjs/opennextjs-cloudflare#1461 ·
Los mantenedores suelen responder en 1 día