The site does not work on mobile devices (yet). It will take a few minutes to load your data the first time you log in.
I’ll be working on the site next weekend so if you encounter a bug, have some feedback, or want a specific feature, then please drop a reply with the details.
Slow and steady wins the race creates annoying edge cases
btw it doesn’t appear optimized for mobile display
Yeah, I’ll have to figure out how to get the bar graph and heatmap to look good on smaller screens. That’s a bit more involved so I’ll see what I can do about it over the weekend
WK did not record level progression until August of 2017, so that’s probably why. @nanyaLang If you want to account for this you would need to look at the subjects’ unlock dates and “guess” when the users leveled up.
How I did it in the Heatmap, if you are curious
It’s probably not the best way, but it works well enough
// Find indefinite level ups by looking at lesson history
let levels = {}
// Sort lessons by level then unlocked date
items.forEach((item) => {
if (
item.object !== 'kanji' ||
!item.assignments ||
!item.assignments.unlocked_at ||
item.assignments.unlocked_at >= first_recorded_date
)
return
let date = new Date(item.assignments.unlocked_at).toDateString()
if (!levels[item.data.level]) levels[item.data.level] = {}
if (!levels[item.data.level][date]) levels[item.data.level][date] = 1
else levels[item.data.level][date]++
})
// Discard dates with less than 10 unlocked
// then discard levels with no dates
// then keep earliest date for each level
for (let [level, data] of Object.entries(levels)) {
for (let [date, count] of Object.entries(data)) {
if (count < 10) delete data[date]
}
if (Object.keys(levels[level]).length == 0) {
delete levels[level]
continue
}
levels[level] = Object.keys(data).reduce((low, curr) => (low < curr ? low : curr), Date.now())
}
// Map to array of [[level0, date0], [level1, date1], ...] Format
levels = Object.entries(levels).map(([level, date]) => [Number(level), date])
// Add definite level ups from API
Object.values(level_progressions).forEach((level) =>
levels.push([level.data.level, new Date(level.data.unlocked_at).toDateString()]),
)
Looks nice so far! But my graph is also a bit confusing. I reset from level 42 to 31, and I’m currently in level 40 again. Levels 31-39 show the duration after the reset, my current level doesn’t appear, and levels 41-42 show the duration before the reset.
Adding something that marks resets would also be nice.
I didn’t have to do this in my script but my hunch is to watch when radicals are unlocked and that is the level up date. For levels with no radicals watch when kanji are unlocked. The logic is that radicals are always unlocked on level up. When there is no radicals kanji are always unlocked on level up.
I’ll try to get your missing levels using the methods the others mentioned. It might take a few days though.
I’m going to need API keys to figure out the issues with resets. WK doesn’t have DMs so if you’re comfortable sharing your API key with me, you can send them over to statkanibugs@gmail.com. (I’ll be sure to delete them once I’m done) @Voi@Cassini
It adds one to my Enlightened and Burn items, though.
Also, I don’t quite understand the graph. Is it supposed to show all the levels including the repeats or did it just show levels 17-21 that I did before the reset just to take up space?