Download button: take advantage of MVT server, download button will now attempt to download everything

This commit is contained in:
Pieter Vander Vennet 2024-02-21 16:35:49 +01:00
parent bccda67e1c
commit e4eb8d6b52
21 changed files with 453 additions and 353 deletions

View file

@ -1,8 +1,7 @@
import { Geometry } from "geojson"
import { Feature as GeojsonFeature } from "geojson"
import { Feature as GeojsonFeature, Geometry } from "geojson"
import { Store, UIEventSource } from "../../UIEventSource"
import { FeatureSourceForTile } from "../FeatureSource"
import { FeatureSourceForTile, UpdatableFeatureSource } from "../FeatureSource"
import Pbf from "pbf"
type Coords = [number, number][]
@ -205,6 +204,7 @@ class Layer {
end
)
}
static _readField(tag, obj, pbf) {
if (tag === 15) obj.version = pbf.readVarint()
else if (tag === 1) obj.name = pbf.readString()
@ -213,6 +213,7 @@ class Layer {
else if (tag === 4) obj.values.push(Value.read(pbf, pbf.readVarint() + pbf.pos))
else if (tag === 5) obj.extent = pbf.readVarint()
}
public static write(obj, pbf) {
if (obj.version) pbf.writeVarintField(15, obj.version)
if (obj.name) pbf.writeStringField(1, obj.name)
@ -230,12 +231,14 @@ class Feature {
static read(pbf, end) {
return pbf.readFields(Feature._readField, { id: 0, tags: [], type: 0, geometry: [] }, end)
}
static _readField(tag, obj, pbf) {
if (tag === 1) obj.id = pbf.readVarint()
else if (tag === 2) pbf.readPackedVarint(obj.tags)
else if (tag === 3) obj.type = pbf.readVarint()
else if (tag === 4) pbf.readPackedVarint(obj.geometry)
}
public static write(obj, pbf) {
if (obj.id) pbf.writeVarintField(1, obj.id)
if (obj.tags) pbf.writePackedVarint(2, obj.tags)
@ -260,6 +263,7 @@ class Value {
end
)
}
static _readField = function (tag, obj, pbf) {
if (tag === 1) obj.string_value = pbf.readString()
else if (tag === 2) obj.float_value = pbf.readFloat()
@ -269,6 +273,7 @@ class Value {
else if (tag === 6) obj.sint_value = pbf.readSVarint()
else if (tag === 7) obj.bool_value = pbf.readBoolean()
}
public static write(obj, pbf) {
if (obj.string_value) pbf.writeStringField(1, obj.string_value)
if (obj.float_value) pbf.writeFloatField(2, obj.float_value)
@ -279,21 +284,10 @@ class Value {
if (obj.bool_value) pbf.writeBooleanField(7, obj.bool_value)
}
}
class Tile {
// code generated by pbf v3.2.1
public static read(pbf, end) {
return pbf.readFields(Tile._readField, { layers: [] }, end)
}
static _readField(tag, obj, pbf) {
if (tag === 3) obj.layers.push(Layer.read(pbf, pbf.readVarint() + pbf.pos))
}
static write(obj, pbf) {
if (obj.layers)
for (var i = 0; i < obj.layers.length; i++)
pbf.writeMessage(3, Layer.write, obj.layers[i])
}
static GeomType = {
UNKNOWN: {
value: 0,
@ -312,10 +306,27 @@ class Tile {
options: {},
},
}
public static read(pbf, end) {
return pbf.readFields(Tile._readField, { layers: [] }, end)
}
static _readField(tag, obj, pbf) {
if (tag === 3) obj.layers.push(Layer.read(pbf, pbf.readVarint() + pbf.pos))
}
static write(obj, pbf) {
if (obj.layers)
for (var i = 0; i < obj.layers.length; i++)
pbf.writeMessage(3, Layer.write, obj.layers[i])
}
}
export default class MvtSource implements FeatureSourceForTile {
export default class MvtSource implements FeatureSourceForTile, UpdatableFeatureSource {
public readonly features: Store<GeojsonFeature<Geometry, { [name: string]: any }>[]>
public readonly x: number
public readonly y: number
public readonly z: number
private readonly _url: string
private readonly _layerName: string
private readonly _features: UIEventSource<
@ -326,9 +337,7 @@ export default class MvtSource implements FeatureSourceForTile {
}
>[]
> = new UIEventSource<GeojsonFeature<Geometry, { [p: string]: any }>[]>([])
public readonly x: number
public readonly y: number
public readonly z: number
private currentlyRunning: Promise<any>
constructor(
url: string,
@ -343,7 +352,7 @@ export default class MvtSource implements FeatureSourceForTile {
this.x = x
this.y = y
this.z = z
this.downloadSync()
this.updateAsync()
this.features = this._features.map(
(fs) => {
if (fs === undefined || isActive?.data === false) {
@ -355,6 +364,13 @@ export default class MvtSource implements FeatureSourceForTile {
)
}
async updateAsync() {
if (!this.currentlyRunning) {
this.currentlyRunning = this.download()
}
await this.currentlyRunning
}
private getValue(v: {
// Exactly one of these values must be present in a valid message
string_value?: string
@ -389,47 +405,37 @@ export default class MvtSource implements FeatureSourceForTile {
return undefined
}
private downloadSync() {
this.download()
.then((d) => {
if (d.length === 0) {
return
}
return this._features.setData(d)
})
.catch((e) => {
console.error(e)
})
}
private async download(): Promise<GeojsonFeature[]> {
const result = await fetch(this._url)
if (result.status !== 200) {
console.error("Could not download tile " + this._url)
return []
}
const buffer = await result.arrayBuffer()
const data = Tile.read(new Pbf(buffer), undefined)
const layers = data.layers
let layer = data.layers[0]
if (layers.length > 1) {
if (!this._layerName) {
throw "Multiple layers in the downloaded tile, but no layername is given to choose from"
private async download(): Promise<void> {
try {
const result = await fetch(this._url)
if (result.status !== 200) {
console.error("Could not download tile " + this._url)
return
}
layer = layers.find((l) => l.name === this._layerName)
}
if (!layer) {
return []
}
const builder = new MvtFeatureBuilder(layer.extent, this.x, this.y, this.z)
const features: GeojsonFeature[] = []
const buffer = await result.arrayBuffer()
const data = Tile.read(new Pbf(buffer), undefined)
const layers = data.layers
let layer = data.layers[0]
if (layers.length > 1) {
if (!this._layerName) {
throw "Multiple layers in the downloaded tile, but no layername is given to choose from"
}
layer = layers.find((l) => l.name === this._layerName)
}
if (!layer) {
return
}
const builder = new MvtFeatureBuilder(layer.extent, this.x, this.y, this.z)
const features: GeojsonFeature[] = []
for (const feature of layer.features) {
const properties = this.inflateProperties(feature.tags, layer.keys, layer.values)
features.push(builder.toGeoJson(feature.geometry, feature.type, properties))
for (const feature of layer.features) {
const properties = this.inflateProperties(feature.tags, layer.keys, layer.values)
features.push(builder.toGeoJson(feature.geometry, feature.type, properties))
}
this._features.setData(features)
} catch (e) {
console.error("Could not download MVT tile due to", e)
}
return features
}
private inflateProperties(tags: number[], keys: string[], values: { string_value: string }[]) {