( daily: DailyRawPoint[], rangeStartIso?: string, rangeEndIso?: string, )
| 74 | } |
| 75 | |
| 76 | export function buildMonthlyEvolution( |
| 77 | daily: DailyRawPoint[], |
| 78 | rangeStartIso?: string, |
| 79 | rangeEndIso?: string, |
| 80 | ): MonthlyDataPoint[] { |
| 81 | const sorted = sortedDaily(daily) |
| 82 | const byMonth = new Map<string, number>() |
| 83 | for (const item of sorted) { |
| 84 | const m = item.day.slice(0, 7) |
| 85 | byMonth.set(m, (byMonth.get(m) ?? 0) + item.value) |
| 86 | } |
| 87 | |
| 88 | const entries = Array.from(byMonth.entries()).sort(([a], [b]) => a.localeCompare(b)) |
| 89 | |
| 90 | return entries.map(([month, value], i) => { |
| 91 | const [y, m] = month.split('-').map(Number) as [number, number] |
| 92 | const total = daysInMonth(y, m - 1) |
| 93 | const isFirst = i === 0 |
| 94 | const isLast = i === entries.length - 1 |
| 95 | |
| 96 | const startDay = isFirst && rangeStartIso ? Number(rangeStartIso.split('-')[2]) : 1 |
| 97 | const endDay = isLast && rangeEndIso ? Number(rangeEndIso.split('-')[2]) : total |
| 98 | const actualDays = endDay - startDay + 1 |
| 99 | |
| 100 | if (actualDays < total) value = fillPartialBucket(value, actualDays, total) |
| 101 | |
| 102 | return { month, value, timestamp: parseIsoDate(`${month}-01`).getTime() } |
| 103 | }) |
| 104 | } |
| 105 | |
| 106 | export function buildYearlyEvolution( |
| 107 | daily: DailyRawPoint[], |
no test coverage detected