import { RasterLayerPolygon } from "../../Models/RasterLayers" import { Polygon } from "geojson" import { RasterLayerProperties } from "../../Models/RasterLayerProperties" import { BBox } from "../../Logic/BBox" import { Utils } from "../../Utils" export class BingRasterLayerProperties implements Partial { private static singleton: BingRasterLayerProperties | "error" name = "Bing Maps Aerial" id = "Bing" type = "bing" category = "photo" min_zoom = 1 max_zoom = 22 best = false attribution = { url: "https://www.bing.com/maps", } url: string private constructor(url: string) { this.url = url } public static async get(): Promise { if (BingRasterLayerProperties.singleton === undefined) { try { const url = await this.getEndpoint() BingRasterLayerProperties.singleton = new BingRasterLayerProperties(url) } catch (e) { BingRasterLayerProperties.singleton = "error" console.error(e) } } return BingRasterLayerProperties.singleton } private static async getEndpoint() { console.log("Getting bing endpoint") // Key by 'pietervdvn@outlook.com' from https://www.bingmapsportal.com/Application // Inspired by https://github.com/zlant/parking-lanes/pull/159 const key = "An0vKZ4r_PZx820sn3seuPKjd1Vyc5WE3s1b-qN4HCgI-Nr6QR83aLOQ-3fbFl08" const url = `https://dev.virtualearth.net/REST/v1/Imagery/Metadata/AerialOSM?include=ImageryProviders&uriScheme=https&key=${key}` // Get the image tiles template: const metadata = await Utils.downloadJson(url) // FYI: // "imageHeight": 256, "imageWidth": 256, // "imageUrlSubdomains": ["t0","t1","t2","t3"], // "zoomMax": 21, const imageryResource = metadata["resourceSets"][0].resources[0] const template = new URL(imageryResource.imageUrl) // Add tile image strictness param (n=) // • n=f -> (Fail) returns a 404 // • n=z -> (Empty) returns a 200 with 0 bytes (no content) // • n=t -> (Transparent) returns a 200 with a transparent (png) tile if (!template.searchParams.has("n")) template.searchParams.append("n", "f") // FYI: `template` looks like this but partly encoded // https://ecn.{subdomain}.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=14107&pr=odbl&n=z const subdomains = ["t0", "t1", "t2", "t3"] const index = Math.floor(Math.random() * subdomains.length) return template.toString().replace("{subdomain}", subdomains[index]) } } export class BingRasterLayer implements RasterLayerPolygon { private static singleton: RasterLayerPolygon | "error" readonly type: "Feature" = "Feature" as const readonly geometry: Polygon = BBox.global.asGeometry() readonly id = "bing" readonly properties: RasterLayerProperties constructor(properties: RasterLayerProperties) { this.properties = properties } public static async get(): Promise { if (BingRasterLayer.singleton === undefined) { const properties = await BingRasterLayerProperties.get() if (properties === "error") { BingRasterLayer.singleton = "error" } else { BingRasterLayer.singleton = new BingRasterLayer(properties) } } return BingRasterLayer.singleton } }