forked from MapComplete/MapComplete
Merge branch 'develop'
This commit is contained in:
commit
cf3ca610b0
41 changed files with 334 additions and 195 deletions
14
Docs/ServerConfig/cache/Caddyfile
vendored
14
Docs/ServerConfig/cache/Caddyfile
vendored
|
@ -1,14 +1,4 @@
|
||||||
cache.mapcomplete.org {
|
cache.mapcomplete.org {
|
||||||
reverse_proxy /summary/* {
|
reverse_proxy /summary/* 127.0.0.1:2345
|
||||||
to http://127.0.0.1:2345
|
reverse_proxy /* 127.0.0.1:7800
|
||||||
}
|
|
||||||
|
|
||||||
reverse_proxy /extractgraph {
|
|
||||||
to http://127.0.0.1:2346
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_proxy /* {
|
|
||||||
to http://127.0.0.1:7800
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,6 @@ https://dynamicdns.park-your-domain.com/update?host=cache&domain=mapcomplete.org
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
See SettingUpPSQL.md
|
See [SettingUpPSQL.md](../SettingUpPSQL.md)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ hosted.mapcomplete.org {
|
||||||
file_server
|
file_server
|
||||||
header {
|
header {
|
||||||
+Permissions-Policy "interest-cohort=()"
|
+Permissions-Policy "interest-cohort=()"
|
||||||
+Report-To `\{"group":"csp-endpoint", "max_age": 86400,"endpoints": [\{"url": "https://report.mapcomplete.org/csp"}], "include_subdomains": true}`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +10,11 @@ countrycoder.mapcomplete.org {
|
||||||
root * tiles/
|
root * tiles/
|
||||||
file_server
|
file_server
|
||||||
header {
|
header {
|
||||||
+Permissions-Policy "interest-cohort=()"
|
+Permissions-Policy "interest-cohort=()"
|
||||||
+Access-Control-Allow-Origin https://hosted.mapcomplete.org https://dev.mapcomplete.org https://mapcomplete.org
|
+Access-Control-Allow-Origin https://hosted.mapcomplete.org https://dev.mapcomplete.org https://mapcomplete.org
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
report.mapcomplete.org {
|
report.mapcomplete.org {
|
||||||
reverse_proxy {
|
reverse_proxy {
|
||||||
to http://127.0.0.1:2600
|
to http://127.0.0.1:2600
|
||||||
|
@ -30,25 +28,7 @@ studio.mapcomplete.org {
|
||||||
}
|
}
|
||||||
|
|
||||||
lod.mapcomplete.org {
|
lod.mapcomplete.org {
|
||||||
reverse_proxy /extractgraph {
|
reverse_proxy /extractgraph {
|
||||||
to http://127.0.0.1:2346
|
to http://127.0.0.1:2346
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
proxy.mapcomplete.org {
|
|
||||||
reverse_proxy {
|
|
||||||
to http://127.0.0.1:1237
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bounce.mapcomplete.org {
|
|
||||||
reverse_proxy {
|
|
||||||
to http://127.0.0.1:1236
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.mapcomplete.org {
|
|
||||||
reverse_proxy /summary/* {
|
|
||||||
to http://127.0.0.1:2345
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,11 +59,13 @@ HP ProLiant DL360 G7 (1U): 2Rx4 DDR3-memory (PC3)
|
||||||
|
|
||||||
## Deploying a tile server
|
## Deploying a tile server
|
||||||
|
|
||||||
pg_tileserv kan hier gedownload worden: https://github.com/CrunchyData/pg_tileserv
|
pg_tileserv can be downloaded here: https://github.com/CrunchyData/pg_tileserv
|
||||||
|
|
||||||
|
In the directory where it is downloaded (e.g. `~/data`), run
|
||||||
|
|
||||||
````
|
````
|
||||||
export DATABASE_URL=postgresql://user:password@localhost:5444/osm-poi
|
export DATABASE_URL=postgresql://user:password@localhost:5444/osm-poi
|
||||||
nohup ./pg_tileserv &
|
nohup ./pg_tileserv > pg_tileserv.log &
|
||||||
````
|
````
|
||||||
|
|
||||||
Tiles are available at:
|
Tiles are available at:
|
||||||
|
@ -74,6 +76,10 @@ map.addSource("drinking_water", {
|
||||||
})
|
})
|
||||||
````
|
````
|
||||||
|
|
||||||
|
# Starting the summary server
|
||||||
|
|
||||||
|
`npm run summary-server` in the git repo
|
||||||
|
|
||||||
# Rebooting:
|
# Rebooting:
|
||||||
|
|
||||||
-> Restart the docker container
|
-> Restart the docker container
|
||||||
|
|
|
@ -201,7 +201,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"#": "ignore-image-in-then",
|
"#": "ignore-image-in-then",
|
||||||
"if": "context:website~*",
|
"if": "contact:website~*",
|
||||||
"then": "<a href='{contact:website}' target='_blank' rel='noopener'><img textmode='🌐' alt='website' src='./assets/layers/icons/website.svg'/></a>"
|
"then": "<a href='{contact:website}' target='_blank' rel='noopener'><img textmode='🌐' alt='website' src='./assets/layers/icons/website.svg'/></a>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -364,5 +364,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"allowMove": true
|
"allowMove": true,
|
||||||
|
"deletion": {
|
||||||
|
"neededChangesets": 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,6 +426,36 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "copyshop-binding",
|
||||||
|
"condition": {
|
||||||
|
"or": [
|
||||||
|
"shop~.*copyshop.*",
|
||||||
|
"shop~.*stationery.*",
|
||||||
|
"service:print=yes"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"question": {
|
||||||
|
"en": "Does this shop offer a binding service?"
|
||||||
|
},
|
||||||
|
"questionHint": {
|
||||||
|
"en": "Does this shop bind a bundle of pages into a small book, e.g. with a comb, a spiral, wire or by gluing?"
|
||||||
|
},
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "service:binding=yes",
|
||||||
|
"then": {
|
||||||
|
"en": "This shop binds papers into a booklet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "service:binding=no",
|
||||||
|
"then": {
|
||||||
|
"en": "This shop does bind books"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "key_cutter",
|
"id": "key_cutter",
|
||||||
"question": {
|
"question": {
|
||||||
|
|
56
package-lock.json
generated
56
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "mapcomplete",
|
"name": "mapcomplete",
|
||||||
"version": "0.42.6",
|
"version": "0.43.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mapcomplete",
|
"name": "mapcomplete",
|
||||||
"version": "0.42.6",
|
"version": "0.43.1",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@comunica/core": "^3.0.1",
|
"@comunica/core": "^3.0.1",
|
||||||
|
@ -7682,10 +7682,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"license": "MIT",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
@ -9756,8 +9757,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
"license": "MIT",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
},
|
},
|
||||||
|
@ -10770,6 +10772,14 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-path-inside": {
|
"node_modules/is-path-inside": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -17710,7 +17720,8 @@
|
||||||
},
|
},
|
||||||
"node_modules/to-regex-range": {
|
"node_modules/to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"license": "MIT",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-number": "^7.0.0"
|
"is-number": "^7.0.0"
|
||||||
},
|
},
|
||||||
|
@ -17718,13 +17729,6 @@
|
||||||
"node": ">=8.0"
|
"node": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/to-regex-range/node_modules/is-number": {
|
|
||||||
"version": "7.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.12.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/topojson-client": {
|
"node_modules/topojson-client": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
@ -24931,9 +24935,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"braces": {
|
"braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"fill-range": "^7.0.1"
|
"fill-range": "^7.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"brorand": {
|
"brorand": {
|
||||||
|
@ -26246,7 +26252,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fill-range": {
|
"fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"to-regex-range": "^5.0.1"
|
"to-regex-range": "^5.0.1"
|
||||||
}
|
}
|
||||||
|
@ -26866,6 +26874,11 @@
|
||||||
"define-properties": "^1.1.3"
|
"define-properties": "^1.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||||
|
},
|
||||||
"is-path-inside": {
|
"is-path-inside": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
@ -31326,13 +31339,10 @@
|
||||||
},
|
},
|
||||||
"to-regex-range": {
|
"to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-number": "^7.0.0"
|
"is-number": "^7.0.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"is-number": {
|
|
||||||
"version": "7.0.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"topojson-client": {
|
"topojson-client": {
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
"url": "https://www.openstreetmap.org"
|
"url": "https://www.openstreetmap.org"
|
||||||
},
|
},
|
||||||
"mvt_layer_server": "https://cache.mapcomplete.org/public.{type}_{layer}/{z}/{x}/{y}.pbf",
|
"mvt_layer_server": "https://cache.mapcomplete.org/public.{type}_{layer}/{z}/{x}/{y}.pbf",
|
||||||
|
"#summary_server": "Should be the endpoint; appending status.json should work",
|
||||||
|
"summary_server": "https://cache.mapcomplete.org/",
|
||||||
"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/",
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Script from "./Script"
|
||||||
import { GeoOperations } from "../src/Logic/GeoOperations"
|
import { GeoOperations } from "../src/Logic/GeoOperations"
|
||||||
import { Feature, Polygon } from "geojson"
|
import { Feature, Polygon } from "geojson"
|
||||||
import { Tiles } from "../src/Models/TileRange"
|
import { Tiles } from "../src/Models/TileRange"
|
||||||
|
import { BBox } from "../src/Logic/BBox"
|
||||||
|
|
||||||
class StatsDownloader {
|
class StatsDownloader {
|
||||||
private readonly urlTemplate =
|
private readonly urlTemplate =
|
||||||
|
@ -123,7 +124,7 @@ class StatsDownloader {
|
||||||
Referer:
|
Referer:
|
||||||
"https://osmcha.org/?filters=%7B%22date__gte%22%3A%5B%7B%22label%22%3A%222020-07-05%22%2C%22value%22%3A%222020-07-05%22%7D%5D%2C%22editor%22%3A%5B%7B%22label%22%3A%22mapcomplete%22%2C%22value%22%3A%22mapcomplete%22%7D%5D%7D",
|
"https://osmcha.org/?filters=%7B%22date__gte%22%3A%5B%7B%22label%22%3A%222020-07-05%22%2C%22value%22%3A%222020-07-05%22%7D%5D%2C%22editor%22%3A%5B%7B%22label%22%3A%22mapcomplete%22%2C%22value%22%3A%22mapcomplete%22%7D%5D%7D",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: "Token 6e422e2afedb79ef66573982012000281f03dc91",
|
Authorization: "Token 9cc11ad2868778272eadbb1a423ebb507184bc04",
|
||||||
DNT: "1",
|
DNT: "1",
|
||||||
Connection: "keep-alive",
|
Connection: "keep-alive",
|
||||||
TE: "Trailers",
|
TE: "Trailers",
|
||||||
|
@ -135,7 +136,7 @@ class StatsDownloader {
|
||||||
ScriptUtils.erasableLog(
|
ScriptUtils.erasableLog(
|
||||||
`Downloading stats for ${year}-${month}-${day}, page ${page} ${url}`
|
`Downloading stats for ${year}-${month}-${day}, page ${page} ${url}`
|
||||||
)
|
)
|
||||||
const result = await Utils.downloadJson(url, headers)
|
const result = await Utils.downloadJson<{features: [], next: string}>(url, headers)
|
||||||
page++
|
page++
|
||||||
allFeatures.push(...result.features)
|
allFeatures.push(...result.features)
|
||||||
if (result.features === undefined) {
|
if (result.features === undefined) {
|
||||||
|
@ -201,11 +202,11 @@ class GenerateSeries extends Script {
|
||||||
const targetDir = args[0] ?? "../../git/MapComplete-data"
|
const targetDir = args[0] ?? "../../git/MapComplete-data"
|
||||||
|
|
||||||
await this.downloadStatistics(targetDir + "/changeset-metadata")
|
await this.downloadStatistics(targetDir + "/changeset-metadata")
|
||||||
await this.generateCenterPoints(
|
this.generateCenterPoints(
|
||||||
targetDir + "/changeset-metadata",
|
targetDir + "/changeset-metadata",
|
||||||
targetDir + "/mapcomplete-changes/",
|
targetDir + "/mapcomplete-changes/",
|
||||||
{
|
{
|
||||||
zoomlevel: 8,
|
zoomlevel: 8
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -248,10 +249,8 @@ class GenerateSeries extends Script {
|
||||||
const allPaths = readdirSync(sourceDir).filter(
|
const allPaths = readdirSync(sourceDir).filter(
|
||||||
(p) => p.startsWith("stats.") && p.endsWith(".json")
|
(p) => p.startsWith("stats.") && p.endsWith(".json")
|
||||||
)
|
)
|
||||||
let allFeatures: ChangeSetData[] = [].concat(
|
let allFeatures: ChangeSetData[] = allPaths.flatMap(
|
||||||
...allPaths.map(
|
|
||||||
(path) => JSON.parse(readFileSync(sourceDir + "/" + path, "utf-8")).features
|
(path) => JSON.parse(readFileSync(sourceDir + "/" + path, "utf-8")).features
|
||||||
)
|
|
||||||
)
|
)
|
||||||
allFeatures = allFeatures.filter(
|
allFeatures = allFeatures.filter(
|
||||||
(f) =>
|
(f) =>
|
||||||
|
@ -270,8 +269,24 @@ class GenerateSeries extends Script {
|
||||||
f.properties.editor.toLowerCase().startsWith("mapcomplete"))
|
f.properties.editor.toLowerCase().startsWith("mapcomplete"))
|
||||||
)
|
)
|
||||||
|
|
||||||
allFeatures = allFeatures.filter((f) => f.properties.metadata?.theme !== "EMPTY CS")
|
allFeatures = allFeatures.filter((f) => f.properties.metadata?.theme !== "EMPTY CS" && f.geometry.coordinates.length > 0)
|
||||||
const centerpoints = allFeatures.map((f) => GeoOperations.centerpoint(f))
|
const centerpointsAll = allFeatures.map((f) => {
|
||||||
|
const centerpoint = GeoOperations.centerpoint(f)
|
||||||
|
const c = centerpoint.geometry.coordinates
|
||||||
|
// OsmCha doesn't adhere to the Geojson standard and uses `lat` `lon` as coordinates instead of `lon`, `lat`
|
||||||
|
centerpoint.geometry.coordinates = [c[1], c[0]]
|
||||||
|
return centerpoint
|
||||||
|
})
|
||||||
|
const centerpoints = centerpointsAll.filter(p => {
|
||||||
|
const bbox= BBox.get(p)
|
||||||
|
if(bbox.minLat === -90 && bbox.maxLat === -90){
|
||||||
|
// Due to some bug somewhere, those invalid bboxes might appear if the latitude is < 90
|
||||||
|
// This crashes the 'spreadIntoBBoxes
|
||||||
|
// As workaround, we simply ignore them for now
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
console.log("Found", centerpoints.length, " changesets in total")
|
console.log("Found", centerpoints.length, " changesets in total")
|
||||||
|
|
||||||
const perBbox = GeoOperations.spreadIntoBboxes(centerpoints, options.zoomlevel)
|
const perBbox = GeoOperations.spreadIntoBboxes(centerpoints, options.zoomlevel)
|
||||||
|
|
|
@ -392,6 +392,8 @@ class GenerateLayouts extends Script {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hosts.add("http://www.schema.org") // Schema.org is _not_ encrypted and thus needs an exception
|
||||||
|
|
||||||
if (hosts.has("*")) {
|
if (hosts.has("*")) {
|
||||||
throw "* is not allowed as connect-src"
|
throw "* is not allowed as connect-src"
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,10 @@ class Compare extends Script {
|
||||||
|
|
||||||
async main(args: string[]): Promise<void> {
|
async main(args: string[]): Promise<void> {
|
||||||
let [velopark, osm, key] = args
|
let [velopark, osm, key] = args
|
||||||
|
if(velopark === undefined || osm === undefined){
|
||||||
|
console.log("Needed argument: velopark.geojson osm.geojson [key]\nThe key is optional and will be `ref:velopark` by default\nUse overpass to get a geojson with ref:velopark")
|
||||||
|
return
|
||||||
|
}
|
||||||
key ??= "ref:velopark"
|
key ??= "ref:velopark"
|
||||||
const veloparkData: FeatureCollection = JSON.parse(fs.readFileSync(velopark, "utf-8"))
|
const veloparkData: FeatureCollection = JSON.parse(fs.readFileSync(velopark, "utf-8"))
|
||||||
const osmData: FeatureCollection = JSON.parse(fs.readFileSync(osm, "utf-8"))
|
const osmData: FeatureCollection = JSON.parse(fs.readFileSync(osm, "utf-8"))
|
||||||
|
@ -82,6 +86,7 @@ class Compare extends Script {
|
||||||
console.error("No velopark entry found for", veloId)
|
console.error("No velopark entry found for", veloId)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
console.log("Veloparking is", veloparking)
|
||||||
diffs.push(this.compare(veloId, parking, veloparking))
|
diffs.push(this.compare(veloId, parking, veloparking))
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
|
|
63
scripts/velopark/diffToCsv.ts
Normal file
63
scripts/velopark/diffToCsv.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import Script from "../Script"
|
||||||
|
import { readFileSync, writeFileSync } from "fs"
|
||||||
|
import { OsmId } from "../../src/Models/OsmFeature"
|
||||||
|
import { Utils } from "../../src/Utils"
|
||||||
|
|
||||||
|
interface DiffItem {
|
||||||
|
/**
|
||||||
|
* Velopark-id
|
||||||
|
*/
|
||||||
|
"ref": string,
|
||||||
|
"osmid": OsmId,
|
||||||
|
"distance": number,
|
||||||
|
"diffs": {
|
||||||
|
key: string,
|
||||||
|
/**
|
||||||
|
* The value in OpenStreetMap
|
||||||
|
* Might be undefined if OSM doesn't have an appropriate value
|
||||||
|
*/
|
||||||
|
osm?: string,
|
||||||
|
velopark: string | number } []
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DiffToCsv extends Script {
|
||||||
|
constructor() {
|
||||||
|
super("Converts a 'report.diff' to a CSV file for people who prefer LibreOffice Calc (or other Spreadsheet Software)")
|
||||||
|
}
|
||||||
|
|
||||||
|
async main(args: string[]): Promise<void> {
|
||||||
|
const file = args[0] ?? "report_diff.json"
|
||||||
|
const json = <{diffs:DiffItem[], distanceBinds: number[]}> JSON.parse(readFileSync(file, "utf8"))
|
||||||
|
const diffs = json.diffs
|
||||||
|
const allKeys = Utils.Dedup(diffs.flatMap(item => item.diffs.map(d => d.key)))
|
||||||
|
allKeys.sort()
|
||||||
|
|
||||||
|
const header = ["osm_id","velopark_id", "distance",...allKeys.flatMap(k => ["osm:"+k, "velopark:"+k])]
|
||||||
|
const lines = [header]
|
||||||
|
for (const diffItem of diffs) {
|
||||||
|
const line = []
|
||||||
|
lines.push(line)
|
||||||
|
line.push(diffItem.osmid)
|
||||||
|
line.push(diffItem.ref)
|
||||||
|
line.push(diffItem.distance)
|
||||||
|
|
||||||
|
const d = diffItem.diffs
|
||||||
|
for (const k of allKeys) {
|
||||||
|
const found = d.find(i => i.key === k)
|
||||||
|
if(!found){
|
||||||
|
line.push("","")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
line.push(found.osm, found.velopark)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
const path = "report_diff.csv"
|
||||||
|
writeFileSync(path,
|
||||||
|
lines.map(l => l.join(",")).join("\n")
|
||||||
|
,"utf8")
|
||||||
|
console.log("Written", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new DiffToCsv().run()
|
|
@ -23,9 +23,9 @@ class VeloParkToGeojson extends Script {
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
extension === ".geojson"
|
extension === ".geojson"
|
||||||
? {
|
? {
|
||||||
type: "FeatureCollection",
|
type: "FeatureCollection",
|
||||||
features,
|
features
|
||||||
}
|
}
|
||||||
: features,
|
: features,
|
||||||
null,
|
null,
|
||||||
" "
|
" "
|
||||||
|
@ -34,34 +34,14 @@ class VeloParkToGeojson extends Script {
|
||||||
console.log("Written", file, "(" + features.length, " features)")
|
console.log("Written", file, "(" + features.length, " features)")
|
||||||
}
|
}
|
||||||
|
|
||||||
public static sumProperties(data: object, addTo: Record<string, Set<string>>) {
|
|
||||||
delete data["@context"]
|
|
||||||
for (const k in data) {
|
|
||||||
if (k === "@graph") {
|
|
||||||
for (const obj of data["@graph"]) {
|
|
||||||
this.sumProperties(obj, addTo)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (addTo[k] === undefined) {
|
|
||||||
addTo[k] = new Set<string>()
|
|
||||||
}
|
|
||||||
addTo[k].add(data[k])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async downloadDataFor(
|
private static async downloadDataFor(
|
||||||
url: string,
|
url: string
|
||||||
allProperties: Record<string, Set<string>>
|
|
||||||
): Promise<Feature[]> {
|
): Promise<Feature[]> {
|
||||||
const cachePath = "/home/pietervdvn/data/velopark_cache/" + url.replace(/[/:.]/g, "_")
|
const cachePath = "/home/pietervdvn/data/velopark_cache_refined/" + url.replace(/[/:.]/g, "_")
|
||||||
if (!fs.existsSync(cachePath)) {
|
if (fs.existsSync(cachePath)) {
|
||||||
const data = await Utils.downloadJson(url)
|
return JSON.parse(fs.readFileSync(cachePath, "utf8"))
|
||||||
fs.writeFileSync(cachePath, JSON.stringify(data), "utf-8")
|
|
||||||
console.log("Saved a backup to", cachePath)
|
|
||||||
}
|
}
|
||||||
|
console.log("Fetching data for", url)
|
||||||
this.sumProperties(JSON.parse(fs.readFileSync(cachePath, "utf-8")), allProperties)
|
|
||||||
|
|
||||||
const linkedData = await LinkedDataLoader.fetchVeloparkEntry(url)
|
const linkedData = await LinkedDataLoader.fetchVeloparkEntry(url)
|
||||||
const allVelopark: Feature[] = []
|
const allVelopark: Feature[] = []
|
||||||
|
@ -70,9 +50,12 @@ class VeloParkToGeojson extends Script {
|
||||||
if (Object.keys(sectionInfo).length === 0) {
|
if (Object.keys(sectionInfo).length === 0) {
|
||||||
console.warn("No result for", url)
|
console.warn("No result for", url)
|
||||||
}
|
}
|
||||||
sectionInfo["ref:velopark"] = [sectionId ?? url]
|
if(!sectionInfo.geometry?.coordinates){
|
||||||
|
throw "Invalid properties!"
|
||||||
|
}
|
||||||
allVelopark.push(sectionInfo)
|
allVelopark.push(sectionInfo)
|
||||||
}
|
}
|
||||||
|
fs.writeFileSync(cachePath, JSON.stringify(allVelopark), "utf8")
|
||||||
return allVelopark
|
return allVelopark
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,20 +68,24 @@ class VeloParkToGeojson extends Script {
|
||||||
let failed = 0
|
let failed = 0
|
||||||
console.log("Got", allVeloparkRaw.length, "items")
|
console.log("Got", allVeloparkRaw.length, "items")
|
||||||
const allVelopark: Feature[] = []
|
const allVelopark: Feature[] = []
|
||||||
const allProperties = {}
|
const batchSize = 50
|
||||||
for (let i = 0; i < allVeloparkRaw.length; i++) {
|
for (let i = 0; i < allVeloparkRaw.length; i += batchSize) {
|
||||||
const f = allVeloparkRaw[i]
|
await Promise.all(Utils.TimesT(batchSize, j => j).map(
|
||||||
console.log("Handling", i + "/" + allVeloparkRaw.length)
|
async j => {
|
||||||
try {
|
const f = allVeloparkRaw[i + j]
|
||||||
const sections: Feature[] = await VeloParkToGeojson.downloadDataFor(
|
if (!f) {
|
||||||
f.url,
|
return
|
||||||
allProperties
|
}
|
||||||
)
|
try {
|
||||||
allVelopark.push(...sections)
|
const sections: Feature[] = await VeloParkToGeojson.downloadDataFor(f.url)
|
||||||
} catch (e) {
|
allVelopark.push(...sections)
|
||||||
console.error("Loading ", f.url, " failed due to", e)
|
} catch (e) {
|
||||||
failed++
|
console.error("Loading ", f.url, " failed due to", e)
|
||||||
}
|
failed++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
"Fetching data done, got ",
|
"Fetching data done, got ",
|
||||||
|
@ -107,11 +94,6 @@ class VeloParkToGeojson extends Script {
|
||||||
failed
|
failed
|
||||||
)
|
)
|
||||||
VeloParkToGeojson.exportGeojsonTo("velopark_all", allVelopark)
|
VeloParkToGeojson.exportGeojsonTo("velopark_all", allVelopark)
|
||||||
for (const k in allProperties) {
|
|
||||||
allProperties[k] = Array.from(allProperties[k])
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync("all_properties_mashup.json", JSON.stringify(allProperties, null, " "))
|
|
||||||
|
|
||||||
return allVelopark
|
return allVelopark
|
||||||
}
|
}
|
||||||
|
@ -158,7 +140,7 @@ class VeloParkToGeojson extends Script {
|
||||||
private static async createDiff(allVelopark: Feature[]) {
|
private static async createDiff(allVelopark: Feature[]) {
|
||||||
const bboxBelgium = new BBox([
|
const bboxBelgium = new BBox([
|
||||||
[2.51357303225, 49.5294835476],
|
[2.51357303225, 49.5294835476],
|
||||||
[6.15665815596, 51.4750237087],
|
[6.15665815596, 51.4750237087]
|
||||||
])
|
])
|
||||||
|
|
||||||
const alreadyLinkedQuery = new Overpass(
|
const alreadyLinkedQuery = new Overpass(
|
||||||
|
@ -201,7 +183,7 @@ class VeloParkToGeojson extends Script {
|
||||||
VeloParkToGeojson.exportExtraAmenities(allVelopark)
|
VeloParkToGeojson.exportExtraAmenities(allVelopark)
|
||||||
await VeloParkToGeojson.createDiff(allVelopark)
|
await VeloParkToGeojson.createDiff(allVelopark)
|
||||||
console.log(
|
console.log(
|
||||||
"Use vite-node script/velopark/compare to compare the results and generate a diff file"
|
"Use vite-node scripts/velopark/compare.ts to compare the results and generate a diff file"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,18 @@ export class BBox {
|
||||||
/***
|
/***
|
||||||
* Coordinates should be [[lon, lat],[lon, lat]]
|
* Coordinates should be [[lon, lat],[lon, lat]]
|
||||||
* @param coordinates
|
* @param coordinates
|
||||||
|
*
|
||||||
|
* const bb = new BBox([[5,6]])
|
||||||
|
* bb.minLat // => 6
|
||||||
|
* bb.minLon // => 5
|
||||||
|
* bb.maxLat // => 6
|
||||||
|
* bb.maxLon // => 5
|
||||||
|
*
|
||||||
|
* const bb = new BBox([[-100,-100]])
|
||||||
|
* bb.minLat // => -90
|
||||||
|
* bb.minLon // => -100
|
||||||
|
* bb.maxLat // => -90
|
||||||
|
* bb.maxLon // => -100
|
||||||
*/
|
*/
|
||||||
constructor(coordinates: [number, number][]) {
|
constructor(coordinates: [number, number][]) {
|
||||||
this.maxLat = -90
|
this.maxLat = -90
|
||||||
|
@ -45,13 +57,24 @@ export class BBox {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bbox from a feature and caches it (by monkeypatching) the relevant feature
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* const f = {type:"Feature",properties: {}, geometry: {type: "Point", coordinates: [-100,45]}}
|
||||||
|
* const bb = BBox.get(f)
|
||||||
|
* bb.minLat // => 45
|
||||||
|
* bb.minLon // => -100
|
||||||
|
*
|
||||||
|
*/
|
||||||
static get(feature: Feature): BBox {
|
static get(feature: Feature): BBox {
|
||||||
const f = <any>feature
|
const f = <any>feature
|
||||||
if (f.bbox?.overlapsWith === undefined) {
|
if (f.bbox?.overlapsWith === undefined) {
|
||||||
const turfBbox: number[] = turf.bbox(feature)
|
const [minX, minY, maxX, maxY]: number[] = turf.bbox(feature)
|
||||||
|
// Note: x is longitude
|
||||||
f["bbox"] = new BBox([
|
f["bbox"] = new BBox([
|
||||||
[turfBbox[0], turfBbox[1]],
|
[minX, minY],
|
||||||
[turfBbox[2], turfBbox[3]],
|
[maxX, maxY],
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
return f["bbox"]
|
return f["bbox"]
|
||||||
|
|
|
@ -26,7 +26,6 @@ export default class LayoutSource extends FeatureSourceMerger {
|
||||||
|
|
||||||
private readonly supportsForceDownload: UpdatableFeatureSource[]
|
private readonly supportsForceDownload: UpdatableFeatureSource[]
|
||||||
|
|
||||||
private readonly fromCache: Map<string, LocalStorageFeatureSource>
|
|
||||||
public static readonly fromCacheZoomLevel = 15
|
public static readonly fromCacheZoomLevel = 15
|
||||||
constructor(
|
constructor(
|
||||||
layers: LayerConfig[],
|
layers: LayerConfig[],
|
||||||
|
|
|
@ -734,7 +734,6 @@ export class GeoOperations {
|
||||||
const splitted: Feature<LineString>[] = [].concat(...lines)
|
const splitted: Feature<LineString>[] = [].concat(...lines)
|
||||||
const kept: Feature<LineString>[] = []
|
const kept: Feature<LineString>[] = []
|
||||||
for (const f of splitted) {
|
for (const f of splitted) {
|
||||||
console.log("Checking", f)
|
|
||||||
if (!GeoOperations.inside(GeoOperations.centerpointCoordinates(f), boundary)) {
|
if (!GeoOperations.inside(GeoOperations.centerpointCoordinates(f), boundary)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,14 +316,16 @@ export default class LinkedDataLoader {
|
||||||
input: Record<string, Set<string>>
|
input: Record<string, Set<string>>
|
||||||
): Record<string, string[]> {
|
): Record<string, string[]> {
|
||||||
const output: Record<string, string[]> = {}
|
const output: Record<string, string[]> = {}
|
||||||
console.log("Input for patchVelopark:", input)
|
|
||||||
for (const k in input) {
|
for (const k in input) {
|
||||||
output[k] = Array.from(input[k])
|
output[k] = Array.from(input[k])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output["type"][0] === "https://data.velopark.be/openvelopark/terms#BicycleLocker") {
|
if (output["type"]?.[0] === "https://data.velopark.be/openvelopark/terms#BicycleLocker") {
|
||||||
output["bicycle_parking"] = ["lockers"]
|
output["bicycle_parking"] = ["lockers"]
|
||||||
}
|
}
|
||||||
|
if(output["type"] === undefined){
|
||||||
|
console.error("No type given for", output)
|
||||||
|
}
|
||||||
delete output["type"]
|
delete output["type"]
|
||||||
|
|
||||||
function on(key: string, applyF: (s: string) => string) {
|
function on(key: string, applyF: (s: string) => string) {
|
||||||
|
@ -506,7 +508,6 @@ export default class LinkedDataLoader {
|
||||||
" ?parking a <http://schema.mobivoc.org/BicycleParkingStation>",
|
" ?parking a <http://schema.mobivoc.org/BicycleParkingStation>",
|
||||||
"?parking " + property + " " + (variable ?? "")
|
"?parking " + property + " " + (variable ?? "")
|
||||||
)
|
)
|
||||||
console.log("Fetching a velopark property gave", property, results)
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,7 @@ export default class Constants {
|
||||||
*/
|
*/
|
||||||
public static VectorTileServer: string | undefined = Constants.config.mvt_layer_server
|
public static VectorTileServer: string | undefined = Constants.config.mvt_layer_server
|
||||||
public static readonly maptilerApiKey = "GvoVAJgu46I5rZapJuAy"
|
public static readonly maptilerApiKey = "GvoVAJgu46I5rZapJuAy"
|
||||||
|
public static readonly SummaryServer: string = Constants.config.summary_server
|
||||||
|
|
||||||
private static isRetina(): boolean {
|
private static isRetina(): boolean {
|
||||||
if (Utils.runningFromConsole) {
|
if (Utils.runningFromConsole) {
|
||||||
|
|
|
@ -80,11 +80,14 @@ export class AvailableRasterLayers {
|
||||||
return GeoOperations.inside(lonlat, eliPolygon)
|
return GeoOperations.inside(lonlat, eliPolygon)
|
||||||
})
|
})
|
||||||
matching.unshift(AvailableRasterLayers.osmCarto)
|
matching.unshift(AvailableRasterLayers.osmCarto)
|
||||||
matching.push(AvailableRasterLayers.defaultBackgroundLayer)
|
|
||||||
if (enableBing?.data) {
|
if (enableBing?.data) {
|
||||||
matching.push(AvailableRasterLayers.bing)
|
matching.push(AvailableRasterLayers.bing)
|
||||||
}
|
}
|
||||||
matching.push(...AvailableRasterLayers.globalLayers)
|
matching.push(...AvailableRasterLayers.globalLayers)
|
||||||
|
if(!matching.some(l => l.id === AvailableRasterLayers.defaultBackgroundLayer.properties.id)){
|
||||||
|
matching.push(AvailableRasterLayers.defaultBackgroundLayer)
|
||||||
|
}
|
||||||
return matching
|
return matching
|
||||||
},
|
},
|
||||||
[enableBing]
|
[enableBing]
|
||||||
|
|
|
@ -690,9 +690,8 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
l.source.geojsonSource === undefined &&
|
l.source.geojsonSource === undefined &&
|
||||||
l.doCount
|
l.doCount
|
||||||
)
|
)
|
||||||
const url = new URL(Constants.VectorTileServer)
|
|
||||||
const summaryTileSource = new SummaryTileSource(
|
const summaryTileSource = new SummaryTileSource(
|
||||||
url.protocol + "//" + url.host + "/summary",
|
Constants.SummaryServer,
|
||||||
layers.map((l) => l.id),
|
layers.map((l) => l.id),
|
||||||
this.mapProperties.zoom.map((z) => Math.max(Math.floor(z), 0)),
|
this.mapProperties.zoom.map((z) => Math.max(Math.floor(z), 0)),
|
||||||
this.mapProperties,
|
this.mapProperties,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
|
||||||
import StylesheetTestGui from "./UI/StylesheetTestGui.svelte"
|
import StylesheetTestGui from "./UI/StylesheetTestGui.svelte"
|
||||||
|
|
||||||
new SvelteUIElement(StylesheetTestGui, {}).AttachTo("main")
|
new StylesheetTestGui({
|
||||||
|
target: document.getElementById("maindiv")
|
||||||
|
})
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<main>
|
||||||
<div class="m-4 flex flex-col">
|
<div class="m-4 flex flex-col">
|
||||||
<LanguagePicker
|
<LanguagePicker
|
||||||
clss="self-end max-w-full"
|
clss="self-end max-w-full"
|
||||||
|
@ -165,3 +166,4 @@
|
||||||
v{Constants.vNumber}
|
v{Constants.vNumber}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
* If set, 'loading' will act as if we are already logged in.
|
* If set, 'loading' will act as if we are already logged in.
|
||||||
*/
|
*/
|
||||||
export let ignoreLoading: boolean = false
|
export let ignoreLoading: boolean = false
|
||||||
|
/**
|
||||||
|
* Only show the 'successful' state, don't show loading or error messages
|
||||||
|
*/
|
||||||
|
export let silentFail : boolean = false
|
||||||
let loadingStatus = state?.osmConnection?.loadingStatus ?? new ImmutableStore("logged-in")
|
let loadingStatus = state?.osmConnection?.loadingStatus ?? new ImmutableStore("logged-in")
|
||||||
let badge = state?.featureSwitches?.featureSwitchEnableLogin ?? new ImmutableStore(true)
|
let badge = state?.featureSwitches?.featureSwitchEnableLogin ?? new ImmutableStore(true)
|
||||||
const t = Translations.t.general
|
const t = Translations.t.general
|
||||||
|
@ -30,11 +34,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $badge}
|
{#if $badge}
|
||||||
{#if !ignoreLoading && $loadingStatus === "loading"}
|
{#if !ignoreLoading && !silentFail && $loadingStatus === "loading"}
|
||||||
<slot name="loading">
|
<slot name="loading">
|
||||||
<Loading />
|
<Loading />
|
||||||
</slot>
|
</slot>
|
||||||
{:else if $loadingStatus === "error"}
|
{:else if !silentFail && $loadingStatus === "error"}
|
||||||
<slot name="error">
|
<slot name="error">
|
||||||
<div class="alert max-w-64 flex items-center">
|
<div class="alert max-w-64 flex items-center">
|
||||||
<Invalid class="m-2 h-8 w-8 shrink-0" />
|
<Invalid class="m-2 h-8 w-8 shrink-0" />
|
||||||
|
@ -43,7 +47,7 @@
|
||||||
</slot>
|
</slot>
|
||||||
{:else if $loadingStatus === "logged-in"}
|
{:else if $loadingStatus === "logged-in"}
|
||||||
<slot />
|
<slot />
|
||||||
{:else if $loadingStatus === "not-attempted"}
|
{:else if !silentFail && $loadingStatus === "not-attempted"}
|
||||||
<slot name="not-logged-in" />
|
<slot name="not-logged-in" />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
import type { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
import type { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
||||||
import AttributedImage from "./AttributedImage.svelte"
|
import AttributedImage from "./AttributedImage.svelte"
|
||||||
import SpecialTranslation from "../Popup/TagRendering/SpecialTranslation.svelte"
|
import SpecialTranslation from "../Popup/TagRendering/SpecialTranslation.svelte"
|
||||||
|
import LoginToggle from "../Base/LoginToggle.svelte"
|
||||||
|
|
||||||
export let tags: UIEventSource<OsmTags>
|
export let tags: UIEventSource<OsmTags>
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
|
@ -68,10 +69,12 @@
|
||||||
previewedImage={state.previewedImage}
|
previewedImage={state.previewedImage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<LoginToggle {state} silentFail={true} >
|
||||||
{#if linkable}
|
{#if linkable}
|
||||||
<label>
|
<label>
|
||||||
<input bind:checked={$isLinked} type="checkbox" />
|
<input bind:checked={$isLinked} type="checkbox" />
|
||||||
<SpecialTranslation t={t.link} {tags} {state} {layer} {feature} />
|
<SpecialTranslation t={t.link} {tags} {state} {layer} {feature} />
|
||||||
</label>
|
</label>
|
||||||
{/if}
|
{/if}
|
||||||
|
</LoginToggle>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
lon,
|
lon,
|
||||||
lat,
|
lat,
|
||||||
allowSpherical: new UIEventSource<boolean>(false),
|
allowSpherical: new UIEventSource<boolean>(false),
|
||||||
blacklist: AllImageProviders.LoadImagesFor(tags),
|
blacklist: AllImageProviders.LoadImagesFor(tags)
|
||||||
},
|
},
|
||||||
state.indexedFeatures
|
state.indexedFeatures
|
||||||
)
|
)
|
||||||
|
@ -39,26 +39,24 @@
|
||||||
let allDone = imagesProvider.allDone
|
let allDone = imagesProvider.allDone
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LoginToggle {state}>
|
<div class="interactive border-interactive rounded-2xl p-2">
|
||||||
<div class="interactive border-interactive rounded-2xl p-2">
|
<div class="flex justify-between">
|
||||||
<div class="flex justify-between">
|
<h4>
|
||||||
<h4>
|
<Tr t={Translations.t.image.nearby.title} />
|
||||||
<Tr t={Translations.t.image.nearby.title} />
|
</h4>
|
||||||
</h4>
|
<slot name="corner" />
|
||||||
<slot name="corner" />
|
</div>
|
||||||
</div>
|
{#if !$allDone}
|
||||||
{#if !$allDone}
|
<Loading />
|
||||||
<Loading />
|
{:else if $images.length === 0}
|
||||||
{:else if $images.length === 0}
|
<Tr t={Translations.t.image.nearby.noNearbyImages} cls="alert" />
|
||||||
<Tr t={Translations.t.image.nearby.noNearbyImages} cls="alert" />
|
{:else}
|
||||||
{:else}
|
<div class="flex w-full space-x-1 overflow-x-auto" style="scroll-snap-type: x proximity">
|
||||||
<div class="flex w-full space-x-1 overflow-x-auto" style="scroll-snap-type: x proximity">
|
{#each $images as image (image.pictureUrl)}
|
||||||
{#each $images as image (image.pictureUrl)}
|
|
||||||
<span class="w-fit shrink-0" style="scroll-snap-align: start">
|
<span class="w-fit shrink-0" style="scroll-snap-align: start">
|
||||||
<LinkableImage {tags} {image} {state} {feature} {layer} {linkable} />
|
<LinkableImage {tags} {image} {state} {feature} {layer} {linkable} />
|
||||||
</span>
|
</span>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</LoginToggle>
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
let expanded = false
|
let expanded = false
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LoginToggle {state}>
|
|
||||||
<div class="my-4">
|
<div class="my-4">
|
||||||
{#if expanded}
|
{#if expanded}
|
||||||
<NearbyImages {tags} {state} {lon} {lat} {feature} {linkable} {layer}>
|
<NearbyImages {tags} {state} {lon} {lat} {feature} {linkable} {layer}>
|
||||||
|
@ -54,4 +53,3 @@
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</LoginToggle>
|
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
}
|
}
|
||||||
> = UIEventSource.FromPromise(Utils.downloadJsonCached(source))
|
> = UIEventSource.FromPromise(Utils.downloadJsonCached(source))
|
||||||
</script>
|
</script>
|
||||||
|
<main>
|
||||||
<h1>Contributed images with MapComplete: leaderboard</h1>
|
<h1>Contributed images with MapComplete: leaderboard</h1>
|
||||||
|
|
||||||
{#if $data}
|
{#if $data}
|
||||||
|
@ -67,3 +67,4 @@
|
||||||
<div>
|
<div>
|
||||||
Logged in as {$loggedInContributor}
|
Logged in as {$loggedInContributor}
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
console.log("???")
|
console.log("???")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<main>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<Tr t={Translations.t.general["404"]} />
|
<Tr t={Translations.t.general["404"]} />
|
||||||
<BackButton
|
<BackButton
|
||||||
|
@ -18,3 +19,4 @@
|
||||||
</div>
|
</div>
|
||||||
</BackButton>
|
</BackButton>
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span {lang}>
|
{#if lang === "*"}
|
||||||
{#each specs as specpart}
|
{#each specs as specpart}
|
||||||
{#if typeof specpart === "string"}
|
{#if typeof specpart === "string"}
|
||||||
<span>
|
<span>
|
||||||
|
@ -74,4 +74,17 @@
|
||||||
<ToSvelte construct={() => createVisualisation(specpart)} />
|
<ToSvelte construct={() => createVisualisation(specpart)} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</span>
|
{:else}
|
||||||
|
<span {lang}>
|
||||||
|
{#each specs as specpart}
|
||||||
|
{#if typeof specpart === "string"}
|
||||||
|
<span>
|
||||||
|
{@html Utils.purify(Utils.SubstituteKeys(specpart, $tags)) }
|
||||||
|
<WeblateLink context={t.context} />
|
||||||
|
</span>
|
||||||
|
{:else if $tags !== undefined}
|
||||||
|
<ToSvelte construct={() => createVisualisation(specpart)} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
userRelatedState: new UserRelatedState(osmConnection)
|
userRelatedState: new UserRelatedState(osmConnection)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<main>
|
||||||
<div class="flex h-screen flex-col overflow-hidden px-4">
|
<div class="flex h-screen flex-col overflow-hidden px-4">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<h2 class="flex items-center">
|
<h2 class="flex items-center">
|
||||||
|
@ -33,3 +33,4 @@
|
||||||
<Tr t={Translations.t.general.backToIndex} />
|
<Tr t={Translations.t.general.backToIndex} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import { UIEventSource } from "../Logic/UIEventSource"
|
import { UIEventSource } from "../Logic/UIEventSource"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<main>
|
||||||
<div>
|
<div>
|
||||||
<h1>Stylesheet testing grounds</h1>
|
<h1>Stylesheet testing grounds</h1>
|
||||||
|
|
||||||
|
@ -167,3 +168,4 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
|
@ -1,16 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Translation } from "./i18n/Translation"
|
|
||||||
import LanguagePicker from "./InputElement/LanguagePicker.svelte"
|
|
||||||
import Tr from "./Base/Tr.svelte"
|
|
||||||
import ToSvelte from "./Base/ToSvelte.svelte"
|
|
||||||
|
|
||||||
const m = new Map<string, string>()
|
|
||||||
m.set("nl", "Nederlands")
|
|
||||||
const tr = Translation.fromMap(m, true)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LanguagePicker/>
|
<main>
|
||||||
<h1>Svelte native</h1>
|
</main>
|
||||||
<Tr t={tr}/>
|
|
||||||
<h1>ToSvelte</h1>
|
|
||||||
<ToSvelte construct={tr}/>
|
|
||||||
|
|
|
@ -203,6 +203,7 @@
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<main>
|
||||||
<div class="absolute top-0 left-0 h-screen w-screen overflow-hidden">
|
<div class="absolute top-0 left-0 h-screen w-screen overflow-hidden">
|
||||||
<MaplibreMap map={maplibremap} mapProperties={mapproperties} />
|
<MaplibreMap map={maplibremap} mapProperties={mapproperties} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -688,3 +689,4 @@
|
||||||
<CloseAnimation isOpened={selectedElement.map(sl => sl !== undefined && sl?.properties?.id === LastClickFeatureSource.newPointElementId)} moveTo={openNewElementButton} debug="newElement"/>
|
<CloseAnimation isOpened={selectedElement.map(sl => sl !== undefined && sl?.properties?.id === LastClickFeatureSource.newPointElementId)} moveTo={openNewElementButton} debug="newElement"/>
|
||||||
<CloseAnimation isOpened={state.guistate.filtersPanelIsOpened} moveTo={openFilterButton} debug="filter"/>
|
<CloseAnimation isOpened={state.guistate.filtersPanelIsOpened} moveTo={openFilterButton} debug="filter"/>
|
||||||
<CloseAnimation isOpened={state.guistate.backgroundLayerSelectionIsOpened} moveTo={openBackgroundButton} debug="bg"/>
|
<CloseAnimation isOpened={state.guistate.backgroundLayerSelectionIsOpened} moveTo={openBackgroundButton} debug="bg"/>
|
||||||
|
</main>
|
||||||
|
|
|
@ -28,4 +28,6 @@ if (layout !== "") {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
new SvelteUIElement(AllThemesGui, {}).AttachTo("main")
|
new AllThemesGui({
|
||||||
|
target: document.getElementById("main")
|
||||||
|
})
|
||||||
|
|
|
@ -28,7 +28,7 @@ async function timeout(timeMS: number): Promise<{ layers: string[] }> {
|
||||||
|
|
||||||
async function getAvailableLayers(): Promise<Set<string>> {
|
async function getAvailableLayers(): Promise<Set<string>> {
|
||||||
try {
|
try {
|
||||||
const host = new URL(Constants.VectorTileServer).host
|
const host = new URL(Constants.SummaryServer).host
|
||||||
const status: { layers: string[] } = await Promise.any([
|
const status: { layers: string[] } = await Promise.any([
|
||||||
Utils.downloadJson<{layers}>("https://" + host + "/summary/status.json"),
|
Utils.downloadJson<{layers}>("https://" + host + "/summary/status.json"),
|
||||||
timeout(2500),
|
timeout(2500),
|
||||||
|
@ -52,8 +52,10 @@ async function main() {
|
||||||
])
|
])
|
||||||
console.log("The available layers on server are", Array.from(availableLayers))
|
console.log("The available layers on server are", Array.from(availableLayers))
|
||||||
const state = new ThemeViewState(layout, availableLayers)
|
const state = new ThemeViewState(layout, availableLayers)
|
||||||
const main = new SvelteUIElement(ThemeViewGUI, { state })
|
new ThemeViewGUI({
|
||||||
main.AttachTo("maindiv")
|
target: document.getElementById("maindiv"),
|
||||||
|
props: {state}
|
||||||
|
})
|
||||||
Array.from(document.getElementsByClassName("delete-on-load")).forEach((el) => {
|
Array.from(document.getElementsByClassName("delete-on-load")).forEach((el) => {
|
||||||
el.parentElement.removeChild(el)
|
el.parentElement.removeChild(el)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import ThemeViewState from "./src/Models/ThemeViewState"
|
import ThemeViewState from "./src/Models/ThemeViewState"
|
||||||
import SvelteUIElement from "./src/UI/Base/SvelteUIElement"
|
|
||||||
import ThemeViewGUI from "./src/UI/ThemeViewGUI.svelte"
|
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";
|
||||||
|
@ -47,8 +46,10 @@ async function main() {
|
||||||
MetaTagging.setThemeMetatagging(new ThemeMetaTagging())
|
MetaTagging.setThemeMetatagging(new ThemeMetaTagging())
|
||||||
// LAYOUT.ADD_LAYERS
|
// LAYOUT.ADD_LAYERS
|
||||||
const state = new ThemeViewState(new LayoutConfig(<any> layout), availableLayers)
|
const state = new ThemeViewState(new LayoutConfig(<any> layout), availableLayers)
|
||||||
const main = new SvelteUIElement(ThemeViewGUI, { state })
|
new ThemeViewGUI({
|
||||||
main.AttachTo("maindiv")
|
target: document.getElementById("maindiv"),
|
||||||
|
props: {state}
|
||||||
|
})
|
||||||
Array.from(document.getElementsByClassName("delete-on-load")).forEach(el => {
|
Array.from(document.getElementsByClassName("delete-on-load")).forEach(el => {
|
||||||
el.parentElement.removeChild(el)
|
el.parentElement.removeChild(el)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
|
||||||
import Leaderboard from "./UI/Leaderboard.svelte"
|
import Leaderboard from "./UI/Leaderboard.svelte"
|
||||||
|
|
||||||
new SvelteUIElement(Leaderboard, {}).AttachTo("main")
|
new Leaderboard({
|
||||||
|
target: document.getElementById("main")
|
||||||
|
})
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
|
||||||
import NotFound from "./UI/NotFound.svelte"
|
import NotFound from "./UI/NotFound.svelte"
|
||||||
|
|
||||||
new SvelteUIElement(NotFound, {}).AttachTo("maindiv")
|
new NotFound({
|
||||||
|
target: document.getElementById("maindiv")
|
||||||
|
})
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
|
||||||
import PrivacyGui from "./UI/PrivacyGui.svelte"
|
import PrivacyGui from "./UI/PrivacyGui.svelte"
|
||||||
new SvelteUIElement(PrivacyGui, {}).AttachTo("main")
|
new PrivacyGui({
|
||||||
|
target: document.getElementById("main")
|
||||||
|
})
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
import SvelteUIElement from "./UI/Base/SvelteUIElement"
|
||||||
import Test from "./UI/Test.svelte"
|
import Test from "./UI/Test.svelte"
|
||||||
|
|
||||||
new SvelteUIElement(Test).AttachTo("maindiv")
|
new Test({
|
||||||
|
target: document.getElementById("maindiv")
|
||||||
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue