forked from MapComplete/MapComplete
		
	Fix CSP issues
This commit is contained in:
		
							parent
							
								
									56b83cfa36
								
							
						
					
					
						commit
						06c2e2fec8
					
				
					 7 changed files with 227 additions and 147 deletions
				
			
		|  | @ -279,6 +279,7 @@ async function generateCsp( | ||||||
|         "https://www.openstreetmap.org", |         "https://www.openstreetmap.org", | ||||||
|         "https://api.openstreetmap.org", |         "https://api.openstreetmap.org", | ||||||
|         "https://pietervdvn.goatcounter.com", |         "https://pietervdvn.goatcounter.com", | ||||||
|  |         "https://cache.mapcomplete.org", | ||||||
|     ].concat(...(await eliUrls())) |     ].concat(...(await eliUrls())) | ||||||
| 
 | 
 | ||||||
|     SpecialVisualizations.specialVisualizations.forEach((sv) => { |     SpecialVisualizations.specialVisualizations.forEach((sv) => { | ||||||
|  | @ -289,15 +290,21 @@ async function generateCsp( | ||||||
|         apiUrls.push(...(sv.needsUrls ?? [])) |         apiUrls.push(...(sv.needsUrls ?? [])) | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
|     const usedSpecialVisualisations = [].concat(...layoutJson.layers.map(l => ValidationUtils.getAllSpecialVisualisations(<QuestionableTagRenderingConfigJson[]> (<LayerConfigJson>l).tagRenderings ?? []))) |     const usedSpecialVisualisations = [].concat( | ||||||
|  |         ...layoutJson.layers.map((l) => | ||||||
|  |             ValidationUtils.getAllSpecialVisualisations( | ||||||
|  |                 <QuestionableTagRenderingConfigJson[]>(<LayerConfigJson>l).tagRenderings ?? [] | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |     ) | ||||||
|     for (const usedSpecialVisualisation of usedSpecialVisualisations) { |     for (const usedSpecialVisualisation of usedSpecialVisualisations) { | ||||||
|         if (typeof usedSpecialVisualisation === "string") { |         if (typeof usedSpecialVisualisation === "string") { | ||||||
|             continue |             continue | ||||||
|         } |         } | ||||||
|         const neededUrls = usedSpecialVisualisation.func.needsUrls ?? [] |         const neededUrls = usedSpecialVisualisation.func.needsUrls ?? [] | ||||||
|         if (typeof neededUrls === "function") { |         if (typeof neededUrls === "function") { | ||||||
|             let needed: string | string[]  = neededUrls(usedSpecialVisualisation.args) |             let needed: string | string[] = neededUrls(usedSpecialVisualisation.args) | ||||||
|             if(typeof needed === "string"){ |             if (typeof needed === "string") { | ||||||
|                 needed = [needed] |                 needed = [needed] | ||||||
|             } |             } | ||||||
|             apiUrls.push(...needed) |             apiUrls.push(...needed) | ||||||
|  | @ -317,8 +324,8 @@ async function generateCsp( | ||||||
|             continue |             continue | ||||||
|         } |         } | ||||||
|         try { |         try { | ||||||
|             if(!connectSource.startsWith("http")){ |             if (!connectSource.startsWith("http")) { | ||||||
|             connectSource = "https://"+connectSource |                 connectSource = "https://" + connectSource | ||||||
|             } |             } | ||||||
|             const url = new URL(connectSource) |             const url = new URL(connectSource) | ||||||
|             hosts.add("https://" + url.host) |             hosts.add("https://" + url.host) | ||||||
|  | @ -349,7 +356,7 @@ async function generateCsp( | ||||||
|         "default-src": "'self'", |         "default-src": "'self'", | ||||||
|         "child-src": "'self' blob: ", |         "child-src": "'self' blob: ", | ||||||
|         "img-src": "* data:", // maplibre depends on 'data:' to load
 |         "img-src": "* data:", // maplibre depends on 'data:' to load
 | ||||||
|         "connect-src": "'self' "+connectSrc.join(" "), |         "connect-src": "'self' " + connectSrc.join(" "), | ||||||
|         "report-to": "https://report.mapcomplete.org/csp", |         "report-to": "https://report.mapcomplete.org/csp", | ||||||
|         "worker-src": "'self' blob:", // Vite somehow loads the worker via a 'blob'
 |         "worker-src": "'self' blob:", // Vite somehow loads the worker via a 'blob'
 | ||||||
|         "style-src": "'self' 'unsafe-inline'", // unsafe-inline is needed to change the default background pin colours
 |         "style-src": "'self' 'unsafe-inline'", // unsafe-inline is needed to change the default background pin colours
 | ||||||
|  |  | ||||||
|  | @ -16,9 +16,9 @@ npm run test && | ||||||
| npm run prepare-deploy && | npm run prepare-deploy && | ||||||
| zip dist.zip -r dist/* && | zip dist.zip -r dist/* && | ||||||
| mv config.json.bu config.json && | mv config.json.bu config.json && | ||||||
| scp ./scripts/hetzner/config/* hetzner:/root/ && | scp ./Docs/ServerConfig/hetzner/* hetzner:/root/ && | ||||||
| rsync -rzh --progress dist.zip hetzner:/root/ && | rsync -rzh --progress dist.zip hetzner:/root/ && | ||||||
| echo "Upload completed, deploying config and booting" && | echo "Upload completed, deploying config and booting" && | ||||||
| ssh hetzner -t "unzip dist.zip && rm dist.zip && rm -rf public/ && mv dist public && caddy stop && caddy start" && | ssh hetzner -t "unzip dist.zip && rm dist.zip && rm -rf public/ && mv dist public && caddy stop && caddy start" && | ||||||
| rm dist.zip | # rm dist.zip | ||||||
| npm run clean | npm run clean | ||||||
|  |  | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| import { Feature, Geometry } from "geojson" | import { Geometry } from "geojson" | ||||||
|  | import { Feature as GeojsonFeature } from "geojson" | ||||||
|  | 
 | ||||||
| import { Store, UIEventSource } from "../../UIEventSource" | import { Store, UIEventSource } from "../../UIEventSource" | ||||||
| import { FeatureSourceForTile } from "../FeatureSource" | import { FeatureSourceForTile } from "../FeatureSource" | ||||||
| import Pbf from "pbf" | import Pbf from "pbf" | ||||||
| import * as pbfCompile from "pbf/compile" |  | ||||||
| import * as PbfSchema from "protocol-buffers-schema" |  | ||||||
| 
 | 
 | ||||||
| type Coords = [number, number][] | type Coords = [number, number][] | ||||||
| 
 | 
 | ||||||
|  | @ -60,12 +60,11 @@ class MvtFeatureBuilder { | ||||||
|             } |             } | ||||||
|             const ccw = area < 0 |             const ccw = area < 0 | ||||||
| 
 | 
 | ||||||
|             if (ccw === (area < 0)) { |             if (ccw === area < 0) { | ||||||
|                 if (currentPolygon) { |                 if (currentPolygon) { | ||||||
|                     polygons.push(currentPolygon) |                     polygons.push(currentPolygon) | ||||||
|                 } |                 } | ||||||
|                 currentPolygon = [ring] |                 currentPolygon = [ring] | ||||||
| 
 |  | ||||||
|             } else { |             } else { | ||||||
|                 currentPolygon.push(ring) |                 currentPolygon.push(ring) | ||||||
|             } |             } | ||||||
|  | @ -77,7 +76,7 @@ class MvtFeatureBuilder { | ||||||
|         return polygons |         return polygons | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public toGeoJson(geometry: number[], typeIndex: 1 | 2 | 3, properties: any): Feature { |     public toGeoJson(geometry: number[], typeIndex: 1 | 2 | 3, properties: any): GeojsonFeature { | ||||||
|         let coords: Coords[] = this.encodeGeometry(geometry) |         let coords: Coords[] = this.encodeGeometry(geometry) | ||||||
|         let classified = undefined |         let classified = undefined | ||||||
|         switch (typeIndex) { |         switch (typeIndex) { | ||||||
|  | @ -159,9 +158,9 @@ class MvtFeatureBuilder { | ||||||
|             if (commandId === 1 || commandId === 2) { |             if (commandId === 1 || commandId === 2) { | ||||||
|                 for (let j = 0; j < commandCount; j++) { |                 for (let j = 0; j < commandCount; j++) { | ||||||
|                     const dx = geometry[i + j * 2 + 1] |                     const dx = geometry[i + j * 2 + 1] | ||||||
|                     cX += ((dx >> 1) ^ (-(dx & 1))) |                     cX += (dx >> 1) ^ -(dx & 1) | ||||||
|                     const dy = geometry[i + j * 2 + 2] |                     const dy = geometry[i + j * 2 + 2] | ||||||
|                     cY += ((dy >> 1) ^ (-(dy & 1))) |                     cY += (dy >> 1) ^ -(dy & 1) | ||||||
|                     currentRing.push([cX, cY]) |                     currentRing.push([cX, cY]) | ||||||
|                 } |                 } | ||||||
|                 i += commandCount * 2 |                 i += commandCount * 2 | ||||||
|  | @ -170,7 +169,6 @@ class MvtFeatureBuilder { | ||||||
|                 currentRing.push([...currentRing[0]]) |                 currentRing.push([...currentRing[0]]) | ||||||
|                 i++ |                 i++ | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|         } |         } | ||||||
|         if (currentRing.length > 0) { |         if (currentRing.length > 0) { | ||||||
|             coordss.push(currentRing) |             coordss.push(currentRing) | ||||||
|  | @ -189,132 +187,182 @@ class MvtFeatureBuilder { | ||||||
|         const size = this._size |         const size = this._size | ||||||
|         for (let i = 0; i < line.length; i++) { |         for (let i = 0; i < line.length; i++) { | ||||||
|             let p = line[i] |             let p = line[i] | ||||||
|             let y2 = 180 - (p[1] + y0) * 360 / size |             let y2 = 180 - ((p[1] + y0) * 360) / size | ||||||
|             line[i] = [ |             line[i] = [ | ||||||
|                 (p[0] + x0) * 360 / size - 180, |                 ((p[0] + x0) * 360) / size - 180, | ||||||
|                 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90, |                 (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90, | ||||||
|             ] |             ] | ||||||
|         } |         } | ||||||
|         return line |         return line | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default class MvtSource implements FeatureSourceForTile { | class Layer { | ||||||
| 
 |     public static read(pbf, end) { | ||||||
|     private static readonly schemaSpec21 = ` |         return pbf.readFields( | ||||||
|     package vector_tile; |             Layer._readField, | ||||||
| 
 |             { version: 0, name: "", features: [], keys: [], values: [], extent: 0 }, | ||||||
| option optimize_for = LITE_RUNTIME; |             end | ||||||
| 
 |         ) | ||||||
| message Tile { |     } | ||||||
| 
 |     static _readField(tag, obj, pbf) { | ||||||
|         // GeomType is described in section 4.3.4 of the specification
 |         if (tag === 15) obj.version = pbf.readVarint() | ||||||
|         enum GeomType { |         else if (tag === 1) obj.name = pbf.readString() | ||||||
|              UNKNOWN = 0; |         else if (tag === 2) obj.features.push(Feature.read(pbf, pbf.readVarint() + pbf.pos)) | ||||||
|              POINT = 1; |         else if (tag === 3) obj.keys.push(pbf.readString()) | ||||||
|              LINESTRING = 2; |         else if (tag === 4) obj.values.push(Value.read(pbf, pbf.readVarint() + pbf.pos)) | ||||||
|              POLYGON = 3; |         else if (tag === 5) obj.extent = pbf.readVarint() | ||||||
|         } |     } | ||||||
| 
 |     public static write(obj, pbf) { | ||||||
|         // Variant type encoding
 |         if (obj.version) pbf.writeVarintField(15, obj.version) | ||||||
|         // The use of values is described in section 4.1 of the specification
 |         if (obj.name) pbf.writeStringField(1, obj.name) | ||||||
|         message Value { |         if (obj.features) | ||||||
|                 // Exactly one of these values must be present in a valid message
 |             for (var i = 0; i < obj.features.length; i++) | ||||||
|                 optional string string_value = 1; |                 pbf.writeMessage(2, Feature.write, obj.features[i]) | ||||||
|                 optional float float_value = 2; |         if (obj.keys) for (i = 0; i < obj.keys.length; i++) pbf.writeStringField(3, obj.keys[i]) | ||||||
|                 optional double double_value = 3; |         if (obj.values) | ||||||
|                 optional int64 int_value = 4; |             for (i = 0; i < obj.values.length; i++) pbf.writeMessage(4, Value.write, obj.values[i]) | ||||||
|                 optional uint64 uint_value = 5; |         if (obj.extent) pbf.writeVarintField(5, obj.extent) | ||||||
|                 optional sint64 sint_value = 6; |     } | ||||||
|                 optional bool bool_value = 7; |  | ||||||
| 
 |  | ||||||
|                 extensions 8 to max; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Features are described in section 4.2 of the specification
 |  | ||||||
|         message Feature { |  | ||||||
|                 optional uint64 id = 1 [ default = 0 ]; |  | ||||||
| 
 |  | ||||||
|                 // Tags of this feature are encoded as repeated pairs of
 |  | ||||||
|                 // integers.
 |  | ||||||
|                 // A detailed description of tags is located in sections
 |  | ||||||
|                 // 4.2 and 4.4 of the specification
 |  | ||||||
|                 repeated uint32 tags = 2 [ packed = true ]; |  | ||||||
| 
 |  | ||||||
|                 // The type of geometry stored in this feature.
 |  | ||||||
|                 optional GeomType type = 3 [ default = UNKNOWN ]; |  | ||||||
| 
 |  | ||||||
|                 // Contains a stream of commands and parameters (vertices).
 |  | ||||||
|                 // A detailed description on geometry encoding is located in
 |  | ||||||
|                 // section 4.3 of the specification.
 |  | ||||||
|                 repeated uint32 geometry = 4 [ packed = true ]; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Layers are described in section 4.1 of the specification
 |  | ||||||
|         message Layer { |  | ||||||
|                 // Any compliant implementation must first read the version
 |  | ||||||
|                 // number encoded in this message and choose the correct
 |  | ||||||
|                 // implementation for this version number before proceeding to
 |  | ||||||
|                 // decode other parts of this message.
 |  | ||||||
|                 required uint32 version = 15 [ default = 1 ]; |  | ||||||
| 
 |  | ||||||
|                 required string name = 1; |  | ||||||
| 
 |  | ||||||
|                 // The actual features in this tile.
 |  | ||||||
|                 repeated Feature features = 2; |  | ||||||
| 
 |  | ||||||
|                 // Dictionary encoding for keys
 |  | ||||||
|                 repeated string keys = 3; |  | ||||||
| 
 |  | ||||||
|                 // Dictionary encoding for values
 |  | ||||||
|                 repeated Value values = 4; |  | ||||||
| 
 |  | ||||||
|                 // Although this is an "optional" field it is required by the specification.
 |  | ||||||
|                 // See https://github.com/mapbox/vector-tile-spec/issues/47
 |  | ||||||
|                 optional uint32 extent = 5 [ default = 4096 ]; |  | ||||||
| 
 |  | ||||||
|                 extensions 16 to max; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         repeated Layer layers = 3; |  | ||||||
| 
 |  | ||||||
|         extensions 16 to 8191; |  | ||||||
| } | } | ||||||
| ` | 
 | ||||||
|     private static readonly tile_schema = (pbfCompile.default ?? pbfCompile)(PbfSchema.parse(MvtSource.schemaSpec21)).Tile | class Feature { | ||||||
|     public readonly features: Store<Feature<Geometry, { [name: string]: any }>[]> |     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) | ||||||
|  |         if (obj.type) pbf.writeVarintField(3, obj.type) | ||||||
|  |         if (obj.geometry) pbf.writePackedVarint(4, obj.geometry) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Value { | ||||||
|  |     public static read(pbf, end) { | ||||||
|  |         return pbf.readFields( | ||||||
|  |             Value._readField, | ||||||
|  |             { | ||||||
|  |                 string_value: "", | ||||||
|  |                 float_value: 0, | ||||||
|  |                 double_value: 0, | ||||||
|  |                 int_value: 0, | ||||||
|  |                 uint_value: 0, | ||||||
|  |                 sint_value: 0, | ||||||
|  |                 bool_value: false, | ||||||
|  |             }, | ||||||
|  |             end | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |     static _readField = function (tag, obj, pbf) { | ||||||
|  |         if (tag === 1) obj.string_value = pbf.readString() | ||||||
|  |         else if (tag === 2) obj.float_value = pbf.readFloat() | ||||||
|  |         else if (tag === 3) obj.double_value = pbf.readDouble() | ||||||
|  |         else if (tag === 4) obj.int_value = pbf.readVarint(true) | ||||||
|  |         else if (tag === 5) obj.uint_value = pbf.readVarint() | ||||||
|  |         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) | ||||||
|  |         if (obj.double_value) pbf.writeDoubleField(3, obj.double_value) | ||||||
|  |         if (obj.int_value) pbf.writeVarintField(4, obj.int_value) | ||||||
|  |         if (obj.uint_value) pbf.writeVarintField(5, obj.uint_value) | ||||||
|  |         if (obj.sint_value) pbf.writeSVarintField(6, obj.sint_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, | ||||||
|  |             options: {}, | ||||||
|  |         }, | ||||||
|  |         POINT: { | ||||||
|  |             value: 1, | ||||||
|  |             options: {}, | ||||||
|  |         }, | ||||||
|  |         LINESTRING: { | ||||||
|  |             value: 2, | ||||||
|  |             options: {}, | ||||||
|  |         }, | ||||||
|  |         POLYGON: { | ||||||
|  |             value: 3, | ||||||
|  |             options: {}, | ||||||
|  |         }, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export default class MvtSource implements FeatureSourceForTile { | ||||||
|  |     public readonly features: Store<GeojsonFeature<Geometry, { [name: string]: any }>[]> | ||||||
|     private readonly _url: string |     private readonly _url: string | ||||||
|     private readonly _layerName: string |     private readonly _layerName: string | ||||||
|     private readonly _features: UIEventSource<Feature<Geometry, { |     private readonly _features: UIEventSource< | ||||||
|         [name: string]: any |         GeojsonFeature< | ||||||
|     }>[]> = new UIEventSource<Feature<Geometry, { [p: string]: any }>[]>([]) |             Geometry, | ||||||
|  |             { | ||||||
|  |                 [name: string]: any | ||||||
|  |             } | ||||||
|  |         >[] | ||||||
|  |     > = new UIEventSource<GeojsonFeature<Geometry, { [p: string]: any }>[]>([]) | ||||||
|     public readonly x: number |     public readonly x: number | ||||||
|     public readonly y: number |     public readonly y: number | ||||||
|     public readonly z: number |     public readonly z: number | ||||||
| 
 | 
 | ||||||
|     constructor(url: string, x: number, y: number, z: number, layerName?: string, isActive?: Store<boolean>) { |     constructor( | ||||||
|  |         url: string, | ||||||
|  |         x: number, | ||||||
|  |         y: number, | ||||||
|  |         z: number, | ||||||
|  |         layerName?: string, | ||||||
|  |         isActive?: Store<boolean> | ||||||
|  |     ) { | ||||||
|         this._url = url |         this._url = url | ||||||
|         this._layerName = layerName |         this._layerName = layerName | ||||||
|         this.x = x |         this.x = x | ||||||
|         this.y = y |         this.y = y | ||||||
|         this.z = z |         this.z = z | ||||||
|         this.downloadSync() |         this.downloadSync() | ||||||
|         this.features = this._features.map(fs => { |         this.features = this._features.map( | ||||||
|             if (fs === undefined || isActive?.data === false) { |             (fs) => { | ||||||
|                 return [] |                 if (fs === undefined || isActive?.data === false) { | ||||||
|             } |                     return [] | ||||||
|             return fs |                 } | ||||||
|         }, [isActive]) |                 return fs | ||||||
|  |             }, | ||||||
|  |             [isActive] | ||||||
|  |         ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private getValue(v: { |     private getValue(v: { | ||||||
|         // Exactly one of these values must be present in a valid message
 |         // Exactly one of these values must be present in a valid message
 | ||||||
|         string_value?: string, |         string_value?: string | ||||||
|         float_value?: number, |         float_value?: number | ||||||
|         double_value?: number, |         double_value?: number | ||||||
|         int_value?: number, |         int_value?: number | ||||||
|         uint_value?: number, |         uint_value?: number | ||||||
|         sint_value?: number, |         sint_value?: number | ||||||
|         bool_value?: boolean |         bool_value?: boolean | ||||||
|     }): string | number | undefined | boolean { |     }): string | number | undefined | boolean { | ||||||
|         if (v.string_value !== "") { |         if (v.string_value !== "") { | ||||||
|  | @ -339,41 +387,42 @@ message Tile { | ||||||
|             return v.bool_value |             return v.bool_value | ||||||
|         } |         } | ||||||
|         return undefined |         return undefined | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private downloadSync() { |     private downloadSync() { | ||||||
|         this.download().then(d => { |         this.download() | ||||||
|             if (d.length === 0) { |             .then((d) => { | ||||||
|                 return |                 if (d.length === 0) { | ||||||
|             } |                     return | ||||||
|             return this._features.setData(d) |                 } | ||||||
|         }).catch(e => { |                 return this._features.setData(d) | ||||||
|             console.error(e) |             }) | ||||||
|         }) |             .catch((e) => { | ||||||
|  |                 console.error(e) | ||||||
|  |             }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private async download(): Promise<Feature[]> { |     private async download(): Promise<GeojsonFeature[]> { | ||||||
|         const result = await fetch(this._url) |         const result = await fetch(this._url) | ||||||
|         if (result.status !== 200) { |         if (result.status !== 200) { | ||||||
|             console.error("Could not download tile " + this._url) |             console.error("Could not download tile " + this._url) | ||||||
|             return [] |             return [] | ||||||
|         } |         } | ||||||
|         const buffer = await result.arrayBuffer() |         const buffer = await result.arrayBuffer() | ||||||
|         const data = MvtSource.tile_schema.read(new Pbf(buffer)) |         const data = Tile.read(new Pbf(buffer), undefined) | ||||||
|         const layers = data.layers |         const layers = data.layers | ||||||
|         let layer = data.layers[0] |         let layer = data.layers[0] | ||||||
|         if (layers.length > 1) { |         if (layers.length > 1) { | ||||||
|             if (!this._layerName) { |             if (!this._layerName) { | ||||||
|                 throw "Multiple layers in the downloaded tile, but no layername is given to choose from" |                 throw "Multiple layers in the downloaded tile, but no layername is given to choose from" | ||||||
|             } |             } | ||||||
|             layer = layers.find(l => l.name === this._layerName) |             layer = layers.find((l) => l.name === this._layerName) | ||||||
|         } |         } | ||||||
|         if (!layer) { |         if (!layer) { | ||||||
|             return [] |             return [] | ||||||
|         } |         } | ||||||
|         const builder = new MvtFeatureBuilder(layer.extent, this.x, this.y, this.z) |         const builder = new MvtFeatureBuilder(layer.extent, this.x, this.y, this.z) | ||||||
|         const features: Feature[] = [] |         const features: GeojsonFeature[] = [] | ||||||
| 
 | 
 | ||||||
|         for (const feature of layer.features) { |         for (const feature of layer.features) { | ||||||
|             const properties = this.inflateProperties(feature.tags, layer.keys, layer.values) |             const properties = this.inflateProperties(feature.tags, layer.keys, layer.values) | ||||||
|  | @ -383,7 +432,6 @@ message Tile { | ||||||
|         return features |         return features | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     private inflateProperties(tags: number[], keys: string[], values: { string_value: string }[]) { |     private inflateProperties(tags: number[], keys: string[], values: { string_value: string }[]) { | ||||||
|         const properties = {} |         const properties = {} | ||||||
|         for (let i = 0; i < tags.length; i += 2) { |         for (let i = 0; i < tags.length; i += 2) { | ||||||
|  | @ -407,5 +455,4 @@ message Tile { | ||||||
| 
 | 
 | ||||||
|         return properties |         return properties | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,8 @@ | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| 
 | 
 | ||||||
|  |    | ||||||
|  |    | ||||||
|  |    | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| No tests | No tests | ||||||
|  |  | ||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -4,6 +4,8 @@ import ThemeViewGUI from "./src/UI/ThemeViewGUI.svelte" | ||||||
| import LayoutConfig from "./src/Models/ThemeConfig/LayoutConfig"; | import LayoutConfig from "./src/Models/ThemeConfig/LayoutConfig"; | ||||||
| import MetaTagging from "./src/Logic/MetaTagging"; | import MetaTagging from "./src/Logic/MetaTagging"; | ||||||
| import { FixedUiElement } from "./src/UI/Base/FixedUiElement"; | import { FixedUiElement } from "./src/UI/Base/FixedUiElement"; | ||||||
|  | import { Utils } from "./src/Utils" | ||||||
|  | import Constants from "./src/Models/Constants" | ||||||
| 
 | 
 | ||||||
| function webgl_support() { | function webgl_support() { | ||||||
|     try { |     try { | ||||||
|  | @ -16,13 +18,27 @@ function webgl_support() { | ||||||
|         return false |         return false | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | async function getAvailableLayers(): Promise<Set<string>> { | ||||||
|  |     try { | ||||||
|  |         const host = new URL(Constants.VectorTileServer).host | ||||||
|  |         const status = await Utils.downloadJson("https://" + host + "/summary/status.json") | ||||||
|  |         return new Set<string>(status.layers) | ||||||
|  |     } catch (e) { | ||||||
|  |         console.error("Could not get MVT available layers due to", e) | ||||||
|  |         return new Set<string>() | ||||||
|  |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| if (!webgl_support()) { | async function main() { | ||||||
|      new FixedUiElement("WebGL is not supported or not enabled. This is essential for MapComplete to function, please enable this.").SetClass("block alert").AttachTo("maindiv") |     if (!webgl_support()) { | ||||||
| }else{ |          new FixedUiElement("WebGL is not supported or not enabled. This is essential for MapComplete to function, please enable this.").SetClass("block alert").AttachTo("maindiv") | ||||||
|     MetaTagging.setThemeMetatagging(new ThemeMetaTagging()) |     }else{ | ||||||
|     // LAYOUT.ADD_LAYERS |         const availableLayers = await getAvailableLayers() | ||||||
|     const state = new ThemeViewState(new LayoutConfig(<any> layout)) |         MetaTagging.setThemeMetatagging(new ThemeMetaTagging()) | ||||||
|     const main = new SvelteUIElement(ThemeViewGUI, { state }) |         // LAYOUT.ADD_LAYERS | ||||||
|     main.AttachTo("maindiv") |         const state = new ThemeViewState(new LayoutConfig(<any> layout), availableLayers) | ||||||
| }     |         const main = new SvelteUIElement(ThemeViewGUI, { state }) | ||||||
|  |         main.AttachTo("maindiv") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | main() | ||||||
|  |  | ||||||
|  | @ -1,4 +1,7 @@ | ||||||
| import SvelteUIElement from "./UI/Base/SvelteUIElement" | import SvelteUIElement from "./UI/Base/SvelteUIElement" | ||||||
| import Test from "./UI/Test.svelte" | import Test from "./UI/Test.svelte" | ||||||
|  | import MvtSource from "./Logic/FeatureSource/Sources/MvtSource" | ||||||
|  | 
 | ||||||
|  | new MvtSource("https://example.org", undefined, undefined, undefined) | ||||||
| 
 | 
 | ||||||
| new SvelteUIElement(Test, {}).AttachTo("maindiv") | new SvelteUIElement(Test, {}).AttachTo("maindiv") | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue