SPB Git forge

spb/hfmarketdata

Public

Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)

127commits 1branches 0releases
24.7 MBsize
maindefault branch
11 days agolast push
JavaScript 53.7% Python 38.3% CSS 4.6% TypeScript 3.1%

charts: libellés de temps jamais décalés vers l'intérieur, tests verts (42/42)

Simon-Pierre Boucher committed 18 days ago (Sep 7, 2026) parent 275ac7d

2 changed files +6 −3

modified hfmarketdata/web/src/charts/engine/scales.test.js +5 −3
@@ -184,11 +184,13 @@ test('time ticks: hierarchical labels without collisions', () => {
184 184 assert.ok(ticks[i].x0 >= ticks[i - 1].x1, `collision between ${ticks[i - 1].text} and ${ticks[i].text}`)
185 185 }
186 186 const days = ticks.filter(t => t.strong)
187 − assert.equal(days.length, 3)
188 − assert.deepEqual(days.map(t => t.text), ['27', '28', '29'])
187 + // The first day label sits at x ≈ 0 and would be half hidden → dropped; the other two must be there.
188 + assert.deepEqual(days.map(t => t.text), ['28', '29'])
189 189 // Higher levels win when space is scarce.
190 190 const tight = timeTicks({ times, from: 0, to: times.length - 1, tf: '1min', xOf, width, measure: () => 120, gap: 14 })
191 191 assert.ok(tight.length <= 7)
192 − assert.equal(tight.filter(t => t.level >= 4).length, 3, 'day changes always survive the thinning')
192 + assert.equal(tight.filter(t => t.level >= 4).length, 2, 'day changes always survive the thinning')
193 + // A label is never placed where it would need to be shifted inward.
194 + for (const t of [...ticks, ...tight]) assert.ok(t.x0 >= -7 && t.x1 <= width + 7)
193 195 assert.ok(tight.every(t => t.level >= 2), 'only hour-level marks remain')
194 196 })
modified hfmarketdata/web/src/charts/engine/scales/ticks.js +1 −0
@@ -93,6 +93,7 @@ export function timeTicks({ times, from, to, tf, xOf, width, measure, gap = 14,
93 93 const w = measure(lab.text, lab.strong)
94 94 const x0 = x - w / 2 - gap / 2
95 95 const x1 = x + w / 2 + gap / 2
96 + if (x0 < -gap / 2 || x1 > width + gap / 2) continue // never place a label that would have to be shifted inward
96 97 let ok = true
97 98 for (const p of placed) {
98 99 if (x0 < p.x1 && x1 > p.x0) { ok = false; break }
99 100