Feature: add image leaderboard
This commit is contained in:
parent
590495fbbc
commit
d10760b8cb
3 changed files with 85 additions and 1 deletions
|
@ -4,6 +4,7 @@ import { RegexTag } from "../src/Logic/Tags/RegexTag"
|
||||||
import { ImmutableStore } from "../src/Logic/UIEventSource"
|
import { ImmutableStore } from "../src/Logic/UIEventSource"
|
||||||
import { BBox } from "../src/Logic/BBox"
|
import { BBox } from "../src/Logic/BBox"
|
||||||
import * as fs from "fs"
|
import * as fs from "fs"
|
||||||
|
import { writeFileSync } from "fs"
|
||||||
import { Feature } from "geojson"
|
import { Feature } from "geojson"
|
||||||
import ScriptUtils from "./ScriptUtils"
|
import ScriptUtils from "./ScriptUtils"
|
||||||
import { Imgur } from "../src/Logic/ImageProviders/Imgur"
|
import { Imgur } from "../src/Logic/ImageProviders/Imgur"
|
||||||
|
@ -30,7 +31,6 @@ export default class GenerateImageAnalysis extends Script {
|
||||||
[],
|
[],
|
||||||
Constants.defaultOverpassUrls[0], //"https://overpass.kumi.systems/api/interpreter",
|
Constants.defaultOverpassUrls[0], //"https://overpass.kumi.systems/api/interpreter",
|
||||||
new ImmutableStore(500),
|
new ImmutableStore(500),
|
||||||
undefined,
|
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
console.log("Starting query...")
|
console.log("Starting query...")
|
||||||
|
@ -291,6 +291,9 @@ export default class GenerateImageAnalysis extends Script {
|
||||||
console.log(countsPerAuthor)
|
console.log(countsPerAuthor)
|
||||||
countsPerAuthor.sort()
|
countsPerAuthor.sort()
|
||||||
const median = countsPerAuthor[Math.floor(countsPerAuthor.length / 2)]
|
const median = countsPerAuthor[Math.floor(countsPerAuthor.length / 2)]
|
||||||
|
const json: {leaderboard: {rank: number, account: string, name: string, nrOfImages: number}[]} = {
|
||||||
|
leaderboard: []
|
||||||
|
}
|
||||||
for (let i = 0; i < 100; i++) {
|
for (let i = 0; i < 100; i++) {
|
||||||
let maxAuthor: string = undefined
|
let maxAuthor: string = undefined
|
||||||
let maxCount = 0
|
let maxCount = 0
|
||||||
|
@ -301,6 +304,12 @@ export default class GenerateImageAnalysis extends Script {
|
||||||
maxCount = count
|
maxCount = count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
json.leaderboard.push({
|
||||||
|
rank: i+1,
|
||||||
|
name: maxAuthor,
|
||||||
|
account: "https://openstreetmap.org/user/"+maxAuthor.replace(/ /g, "%20"),
|
||||||
|
nrOfImages: maxCount
|
||||||
|
})
|
||||||
console.log(
|
console.log(
|
||||||
"|",
|
"|",
|
||||||
i + 1,
|
i + 1,
|
||||||
|
@ -315,9 +324,11 @@ export default class GenerateImageAnalysis extends Script {
|
||||||
|
|
||||||
const totalAuthors = byAuthor.size
|
const totalAuthors = byAuthor.size
|
||||||
let totalLicensedImages = 0
|
let totalLicensedImages = 0
|
||||||
|
json["totalAuthors"] = totalAuthors
|
||||||
for (const license in byLicenseCount) {
|
for (const license in byLicenseCount) {
|
||||||
totalLicensedImages += byLicenseCount[license]
|
totalLicensedImages += byLicenseCount[license]
|
||||||
}
|
}
|
||||||
|
json["byLicense"] = {}
|
||||||
for (const license in byLicenseCount) {
|
for (const license in byLicenseCount) {
|
||||||
const total = byLicenseCount[license]
|
const total = byLicenseCount[license]
|
||||||
const authors = licenseByAuthorCount[license]
|
const authors = licenseByAuthorCount[license]
|
||||||
|
@ -328,6 +339,9 @@ export default class GenerateImageAnalysis extends Script {
|
||||||
Math.floor((1000 * authors) / totalAuthors) / 10
|
Math.floor((1000 * authors) / totalAuthors) / 10
|
||||||
}%), ${Math.floor(total / authors)} images/author`
|
}%), ${Math.floor(total / authors)} images/author`
|
||||||
)
|
)
|
||||||
|
json["byLicense"] = {
|
||||||
|
license, total, authors
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const nonDefaultAuthors = [
|
const nonDefaultAuthors = [
|
||||||
|
@ -348,6 +362,9 @@ export default class GenerateImageAnalysis extends Script {
|
||||||
nonDefaultAuthors.length
|
nonDefaultAuthors.length
|
||||||
)
|
)
|
||||||
console.log("Median contributions per author:", median)
|
console.log("Median contributions per author:", median)
|
||||||
|
json["median"] = median
|
||||||
|
json["date"] = new Date().toISOString()
|
||||||
|
writeFileSync("../../git/MapComplete-data/picture-leaderboard.json", JSON.stringify(json), "utf8")
|
||||||
}
|
}
|
||||||
|
|
||||||
async main(args: string[]): Promise<void> {
|
async main(args: string[]): Promise<void> {
|
||||||
|
|
63
src/UI/Leaderboard.svelte
Normal file
63
src/UI/Leaderboard.svelte
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
import { Utils } from "../Utils"
|
||||||
|
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||||
|
import Loading from "./Base/Loading.svelte"
|
||||||
|
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||||
|
|
||||||
|
const osmConnection = new OsmConnection({
|
||||||
|
attemptLogin: true
|
||||||
|
})
|
||||||
|
let loggedInContributor: Store<string> = osmConnection.userDetails.map(ud => ud.name)
|
||||||
|
export let source = "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/picture-leaderboard.json"
|
||||||
|
let data: Store<undefined | {
|
||||||
|
leaderboard: {
|
||||||
|
rank: number,
|
||||||
|
name: string,
|
||||||
|
account: string,
|
||||||
|
nrOfImages: number
|
||||||
|
}[],
|
||||||
|
median: number,
|
||||||
|
totalAuthors: number,
|
||||||
|
byLicense: {
|
||||||
|
license: string, total: number, authors: string[]
|
||||||
|
},
|
||||||
|
date: string
|
||||||
|
}> = UIEventSource.FromPromise(Utils.downloadJsonCached(source))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h1>Contributed images with MapComplete: leaderboard</h1>
|
||||||
|
|
||||||
|
{#if $data}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Rank</th>
|
||||||
|
<th>Contributor</th>
|
||||||
|
<th>Number of images contributed</th>
|
||||||
|
</tr>
|
||||||
|
{#each $data.leaderboard as contributor}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{contributor.rank}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{#if $loggedInContributor === contributor.name}
|
||||||
|
<a class="thanks" href="{contributor.account}">{contributor.name}</a>
|
||||||
|
{:else}
|
||||||
|
<a href="{contributor.account}">{contributor.name}</a>
|
||||||
|
{/if}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b>{contributor.nrOfImages}</b> total images
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</table>
|
||||||
|
Statistics generated on {$data.date}
|
||||||
|
{:else}
|
||||||
|
<Loading />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Logged in as {$loggedInContributor}
|
||||||
|
</div>
|
4
src/leaderboard.ts
Normal file
4
src/leaderboard.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
||||||
|
import Leaderboard from "./UI/Leaderboard.svelte"
|
||||||
|
|
||||||
|
new SvelteUIElement(Leaderboard, {}).AttachTo("main")
|
Loading…
Reference in a new issue