forked from MapComplete/MapComplete
		
	LayerServer: first version which can use a local MVT-server
This commit is contained in:
		
							parent
							
								
									35228daa8f
								
							
						
					
					
						commit
						ef2f1487c6
					
				
					 17 changed files with 1009 additions and 82 deletions
				
			
		|  | @ -25,13 +25,13 @@ Use scripts/osm2pgsl | ||||||
| To seed the database: | To seed the database: | ||||||
| 
 | 
 | ||||||
| ```` | ```` | ||||||
| osm2pgsql -O flex -S drinking_water.lua -s  --flat-nodes=import-help-file -d postgresql://user:none@localhost:5444/osm-poi andorra-latest.osm.pbf  | osm2pgsql -O flex -E 4326 -S build_db.lua -s  --flat-nodes=import-help-file -d postgresql://user:password@localhost:5444/osm-poi andorra-latest.osm.pbf  | ||||||
| ```` | ```` | ||||||
| 
 | 
 | ||||||
| ## Deploying a tile server | ## Deploying a tile server | ||||||
| 
 | 
 | ||||||
| ```` | ```` | ||||||
| export DATABASE_URL=postgresql://user:none@localhost:5444/osm-poi | export DATABASE_URL=postgresql://user:password@localhost:5444/osm-poi | ||||||
| ./pg_tileserv | ./pg_tileserv | ||||||
| ```` | ```` | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ | ||||||
|   "source": { |   "source": { | ||||||
|     "osmTags": "amenity=shower" |     "osmTags": "amenity=shower" | ||||||
|   }, |   }, | ||||||
|   "minzoom": 12, |   "minzoom": 8, | ||||||
|   "title": { |   "title": { | ||||||
|     "render": { |     "render": { | ||||||
|       "en": "Shower", |       "en": "Shower", | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ | ||||||
|   "source": { |   "source": { | ||||||
|     "osmTags": "amenity=toilets" |     "osmTags": "amenity=toilets" | ||||||
|   }, |   }, | ||||||
|   "minzoom": 12, |   "minzoom": 9, | ||||||
|   "title": { |   "title": { | ||||||
|     "render": { |     "render": { | ||||||
|       "en": "Toilet", |       "en": "Toilet", | ||||||
|  |  | ||||||
							
								
								
									
										386
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										386
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -20,6 +20,7 @@ | ||||||
|         "@turf/length": "^6.5.0", |         "@turf/length": "^6.5.0", | ||||||
|         "@turf/turf": "^6.5.0", |         "@turf/turf": "^6.5.0", | ||||||
|         "@types/dompurify": "^3.0.2", |         "@types/dompurify": "^3.0.2", | ||||||
|  |         "@types/pg": "^8.10.9", | ||||||
|         "@types/qrcode-generator": "^1.0.6", |         "@types/qrcode-generator": "^1.0.6", | ||||||
|         "@types/showdown": "^2.0.0", |         "@types/showdown": "^2.0.0", | ||||||
|         "chart.js": "^3.8.0", |         "chart.js": "^3.8.0", | ||||||
|  | @ -50,6 +51,8 @@ | ||||||
|         "osmtogeojson": "^3.0.0-beta.5", |         "osmtogeojson": "^3.0.0-beta.5", | ||||||
|         "panzoom": "^9.4.3", |         "panzoom": "^9.4.3", | ||||||
|         "papaparse": "^5.3.1", |         "papaparse": "^5.3.1", | ||||||
|  |         "pbf": "^3.2.1", | ||||||
|  |         "pg": "^8.11.3", | ||||||
|         "pic4carto": "^2.1.15", |         "pic4carto": "^2.1.15", | ||||||
|         "prompt-sync": "^4.2.0", |         "prompt-sync": "^4.2.0", | ||||||
|         "qrcode-generator": "^1.4.4", |         "qrcode-generator": "^1.4.4", | ||||||
|  | @ -4223,6 +4226,68 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.3.tgz", |       "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.3.tgz", | ||||||
|       "integrity": "sha512-hw6bDMjvm+QTvEC+pRLpnTknQXoPu8Fnf+A+zX9HB7j/7RfYajFSbdukabo3adPwvvEHhIMafQl0R0Tpej7clQ==" |       "integrity": "sha512-hw6bDMjvm+QTvEC+pRLpnTknQXoPu8Fnf+A+zX9HB7j/7RfYajFSbdukabo3adPwvvEHhIMafQl0R0Tpej7clQ==" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/pg": { | ||||||
|  |       "version": "8.10.9", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.9.tgz", | ||||||
|  |       "integrity": "sha512-UksbANNE/f8w0wOMxVKKIrLCbEMV+oM1uKejmwXr39olg4xqcfBDbXxObJAt6XxHbDa4XTKOlUEcEltXDX+XLQ==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@types/node": "*", | ||||||
|  |         "pg-protocol": "*", | ||||||
|  |         "pg-types": "^4.0.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@types/pg/node_modules/pg-types": { | ||||||
|  |       "version": "4.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz", | ||||||
|  |       "integrity": "sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "pg-int8": "1.0.1", | ||||||
|  |         "pg-numeric": "1.0.2", | ||||||
|  |         "postgres-array": "~3.0.1", | ||||||
|  |         "postgres-bytea": "~3.0.0", | ||||||
|  |         "postgres-date": "~2.0.1", | ||||||
|  |         "postgres-interval": "^3.0.0", | ||||||
|  |         "postgres-range": "^1.1.1" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=10" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@types/pg/node_modules/postgres-array": { | ||||||
|  |       "version": "3.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", | ||||||
|  |       "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@types/pg/node_modules/postgres-bytea": { | ||||||
|  |       "version": "3.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", | ||||||
|  |       "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "obuf": "~1.1.2" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 6" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@types/pg/node_modules/postgres-date": { | ||||||
|  |       "version": "2.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", | ||||||
|  |       "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@types/pg/node_modules/postgres-interval": { | ||||||
|  |       "version": "3.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", | ||||||
|  |       "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=12" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@types/prompt-sync": { |     "node_modules/@types/prompt-sync": { | ||||||
|       "version": "4.2.0", |       "version": "4.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/prompt-sync/-/prompt-sync-4.2.0.tgz", |       "resolved": "https://registry.npmjs.org/@types/prompt-sync/-/prompt-sync-4.2.0.tgz", | ||||||
|  | @ -5277,6 +5342,14 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", |       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", | ||||||
|       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" |       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/buffer-writer": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", | ||||||
|  |       "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/bytewise": { |     "node_modules/bytewise": { | ||||||
|       "version": "1.1.0", |       "version": "1.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", |       "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", | ||||||
|  | @ -9606,6 +9679,11 @@ | ||||||
|         "node": ">= 0.4" |         "node": ">= 0.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/obuf": { | ||||||
|  |       "version": "1.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", | ||||||
|  |       "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" | ||||||
|  |     }, | ||||||
|     "node_modules/once": { |     "node_modules/once": { | ||||||
|       "version": "1.4.0", |       "version": "1.4.0", | ||||||
|       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", |       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | ||||||
|  | @ -9845,6 +9923,11 @@ | ||||||
|         "url": "https://github.com/sponsors/sindresorhus" |         "url": "https://github.com/sponsors/sindresorhus" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/packet-reader": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", | ||||||
|  |       "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" | ||||||
|  |     }, | ||||||
|     "node_modules/panzoom": { |     "node_modules/panzoom": { | ||||||
|       "version": "9.4.3", |       "version": "9.4.3", | ||||||
|       "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz", |       "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz", | ||||||
|  | @ -9954,6 +10037,97 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", |       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", | ||||||
|       "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" |       "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/pg": { | ||||||
|  |       "version": "8.11.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", | ||||||
|  |       "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "buffer-writer": "2.0.0", | ||||||
|  |         "packet-reader": "1.0.0", | ||||||
|  |         "pg-connection-string": "^2.6.2", | ||||||
|  |         "pg-pool": "^3.6.1", | ||||||
|  |         "pg-protocol": "^1.6.0", | ||||||
|  |         "pg-types": "^2.1.0", | ||||||
|  |         "pgpass": "1.x" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 8.0.0" | ||||||
|  |       }, | ||||||
|  |       "optionalDependencies": { | ||||||
|  |         "pg-cloudflare": "^1.1.1" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "pg-native": ">=3.0.1" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "pg-native": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/pg-cloudflare": { | ||||||
|  |       "version": "1.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", | ||||||
|  |       "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "node_modules/pg-connection-string": { | ||||||
|  |       "version": "2.6.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", | ||||||
|  |       "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/pg-int8": { | ||||||
|  |       "version": "1.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", | ||||||
|  |       "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=4.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/pg-numeric": { | ||||||
|  |       "version": "1.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", | ||||||
|  |       "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/pg-pool": { | ||||||
|  |       "version": "3.6.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", | ||||||
|  |       "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "pg": ">=8.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/pg-protocol": { | ||||||
|  |       "version": "1.6.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", | ||||||
|  |       "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" | ||||||
|  |     }, | ||||||
|  |     "node_modules/pg-types": { | ||||||
|  |       "version": "2.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", | ||||||
|  |       "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "pg-int8": "1.0.1", | ||||||
|  |         "postgres-array": "~2.0.0", | ||||||
|  |         "postgres-bytea": "~1.0.0", | ||||||
|  |         "postgres-date": "~1.0.4", | ||||||
|  |         "postgres-interval": "^1.1.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/pgpass": { | ||||||
|  |       "version": "1.0.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", | ||||||
|  |       "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "split2": "^4.1.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/pic4carto": { |     "node_modules/pic4carto": { | ||||||
|       "version": "2.1.15", |       "version": "2.1.15", | ||||||
|       "resolved": "https://registry.npmjs.org/pic4carto/-/pic4carto-2.1.15.tgz", |       "resolved": "https://registry.npmjs.org/pic4carto/-/pic4carto-2.1.15.tgz", | ||||||
|  | @ -10138,6 +10312,46 @@ | ||||||
|         "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" |         "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/postgres-array": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", | ||||||
|  |       "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=4" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/postgres-bytea": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", | ||||||
|  |       "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.10.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/postgres-date": { | ||||||
|  |       "version": "1.0.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", | ||||||
|  |       "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.10.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/postgres-interval": { | ||||||
|  |       "version": "1.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", | ||||||
|  |       "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "xtend": "^4.0.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.10.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/postgres-range": { | ||||||
|  |       "version": "1.1.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", | ||||||
|  |       "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==" | ||||||
|  |     }, | ||||||
|     "node_modules/potpack": { |     "node_modules/potpack": { | ||||||
|       "version": "2.0.0", |       "version": "2.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", |       "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", | ||||||
|  | @ -11461,6 +11675,14 @@ | ||||||
|         "node": ">=0.10.0" |         "node": ">=0.10.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/split2": { | ||||||
|  |       "version": "4.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", | ||||||
|  |       "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 10.x" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/sshpk": { |     "node_modules/sshpk": { | ||||||
|       "version": "1.17.0", |       "version": "1.17.0", | ||||||
|       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", |       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", | ||||||
|  | @ -16835,6 +17057,55 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.3.tgz", |       "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.3.tgz", | ||||||
|       "integrity": "sha512-hw6bDMjvm+QTvEC+pRLpnTknQXoPu8Fnf+A+zX9HB7j/7RfYajFSbdukabo3adPwvvEHhIMafQl0R0Tpej7clQ==" |       "integrity": "sha512-hw6bDMjvm+QTvEC+pRLpnTknQXoPu8Fnf+A+zX9HB7j/7RfYajFSbdukabo3adPwvvEHhIMafQl0R0Tpej7clQ==" | ||||||
|     }, |     }, | ||||||
|  |     "@types/pg": { | ||||||
|  |       "version": "8.10.9", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.9.tgz", | ||||||
|  |       "integrity": "sha512-UksbANNE/f8w0wOMxVKKIrLCbEMV+oM1uKejmwXr39olg4xqcfBDbXxObJAt6XxHbDa4XTKOlUEcEltXDX+XLQ==", | ||||||
|  |       "requires": { | ||||||
|  |         "@types/node": "*", | ||||||
|  |         "pg-protocol": "*", | ||||||
|  |         "pg-types": "^4.0.1" | ||||||
|  |       }, | ||||||
|  |       "dependencies": { | ||||||
|  |         "pg-types": { | ||||||
|  |           "version": "4.0.1", | ||||||
|  |           "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz", | ||||||
|  |           "integrity": "sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==", | ||||||
|  |           "requires": { | ||||||
|  |             "pg-int8": "1.0.1", | ||||||
|  |             "pg-numeric": "1.0.2", | ||||||
|  |             "postgres-array": "~3.0.1", | ||||||
|  |             "postgres-bytea": "~3.0.0", | ||||||
|  |             "postgres-date": "~2.0.1", | ||||||
|  |             "postgres-interval": "^3.0.0", | ||||||
|  |             "postgres-range": "^1.1.1" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "postgres-array": { | ||||||
|  |           "version": "3.0.2", | ||||||
|  |           "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", | ||||||
|  |           "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==" | ||||||
|  |         }, | ||||||
|  |         "postgres-bytea": { | ||||||
|  |           "version": "3.0.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", | ||||||
|  |           "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", | ||||||
|  |           "requires": { | ||||||
|  |             "obuf": "~1.1.2" | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         "postgres-date": { | ||||||
|  |           "version": "2.0.1", | ||||||
|  |           "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", | ||||||
|  |           "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==" | ||||||
|  |         }, | ||||||
|  |         "postgres-interval": { | ||||||
|  |           "version": "3.0.0", | ||||||
|  |           "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", | ||||||
|  |           "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "@types/prompt-sync": { |     "@types/prompt-sync": { | ||||||
|       "version": "4.2.0", |       "version": "4.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/prompt-sync/-/prompt-sync-4.2.0.tgz", |       "resolved": "https://registry.npmjs.org/@types/prompt-sync/-/prompt-sync-4.2.0.tgz", | ||||||
|  | @ -17608,6 +17879,11 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", |       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", | ||||||
|       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" |       "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" | ||||||
|     }, |     }, | ||||||
|  |     "buffer-writer": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", | ||||||
|  |       "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" | ||||||
|  |     }, | ||||||
|     "bytewise": { |     "bytewise": { | ||||||
|       "version": "1.1.0", |       "version": "1.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", |       "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", | ||||||
|  | @ -20874,6 +21150,11 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", |       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", | ||||||
|       "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" |       "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" | ||||||
|     }, |     }, | ||||||
|  |     "obuf": { | ||||||
|  |       "version": "1.1.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", | ||||||
|  |       "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" | ||||||
|  |     }, | ||||||
|     "once": { |     "once": { | ||||||
|       "version": "1.4.0", |       "version": "1.4.0", | ||||||
|       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", |       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | ||||||
|  | @ -21049,6 +21330,11 @@ | ||||||
|         "p-limit": "^3.0.2" |         "p-limit": "^3.0.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "packet-reader": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", | ||||||
|  |       "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" | ||||||
|  |     }, | ||||||
|     "panzoom": { |     "panzoom": { | ||||||
|       "version": "9.4.3", |       "version": "9.4.3", | ||||||
|       "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz", |       "resolved": "https://registry.npmjs.org/panzoom/-/panzoom-9.4.3.tgz", | ||||||
|  | @ -21134,6 +21420,73 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", |       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", | ||||||
|       "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" |       "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" | ||||||
|     }, |     }, | ||||||
|  |     "pg": { | ||||||
|  |       "version": "8.11.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", | ||||||
|  |       "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", | ||||||
|  |       "requires": { | ||||||
|  |         "buffer-writer": "2.0.0", | ||||||
|  |         "packet-reader": "1.0.0", | ||||||
|  |         "pg-cloudflare": "^1.1.1", | ||||||
|  |         "pg-connection-string": "^2.6.2", | ||||||
|  |         "pg-pool": "^3.6.1", | ||||||
|  |         "pg-protocol": "^1.6.0", | ||||||
|  |         "pg-types": "^2.1.0", | ||||||
|  |         "pgpass": "1.x" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "pg-cloudflare": { | ||||||
|  |       "version": "1.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", | ||||||
|  |       "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", | ||||||
|  |       "optional": true | ||||||
|  |     }, | ||||||
|  |     "pg-connection-string": { | ||||||
|  |       "version": "2.6.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", | ||||||
|  |       "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" | ||||||
|  |     }, | ||||||
|  |     "pg-int8": { | ||||||
|  |       "version": "1.0.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", | ||||||
|  |       "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" | ||||||
|  |     }, | ||||||
|  |     "pg-numeric": { | ||||||
|  |       "version": "1.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", | ||||||
|  |       "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==" | ||||||
|  |     }, | ||||||
|  |     "pg-pool": { | ||||||
|  |       "version": "3.6.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", | ||||||
|  |       "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", | ||||||
|  |       "requires": {} | ||||||
|  |     }, | ||||||
|  |     "pg-protocol": { | ||||||
|  |       "version": "1.6.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", | ||||||
|  |       "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" | ||||||
|  |     }, | ||||||
|  |     "pg-types": { | ||||||
|  |       "version": "2.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", | ||||||
|  |       "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", | ||||||
|  |       "requires": { | ||||||
|  |         "pg-int8": "1.0.1", | ||||||
|  |         "postgres-array": "~2.0.0", | ||||||
|  |         "postgres-bytea": "~1.0.0", | ||||||
|  |         "postgres-date": "~1.0.4", | ||||||
|  |         "postgres-interval": "^1.1.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "pgpass": { | ||||||
|  |       "version": "1.0.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", | ||||||
|  |       "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", | ||||||
|  |       "requires": { | ||||||
|  |         "split2": "^4.1.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "pic4carto": { |     "pic4carto": { | ||||||
|       "version": "2.1.15", |       "version": "2.1.15", | ||||||
|       "resolved": "https://registry.npmjs.org/pic4carto/-/pic4carto-2.1.15.tgz", |       "resolved": "https://registry.npmjs.org/pic4carto/-/pic4carto-2.1.15.tgz", | ||||||
|  | @ -21238,6 +21591,34 @@ | ||||||
|         "util-deprecate": "^1.0.2" |         "util-deprecate": "^1.0.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "postgres-array": { | ||||||
|  |       "version": "2.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", | ||||||
|  |       "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" | ||||||
|  |     }, | ||||||
|  |     "postgres-bytea": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", | ||||||
|  |       "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" | ||||||
|  |     }, | ||||||
|  |     "postgres-date": { | ||||||
|  |       "version": "1.0.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", | ||||||
|  |       "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" | ||||||
|  |     }, | ||||||
|  |     "postgres-interval": { | ||||||
|  |       "version": "1.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", | ||||||
|  |       "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", | ||||||
|  |       "requires": { | ||||||
|  |         "xtend": "^4.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "postgres-range": { | ||||||
|  |       "version": "1.1.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", | ||||||
|  |       "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==" | ||||||
|  |     }, | ||||||
|     "potpack": { |     "potpack": { | ||||||
|       "version": "2.0.0", |       "version": "2.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", |       "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", | ||||||
|  | @ -22195,6 +22576,11 @@ | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "split2": { | ||||||
|  |       "version": "4.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", | ||||||
|  |       "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" | ||||||
|  |     }, | ||||||
|     "sshpk": { |     "sshpk": { | ||||||
|       "version": "1.17.0", |       "version": "1.17.0", | ||||||
|       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", |       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ | ||||||
|       "oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg", |       "oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg", | ||||||
|       "url": "https://www.openstreetmap.org" |       "url": "https://www.openstreetmap.org" | ||||||
|     }, |     }, | ||||||
|  |     "mvt_layer_server": "http://127.0.0.1:7800/public.{layer}/{z}/{x}/{y}.pbf", | ||||||
|     "disabled:oauth_credentials": { |     "disabled:oauth_credentials": { | ||||||
|       "##": "DEV", |       "##": "DEV", | ||||||
|       "#": "This client-id is registered by 'MapComplete' on https://master.apis.dev.openstreetmap.org/", |       "#": "This client-id is registered by 'MapComplete' on https://master.apis.dev.openstreetmap.org/", | ||||||
|  | @ -118,6 +119,7 @@ | ||||||
|     "@turf/length": "^6.5.0", |     "@turf/length": "^6.5.0", | ||||||
|     "@turf/turf": "^6.5.0", |     "@turf/turf": "^6.5.0", | ||||||
|     "@types/dompurify": "^3.0.2", |     "@types/dompurify": "^3.0.2", | ||||||
|  |     "@types/pg": "^8.10.9", | ||||||
|     "@types/qrcode-generator": "^1.0.6", |     "@types/qrcode-generator": "^1.0.6", | ||||||
|     "@types/showdown": "^2.0.0", |     "@types/showdown": "^2.0.0", | ||||||
|     "chart.js": "^3.8.0", |     "chart.js": "^3.8.0", | ||||||
|  | @ -148,6 +150,8 @@ | ||||||
|     "osmtogeojson": "^3.0.0-beta.5", |     "osmtogeojson": "^3.0.0-beta.5", | ||||||
|     "panzoom": "^9.4.3", |     "panzoom": "^9.4.3", | ||||||
|     "papaparse": "^5.3.1", |     "papaparse": "^5.3.1", | ||||||
|  |     "pbf": "^3.2.1", | ||||||
|  |     "pg": "^8.11.3", | ||||||
|     "pic4carto": "^2.1.15", |     "pic4carto": "^2.1.15", | ||||||
|     "prompt-sync": "^4.2.0", |     "prompt-sync": "^4.2.0", | ||||||
|     "qrcode-generator": "^1.4.4", |     "qrcode-generator": "^1.4.4", | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ import { AllSharedLayers } from "../../src/Customizations/AllSharedLayers" | ||||||
| import fs from "fs" | import fs from "fs" | ||||||
| import { Or } from "../../src/Logic/Tags/Or" | import { Or } from "../../src/Logic/Tags/Or" | ||||||
| import { RegexTag } from "../../src/Logic/Tags/RegexTag" | import { RegexTag } from "../../src/Logic/Tags/RegexTag" | ||||||
|  | import { Utils } from "../../src/Utils" | ||||||
| 
 | 
 | ||||||
| class LuaSnippets{ | class LuaSnippets{ | ||||||
|     /** |     /** | ||||||
|  | @ -40,18 +41,24 @@ class GenerateLayerLua { | ||||||
|     } |     } | ||||||
|     public functionName(){ |     public functionName(){ | ||||||
|         const l = this._layer |         const l = this._layer | ||||||
|  |         if(!l.source?.osmTags){ | ||||||
|  |             return undefined | ||||||
|  |         } | ||||||
|         return `process_poi_${l.id}` |         return `process_poi_${l.id}` | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public generateFunction(): string { |     public generateFunction(): string { | ||||||
|         const l = this._layer |         const l = this._layer | ||||||
|  |         if(!l.source?.osmTags){ | ||||||
|  |             return undefined | ||||||
|  |         } | ||||||
|         return [ |         return [ | ||||||
|             `local pois_${l.id} = osm2pgsql.define_table({`, |             `local pois_${l.id} = osm2pgsql.define_table({`, | ||||||
|             `  name = '${l.id}',`, |             `  name = '${l.id}',`, | ||||||
|             "  ids = { type = 'any', type_column = 'osm_type', id_column = 'osm_id' },", |             "  ids = { type = 'any', type_column = 'osm_type', id_column = 'osm_id' },", | ||||||
|             "  columns = {", |             "  columns = {", | ||||||
|             "    { column = 'tags', type = 'jsonb' },", |             "    { column = 'tags', type = 'jsonb' },", | ||||||
|             "    { column = 'geom', type = 'point', not_null = true },", |             "    { column = 'geom', type = 'point', projection = 4326, not_null = true },", | ||||||
|             "  }" + |             "  }" + | ||||||
|             "})", |             "})", | ||||||
|             "", |             "", | ||||||
|  | @ -117,14 +124,13 @@ class GenerateLayerFile extends Script { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async main(args: string[]) { |     async main(args: string[]) { | ||||||
|         let dw = AllSharedLayers.sharedLayers.get("drinking_water") |         const layerNames = Array.from(AllSharedLayers.sharedLayers.values()) | ||||||
|         let t = AllSharedLayers.sharedLayers.get("toilet") |  | ||||||
| 
 | 
 | ||||||
|         const generators = [dw, t].map(l => new GenerateLayerLua(l)) |         const generators = layerNames.map(l => new GenerateLayerLua(l)) | ||||||
| 
 | 
 | ||||||
|         const script = [ |         const script = [ | ||||||
|             ...generators.map(g => g.generateFunction()), |             ...generators.map(g => g.generateFunction()), | ||||||
|             LuaSnippets.combine(generators.map(g => g.functionName())), |             LuaSnippets.combine(Utils.NoNull(generators.map(g => g.functionName()))), | ||||||
|             LuaSnippets.tail |             LuaSnippets.tail | ||||||
|         ].join("\n\n\n") |         ].join("\n\n\n") | ||||||
|         const path = "build_db.lua" |         const path = "build_db.lua" | ||||||
|  |  | ||||||
							
								
								
									
										44
									
								
								scripts/osm2pgsql/tilecountServer.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								scripts/osm2pgsql/tilecountServer.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | ||||||
|  | import { BBox } from "../../src/Logic/BBox" | ||||||
|  | import { Client } from "pg" | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Connects with a Postgis database, gives back how much items there are within the given BBOX | ||||||
|  |  */ | ||||||
|  | export default class TilecountServer { | ||||||
|  |     private readonly _client: Client | ||||||
|  |     private isConnected = false | ||||||
|  | 
 | ||||||
|  |     constructor(connectionString: string) { | ||||||
|  |         this._client = new Client(connectionString) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async getCount(layer: string, bbox: BBox = undefined): Promise<number> { | ||||||
|  |         if (!this.isConnected) { | ||||||
|  |             await this._client.connect() | ||||||
|  |             this.isConnected = true | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let query = "SELECT COUNT(*) FROM " + layer | ||||||
|  | 
 | ||||||
|  |         if(bbox){ | ||||||
|  |             query += ` WHERE ST_MakeEnvelope (${bbox.minLon}, ${bbox.minLat}, ${bbox.maxLon}, ${bbox.maxLat}, 4326) ~ geom` | ||||||
|  |         } | ||||||
|  | console.log(query) | ||||||
|  |         const result = await this._client.query(query) | ||||||
|  |         return result.rows[0].count | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     disconnect() { | ||||||
|  |         this._client.end() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const tcs = new TilecountServer("postgresql://user:none@localhost:5444/osm-poi") | ||||||
|  | console.log(">>>", await tcs.getCount("drinking_water", new BBox([ | ||||||
|  |     [1.5052013991654007, | ||||||
|  |         42.57480750272123, | ||||||
|  |     ], [ | ||||||
|  |         1.6663677350703097, | ||||||
|  |         42.499856652770745, | ||||||
|  |     ]]))) | ||||||
|  | tcs.disconnect() | ||||||
|  | @ -11,6 +11,9 @@ import DynamicGeoJsonTileSource from "../TiledFeatureSource/DynamicGeoJsonTileSo | ||||||
| import { BBox } from "../../BBox" | import { BBox } from "../../BBox" | ||||||
| import LocalStorageFeatureSource from "../TiledFeatureSource/LocalStorageFeatureSource" | import LocalStorageFeatureSource from "../TiledFeatureSource/LocalStorageFeatureSource" | ||||||
| import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource" | import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource" | ||||||
|  | import { Features } from "@rgossiaux/svelte-headlessui/types" | ||||||
|  | import DynamicMvtileSource from "../TiledFeatureSource/DynamicMvtTileSource" | ||||||
|  | import { layouts } from "chart.js" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * This source will fetch the needed data from various sources for the given layout. |  * This source will fetch the needed data from various sources for the given layout. | ||||||
|  | @ -44,14 +47,18 @@ export default class LayoutSource extends FeatureSourceMerger { | ||||||
|                     maxAge: l.maxAgeOfCache, |                     maxAge: l.maxAgeOfCache, | ||||||
|                 }) |                 }) | ||||||
|         ) |         ) | ||||||
|  |         console.log(mapProperties) | ||||||
|  |         const mvtSources: FeatureSource[] = osmLayers.map(l => LayoutSource.setupMvtSource(l, mapProperties, isDisplayed(l.id))) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |         /* | ||||||
|         const overpassSource = LayoutSource.setupOverpass( |         const overpassSource = LayoutSource.setupOverpass( | ||||||
|             backend, |             backend, | ||||||
|             osmLayers, |             osmLayers, | ||||||
|             bounds, |             bounds, | ||||||
|             zoom, |             zoom, | ||||||
|             featureSwitches |             featureSwitches | ||||||
|         ) |         )//*/
 | ||||||
| 
 | 
 | ||||||
|         const osmApiSource = LayoutSource.setupOsmApiSource( |         const osmApiSource = LayoutSource.setupOsmApiSource( | ||||||
|             osmLayers, |             osmLayers, | ||||||
|  | @ -61,22 +68,27 @@ export default class LayoutSource extends FeatureSourceMerger { | ||||||
|             featureSwitches, |             featureSwitches, | ||||||
|             fullNodeDatabaseSource |             fullNodeDatabaseSource | ||||||
|         ) |         ) | ||||||
|  | 
 | ||||||
|         const geojsonSources: FeatureSource[] = geojsonlayers.map((l) => |         const geojsonSources: FeatureSource[] = geojsonlayers.map((l) => | ||||||
|             LayoutSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)) |             LayoutSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         super(overpassSource, osmApiSource, ...geojsonSources, ...fromCache) | 
 | ||||||
|  |         super(osmApiSource, ...geojsonSources, ...fromCache, ...mvtSources) | ||||||
| 
 | 
 | ||||||
|         const self = this |         const self = this | ||||||
|         function setIsLoading() { |         function setIsLoading() { | ||||||
|             const loading = overpassSource?.runningQuery?.data || osmApiSource?.isRunning?.data |            // const loading = overpassSource?.runningQuery?.data || osmApiSource?.isRunning?.data
 | ||||||
|             self._isLoading.setData(loading) |            // self._isLoading.setData(loading)
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         overpassSource?.runningQuery?.addCallbackAndRun((_) => setIsLoading()) |         // overpassSource?.runningQuery?.addCallbackAndRun((_) => setIsLoading())
 | ||||||
|         osmApiSource?.isRunning?.addCallbackAndRun((_) => setIsLoading()) |         osmApiSource?.isRunning?.addCallbackAndRun((_) => setIsLoading()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private static setupMvtSource(layer: LayerConfig, mapProperties:  { zoom: Store<number>; bounds: Store<BBox> },    isActive?: Store<boolean>): FeatureSource{ | ||||||
|  |         return new DynamicMvtileSource(layer, mapProperties, { isActive }) | ||||||
|  |     } | ||||||
|     private static setupGeojsonSource( |     private static setupGeojsonSource( | ||||||
|         layer: LayerConfig, |         layer: LayerConfig, | ||||||
|         mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, |         mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, | ||||||
|  |  | ||||||
							
								
								
									
										378
									
								
								src/Logic/FeatureSource/Sources/MvtSource.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								src/Logic/FeatureSource/Sources/MvtSource.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,378 @@ | ||||||
|  | import { Feature, Geometry } from "geojson" | ||||||
|  | import { Store, UIEventSource } from "../../UIEventSource" | ||||||
|  | import { FeatureSource } from "../FeatureSource" | ||||||
|  | import Pbf from "pbf" | ||||||
|  | import * as pbfCompile from "pbf/compile" | ||||||
|  | import * as PbfSchema from "protocol-buffers-schema" | ||||||
|  | 
 | ||||||
|  | type Coords = [number, number][] | ||||||
|  | 
 | ||||||
|  | class MvtFeatureBuilder { | ||||||
|  |     private static readonly geom_types = ["Unknown", "Point", "LineString", "Polygon"] as const | ||||||
|  |     private readonly _size: number | ||||||
|  |     private readonly _x0: number | ||||||
|  |     private readonly _y0: number | ||||||
|  | 
 | ||||||
|  |     constructor(extent: number, x: number, y: number, z: number) { | ||||||
|  |         this._size = extent * Math.pow(2, z) | ||||||
|  |         this._x0 = extent * x | ||||||
|  |         this._y0 = extent * y | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public toGeoJson(geometry, typeIndex, properties): Feature { | ||||||
|  |         let coords: [number, number] | Coords | Coords[] = this.encodeGeometry(geometry) | ||||||
|  |         switch (typeIndex) { | ||||||
|  |             case 1: | ||||||
|  |                 const points = [] | ||||||
|  |                 for (let i = 0; i < coords.length; i++) { | ||||||
|  |                     points[i] = coords[i][0] | ||||||
|  |                 } | ||||||
|  |                 coords = points | ||||||
|  |                 this.project(<any>coords) | ||||||
|  |                 break | ||||||
|  | 
 | ||||||
|  |             case 2: | ||||||
|  |                 for (let i = 0; i < coords.length; i++) { | ||||||
|  |                     this.project(coords[i]) | ||||||
|  |                 } | ||||||
|  |                 break | ||||||
|  | 
 | ||||||
|  |             case 3: | ||||||
|  |                 let classified = this.classifyRings(coords) | ||||||
|  |                 for (let i = 0; i < coords.length; i++) { | ||||||
|  |                     for (let j = 0; j < coords[i].length; j++) { | ||||||
|  |                         this.project(classified[i][j]) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 break | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let type: string = MvtFeatureBuilder.geom_types[typeIndex] | ||||||
|  |         if (coords.length === 1) { | ||||||
|  |             coords = coords[0] | ||||||
|  |         } else { | ||||||
|  |             type = "Multi" + type | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return { | ||||||
|  |             type: "Feature", | ||||||
|  |             geometry: { | ||||||
|  |                 type: <any>type, | ||||||
|  |                 coordinates: <any>coords, | ||||||
|  |             }, | ||||||
|  |             properties, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private encodeGeometry(geometry: number[]) { | ||||||
|  |         let cX = 0 | ||||||
|  |         let cY = 0 | ||||||
|  |         let coordss: Coords[] = [] | ||||||
|  |         let currentRing: Coords = [] | ||||||
|  |         for (let i = 0; i < geometry.length; i++) { | ||||||
|  |             let commandInteger = geometry[i] | ||||||
|  |             let commandId = commandInteger & 0x7 | ||||||
|  |             let commandCount = commandInteger >> 3 | ||||||
|  |             /* | ||||||
|  |             Command 	Id 	Parameters 	Parameter Count | ||||||
|  |                         MoveTo 	1 	dX, dY 	2 | ||||||
|  |                         LineTo 	2 	dX, dY 	2 | ||||||
|  |                         ClosePath 	7 	No parameters 	0 | ||||||
|  |             */ | ||||||
|  |             if (commandId === 1) { | ||||||
|  |                 // MoveTo means: we start a new ring
 | ||||||
|  |                 if (currentRing.length !== 0) { | ||||||
|  |                     coordss.push(currentRing) | ||||||
|  |                     currentRing = [] | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (commandId === 1 || commandId === 2){ | ||||||
|  |                 for (let j = 0; j < commandCount; j++) { | ||||||
|  |                     const dx = geometry[i + j * 2 + 1] | ||||||
|  |                     cX += ((dx >> 1) ^ (-(dx & 1))) | ||||||
|  |                     const dy = geometry[i + j * 2 + 2] | ||||||
|  |                     cY += ((dy >> 1) ^ (-(dy & 1))) | ||||||
|  |                     currentRing.push([cX, cY]) | ||||||
|  |                 } | ||||||
|  |                 i = commandCount * 2 | ||||||
|  |             } | ||||||
|  |             if(commandId === 7){ | ||||||
|  |                 currentRing.push([...currentRing[0]]) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |         if (currentRing.length > 0) { | ||||||
|  |             coordss.push(currentRing) | ||||||
|  |         } | ||||||
|  |         return coordss | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private signedArea(ring: Coords): number { | ||||||
|  |         let sum = 0 | ||||||
|  |         const len = ring.length | ||||||
|  |         // J is basically (i - 1) % len
 | ||||||
|  |         let j = len - 1 | ||||||
|  |         let p1 | ||||||
|  |         let p2 | ||||||
|  |         for (let i = 0; i < len; i++) { | ||||||
|  |             p1 = ring[i] | ||||||
|  |             p2 = ring[j] | ||||||
|  |             sum += (p2.x - p1.x) * (p1.y + p2.y) | ||||||
|  |             j = i | ||||||
|  |         } | ||||||
|  |         return sum | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private classifyRings(rings: Coords[]): Coords[][] { | ||||||
|  |         const len = rings.length | ||||||
|  | 
 | ||||||
|  |         if (len <= 1) return [rings] | ||||||
|  | 
 | ||||||
|  |         const polygons = [] | ||||||
|  |         let polygon | ||||||
|  |         // CounterClockWise
 | ||||||
|  |         let ccw: boolean | ||||||
|  | 
 | ||||||
|  |         for (let i = 0; i < len; i++) { | ||||||
|  |             const area = this.signedArea(rings[i]) | ||||||
|  |             if (area === 0) continue | ||||||
|  | 
 | ||||||
|  |             if (ccw === undefined) { | ||||||
|  |                 ccw = area < 0 | ||||||
|  |             } | ||||||
|  |             if (ccw === (area < 0)) { | ||||||
|  |                 if (polygon) { | ||||||
|  |                     polygons.push(polygon) | ||||||
|  |                 } | ||||||
|  |                 polygon = [rings[i]] | ||||||
|  | 
 | ||||||
|  |             } else { | ||||||
|  |                 polygon.push(rings[i]) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (polygon) { | ||||||
|  |             polygons.push(polygon) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return polygons | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Inline replacement of the location by projecting | ||||||
|  |      * @param line | ||||||
|  |      * @private | ||||||
|  |      */ | ||||||
|  |     private project(line: [number, number][]) { | ||||||
|  |         const y0 = this._y0 | ||||||
|  |         const x0 = this._x0 | ||||||
|  |         const size = this._size | ||||||
|  |         for (let i = 0; i < line.length; i++) { | ||||||
|  |             let p = line[i] | ||||||
|  |             let y2 = 180 - (p[1] + y0) * 360 / size | ||||||
|  |             line[i] = [ | ||||||
|  |                 (p[0] + x0) * 360 / size - 180, | ||||||
|  |                 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90, | ||||||
|  |             ] | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export default class MvtSource implements FeatureSource { | ||||||
|  | 
 | ||||||
|  |     private static readonly schemaSpec = ` | ||||||
|  |     package vector_tile; | ||||||
|  | 
 | ||||||
|  | option optimize_for = LITE_RUNTIME; | ||||||
|  | 
 | ||||||
|  | message Tile { | ||||||
|  | 
 | ||||||
|  |         // GeomType is described in section 4.3.4 of the specification
 | ||||||
|  |         enum GeomType { | ||||||
|  |              UNKNOWN = 0; | ||||||
|  |              POINT = 1; | ||||||
|  |              LINESTRING = 2; | ||||||
|  |              POLYGON = 3; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Variant type encoding
 | ||||||
|  |         // The use of values is described in section 4.1 of the specification
 | ||||||
|  |         message Value { | ||||||
|  |                 // Exactly one of these values must be present in a valid message
 | ||||||
|  |                 optional string string_value = 1; | ||||||
|  |                 optional float float_value = 2; | ||||||
|  |                 optional double double_value = 3; | ||||||
|  |                 optional int64 int_value = 4; | ||||||
|  |                 optional uint64 uint_value = 5; | ||||||
|  |                 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(PbfSchema.parse(MvtSource.schemaSpec)).Tile | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     private readonly _url: string | ||||||
|  |     private readonly _layerName: string | ||||||
|  |     private readonly _features: UIEventSource<Feature<Geometry, { | ||||||
|  |         [name: string]: any | ||||||
|  |     }>[]> = new UIEventSource<Feature<Geometry, { [p: string]: any }>[]>([]) | ||||||
|  |     public readonly features: Store<Feature<Geometry, { [name: string]: any }>[]> = this._features | ||||||
|  |     private readonly x: number | ||||||
|  |     private readonly y: number | ||||||
|  |     private readonly z: number | ||||||
|  | 
 | ||||||
|  |     constructor(url: string, x: number, y: number, z: number, layerName?: string) { | ||||||
|  |         this._url = url | ||||||
|  |         this._layerName = layerName | ||||||
|  |         this.x = x | ||||||
|  |         this.y = y | ||||||
|  |         this.z = z | ||||||
|  |         this.downloadSync() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private getValue(v: { | ||||||
|  |         // Exactly one of these values must be present in a valid message
 | ||||||
|  |         string_value?: string, | ||||||
|  |         float_value?: number, | ||||||
|  |         double_value?: number, | ||||||
|  |         int_value?: number, | ||||||
|  |         uint_value?: number, | ||||||
|  |         sint_value?: number, | ||||||
|  |         bool_value?: boolean | ||||||
|  |     }): string | number | undefined | boolean { | ||||||
|  |         if (v.string_value !== "") { | ||||||
|  |             return v.string_value | ||||||
|  |         } | ||||||
|  |         if (v.double_value !== 0) { | ||||||
|  |             return v.double_value | ||||||
|  |         } | ||||||
|  |         if (v.float_value !== 0) { | ||||||
|  |             return v.float_value | ||||||
|  |         } | ||||||
|  |         if (v.int_value !== 0) { | ||||||
|  |             return v.int_value | ||||||
|  |         } | ||||||
|  |         if (v.uint_value !== 0) { | ||||||
|  |             return v.uint_value | ||||||
|  |         } | ||||||
|  |         if (v.sint_value !== 0) { | ||||||
|  |             return v.sint_value | ||||||
|  |         } | ||||||
|  |         if (v.bool_value !== false) { | ||||||
|  |             return v.bool_value | ||||||
|  |         } | ||||||
|  |         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<Feature[]> { | ||||||
|  |         const result = await fetch(this._url) | ||||||
|  |         const buffer = await result.arrayBuffer() | ||||||
|  |         const data = MvtSource.tile_schema.read(new Pbf(buffer)) | ||||||
|  |         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: Feature[] = [] | ||||||
|  | 
 | ||||||
|  |         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)) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return features | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     private inflateProperties(tags: number[], keys: string[], values: { string_value: string }[]) { | ||||||
|  |         const properties = {} | ||||||
|  |         for (let i = 0; i < tags.length; i += 2) { | ||||||
|  |             properties[keys[tags[i]]] = this.getValue(values[tags[i + 1]]) | ||||||
|  |         } | ||||||
|  |         let type: string | ||||||
|  |         switch (properties["osm_type"]) { | ||||||
|  |             case "N": | ||||||
|  |                 type = "node" | ||||||
|  |                 break | ||||||
|  |             case "W": | ||||||
|  |                 type = "way" | ||||||
|  |                 break | ||||||
|  |             case "R": | ||||||
|  |                 type = "relation" | ||||||
|  |                 break | ||||||
|  |         } | ||||||
|  |         properties["id"] = type + "/" + properties["osm_id"] | ||||||
|  |         delete properties["osm_id"] | ||||||
|  |         delete properties["osm_type"] | ||||||
|  | 
 | ||||||
|  |         return properties | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,39 @@ | ||||||
|  | import { Store } from "../../UIEventSource" | ||||||
|  | import DynamicTileSource from "./DynamicTileSource" | ||||||
|  | import { Utils } from "../../../Utils" | ||||||
|  | import { BBox } from "../../BBox" | ||||||
|  | import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" | ||||||
|  | import MvtSource from "../Sources/MvtSource" | ||||||
|  | import { Tiles } from "../../../Models/TileRange" | ||||||
|  | import Constants from "../../../Models/Constants" | ||||||
|  | 
 | ||||||
|  | export default class DynamicMvtileSource extends DynamicTileSource { | ||||||
|  | 
 | ||||||
|  |     constructor( | ||||||
|  |         layer: LayerConfig, | ||||||
|  |         mapProperties: { | ||||||
|  |             zoom: Store<number> | ||||||
|  |             bounds: Store<BBox> | ||||||
|  |         }, | ||||||
|  |         options?: { | ||||||
|  |             isActive?: Store<boolean> | ||||||
|  |         }, | ||||||
|  |     ) { | ||||||
|  |         super( | ||||||
|  |             mapProperties.zoom, | ||||||
|  |             layer.minzoom, | ||||||
|  |             (zxy) => { | ||||||
|  |                 const [z, x, y] = Tiles.tile_from_index(zxy) | ||||||
|  |                 const url = Utils.SubstituteKeys(Constants.VectorTileServer, | ||||||
|  |                     { | ||||||
|  |                         z, x, y, layer: layer.id, | ||||||
|  |                     }) | ||||||
|  |                 return new MvtSource(url, x, y, z) | ||||||
|  |             }, | ||||||
|  |             mapProperties, | ||||||
|  |             { | ||||||
|  |                 isActive: options?.isActive, | ||||||
|  |             }, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -10,9 +10,9 @@ import FeatureSourceMerger from "../Sources/FeatureSourceMerger" | ||||||
|  */ |  */ | ||||||
| export default class DynamicTileSource extends FeatureSourceMerger { | export default class DynamicTileSource extends FeatureSourceMerger { | ||||||
|     constructor( |     constructor( | ||||||
|         zoomlevel: number, |         zoomlevel: Store<number>, | ||||||
|         minzoom: number, |         minzoom: number, | ||||||
|         constructSource: (tileIndex) => FeatureSource, |         constructSource: (tileIndex: number) => FeatureSource, | ||||||
|         mapProperties: { |         mapProperties: { | ||||||
|             bounds: Store<BBox> |             bounds: Store<BBox> | ||||||
|             zoom: Store<number> |             zoom: Store<number> | ||||||
|  | @ -34,8 +34,9 @@ export default class DynamicTileSource extends FeatureSourceMerger { | ||||||
|                         if (mapProperties.zoom.data < minzoom) { |                         if (mapProperties.zoom.data < minzoom) { | ||||||
|                             return undefined |                             return undefined | ||||||
|                         } |                         } | ||||||
|  |                         const z = Math.round(zoomlevel.data) | ||||||
|                         const tileRange = Tiles.TileRangeBetween( |                         const tileRange = Tiles.TileRangeBetween( | ||||||
|                             zoomlevel, |                             z, | ||||||
|                             bounds.getNorth(), |                             bounds.getNorth(), | ||||||
|                             bounds.getEast(), |                             bounds.getEast(), | ||||||
|                             bounds.getSouth(), |                             bounds.getSouth(), | ||||||
|  | @ -49,7 +50,7 @@ export default class DynamicTileSource extends FeatureSourceMerger { | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         const needed = Tiles.MapRange(tileRange, (x, y) => |                         const needed = Tiles.MapRange(tileRange, (x, y) => | ||||||
|                             Tiles.tile_index(zoomlevel, x, y) |                             Tiles.tile_index(z, x, y) | ||||||
|                         ).filter((i) => !loadedTiles.has(i)) |                         ).filter((i) => !loadedTiles.has(i)) | ||||||
|                         if (needed.length === 0) { |                         if (needed.length === 0) { | ||||||
|                             return undefined |                             return undefined | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import DynamicTileSource from "./DynamicTileSource" | import DynamicTileSource from "./DynamicTileSource" | ||||||
| import { Store } from "../../UIEventSource" | import { ImmutableStore, Store } from "../../UIEventSource" | ||||||
| import { BBox } from "../../BBox" | import { BBox } from "../../BBox" | ||||||
| import TileLocalStorage from "../Actors/TileLocalStorage" | import TileLocalStorage from "../Actors/TileLocalStorage" | ||||||
| import { Feature } from "geojson" | import { Feature } from "geojson" | ||||||
|  | @ -27,7 +27,7 @@ export default class LocalStorageFeatureSource extends DynamicTileSource { | ||||||
|             options?.maxAge ?? 24 * 60 * 60 |             options?.maxAge ?? 24 * 60 * 60 | ||||||
|         ) |         ) | ||||||
|         super( |         super( | ||||||
|             zoomlevel, |            new ImmutableStore(zoomlevel), | ||||||
|             layer.minzoom, |             layer.minzoom, | ||||||
|             (tileIndex) => |             (tileIndex) => | ||||||
|                 new StaticFeatureSource( |                 new StaticFeatureSource( | ||||||
|  |  | ||||||
|  | @ -154,6 +154,11 @@ export default class Constants { | ||||||
| 
 | 
 | ||||||
|     ] as const |     ] as const | ||||||
|     public static readonly defaultPinIcons: string[] = <any>Constants._defaultPinIcons |     public static readonly defaultPinIcons: string[] = <any>Constants._defaultPinIcons | ||||||
|  |     /** | ||||||
|  |      * The location that the MVT-layer is hosted. | ||||||
|  |      * This is a MapLibre/MapBox vector tile server which hosts vector tiles for every (official) layer | ||||||
|  |      */ | ||||||
|  |     public static VectorTileServer: string | undefined = Constants.config.mvt_layer_server | ||||||
| 
 | 
 | ||||||
|     private static isRetina(): boolean { |     private static isRetina(): boolean { | ||||||
|         if (Utils.runningFromConsole) { |         if (Utils.runningFromConsole) { | ||||||
|  |  | ||||||
|  | @ -178,7 +178,6 @@ class AddDefaultLayers extends DesugaringStep<LayoutConfigJson> { | ||||||
|             if (v === undefined) { |             if (v === undefined) { | ||||||
|                 const msg = `Default layer ${layerName} not found. ${state.sharedLayers.size} layers are available` |                 const msg = `Default layer ${layerName} not found. ${state.sharedLayers.size} layers are available` | ||||||
|                 if (layerName === "favourite") { |                 if (layerName === "favourite") { | ||||||
|                     context.warn(msg) |  | ||||||
|                     continue |                     continue | ||||||
|                 } |                 } | ||||||
|                 context.err(msg) |                 context.err(msg) | ||||||
|  |  | ||||||
|  | @ -303,6 +303,7 @@ class LineRenderingLayer { | ||||||
|                         type: "FeatureCollection", |                         type: "FeatureCollection", | ||||||
|                         features, |                         features, | ||||||
|                     }, |                     }, | ||||||
|  |                     cluster: true, | ||||||
|                     promoteId: "id", |                     promoteId: "id", | ||||||
|                 }) |                 }) | ||||||
|                 const linelayer = this._layername + "_line" |                 const linelayer = this._layername + "_line" | ||||||
|  |  | ||||||
|  | @ -1,70 +1,122 @@ | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
|   // Testing grounds |     // Testing grounds | ||||||
|   import { UIEventSource } from "../Logic/UIEventSource" |     import { UIEventSource } from "../Logic/UIEventSource" | ||||||
|   import MaplibreMap from "./Map/MaplibreMap.svelte" |     import MaplibreMap from "./Map/MaplibreMap.svelte" | ||||||
|   import { Map as MlMap } from "maplibre-gl" |     import { Map as MlMap } from "maplibre-gl" | ||||||
|   import { MapLibreAdaptor } from "./Map/MapLibreAdaptor" |     import { MapLibreAdaptor } from "./Map/MapLibreAdaptor" | ||||||
|  |     import Constants from "../Models/Constants" | ||||||
|  |     import toilet from "../assets/generated/layers/toilet.json" | ||||||
|  |     import LayerConfig from "../Models/ThemeConfig/LayerConfig" | ||||||
|  |     import DynamicMvtileSource from "../Logic/FeatureSource/TiledFeatureSource/DynamicMvtTileSource" | ||||||
|  |     import ShowDataLayer from "./Map/ShowDataLayer" | ||||||
| 
 | 
 | ||||||
|   let map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined) |     const tl = new LayerConfig(<any>toilet) | ||||||
|   let adaptor = new MapLibreAdaptor(map) |  | ||||||
|   adaptor.location.setData({ |  | ||||||
|     lat: 42.5404, |  | ||||||
|     lon:1.4832 |  | ||||||
| 
 | 
 | ||||||
|   }) |  | ||||||
|   adaptor.zoom.setData(10) |  | ||||||
|   map.addCallbackAndRunD(map => { |  | ||||||
|     map.on("load", () => { |  | ||||||
| 
 | 
 | ||||||
|       map.addSource("drinking_water", { |     let map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined) | ||||||
|         "type": "vector", |     let adaptor = new MapLibreAdaptor(map) | ||||||
|         "tiles": ["http://127.0.0.2:7800/public.drinking_water/{z}/{x}/{y}.pbf"] // http://127.0.0.2:7800/public.drinking_water.json", |  | ||||||
|       }) |  | ||||||
| 
 | 
 | ||||||
|       map.addLayer( |     const src = new DynamicMvtileSource(tl, adaptor) | ||||||
|         { |     src.features.addCallbackAndRun(f => console.log(">>> Features are", f)) | ||||||
|           "id": "drinking_water_layer", |     new ShowDataLayer(map, { | ||||||
|           "type": "circle", |         layer: tl, | ||||||
|           "source": "drinking_water", |         features: src | ||||||
|           "source-layer": "public.drinking_water", |     }) | ||||||
|           "paint": { | 
 | ||||||
|             "circle-radius": 5, |     adaptor.location.setData({ | ||||||
|             "circle-color": "#ff00ff", |         lat: 51.2095, lon: 3.2260, | ||||||
|             "circle-stroke-width": 2, |     }) | ||||||
|             "circle-stroke-color": "#000000", |     adaptor.zoom.setData(13) | ||||||
|           }, |     const loadedIcons = new Set<string>() | ||||||
|         }, | 
 | ||||||
|       ) |     async function loadImage(map: MlMap, url: string, name: string): Promise<void> { | ||||||
| 
 |         return new Promise((resolve, reject) => { | ||||||
|         map.addSource("toilet", { |             if (loadedIcons.has(name)) { | ||||||
|             "type": "vector", |                 return new Promise<void>((resolve, reject) => resolve()) | ||||||
|             "tiles": ["http://127.0.0.2:7800/public.toilet/{z}/{x}/{y}.pbf"] // http://127.0.0.2:7800/public.drinking_water.json", |             } | ||||||
|         }) |             loadedIcons.add(name) | ||||||
| 
 |             if (Constants.defaultPinIcons.indexOf(url) >= 0) { | ||||||
|         map.addLayer( |                 url = "./assets/svg/" + url + ".svg" | ||||||
|             { |             } | ||||||
|                 "id": "toilet_layer", |             map.loadImage( | ||||||
|                 "type": "circle", |                 url, | ||||||
|                 "source": "toilet", |                 (error, image) => { | ||||||
|                 "source-layer": "public.toilet", |                     if (error) { | ||||||
|                 "paint": { |                         reject(error) | ||||||
|                     "circle-radius": 5, |                     } | ||||||
|                     "circle-color": "#0000ff", |                     map.addImage(name, image) | ||||||
|                     "circle-stroke-width": 2, |                     resolve() | ||||||
|                     "circle-stroke-color": "#000000", |                 }) | ||||||
|                 }, |         }) | ||||||
|             }, |     } | ||||||
|         ) | 
 | ||||||
| 
 |     map.addCallbackAndRunD(map => { | ||||||
|       map.on('click', 'drinking_water_layer', (e) => { |         map.on("load", async () => { | ||||||
| // Copy coordinates array. |             console.log("Onload") | ||||||
|         console.log(e) |             await loadImage(map, "https://upload.wikimedia.org/wikipedia/commons/7/7c/201408_cat.png", "cat") | ||||||
| console.warn(">>>", e.features[0]) | 
 | ||||||
|       }) |             /* | ||||||
|  |             map.addSource("drinking_water", { | ||||||
|  |                 "type": "vector", | ||||||
|  |                 "tiles": ["http://127.0.0.2:7800/public.drinking_water/{z}/{x}/{y}.pbf"], // http://127.0.0.2:7800/public.drinking_water.json", | ||||||
|  |             }) | ||||||
|  | 
 | ||||||
|  |             map.addLayer( | ||||||
|  |                 { | ||||||
|  |                     "id": "drinking_water_layer", | ||||||
|  |                     "type": "circle", | ||||||
|  |                     "source": "drinking_water", | ||||||
|  |                     "source-layer": "public.drinking_water", | ||||||
|  |                     "paint": { | ||||||
|  |                         "circle-radius": 5, | ||||||
|  |                         "circle-color": "#ff00ff", | ||||||
|  |                         "circle-stroke-width": 2, | ||||||
|  |                         "circle-stroke-color": "#000000", | ||||||
|  |                     }, | ||||||
|  |                 }, | ||||||
|  |             )*/ | ||||||
|  |             /* | ||||||
|  |                         map.addSource("toilet", { | ||||||
|  |                             "type": "vector", | ||||||
|  |                             "tiles": ["http://127.0.0.2:7800/public.toilet/{z}/{x}/{y}.pbf"], // http://127.0.0.2:7800/public.drinking_water.json", | ||||||
|  |                         }) | ||||||
|  |              | ||||||
|  |                         map.addLayer( | ||||||
|  |                             { | ||||||
|  |                                 "id": "toilet_layer", | ||||||
|  |                                 "type": "circle", | ||||||
|  |                                 "source": "toilet", | ||||||
|  |                                 "source-layer": "public.toilet", | ||||||
|  |                                 "paint": { | ||||||
|  |                                     "circle-radius": 5, | ||||||
|  |                                     "circle-color": "#0000ff", | ||||||
|  |                                     "circle-stroke-width": 2, | ||||||
|  |                                     "circle-stroke-color": "#000000", | ||||||
|  |                                 }, | ||||||
|  |                             }, | ||||||
|  |                         ) | ||||||
|  |                         map.addLayer({ | ||||||
|  |                             "id": "points", | ||||||
|  |                             "type": "symbol", | ||||||
|  |                             "source": "toilet", | ||||||
|  |                             "source-layer": "public.toilet", | ||||||
|  |                             "layout": { | ||||||
|  |                                 "icon-overlap": "always", | ||||||
|  |                                 "icon-image": "cat", | ||||||
|  |                                 "icon-size": 0.05, | ||||||
|  |                             }, | ||||||
|  |                         })*/ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             map.on("click", "drinking_water_layer", (e) => { | ||||||
|  | // Copy coordinates array. | ||||||
|  |                 console.log(e) | ||||||
|  |                 console.warn(">>>", e.features[0]) | ||||||
|  |             }) | ||||||
|  |         }) | ||||||
|     }) |     }) | ||||||
|   }) |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div class="h-screen w-screen"> | <div class="h-screen w-screen"> | ||||||
| <MaplibreMap {map} /> |   <MaplibreMap {map} /> | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue