Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions benchmarks/conformance/cases/90-zoomable-time-window/model.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,31 @@ export function visibleZoomData(rows: readonly AaplRow[], window: ZoomWindow) {
})
}

export function visibleZoomDataWithNeighbors(
rows: readonly AaplRow[],
window: ZoomWindow,
) {
const start = window.start.getTime()
const end = window.end.getTime()
let firstVisible = -1
let lastVisible = -1

for (let index = 0; index < rows.length; index += 1) {
const timestamp = rows[index]!.Date.getTime()
if (timestamp < start) continue
if (timestamp > end) break
if (firstVisible < 0) firstVisible = index
Comment on lines +56 to +60

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
ast-grep outline benchmarks/conformance/cases/90-zoomable-time-window/model.ts --items all
rg -n -C 8 '\bselectZoomRows\b|\bzoomRows\b' \
benchmarks/conformance/cases/90-zoomable-time-window
rg -n -C 6 'sort\(|Date\.getTime\(|Date' \
packages/charts-demo-data \
benchmarks/conformance/cases/90-zoomable-time-window

Repository: TanStack/charts

Length of output: 50372


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
# Inspect the target file around the helper and data source usages.
sed -n '1,140p' benchmarks/conformance/cases/90-zoomable-time-window/model.ts
# Locate selectZoomRows definitions/usages narrowly.
rg -n -C 5 '\bsselectZoomRows\b|selectZoomRows\('.# Locate aapl dataset/exports and nearby file contents.
rg -n -C 6 '(aapl|Aapl|AAPL|AaplRow)' benchmarks/conformance/cases/90-zoomable-time-window packages/charts-demo-data | head -n 240
# Behavioral probe: implement the helper loop for representative orderings.
node - <<'JS'function selectZoomRows(rows, window) { const start = window.start.getTime() const end = window.end.getTime() let firstVisible = -1 const visible = [] for (let index = 0; index < rows.length; index += 1) { const timestamp = rows[index].Date.getTime() if (timestamp < start) continue if (timestamp > end) break if (firstVisible < 0) firstVisible = index visible.push(rows[index]) } return visible}const window = { start: new Date('2007-08-24T00:00:00Z'), end: new Date('2007-08-31T00:00:00Z') }const rows = [ {Date: new Date('2007-08-24Z')}, {Date: new Date('2007-08-27Z')}, {Date: new Date('2007-08-28Z')}, {Date: new Date('2007-08-25Z')}, {Date: new Date('2010-01-01Z')}]console.log(JSON.stringify({ ascendingSlice: selectZoomRows( rows.filter((_, i, a) => i < 3), window ), outOfOrderSlice: selectZoomRows(rows, window), descendingSlice: selectZoomRows(rows.slice(0, 3).reverse(), window)}))JS

Repository: TanStack/charts

Length of output: 29091


Fix the neighbor scan to be order-agnostic.

visibleZoomData selects rows by timestamp, but the new visibleZoomDataWithNeighbors stops the scan after timestamp > end. That can miss out-of-order rows still inside the window and return neighbors for only a prefix of the selected rows. Update it to scan all rows from both sides/nearest rows, or keep it dependent on an explicit ascending Date invariant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@benchmarks/conformance/cases/90-zoomable-time-window/model.ts` around lines
56 - 60, The neighbor scan in visibleZoomDataWithNeighbors must not break when a
timestamp exceeds end, because rows may be out of order. Remove the early
termination and scan every row, preserving selection of the first visible row
and collecting neighbors based on each row’s timestamp within the window;
alternatively, explicitly enforce and document an ascending Date invariant
before retaining the break.

lastVisible = index
}

if (firstVisible < 0) return []

return rows.slice(
Math.max(0, firstVisible - 1),
Math.min(rows.length, lastVisible + 2),
)
}

export function zoomSpanDays(window: ZoomWindow) {
return (window.end.getTime() - window.start.getTime()) / millisecondsPerDay
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@ import {
initialZoomWindow,
selectZoomRows,
visibleZoomData,
visibleZoomDataWithNeighbors,
zoomDateFromAnchor,
zoomDateKey,
zoomFullDomain,
Expand DownExpand Up@@ -69,19 +70,20 @@ const ZoomableTimeWindowExample = forwardRef<
})
const [state, setState] = useState(stateRef.current)
const [scene, setScene] = useState<ChartScene<AaplRow> | null>(null)
const rows = visibleZoomData(zoomRows, state.window)
const visibleRows = visibleZoomData(zoomRows, state.window)
const lineRows = visibleZoomDataWithNeighbors(zoomRows, state.window)
const definition = useMemo(
() =>
defineChart(
defineChart({
marks: [
lineY(rows, {
lineY(lineRows, {
x: 'Date',
y: 'Close',
stroke: color,
strokeWidth: 2.5,
}),
dot(rows, {
dot(visibleRows, {
Comment on lines +73 to +86

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
rg -n -C 8 'zoomGeometry|pointsBounds|geometry|role|visibleZoomData' \
benchmarks/conformance

Repository: TanStack/charts

Length of output: 50372


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
echo"## target view.tsx relevant sections"
sed -n '1,180p' benchmarks/conformance/cases/90-zoomable-time-window/view.tsx
echo
sed -n '480,560p' benchmarks/conformance/cases/90-zoomable-time-window/view.tsx
echoecho"## local model exports"
sed -n '1,90p' benchmarks/conformance/cases/90-zoomable-time-window/model.ts
echoecho"## focused conformance files"
sed -n '20,30p' benchmarks/conformance/cases/90-zoomable-time-window/case.json
rg -n -C 4 'zoomGeometry|pointsBounds|geometry|role' benchmarks/conformance/cases/90-zoomable-time-window/view.tsx

Repository: TanStack/charts

Length of output: 13027


🏁 Script executed:

#!/usr/bin/env bashset -euo pipefail
echo"## rest of target view.tsx"
sed -n '560,630p' benchmarks/conformance/cases/90-zoomable-time-window/view.tsx
echoecho"## behavioral simulation of point/window/data splits"
node - <<'JS'const zoomFullDomain = [ new Date(Date.UTC(2018, 0, 2)), new Date(Date.UTC(2018, 0, 18)),]const row = (dayOffset) => ({ Date: new Date(zoomFullDomain[0].getTime() + dayOffset * 86400_000), Close: dayOffset,})const zoomRows = Array.from({ length: 17 }, (_, i) => row(i))const window = { start: zoomRows[6].Date, end: zoomRows[8].Date }function visibleZoomData(rows, window) { const start = window.start.getTime() const end = window.end.getTime() return rows.filter((row) => { const timestamp = row.Date.getTime() return timestamp >= start && timestamp <= end })}function visibleZoomDataWithNeighbors(rows, window) { const start = window.start.getTime() const end = window.end.getTime() let firstVisible = -1 let lastVisible = -1 for (let index = 0; index < rows.length; index += 1) { const timestamp = rows[index].Date.getTime() if (timestamp < start) continue if (timestamp > end) break if (firstVisible < 0) firstVisible = index lastVisible = index } if (firstVisible < 0) return [] return rows.slice(Math.max(0, firstVisible - 1), Math.min(rows.length, lastVisible + 2))}function pointsBounds(points, bounds, scaleX, scaleY, color) { if (points.length === 0) return null let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity const halfStroke = 1.25 for (const [px, py] of points) { minX = Math.min(minX, px) maxX = Math.max(maxX, px) minY = Math.min(minY, py) maxY = Math.max(maxY, py) } minX = Math.max(bounds.left, minX - halfStroke) maxX = Math.min(bounds.left + bounds.width, maxX + halfStroke) minY = Math.max(bounds.top, minY - halfStroke) maxY = Math.min(bounds.top + bounds.height, maxY + halfStroke) if (maxX - minX < 0 || maxY - minY < 0) return null return { x: minX, y: minY, width: maxX - minX, height: maxY - minY, paint: color }}const modelStart = new Date('2018-01-07T00:00:00Z')const modelEnd = new Date('2018-01-09T00:00:00Z')const bounds = { left: 58, top: 56, width: 450, height: 340 }const scaleX = bounds.width / bounds.widthconst scaleY = bounds.height / bounds.heightconst visible = visibleZoomData(zoomRows, window)const lineData = visibleZoomDataWithNeighbors(zoomRows, window)console.log(JSON.stringify({ windowRange: [window.start.toISOString().slice(0,10), modelEnd.toISOString().slice(0,10)], visibleDataDays: visible.map(r => r.Date.toISOString().slice(0,10)), lineDataDays: lineData.map(r => r.Date.toISOString().slice(0,10)), visiblePointsCount: visible.length, linePointsCount: lineData.length, visibleBoundsIfUsed: pointsBounds(visible.map(r => [r.Date.getTime(), r.Close]), bounds, scaleX, scaleY, 'red'), lineBoundsIfUsed: pointsBounds(lineData.map(r => [r.Date.getTime(), r.Close]), bounds, scaleX, scaleY, 'red'),}, null, 2))JS

Repository: TanStack/charts

Length of output: 1545


Use the rendered line data for line geometry.

lineY renders lineRows, and those include the window neighbors needed for viewport-edge line segments. Keep visibleZoomData for role: 'dot', but build the role: 'line' bounds from visibleZoomDataWithNeighbors(zoomRows, state.window); clip the returned rectangle into the chart area to keep the geometry contract aligned with the rendered mark.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@benchmarks/conformance/cases/90-zoomable-time-window/view.tsx` around lines
73 - 86, Update the line geometry bounds in the chart definition around lineY
and visibleZoomDataWithNeighbors to use the rendered lineRows data, while
keeping visibleRows for the dot mark. Build the role: 'line' bounds from
lineRows and clip the resulting rectangle to the chart area so it remains within
the geometry contract.

x: 'Date',
y: 'Close',
fill: color,
Expand DownExpand Up@@ -109,6 +111,7 @@ const ZoomableTimeWindowExample = forwardRef<
grid: true,
axis: { ticks: { count: 4 }, label: 'AAPL close ($)' },
},
clip: true,
margin: { top: 56, right: 24, bottom: 44, left: 58 },
}),
{ animate: false, keyboard: false, focus: focusDisabled },
Expand Down