Skip to content

Commit c733c1b

Browse files
committed
manage single point serie
1 parent 98e26a6 commit c733c1b

2 files changed

Lines changed: 48 additions & 20 deletions

File tree

app/utils/chart-data-buckets.ts

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,14 @@ export function buildMonthlyEvolution(
101101
return entries.map(([month, value], i) => {
102102
const [y, m] = month.split('-').map(Number) as [number, number]
103103
const total = daysInMonth(y, m - 1)
104+
const isFirst = i === 0
105+
const isLast = i === entries.length - 1
104106

105-
if (i === 0 && rangeStartIso) {
106-
const startDay = Number(rangeStartIso.split('-')[2])
107-
if (startDay > 1) value = fillPartialBucket(value, total - startDay + 1, total)
108-
}
109-
if (i === entries.length - 1 && rangeEndIso) {
110-
const endDay = Number(rangeEndIso.split('-')[2])
111-
if (endDay < total) value = fillPartialBucket(value, endDay, total)
112-
}
107+
const startDay = isFirst && rangeStartIso ? Number(rangeStartIso.split('-')[2]) : 1
108+
const endDay = isLast && rangeEndIso ? Number(rangeEndIso.split('-')[2]) : total
109+
const actualDays = endDay - startDay + 1
110+
111+
if (actualDays < total) value = fillPartialBucket(value, actualDays, total)
113112

114113
return { month, value, timestamp: parseIsoDate(`${month}-01`).getTime() }
115114
})
@@ -132,18 +131,20 @@ export function buildYearlyEvolution(
132131
return entries.map(([year, value], i) => {
133132
const total = daysInYear(Number(year))
134133
const yearStart = parseIsoDate(`${year}-01-01`)
135-
136-
if (i === 0 && rangeStartIso) {
137-
const dayOfYear = Math.floor(
138-
(parseIsoDate(rangeStartIso).getTime() - yearStart.getTime()) / DAY_MS,
139-
)
140-
if (dayOfYear > 0) value = fillPartialBucket(value, total - dayOfYear, total)
141-
}
142-
if (i === entries.length - 1 && rangeEndIso) {
143-
const actualDays =
144-
Math.floor((parseIsoDate(rangeEndIso).getTime() - yearStart.getTime()) / DAY_MS) + 1
145-
if (actualDays < total) value = fillPartialBucket(value, actualDays, total)
146-
}
134+
const isFirst = i === 0
135+
const isLast = i === entries.length - 1
136+
137+
const startOffset =
138+
isFirst && rangeStartIso
139+
? Math.floor((parseIsoDate(rangeStartIso).getTime() - yearStart.getTime()) / DAY_MS)
140+
: 0
141+
const endOffset =
142+
isLast && rangeEndIso
143+
? Math.floor((parseIsoDate(rangeEndIso).getTime() - yearStart.getTime()) / DAY_MS) + 1
144+
: total
145+
const actualDays = endOffset - startOffset
146+
147+
if (actualDays < total) value = fillPartialBucket(value, actualDays, total)
147148

148149
return { year, value, timestamp: yearStart.getTime() }
149150
})

test/unit/app/utils/chart-data-buckets.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,19 @@ describe('buildMonthlyEvolution', () => {
138138
expect(buildMonthlyEvolution([])).toEqual([])
139139
})
140140

141+
it('scales single month partial on both ends without double-scaling', () => {
142+
// 2025-01-10 to 2025-01-20 = 11 days out of 31
143+
const daily = Array.from({ length: 11 }, (_, i) => ({
144+
day: `2025-01-${String(i + 10).padStart(2, '0')}`,
145+
value: 10,
146+
}))
147+
148+
const result = buildMonthlyEvolution(daily, '2025-01-10', '2025-01-20')
149+
150+
expect(result).toHaveLength(1)
151+
expect(result[0]!.value).toBe(Math.round((110 * 31) / 11))
152+
})
153+
141154
it('scales up partial first month', () => {
142155
const daily = Array.from({ length: 14 }, (_, i) => ({
143156
day: `2025-03-${String(i + 18).padStart(2, '0')}`,
@@ -188,6 +201,20 @@ describe('buildYearlyEvolution', () => {
188201
expect(buildYearlyEvolution([])).toEqual([])
189202
})
190203

204+
it('scales single year partial on both ends without double-scaling', () => {
205+
// 2025-04-01 to 2025-06-30 = 91 days out of 365
206+
const daily = Array.from({ length: 91 }, (_, i) => {
207+
const d = new Date(Date.UTC(2025, 3, 1))
208+
d.setUTCDate(d.getUTCDate() + i)
209+
return { day: d.toISOString().slice(0, 10), value: 10 }
210+
})
211+
212+
const result = buildYearlyEvolution(daily, '2025-04-01', '2025-06-30')
213+
214+
expect(result).toHaveLength(1)
215+
expect(result[0]!.value).toBe(Math.round((910 * 365) / 91))
216+
})
217+
191218
it('scales up partial first year', () => {
192219
const daily = Array.from({ length: 184 }, (_, i) => {
193220
const d = new Date(Date.UTC(2025, 6, 1))

0 commit comments

Comments
 (0)