(reads: number, div = 1)
| 159 | * to rank on `toNext`. |
| 160 | */ |
| 161 | export const levelProgress = (reads: number, div = 1): LevelProgress => { |
| 162 | const level = div === 1 ? levelOf(reads) : realmLevelOf(reads); |
| 163 | if (level >= MAX_LEVEL) { |
| 164 | return { level, toNext: 0, fraction: 1 }; |
| 165 | } |
| 166 | |
| 167 | const ceiling = LEVELS[level].reads * div; |
| 168 | /* `realmLevelOf` floors at L1, so a realm sitting on its first rung can hold |
| 169 | fewer articles than that rung's own threshold. Clamping the floor to what |
| 170 | has actually been read keeps such a realm at the START of the bar instead |
| 171 | of behind it. A district cannot reach L1 below the threshold, so this is |
| 172 | the identity for everything else. */ |
| 173 | const floor = Math.min(floorOf(level) * div, reads); |
| 174 | |
| 175 | return { |
| 176 | level, |
| 177 | /* Ceiled: the ladder is walked in whole articles, and a realm 0.4 of an |
| 178 | article short still needs one more read to cross. */ |
| 179 | toNext: Math.ceil(ceiling - reads), |
| 180 | fraction: (reads - floor) / (ceiling - floor), |
| 181 | next: LEVELS[level], |
| 182 | }; |
| 183 | }; |
| 184 | |
| 185 | /** The least a district has to carry to be worth pointing at. */ |
| 186 | export interface LadderRow { |
no test coverage detected