forked from MapComplete/MapComplete
		
	Fetch taginfo: add code to get all countries, imrove docs
This commit is contained in:
		
							parent
							
								
									68602cba94
								
							
						
					
					
						commit
						5c2823287a
					
				
					 1 changed files with 76 additions and 2 deletions
				
			
		| 
						 | 
					@ -1,35 +1,48 @@
 | 
				
			||||||
import { Utils } from "../../Utils"
 | 
					import { Utils } from "../../Utils"
 | 
				
			||||||
 | 
					import type { FeatureCollection } from "geojson"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface TagInfoStats {
 | 
					export interface TagInfoStats {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The total number of entries in the data array, **not** the total number of objects known in OSM!
 | 
					     * The total number of entries in the data array, **not** the total number of objects known in OSM!
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * Use `data.find(item => item.type==="all").count` for this
 | 
					     * Use `data.find(item => item.type==="all").count` for this
 | 
				
			||||||
 | 
					     * @deprecated: you probably want to use data.find(item => item.type==="all").count
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    total: number
 | 
					    total: number
 | 
				
			||||||
    data: {
 | 
					    data: {
 | 
				
			||||||
        type: "all" | "nodes" | "ways" | "relations"
 | 
					        type: "all" | "nodes" | "ways" | "relations"
 | 
				
			||||||
 | 
					        // Absolute number
 | 
				
			||||||
        count: number
 | 
					        count: number
 | 
				
			||||||
 | 
					        // Relative, percentage
 | 
				
			||||||
        count_fraction: number
 | 
					        count_fraction: number
 | 
				
			||||||
    }[]
 | 
					    }[]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface GeofabrikCountryProperties {
 | 
				
			||||||
 | 
					    id: string,
 | 
				
			||||||
 | 
					    parent: string | "europe" | "asia",
 | 
				
			||||||
 | 
					    urls: string[],
 | 
				
			||||||
 | 
					    name: string,
 | 
				
			||||||
 | 
					    "iso3166-1:alpha2": string[]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class TagInfo {
 | 
					export default class TagInfo {
 | 
				
			||||||
    public static readonly global = new TagInfo()
 | 
					    public static readonly global = new TagInfo()
 | 
				
			||||||
    private readonly _backend: string
 | 
					    private readonly _backend: string
 | 
				
			||||||
 | 
					    private static _geofabrikCountries = undefined
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(backend = "https://taginfo.openstreetmap.org/") {
 | 
					    constructor(backend = "https://taginfo.openstreetmap.org/") {
 | 
				
			||||||
        this._backend = backend
 | 
					        this._backend = backend
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public getStats(key: string, value?: string): Promise<TagInfoStats> {
 | 
					    public async getStats(key: string, value?: string): Promise<TagInfoStats> {
 | 
				
			||||||
        let url: string
 | 
					        let url: string
 | 
				
			||||||
        if (value) {
 | 
					        if (value) {
 | 
				
			||||||
            url = `${this._backend}api/4/tag/stats?key=${key}&value=${value}`
 | 
					            url = `${this._backend}api/4/tag/stats?key=${key}&value=${value}`
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            url = `${this._backend}api/4/key/stats?key=${key}`
 | 
					            url = `${this._backend}api/4/key/stats?key=${key}`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return Utils.downloadJsonCached(url, 1000 * 60 * 60)
 | 
					        return await Utils.downloadJsonCached<TagInfoStats>(url, 1000 * 60 * 60)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					@ -44,4 +57,65 @@ export default class TagInfo {
 | 
				
			||||||
            return `${this._backend}/keys/${k}#overview`
 | 
					            return `${this._backend}/keys/${k}#overview`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Does not work in the browser due to some resources not being CORS-accessible
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static async geofabrikCountries(): Promise<GeofabrikCountryProperties[]> {
 | 
				
			||||||
 | 
					        if (TagInfo._geofabrikCountries) {
 | 
				
			||||||
 | 
					            return TagInfo._geofabrikCountries
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const countriesFC: FeatureCollection = await Utils.downloadJsonCached<FeatureCollection>("https://download.geofabrik.de/index-v1-nogeom.json", 24 * 1000 * 60 * 60)
 | 
				
			||||||
 | 
					        TagInfo._geofabrikCountries = countriesFC.features.map(f => <GeofabrikCountryProperties>f.properties)
 | 
				
			||||||
 | 
					        return TagInfo._geofabrikCountries
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates a TagInfo-api-object for geofabrik for the given country.
 | 
				
			||||||
 | 
					     * Returns undefined if geofabrik does not have such a country
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Does not work in the browser due to some resources not being CORS-accessible
 | 
				
			||||||
 | 
					     * @param countryCode: an iso3166-1:alpha2 code
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static async getInstanceFor(countryCode: string) {
 | 
				
			||||||
 | 
					        const countries = await this.geofabrikCountries()
 | 
				
			||||||
 | 
					        countryCode = countryCode.toUpperCase()
 | 
				
			||||||
 | 
					        const country = countries.find(c => c["iso3166-1:alpha2"]?.indexOf(countryCode) >= 0)
 | 
				
			||||||
 | 
					        if (!country || !country?.parent || !country?.id) {
 | 
				
			||||||
 | 
					            return undefined
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const url = `https://taginfo.geofabrik.de/${country.parent}:${country.id}/`
 | 
				
			||||||
 | 
					        return new TagInfo(url)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static async getDistributionsFor(countryCode: string, key: string, value?: string): Promise<TagInfoStats>{
 | 
				
			||||||
 | 
					        if (!countryCode) {
 | 
				
			||||||
 | 
					            return undefined
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const ti = await TagInfo.getInstanceFor(countryCode)
 | 
				
			||||||
 | 
					        if (!ti) {
 | 
				
			||||||
 | 
					            return undefined
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					           return await ti.getStats(key, value)
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            console.warn("Could not fetch info for", countryCode,key,value, "due to", e)
 | 
				
			||||||
 | 
					            return undefined
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static async getGlobalDistributionsFor(key: string, value?: string): Promise<Record<string, TagInfoStats>> {
 | 
				
			||||||
 | 
					        const countries = await this.geofabrikCountries()
 | 
				
			||||||
 | 
					        const perCountry: Record<string, TagInfoStats> = {}
 | 
				
			||||||
 | 
					        const results = await Promise.all(countries.map(country => TagInfo.getDistributionsFor(country?.["iso3166-1:alpha2"]?.[0], key, value)))
 | 
				
			||||||
 | 
					        for (let i = 0; i < countries.length; i++){
 | 
				
			||||||
 | 
					            const country = countries[i]
 | 
				
			||||||
 | 
					            const countryCode = country["iso3166-1:alpha2"]?.[0]
 | 
				
			||||||
 | 
					            if(results[i]){
 | 
				
			||||||
 | 
					             perCountry[countryCode] = results[i]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return perCountry
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue