forked from MapComplete/MapComplete
Merge branch 'develop' into Robin-patch-1
This commit is contained in:
commit
217d206a06
23 changed files with 327 additions and 769698 deletions
|
@ -401,6 +401,13 @@
|
|||
"uk": "Кронштейн з можливістю використання замка через вушко. Підсідельна труба може утримуватися на стійці за допомогою анкера",
|
||||
"ca": "Un suport inclinat amb possibilitat d'utilitzar un cadenat a través de l'ullet. El tub del seient es pot sostenir al suport amb un anclatge"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "bicycle_parking=anchors",
|
||||
"then": {
|
||||
"en": "An anchor - a metal loop wide enough for a bike lock attached to a wall, the floor or a boulder.",
|
||||
"nl": "Een anker - een metalen lus waar een fietsslot door kan en vastgemaakt aan de muur of vloer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": "Bicycle parking type"
|
||||
|
|
|
@ -102,7 +102,13 @@
|
|||
"render": "#000000",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "maxspeed=",
|
||||
"if": {
|
||||
"and": [
|
||||
"maxspeed=",
|
||||
"maxspeed:forward=",
|
||||
"maxspeed:backward="
|
||||
]
|
||||
},
|
||||
"then": "#ff0000"
|
||||
}
|
||||
]
|
||||
|
@ -112,6 +118,7 @@
|
|||
],
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "maxspeed-maxspeed",
|
||||
"render": {
|
||||
"en": "The maximum allowed speed on this road is {canonical(maxspeed)}",
|
||||
"de": "Die zulässige Höchstgeschwindigkeit auf dieser Straße beträgt {canonical(maxspeed)}",
|
||||
|
@ -135,7 +142,10 @@
|
|||
},
|
||||
"freeform": {
|
||||
"key": "maxspeed",
|
||||
"type": "pnat"
|
||||
"type": "pnat",
|
||||
"addExtraTags": [
|
||||
"_forward_backward=no"
|
||||
]
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
|
@ -162,9 +172,70 @@
|
|||
"maxspeed=20"
|
||||
],
|
||||
"hideInAnswer": "_country!=be"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"maxspeed=",
|
||||
"_forward_backward=yes"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"en": "The maximum allowed speed on this road depends on the direction a vehicle goes"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": "maxspeed-maxspeed"
|
||||
"condition": {
|
||||
"or": [
|
||||
"maxspeed~*",
|
||||
{
|
||||
"and": [
|
||||
"maxspeed:forward=",
|
||||
"maxspeed:backward="
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "maxspeed-forward",
|
||||
"condition": {
|
||||
"or": [
|
||||
"maxspeed:backward~*",
|
||||
"maxspeed:forward~*",
|
||||
"_forward_backward=yes"
|
||||
]
|
||||
},
|
||||
"question": {
|
||||
"en": "What is the maximum allowed speed when travelling {direction_absolute()}?"
|
||||
},
|
||||
"render": {
|
||||
"en": "The maximum allowed speed when travelling {direction_absolute()} on this road is {canonical(maxspeed:forward)}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "maxspeed:forward",
|
||||
"type": "pnat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "maxspeed-backward",
|
||||
"condition": {
|
||||
"or": [
|
||||
"maxspeed:forward~*",
|
||||
"maxspeed:backward~*",
|
||||
"_forward_backward=yes"
|
||||
]
|
||||
},
|
||||
"question": {
|
||||
"en": "What is the maximum allowed speed when travelling {direction_absolute(,180)}?"
|
||||
},
|
||||
"render": {
|
||||
"en": "The maximum allowed speed when travelling {direction_absolute(,180)} on this road is {canonical(maxspeed:backward)}"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "maxspeed:backward",
|
||||
"type": "pnat"
|
||||
}
|
||||
}
|
||||
],
|
||||
"allowMove": false,
|
||||
|
@ -177,6 +248,20 @@
|
|||
"denominations": [
|
||||
"mph"
|
||||
]
|
||||
},
|
||||
"maxspeed:forward": {
|
||||
"quantity": "speed",
|
||||
"canonical": "kmh",
|
||||
"denominations": [
|
||||
"mph"
|
||||
]
|
||||
},
|
||||
"maxspeed:backward": {
|
||||
"quantity": "speed",
|
||||
"canonical": "kmh",
|
||||
"denominations": [
|
||||
"mph"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
"ko": "감시 카메라 및 기타 감시 수단"
|
||||
},
|
||||
"icon": "./assets/themes/surveillance/logo.svg",
|
||||
"defaultBackgroundId": "maptiler.carto",
|
||||
"layers": [
|
||||
"surveillance_camera",
|
||||
{
|
||||
|
|
|
@ -391,6 +391,7 @@
|
|||
"recentThemes": "Recently visited maps",
|
||||
"recents": "Recently seen places",
|
||||
"search": "Search a location",
|
||||
"searchShort": "Search…",
|
||||
"searching": "Searching…"
|
||||
},
|
||||
"searchAnswer": "Search an option",
|
||||
|
|
|
@ -7542,6 +7542,65 @@
|
|||
"render": "Memorial plaque"
|
||||
}
|
||||
},
|
||||
"mobility_hub": {
|
||||
"description": "Mobility hubs are places where different kinds of transit meet, making it easy to switch between them. These places are usually part of a larger network or system.",
|
||||
"name": "Mobility Hubs",
|
||||
"presets": {
|
||||
"0": {
|
||||
"description": "A mobility hub which is marked by a physical sign, usually with a logo.",
|
||||
"title": "a mobility hub"
|
||||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"name": {
|
||||
"freeform": {
|
||||
"placeholder": "Name of the mobility hub"
|
||||
},
|
||||
"question": "What is the name of this mobility hub?",
|
||||
"render": "This mobility hub is called {name}"
|
||||
},
|
||||
"network": {
|
||||
"freeform": {
|
||||
"placeholder": "Network for this mobility hub"
|
||||
},
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This mobility hub belongs to the Groningen-Drenthe network"
|
||||
},
|
||||
"1": {
|
||||
"then": "This mobility hub belongs to the Hoppin network"
|
||||
},
|
||||
"2": {
|
||||
"then": "This mobility hub belongs to the Jelbi network"
|
||||
}
|
||||
},
|
||||
"question": "To which network does this mobility hub belong to?",
|
||||
"render": "This mobility hub belongs to the network {network}"
|
||||
},
|
||||
"physical_marker": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This mobility hub is marked by a board, containing information about the hub"
|
||||
},
|
||||
"1": {
|
||||
"then": "This mobility hub is marked by a sign with an electronic display"
|
||||
},
|
||||
"2": {
|
||||
"then": "This mobility hub is marked by a simple sign showing only basic information like the logo or name"
|
||||
}
|
||||
},
|
||||
"question": "What kind of physical marker is used to mark this mobility hub?"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Mobility hub {name}"
|
||||
}
|
||||
},
|
||||
"render": "Mobility hub"
|
||||
}
|
||||
},
|
||||
"mountain_rescue": {
|
||||
"description": "A building where first aid responders store material and might be on watch",
|
||||
"name": "Mountain rescue stations",
|
||||
|
|
|
@ -6566,6 +6566,65 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"mobility_hub": {
|
||||
"description": "Mobiliteitshubs zijn plaatsen waar verschillende soorten vervoer bij elkaar komen, waardoor het makkelijk is om te wisselen van vervoer. Deze plaatsen maken meestal deel uit van een groter netwerk of systeem.",
|
||||
"name": "Mobiliteitshubs",
|
||||
"presets": {
|
||||
"0": {
|
||||
"description": "Een mobiliteitshub die gemarkeerd is door een fysiek bord, meestal met een logo.",
|
||||
"title": "een mobiliteitshub"
|
||||
}
|
||||
},
|
||||
"tagRenderings": {
|
||||
"name": {
|
||||
"freeform": {
|
||||
"placeholder": "Naam van de mobiliteitshub"
|
||||
},
|
||||
"question": "Wat is de naam van deze mobiliteitshub?",
|
||||
"render": "Deze mobiliteitshub heet {name}"
|
||||
},
|
||||
"network": {
|
||||
"freeform": {
|
||||
"placeholder": "Netwerk van deze mobiliteitshub"
|
||||
},
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Deze mobiliteitshub hoort bij het netwerk Groningen-Drenthe"
|
||||
},
|
||||
"1": {
|
||||
"then": "Deze mobiliteitshub hoort bij het Hoppin netwerk"
|
||||
},
|
||||
"2": {
|
||||
"then": "Deze mobiliteitshub hoort bij het Jelbi netwerk"
|
||||
}
|
||||
},
|
||||
"question": "Bij welk netwerk hoort deze mobiliteitshub?",
|
||||
"render": "Deze mobiliteitshub hoort bij het netwerk {network}"
|
||||
},
|
||||
"physical_marker": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Deze mobiliteitshub is gemarkeerd door een bord, met informatie over de hub"
|
||||
},
|
||||
"1": {
|
||||
"then": "Deze mobiliteitshub is gemarkeerd door een bord met een elektronisch display"
|
||||
},
|
||||
"2": {
|
||||
"then": "Deze mobiliteitshub is gemarkeerd door een eenvoudig bord met alleen simpele informatie zoals het logo of de naam"
|
||||
}
|
||||
},
|
||||
"question": "Wat voor fysieke markering is er voor deze mobiliteitshub?"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Mobiliteitshub {name}"
|
||||
}
|
||||
},
|
||||
"render": "Mobiliteitshub"
|
||||
}
|
||||
},
|
||||
"nature_reserve": {
|
||||
"description": "Een natuurgebied is een gebied waar actief ruimte gemaakt word voor de natuur. Typisch zijn deze in beheer van Natuurpunt of het Agentschap Natuur en Bos of zijn deze erkend door de overheid.",
|
||||
"filter": {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -362,11 +362,7 @@ class NsiLogos extends Script {
|
|||
|
||||
private async patchNsiFile() {
|
||||
const files = NsiLogos.downloadedFiles()
|
||||
let path = "./public/assets/data/nsi/nsi.min.json"
|
||||
const otherPath = "./assets/data/nsi/nsi.min.json"
|
||||
if (existsSync(otherPath) && !existsSync(path)) {
|
||||
path = otherPath
|
||||
}
|
||||
const path = "./public/assets/data/nsi/nsi.min.json"
|
||||
const nsi = JSON.parse(readFileSync(path, "utf8"))
|
||||
const types = nsi.nsi
|
||||
|
||||
|
|
|
@ -21,24 +21,8 @@ class ServerLdScrape extends Script {
|
|||
/* {
|
||||
"User-Agent": "MapComplete/openstreetmap scraper; pietervdvn@posteo.net; https://source.mapcomplete.org/MapComplete",
|
||||
"accept": "application/html"
|
||||
},
|
||||
{
|
||||
Host: host,
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:122.0) Gecko/20100101 Firefox/122.0",
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,* /*;q=0.8", TODO remove space in * /*
|
||||
"Accept-Language": "en-US,en;q=0.5",
|
||||
"Accept-Encoding": "gzip, deflate, br",
|
||||
"Alt-Used": host,
|
||||
DNT: 1,
|
||||
"Sec-GPC": 1,
|
||||
"Upgrade-Insecure-Requests": 1,
|
||||
"Sec-Fetch-Dest": "document",
|
||||
"Sec-Fetch-Mode": "navigate",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"Sec-Fetch-User":"?1",
|
||||
"TE": "trailers",
|
||||
Connection: "keep-alive"
|
||||
}*/
|
||||
},*/
|
||||
|
||||
]
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
try {
|
||||
|
|
|
@ -10,12 +10,12 @@ import {
|
|||
MultiPolygon,
|
||||
Point,
|
||||
Polygon,
|
||||
Position,
|
||||
Position
|
||||
} from "geojson"
|
||||
import { Tiles } from "../Models/TileRange"
|
||||
import { Utils } from "../Utils"
|
||||
|
||||
;("use strict")
|
||||
("use strict")
|
||||
|
||||
export class GeoOperations {
|
||||
private static readonly _earthRadius: number = 6378137
|
||||
|
@ -1051,6 +1051,8 @@ export class GeoOperations {
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts various types of possible bearings into degrees, with 0 being north, 90 being east.
|
||||
*
|
||||
* GeoOperations.parseBearing("N") // => 0
|
||||
* GeoOperations.parseBearing("E") // => 90
|
||||
* GeoOperations.parseBearing("NE") // => 45
|
||||
|
@ -1064,7 +1066,7 @@ export class GeoOperations {
|
|||
* GeoOperations.parseBearing(-270) // => 90
|
||||
*
|
||||
*/
|
||||
public static parseBearing(str: string | number) {
|
||||
public static parseBearing(str: string | number): number {
|
||||
let n: number
|
||||
if (typeof str === "string") {
|
||||
str = str.trim()
|
||||
|
|
|
@ -11,15 +11,14 @@ import ChangeTagAction from "./ChangeTagAction"
|
|||
import { And } from "../../Tags/And"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { OsmConnection } from "../OsmConnection"
|
||||
import { Feature } from "@turf/turf"
|
||||
import { Geometry, LineString, Point } from "geojson"
|
||||
import { Feature, Geometry, LineString, Point } from "geojson"
|
||||
import FullNodeDatabaseSource from "../../FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
|
||||
|
||||
export default class ReplaceGeometryAction extends OsmChangeAction implements PreviewableAction {
|
||||
/**
|
||||
* The target feature - mostly used for the metadata
|
||||
*/
|
||||
private readonly feature: any
|
||||
private readonly feature: Feature
|
||||
private readonly state: {
|
||||
osmConnection: OsmConnection
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
|
@ -48,7 +47,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
osmConnection: OsmConnection
|
||||
fullNodeDatabase?: FullNodeDatabaseSource
|
||||
},
|
||||
feature: any,
|
||||
feature: Feature,
|
||||
wayToReplaceId: string,
|
||||
options: {
|
||||
theme: string
|
||||
|
@ -65,13 +64,13 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
const geom = this.feature.geometry
|
||||
let coordinates: [number, number][]
|
||||
if (geom.type === "LineString") {
|
||||
coordinates = geom.coordinates
|
||||
coordinates = <[number, number][]>geom.coordinates
|
||||
} else if (geom.type === "Polygon") {
|
||||
coordinates = geom.coordinates[0]
|
||||
coordinates = <[number, number][]>geom.coordinates[0]
|
||||
}
|
||||
this.targetCoordinates = coordinates
|
||||
|
||||
this.identicalTo = coordinates.map((_) => undefined)
|
||||
this.identicalTo = coordinates.map(() => undefined)
|
||||
|
||||
for (let i = 0; i < coordinates.length; i++) {
|
||||
if (this.identicalTo[i] !== undefined) {
|
||||
|
@ -204,7 +203,6 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
if (nodeDb === undefined) {
|
||||
throw "PANIC: replaceGeometryAction needs the FullNodeDatabase, which is undefined. This should be initialized by having the 'type_node'-layer enabled in your theme. (NB: the replacebutton has type_node as dependency)"
|
||||
}
|
||||
const self = this
|
||||
let parsed: OsmObject[]
|
||||
{
|
||||
// Gather the needed OsmObjects
|
||||
|
@ -214,6 +212,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
if (idN < 0 || type !== "way") {
|
||||
throw "Invalid ID to conflate: " + this.wayToReplaceId
|
||||
}
|
||||
|
||||
const url = `${
|
||||
this.state.osmConnection?._oauth_config?.url ?? "https://api.openstreetmap.org"
|
||||
}/api/0.6/${this.wayToReplaceId}/full`
|
||||
|
@ -270,7 +269,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
const partOfSomeWay = parentWayIds.length > 0
|
||||
const hasTags = Object.keys(node.tags).length > 1
|
||||
|
||||
const nodeDistances = this.targetCoordinates.map((_) => undefined)
|
||||
const nodeDistances = this.targetCoordinates.map(() => undefined)
|
||||
for (let i = 0; i < this.targetCoordinates.length; i++) {
|
||||
if (this.identicalTo[i] !== undefined) {
|
||||
continue
|
||||
|
@ -295,7 +294,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
})
|
||||
}
|
||||
|
||||
const closestIds = this.targetCoordinates.map((_) => undefined)
|
||||
const closestIds = this.targetCoordinates.map(() => undefined)
|
||||
const unusedIds = new Map<
|
||||
number,
|
||||
{
|
||||
|
@ -330,7 +329,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
// We found a candidate... Search the corresponding target id:
|
||||
let targetId: number = undefined
|
||||
let lowestDistance = Number.MAX_VALUE
|
||||
let nodeDistances = distances.get(candidate)
|
||||
const nodeDistances = distances.get(candidate)
|
||||
for (let i = 0; i < nodeDistances.length; i++) {
|
||||
const d = nodeDistances[i]
|
||||
if (d !== undefined && d < lowestDistance) {
|
||||
|
@ -400,7 +399,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
properties: {},
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: self.targetCoordinates,
|
||||
coordinates: this.targetCoordinates
|
||||
},
|
||||
}
|
||||
const projected = GeoOperations.nearestPoint(way, [node.lon, node.lat])
|
||||
|
@ -528,7 +527,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction implements Pr
|
|||
|
||||
// Some nodes might need to be deleted
|
||||
if (detachedNodes.size > 0) {
|
||||
detachedNodes.forEach(({ hasTags, reason }, nodeId) => {
|
||||
detachedNodes.forEach(({ hasTags }, nodeId) => {
|
||||
const parentWays = nodeDb.GetParentWays(nodeId)
|
||||
const index = parentWays.data.map((w) => w.id).indexOf(osmWay.id)
|
||||
if (index < 0) {
|
||||
|
|
|
@ -233,7 +233,6 @@ export class Changes {
|
|||
...addSource(DeleteAction.metatags, "DeleteAction"),
|
||||
// TODO
|
||||
/*
|
||||
...DeleteAction.metatags,
|
||||
...LinkImageAction.metatags,
|
||||
...OsmChangeAction.metatags,
|
||||
...RelationSplitHandler.metatags,
|
||||
|
@ -446,6 +445,10 @@ export class Changes {
|
|||
// Apply tag changes
|
||||
for (const kv of change.tags ?? []) {
|
||||
const k = kv.k
|
||||
if (k.startsWith("_")) {
|
||||
// These values are ignored later on anyways
|
||||
continue
|
||||
}
|
||||
let v = kv.v
|
||||
|
||||
if (v === "") {
|
||||
|
|
|
@ -149,16 +149,14 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
|
|||
}
|
||||
|
||||
if (json.defaultBackgroundId) {
|
||||
/*
|
||||
TODO re-enable this check
|
||||
const backgroundId = json.defaultBackgroundId
|
||||
|
||||
const isCategory =
|
||||
backgroundId === "photo" || backgroundId === "map" || backgroundId === "osmbasedmap"
|
||||
|
||||
if (!isCategory && !ValidateTheme._availableLayers.has(backgroundId)) {
|
||||
const options = Array.from(ValidateTheme._availableLayers)
|
||||
const nearby = Utils.sortedByLevenshteinDistance(backgroundId, options, (t) => t)
|
||||
const knownIds = Array.from(AvailableRasterLayers.allAvailableGlobalLayers).map(l => l.properties.id)
|
||||
const available = new Set(knownIds)
|
||||
if (!isCategory && !available.has(backgroundId)) {
|
||||
const nearby = Utils.sortedByLevenshteinDistance(backgroundId, knownIds, (t) => t)
|
||||
context
|
||||
.enter("defaultBackgroundId")
|
||||
.err(
|
||||
|
@ -166,7 +164,7 @@ export class ValidateTheme extends DesugaringStep<ThemeConfigJson> {
|
|||
.slice(0, 5)
|
||||
.join(", ")}`,
|
||||
)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < theme.layers.length; i++) {
|
||||
|
|
|
@ -363,7 +363,7 @@ export class DetectNonErasedKeysInMappings extends DesugaringStep<QuestionableTa
|
|||
addAll(mappingKey, neededKeys)
|
||||
}
|
||||
|
||||
neededKeys.delete("fixme") // fixme gets a free pass
|
||||
neededKeys.delete("fixme") // gets a free pass
|
||||
|
||||
if (json.freeform) {
|
||||
for (const neededKey of neededKeys) {
|
||||
|
|
|
@ -35,7 +35,7 @@ export interface DeleteConfigJson {
|
|||
*/
|
||||
explanation: string | any
|
||||
/**
|
||||
* The text that will be uploaded into the changeset or will be used in the fixme in case of a soft deletion
|
||||
* The text that will be uploaded into the changeset or will be used in the `fix me` in case of a soft deletion
|
||||
* Should be a few words, in english
|
||||
*
|
||||
* question: What should be added to the changeset as delete reason?
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<label
|
||||
class="neutral-label normal-background box-shadow flex w-full items-center rounded-full border border-black"
|
||||
>
|
||||
<SearchIcon aria-hidden="true" class="ml-2 h-8 w-8" />
|
||||
<SearchIcon aria-hidden="true" class="ml-2 h-6 w-6 shrink-0" />
|
||||
|
||||
<input
|
||||
bind:this={inputElement}
|
||||
|
@ -59,8 +59,11 @@
|
|||
type="search"
|
||||
style=" --tw-ring-color: rgb(0 0 0 / 0) !important;"
|
||||
class="ml-1 w-full border-none px-0 outline-none"
|
||||
on:keypress={(keypr) => {
|
||||
return keypr.key === "Enter" ? dispatch("search") : undefined
|
||||
on:keypress={(event) => {
|
||||
if( event.key === "Enter"){
|
||||
dispatch("search")
|
||||
event.preventDefault()
|
||||
}
|
||||
}}
|
||||
bind:value={_value}
|
||||
use:set_placeholder={placeholder}
|
||||
|
@ -79,5 +82,6 @@
|
|||
{:else}
|
||||
<div class="mr-3 w-6" />
|
||||
{/if}
|
||||
<slot name="button-right" />
|
||||
</label>
|
||||
</form>
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
undefined
|
||||
)
|
||||
|
||||
const map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined)
|
||||
export let map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined)
|
||||
export let mapProperties: Partial<MapProperties> & { location } = {
|
||||
zoom: new UIEventSource<number>(19),
|
||||
maxbounds: new UIEventSource(undefined),
|
||||
|
|
|
@ -9,7 +9,8 @@ import FilteredLayer from "../../../Models/FilteredLayer"
|
|||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
import { LayerConfigJson } from "../../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
import conflation_json from "../../../../assets/layers/conflation/conflation.json"
|
||||
import ThemeViewState from "../../../Models/ThemeViewState"
|
||||
import { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
import { OsmTags } from "../../../Models/OsmFeature"
|
||||
|
||||
export interface ImportFlowArguments {
|
||||
readonly text: string
|
||||
|
@ -65,7 +66,7 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
* Given the tagsstore of the point which represents the challenge, creates a new store with tags that should be applied onto the newly created point,
|
||||
*/
|
||||
public static getTagsToApply(
|
||||
originalFeatureTags: UIEventSource<any>,
|
||||
originalFeatureTags: UIEventSource<OsmTags>,
|
||||
args: { tags: string }
|
||||
): Store<Tag[]> {
|
||||
if (originalFeatureTags === undefined) {
|
||||
|
@ -109,9 +110,7 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
* Others (e.g.: snapOnto-layers) are not to be handled here
|
||||
*/
|
||||
public static getLayerDependencies(argsRaw: string[], argSpec?): string[] {
|
||||
const args: ImportFlowArguments = <any>(
|
||||
Utils.ParseVisArgs(argSpec ?? ImportFlowUtils.generalArguments, argsRaw)
|
||||
)
|
||||
const args = Utils.ParseVisArgs<ImportFlowArguments>(argSpec ?? ImportFlowUtils.generalArguments, argsRaw)
|
||||
return args.targetLayer.split(" ")
|
||||
}
|
||||
|
||||
|
@ -139,14 +138,14 @@ ${Utils.special_visualizations_importRequirementDocs}
|
|||
* This class works together closely with ImportFlow.svelte
|
||||
*/
|
||||
export default abstract class ImportFlow<ArgT extends ImportFlowArguments> {
|
||||
public readonly state: ThemeViewState
|
||||
public readonly state: SpecialVisualizationState
|
||||
public readonly args: ArgT
|
||||
public readonly targetLayer: FilteredLayer[]
|
||||
public readonly tagsToApply: Store<Tag[]>
|
||||
protected readonly _originalFeatureTags: UIEventSource<Record<string, string>>
|
||||
|
||||
constructor(
|
||||
state: ThemeViewState,
|
||||
state: SpecialVisualizationState,
|
||||
args: ArgT,
|
||||
tagsToApply: Store<Tag[]>,
|
||||
originalTags: UIEventSource<Record<string, string>>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import type { MoveReason } from "./MoveWizardState"
|
||||
import { MoveWizardState } from "./MoveWizardState"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
|
@ -15,11 +15,18 @@
|
|||
import Constants from "../../Models/Constants"
|
||||
import LoginToggle from "../Base/LoginToggle.svelte"
|
||||
import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
|
||||
|
||||
|
||||
import ChevronLeft from "@babeard/svelte-heroicons/solid/ChevronLeft"
|
||||
import ThemeViewState from "../../Models/ThemeViewState"
|
||||
import Icon from "../Map/Icon.svelte"
|
||||
import NewPointLocationInput from "../BigComponents/NewPointLocationInput.svelte"
|
||||
import type { WayId } from "../../Models/OsmFeature"
|
||||
import Searchbar from "../Base/Searchbar.svelte"
|
||||
import { NominatimGeocoding } from "../../Logic/Search/NominatimGeocoding"
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import { Map as MlMap } from "maplibre-gl"
|
||||
import type { GeocodeResult } from "../../Logic/Search/GeocodingProvider"
|
||||
|
||||
export let state: ThemeViewState
|
||||
|
||||
|
@ -37,8 +44,8 @@
|
|||
|
||||
let snappedTo = new UIEventSource<WayId | undefined>(undefined)
|
||||
|
||||
function initMapProperties(reason: MoveReason) {
|
||||
return <any>{
|
||||
function initMapProperties(reason: MoveReason): Partial<MapProperties> & { location } {
|
||||
return {
|
||||
allowMoving: new UIEventSource(true),
|
||||
allowRotating: new UIEventSource(false),
|
||||
allowZooming: new UIEventSource(true),
|
||||
|
@ -55,7 +62,30 @@
|
|||
reason.setData(moveWizardState.reasons[0])
|
||||
}
|
||||
let notAllowed = moveWizardState.moveDisallowedReason
|
||||
let currentMapProperties: MapProperties = undefined
|
||||
let currentMapProperties: Store<Partial<MapProperties> & { location }> = reason.mapD(r => initMapProperties(r))
|
||||
let map: UIEventSource<MlMap> = new UIEventSource<MlMap>(undefined)
|
||||
|
||||
|
||||
let searchValue = new UIEventSource<string>("")
|
||||
let isSearching = new UIEventSource<boolean>(false)
|
||||
const searcher = new NominatimGeocoding(1)
|
||||
|
||||
|
||||
async function searchPressed() {
|
||||
const v = searchValue.data
|
||||
console.log("Search is pressed", v)
|
||||
isSearching.set(true)
|
||||
const result: GeocodeResult[] = await searcher.search(v)
|
||||
isSearching.set(false)
|
||||
if (result.length == 0 || currentMapProperties.data === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const loc = result[0]
|
||||
console.log("Found", result, "flying")
|
||||
map.data.flyTo({ zoom: 18, center: [loc.lon, loc.lat] })
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{#if moveWizardState.reasons.length > 0}
|
||||
|
@ -94,9 +124,23 @@
|
|||
</button>
|
||||
{/each}
|
||||
{:else if currentStep === "pick_location" || currentStep === "reason"}
|
||||
{#if $reason.includeSearch}
|
||||
<Searchbar value={searchValue} on:search={() => searchPressed()}>
|
||||
<svelte:fragment slot="button-right">
|
||||
{#if $isSearching}
|
||||
<Loading />
|
||||
{:else}
|
||||
<button class="primary" class:disabled={$searchValue.length === 0} on:click={() => searchPressed()}>
|
||||
<Tr t={Translations.t.general.search.searchShort} />
|
||||
</button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Searchbar>
|
||||
{/if}
|
||||
<div class="relative h-64 w-full">
|
||||
<NewPointLocationInput
|
||||
mapProperties={(currentMapProperties = initMapProperties($reason))}
|
||||
{map}
|
||||
mapProperties={$currentMapProperties}
|
||||
value={newLocation}
|
||||
{state}
|
||||
coordinate={{ lon, lat }}
|
||||
|
@ -112,13 +156,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{#if $reason.includeSearch}
|
||||
<!-- TODO -->
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<If
|
||||
condition={currentMapProperties.zoom.mapD(
|
||||
condition={$currentMapProperties.zoom.mapD(
|
||||
(zoom) => zoom >= Constants.minZoomLevelToAddNewPoint
|
||||
)}
|
||||
>
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
</script>
|
||||
|
||||
{#if tags?.length > 0}
|
||||
<div class="flex gap-x-4">
|
||||
|
||||
{#each tags as tag}
|
||||
<div class="break-words" style="word-break: break-word">
|
||||
{#if tag["value"] === ""}
|
||||
|
@ -25,6 +27,7 @@
|
|||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<slot name="no-tags">
|
||||
<Tr cls="subtle" t={Translations.t.general.noTagsSelected} />
|
||||
|
|
|
@ -137,7 +137,6 @@
|
|||
}
|
||||
unseenFreeformValues.splice(index, 1)
|
||||
}
|
||||
// TODO this has _to much_ values
|
||||
freeformInput.set(unseenFreeformValues.join(";"))
|
||||
if (checkedMappings.length + 1 < mappings.length) {
|
||||
checkedMappings.push(unseenFreeformValues.length > 0)
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { FixedUiElement } from "./Base/FixedUiElement"
|
||||
import BaseUIElement from "./BaseUIElement"
|
||||
import { default as FeatureTitle } from "./Popup/Title.svelte"
|
||||
import {
|
||||
RenderingSpecification,
|
||||
SpecialVisualization,
|
||||
SpecialVisualizationState,
|
||||
} from "./SpecialVisualization"
|
||||
import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization"
|
||||
import { HistogramViz } from "./Popup/HistogramViz"
|
||||
import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
|
||||
import { MultiApplyViz } from "./Popup/MultiApplyViz"
|
||||
|
@ -40,8 +36,11 @@ import { UISpecialVisualisations } from "./SpecialVisualisations/UISpecialVisual
|
|||
import { SettingsVisualisations } from "./SpecialVisualisations/SettingsVisualisations"
|
||||
import { ReviewSpecialVisualisations } from "./SpecialVisualisations/ReviewSpecialVisualisations"
|
||||
import { DataImportSpecialVisualisations } from "./SpecialVisualisations/DataImportSpecialVisualisations"
|
||||
import TagrenderingManipulationSpecialVisualisations from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations"
|
||||
import { WebAndCommunicationSpecialVisualisations } from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations"
|
||||
import TagrenderingManipulationSpecialVisualisations
|
||||
from "./SpecialVisualisations/TagrenderingManipulationSpecialVisualisations"
|
||||
import {
|
||||
WebAndCommunicationSpecialVisualisations
|
||||
} from "./SpecialVisualisations/WebAndCommunicationSpecialVisualisations"
|
||||
import ClearGPSHistory from "./BigComponents/ClearGPSHistory.svelte"
|
||||
import AllFeaturesStatistics from "./Statistics/AllFeaturesStatistics.svelte"
|
||||
|
||||
|
@ -524,6 +523,11 @@ export default class SpecialVisualizations {
|
|||
doc: "The attribute containing the degrees",
|
||||
defaultValue: "_direction:centerpoint",
|
||||
},
|
||||
{
|
||||
name: "offset",
|
||||
doc: "Offset value that is added to the actual value, e.g. `180` to indicate the opposite (backward) direction",
|
||||
defaultValue: "0"
|
||||
}
|
||||
],
|
||||
|
||||
constr(
|
||||
|
@ -532,6 +536,8 @@ export default class SpecialVisualizations {
|
|||
args: string[]
|
||||
): BaseUIElement {
|
||||
const key = args[0] === "" ? "_direction:centerpoint" : args[0]
|
||||
const offset = args[1] === "" ? 0 : Number(args[1])
|
||||
|
||||
return new VariableUiElement(
|
||||
tagSource
|
||||
.map((tags) => {
|
||||
|
@ -540,7 +546,7 @@ export default class SpecialVisualizations {
|
|||
})
|
||||
.mapD((value) => {
|
||||
const dir = GeoOperations.bearingToHuman(
|
||||
GeoOperations.parseBearing(value)
|
||||
GeoOperations.parseBearing(value) + offset
|
||||
)
|
||||
console.log("Human dir", dir)
|
||||
return Translations.t.general.visualFeedback.directionsAbsolute[dir]
|
||||
|
|
|
@ -81,7 +81,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
/**
|
||||
* Parses the arguments for special visualisations
|
||||
*/
|
||||
public static ParseVisArgs<T extends Record<string, string>>(
|
||||
public static ParseVisArgs<T = Record<string, string>>(
|
||||
specs: { name: string; defaultValue?: string }[],
|
||||
args: string[]
|
||||
): T {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue