Merge branch 'develop'
This commit is contained in:
commit
217c103adc
75 changed files with 4344 additions and 2521 deletions
30
Docs/Hotkeys.md
Normal file
30
Docs/Hotkeys.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
|
||||
Hotkeys
|
||||
=========
|
||||
|
||||
|
||||
|
||||
## Table of contents
|
||||
|
||||
1. [Hotkeys](#hotkeys)
|
||||
|
||||
|
||||
|
||||
MapComplete supports the following keys:
|
||||
|
||||
|
||||
|
||||
Key combination | Action
|
||||
----------------- | --------
|
||||
B | Opens the Background, layers and filters panel
|
||||
Escape | Close the sidebar
|
||||
L | Pan the map to the current location or zoom the map to the current location. Requests geopermission
|
||||
M | Switch to a background layer of category map
|
||||
O | Switch to a background layer of category osmbasedmap
|
||||
P | Switch to a background layer of category photo
|
||||
ctrl+F | Select the search bar to search locations
|
||||
shift+O | Switch to default Mapnik-OpenStreetMap background
|
||||
|
||||
|
||||
This document is autogenerated from
|
|
@ -1,230 +1,135 @@
|
|||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import Svg from "../../Svg"
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
import { VariableUiElement } from "../../UI/Base/VariableUIElement"
|
||||
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
||||
import { QueryParameters } from "../Web/QueryParameters"
|
||||
import { BBox } from "../BBox"
|
||||
import Constants from "../../Models/Constants"
|
||||
import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource"
|
||||
import { GeoLocationPointProperties, GeoLocationState } from "../State/GeoLocationState"
|
||||
import State from "../../State"
|
||||
import { UIEventSource } from "../UIEventSource"
|
||||
|
||||
export interface GeoLocationPointProperties {
|
||||
id: "gps"
|
||||
"user:location": "yes"
|
||||
date: string
|
||||
latitude: number
|
||||
longitude: number
|
||||
speed: number
|
||||
accuracy: number
|
||||
heading: number
|
||||
altitude: number
|
||||
}
|
||||
/**
|
||||
* The geolocation-handler takes a map-location and a geolocation state.
|
||||
* It'll move the map as appropriate given the state of the geolocation-API
|
||||
* It will also copy the geolocation into the appropriate FeatureSource to display on the map
|
||||
*/
|
||||
export default class GeoLocationHandler {
|
||||
public readonly geolocationState: GeoLocationState
|
||||
private readonly _state: State
|
||||
public readonly mapHasMoved: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
|
||||
export default class GeoLocationHandler extends VariableUiElement {
|
||||
private readonly currentLocation?: SimpleFeatureSource
|
||||
|
||||
/**
|
||||
* Wether or not the geolocation is active, aka the user requested the current location
|
||||
*/
|
||||
private readonly _isActive: UIEventSource<boolean>
|
||||
|
||||
/**
|
||||
* Wether or not the geolocation is locked, aka the user requested the current location and wants the crosshair to follow the user
|
||||
*/
|
||||
private readonly _isLocked: UIEventSource<boolean>
|
||||
|
||||
/**
|
||||
* The callback over the permission API
|
||||
* @private
|
||||
*/
|
||||
private readonly _permission: UIEventSource<string>
|
||||
/**
|
||||
* Literally: _currentGPSLocation.data != undefined
|
||||
* @private
|
||||
*/
|
||||
private readonly _hasLocation: Store<boolean>
|
||||
private readonly _currentGPSLocation: UIEventSource<GeolocationCoordinates>
|
||||
/**
|
||||
* Kept in order to update the marker
|
||||
* @private
|
||||
*/
|
||||
private readonly _leafletMap: UIEventSource<L.Map>
|
||||
|
||||
/**
|
||||
* The date when the user requested the geolocation. If we have a location, it'll autozoom to it the first 30 secs
|
||||
*/
|
||||
private _lastUserRequest: UIEventSource<Date>
|
||||
|
||||
/**
|
||||
* A small flag on localstorage. If the user previously granted the geolocation, it will be set.
|
||||
* On firefox, the permissions api is broken (probably fingerprint resistiance) and "granted + don't ask again" doesn't stick between sessions.
|
||||
*
|
||||
* Instead, we set this flag. If this flag is set upon loading the page, we start geolocating immediately.
|
||||
* If the user denies the geolocation this time, we unset this flag
|
||||
* @private
|
||||
*/
|
||||
private readonly _previousLocationGrant: UIEventSource<string>
|
||||
private readonly _layoutToUse: LayoutConfig
|
||||
|
||||
constructor(state: {
|
||||
selectedElement: UIEventSource<any>
|
||||
currentUserLocation?: SimpleFeatureSource
|
||||
leafletMap: UIEventSource<any>
|
||||
layoutToUse: LayoutConfig
|
||||
featureSwitchGeolocation: UIEventSource<boolean>
|
||||
}) {
|
||||
const currentGPSLocation = new UIEventSource<GeolocationCoordinates>(
|
||||
undefined,
|
||||
"GPS-coordinate"
|
||||
)
|
||||
const leafletMap = state.leafletMap
|
||||
const initedAt = new Date()
|
||||
let autozoomDone = false
|
||||
const hasLocation = currentGPSLocation.map((location) => location !== undefined)
|
||||
const previousLocationGrant = LocalStorageSource.Get("geolocation-permissions")
|
||||
const isActive = new UIEventSource<boolean>(false)
|
||||
const isLocked = new UIEventSource<boolean>(false)
|
||||
const permission = new UIEventSource<string>("")
|
||||
const lastClick = new UIEventSource<Date>(undefined)
|
||||
const lastClickWithinThreeSecs = lastClick.map((lastClick) => {
|
||||
if (lastClick === undefined) {
|
||||
return false
|
||||
constructor(
|
||||
geolocationState: GeoLocationState,
|
||||
state: State // { locationControl: UIEventSource<Loc>, selectedElement: UIEventSource<any>, leafletMap?: UIEventSource<any> })
|
||||
) {
|
||||
this.geolocationState = geolocationState
|
||||
this._state = state
|
||||
const mapLocation = state.locationControl
|
||||
// Did an interaction move the map?
|
||||
let self = this
|
||||
let initTime = new Date()
|
||||
mapLocation.addCallbackD((_) => {
|
||||
if (new Date().getTime() - initTime.getTime() < 250) {
|
||||
return
|
||||
}
|
||||
const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
|
||||
return timeDiff <= 3
|
||||
self.mapHasMoved.setData(true)
|
||||
return true // Unsubscribe
|
||||
})
|
||||
|
||||
const latLonGiven =
|
||||
QueryParameters.wasInitialized("lat") && QueryParameters.wasInitialized("lon")
|
||||
const willFocus = lastClick.map((lastUserRequest) => {
|
||||
const timeDiffInited = (new Date().getTime() - initedAt.getTime()) / 1000
|
||||
if (!latLonGiven && !autozoomDone && timeDiffInited < Constants.zoomToLocationTimeout) {
|
||||
return true
|
||||
}
|
||||
if (lastUserRequest === undefined) {
|
||||
return false
|
||||
}
|
||||
const timeDiff = (new Date().getTime() - lastUserRequest.getTime()) / 1000
|
||||
return timeDiff <= Constants.zoomToLocationTimeout
|
||||
})
|
||||
const latLonGivenViaUrl =
|
||||
QueryParameters.wasInitialized("lat") || QueryParameters.wasInitialized("lon")
|
||||
if (latLonGivenViaUrl) {
|
||||
// The URL counts as a 'user interaction'
|
||||
this.mapHasMoved.setData(true)
|
||||
}
|
||||
|
||||
lastClick.addCallbackAndRunD((_) => {
|
||||
window.setTimeout(() => {
|
||||
if (lastClickWithinThreeSecs.data || willFocus.data) {
|
||||
lastClick.ping()
|
||||
this.geolocationState.currentGPSLocation.addCallbackAndRunD((newLocation) => {
|
||||
const timeSinceLastRequest =
|
||||
(new Date().getTime() - geolocationState.requestMoment.data?.getTime() ?? 0) / 1000
|
||||
if (!this.mapHasMoved.data) {
|
||||
// The map hasn't moved yet; we received our first coordinates, so let's move there!
|
||||
console.log(
|
||||
"Moving the map to an initial location; time since last request is",
|
||||
timeSinceLastRequest
|
||||
)
|
||||
if (timeSinceLastRequest < Constants.zoomToLocationTimeout) {
|
||||
self.MoveMapToCurrentLocation()
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
if (this.geolocationState.isLocked.data) {
|
||||
// Jup, the map is locked to the bound location: move automatically
|
||||
self.MoveMapToCurrentLocation()
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
super(
|
||||
hasLocation.map(
|
||||
(hasLocationData) => {
|
||||
if (permission.data === "denied") {
|
||||
return Svg.location_refused_svg()
|
||||
}
|
||||
|
||||
if (!isActive.data) {
|
||||
return Svg.location_empty_svg()
|
||||
}
|
||||
if (!hasLocationData) {
|
||||
// Position not yet found but we are active: we spin to indicate activity
|
||||
// If will focus is active too, we indicate this differently
|
||||
const icon = willFocus.data ? Svg.location_svg() : Svg.location_empty_svg()
|
||||
icon.SetStyle("animation: spin 4s linear infinite;")
|
||||
return icon
|
||||
}
|
||||
if (isLocked.data) {
|
||||
return Svg.location_locked_svg()
|
||||
}
|
||||
if (lastClickWithinThreeSecs.data) {
|
||||
return Svg.location_unlocked_svg()
|
||||
}
|
||||
|
||||
// We have a location, so we show a dot in the center
|
||||
return Svg.location_svg()
|
||||
},
|
||||
[isActive, isLocked, permission, lastClickWithinThreeSecs, willFocus]
|
||||
)
|
||||
)
|
||||
this.SetClass("mapcontrol")
|
||||
this._isActive = isActive
|
||||
this._isLocked = isLocked
|
||||
this._permission = permission
|
||||
this._previousLocationGrant = previousLocationGrant
|
||||
this._currentGPSLocation = currentGPSLocation
|
||||
this._leafletMap = leafletMap
|
||||
this._layoutToUse = state.layoutToUse
|
||||
this._hasLocation = hasLocation
|
||||
this._lastUserRequest = lastClick
|
||||
const self = this
|
||||
|
||||
const currentPointer = this._isActive.map(
|
||||
(isActive) => {
|
||||
if (isActive && !self._hasLocation.data) {
|
||||
return "cursor-wait"
|
||||
}
|
||||
return "cursor-pointer"
|
||||
},
|
||||
[this._hasLocation]
|
||||
)
|
||||
currentPointer.addCallbackAndRun((pointerClass) => {
|
||||
self.RemoveClass("cursor-wait")
|
||||
self.RemoveClass("cursor-pointer")
|
||||
self.SetClass(pointerClass)
|
||||
})
|
||||
|
||||
this.onClick(() => {
|
||||
/*
|
||||
* If the previous click was within 3 seconds (and we have an active location), then we lock to the location
|
||||
*/
|
||||
if (self._hasLocation.data) {
|
||||
if (isLocked.data) {
|
||||
isLocked.setData(false)
|
||||
} else if (lastClick.data !== undefined) {
|
||||
const timeDiff = (new Date().getTime() - lastClick.data.getTime()) / 1000
|
||||
if (timeDiff <= 3) {
|
||||
isLocked.setData(true)
|
||||
lastClick.setData(undefined)
|
||||
} else {
|
||||
lastClick.setData(new Date())
|
||||
}
|
||||
geolocationState.isLocked.map(
|
||||
(isLocked) => {
|
||||
if (isLocked) {
|
||||
state.leafletMap?.data?.dragging?.disable()
|
||||
} else {
|
||||
lastClick.setData(new Date())
|
||||
state.leafletMap?.data?.dragging?.enable()
|
||||
}
|
||||
},
|
||||
[state.leafletMap]
|
||||
)
|
||||
|
||||
this.CopyGeolocationIntoMapstate()
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the map to the GPS-location, except:
|
||||
* - If there is a selected element
|
||||
* - The location is out of the locked bound
|
||||
* - The GPS-location iss NULL-island
|
||||
* @constructor
|
||||
*/
|
||||
public MoveMapToCurrentLocation() {
|
||||
const newLocation = this.geolocationState.currentGPSLocation.data
|
||||
const mapLocation = this._state.locationControl
|
||||
const state = this._state
|
||||
// We got a new location.
|
||||
// Do we move the map to it?
|
||||
|
||||
if (state.selectedElement.data !== undefined) {
|
||||
// Nope, there is something selected, so we don't move to the current GPS-location
|
||||
return
|
||||
}
|
||||
if (newLocation.latitude === 0 && newLocation.longitude === 0) {
|
||||
console.debug("Not moving to GPS-location: it is null island")
|
||||
return
|
||||
}
|
||||
|
||||
// We check that the GPS location is not out of bounds
|
||||
const bounds = state.layoutToUse.lockLocation
|
||||
if (bounds && bounds !== true) {
|
||||
// B is an array with our lock-location
|
||||
const inRange = new BBox(bounds).contains([newLocation.longitude, newLocation.latitude])
|
||||
if (!inRange) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
self.init(true, true)
|
||||
mapLocation.setData({
|
||||
zoom: mapLocation.data.zoom,
|
||||
lon: newLocation.longitude,
|
||||
lat: newLocation.latitude,
|
||||
})
|
||||
this.mapHasMoved.setData(true)
|
||||
}
|
||||
|
||||
const doAutoZoomToLocation =
|
||||
!latLonGiven &&
|
||||
state.featureSwitchGeolocation.data &&
|
||||
state.selectedElement.data !== undefined
|
||||
this.init(false, doAutoZoomToLocation)
|
||||
|
||||
isLocked.addCallbackAndRunD((isLocked) => {
|
||||
if (isLocked) {
|
||||
leafletMap.data?.dragging?.disable()
|
||||
} else {
|
||||
leafletMap.data?.dragging?.enable()
|
||||
private CopyGeolocationIntoMapstate() {
|
||||
const state = this._state
|
||||
this.geolocationState.currentGPSLocation.addCallbackAndRun((location) => {
|
||||
if (location === undefined) {
|
||||
state.currentUserLocation?.features?.setData([])
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
this.currentLocation = state.currentUserLocation
|
||||
this._currentGPSLocation.addCallback((location) => {
|
||||
self._previousLocationGrant.setData("granted")
|
||||
const feature = {
|
||||
type: "Feature",
|
||||
properties: <GeoLocationPointProperties>{
|
||||
id: "gps",
|
||||
"user:location": "yes",
|
||||
date: new Date().toISOString(),
|
||||
latitude: location.latitude,
|
||||
longitude: location.longitude,
|
||||
speed: location.speed,
|
||||
accuracy: location.accuracy,
|
||||
heading: location.heading,
|
||||
altitude: location.altitude,
|
||||
...location,
|
||||
},
|
||||
geometry: {
|
||||
type: "Point",
|
||||
|
@ -232,164 +137,7 @@ export default class GeoLocationHandler extends VariableUiElement {
|
|||
},
|
||||
}
|
||||
|
||||
self.currentLocation?.features?.setData([{ feature, freshness: new Date() }])
|
||||
|
||||
if (willFocus.data) {
|
||||
console.log("Zooming to user location: willFocus is set")
|
||||
lastClick.setData(undefined)
|
||||
autozoomDone = true
|
||||
self.MoveToCurrentLocation(16)
|
||||
} else if (self._isLocked.data) {
|
||||
self.MoveToCurrentLocation()
|
||||
}
|
||||
state.currentUserLocation?.features?.setData([{ feature, freshness: new Date() }])
|
||||
})
|
||||
}
|
||||
|
||||
private init(askPermission: boolean, zoomToLocation: boolean) {
|
||||
const self = this
|
||||
|
||||
if (self._isActive.data) {
|
||||
self.MoveToCurrentLocation(16)
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof navigator === "undefined") {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
navigator?.permissions?.query({ name: "geolocation" })?.then(function (status) {
|
||||
console.log("Geolocation permission is ", status.state)
|
||||
if (status.state === "granted") {
|
||||
self.StartGeolocating(zoomToLocation)
|
||||
}
|
||||
self._permission.setData(status.state)
|
||||
status.onchange = function () {
|
||||
self._permission.setData(status.state)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
if (askPermission) {
|
||||
self.StartGeolocating(zoomToLocation)
|
||||
} else if (this._previousLocationGrant.data === "granted") {
|
||||
this._previousLocationGrant.setData("")
|
||||
self.StartGeolocating(zoomToLocation)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves to the currently loaded location.
|
||||
*
|
||||
* // Should move to any location
|
||||
* let resultingLocation = undefined
|
||||
* let resultingzoom = 1
|
||||
* const state = {
|
||||
* selectedElement: new UIEventSource<any>(undefined);
|
||||
* currentUserLocation: undefined ,
|
||||
* leafletMap: new UIEventSource<any>({getZoom: () => resultingzoom; setView: (loc, zoom) => {resultingLocation = loc; resultingzoom = zoom}),
|
||||
* layoutToUse: new LayoutConfig(<any>{
|
||||
* id: 'test',
|
||||
* title: {"en":"test"}
|
||||
* description: "A testing theme",
|
||||
* layers: []
|
||||
* }),
|
||||
* featureSwitchGeolocation : new UIEventSource<boolean>(true)
|
||||
* }
|
||||
* const handler = new GeoLocationHandler(state)
|
||||
* handler._currentGPSLocation.setData(<any> {latitude : 51.3, longitude: 4.1})
|
||||
* handler.MoveToCurrentLocation()
|
||||
* resultingLocation // => [51.3, 4.1]
|
||||
* handler._currentGPSLocation.setData(<any> {latitude : 60, longitude: 60) // out of bounds
|
||||
* handler.MoveToCurrentLocation()
|
||||
* resultingLocation // => [60, 60]
|
||||
*
|
||||
* // should refuse to move if out of bounds
|
||||
* let resultingLocation = undefined
|
||||
* let resultingzoom = 1
|
||||
* const state = {
|
||||
* selectedElement: new UIEventSource<any>(undefined);
|
||||
* currentUserLocation: undefined ,
|
||||
* leafletMap: new UIEventSource<any>({getZoom: () => resultingzoom; setView: (loc, zoom) => {resultingLocation = loc; resultingzoom = zoom}),
|
||||
* layoutToUse: new LayoutConfig(<any>{
|
||||
* id: 'test',
|
||||
* title: {"en":"test"}
|
||||
* "lockLocation": [ [ 2.1, 50.4], [6.4, 51.54 ]],
|
||||
* description: "A testing theme",
|
||||
* layers: []
|
||||
* }),
|
||||
* featureSwitchGeolocation : new UIEventSource<boolean>(true)
|
||||
* }
|
||||
* const handler = new GeoLocationHandler(state)
|
||||
* handler._currentGPSLocation.setData(<any> {latitude : 51.3, longitude: 4.1})
|
||||
* handler.MoveToCurrentLocation()
|
||||
* resultingLocation // => [51.3, 4.1]
|
||||
* handler._currentGPSLocation.setData(<any> {latitude : 60, longitude: 60) // out of bounds
|
||||
* handler.MoveToCurrentLocation()
|
||||
* resultingLocation // => [51.3, 4.1]
|
||||
*/
|
||||
private MoveToCurrentLocation(targetZoom?: number) {
|
||||
const location = this._currentGPSLocation.data
|
||||
this._lastUserRequest.setData(undefined)
|
||||
|
||||
if (
|
||||
this._currentGPSLocation.data.latitude === 0 &&
|
||||
this._currentGPSLocation.data.longitude === 0
|
||||
) {
|
||||
console.debug("Not moving to GPS-location: it is null island")
|
||||
return
|
||||
}
|
||||
|
||||
// We check that the GPS location is not out of bounds
|
||||
const b = this._layoutToUse.lockLocation
|
||||
let inRange = true
|
||||
if (b) {
|
||||
if (b !== true) {
|
||||
// B is an array with our locklocation
|
||||
inRange = new BBox(b).contains([location.longitude, location.latitude])
|
||||
}
|
||||
}
|
||||
if (!inRange) {
|
||||
console.log("Not zooming to GPS location: out of bounds", b, location)
|
||||
} else {
|
||||
const currentZoom = this._leafletMap.data.getZoom()
|
||||
this._leafletMap.data.setView(
|
||||
[location.latitude, location.longitude],
|
||||
Math.max(targetZoom ?? 0, currentZoom)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private StartGeolocating(zoomToGPS = true) {
|
||||
const self = this
|
||||
|
||||
this._lastUserRequest.setData(zoomToGPS ? new Date() : new Date(0))
|
||||
if (self._permission.data === "denied") {
|
||||
self._previousLocationGrant.setData("")
|
||||
self._isActive.setData(false)
|
||||
return ""
|
||||
}
|
||||
if (this._currentGPSLocation.data !== undefined) {
|
||||
this.MoveToCurrentLocation(16)
|
||||
}
|
||||
|
||||
if (self._isActive.data) {
|
||||
return
|
||||
}
|
||||
self._isActive.setData(true)
|
||||
|
||||
navigator.geolocation.watchPosition(
|
||||
function (position) {
|
||||
self._currentGPSLocation.setData(position.coords)
|
||||
},
|
||||
function () {
|
||||
console.warn("Could not get location with navigator.geolocation")
|
||||
},
|
||||
{
|
||||
enableHighAccuracy: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import * as L from "leaflet"
|
||||
import { UIEventSource } from "../UIEventSource"
|
||||
import ScrollableFullScreen from "../../UI/Base/ScrollableFullScreen"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import Constants from "../../Models/Constants"
|
||||
import ScrollableFullScreen from "../../UI/Base/ScrollableFullScreen"
|
||||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
|
||||
/**
|
||||
|
@ -10,70 +8,16 @@ import BaseUIElement from "../../UI/BaseUIElement"
|
|||
* Shows the given uiToShow-element in the messagebox
|
||||
*/
|
||||
export default class StrayClickHandler {
|
||||
private _lastMarker
|
||||
|
||||
constructor(
|
||||
public static construct = (
|
||||
state: {
|
||||
LastClickLocation: UIEventSource<{ lat: number; lon: number }>
|
||||
selectedElement: UIEventSource<string>
|
||||
filteredLayers: UIEventSource<FilteredLayer[]>
|
||||
leafletMap: UIEventSource<L.Map>
|
||||
leafletMap: UIEventSource<any>
|
||||
},
|
||||
uiToShow: ScrollableFullScreen,
|
||||
iconToShow: BaseUIElement
|
||||
) {
|
||||
const self = this
|
||||
const leafletMap = state.leafletMap
|
||||
state.filteredLayers.data.forEach((filteredLayer) => {
|
||||
filteredLayer.isDisplayed.addCallback((isEnabled) => {
|
||||
if (isEnabled && self._lastMarker && leafletMap.data !== undefined) {
|
||||
// When a layer is activated, we remove the 'last click location' in order to force the user to reclick
|
||||
// This reclick might be at a location where a feature now appeared...
|
||||
state.leafletMap.data.removeLayer(self._lastMarker)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
state.LastClickLocation.addCallback(function (lastClick) {
|
||||
if (self._lastMarker !== undefined) {
|
||||
state.leafletMap.data?.removeLayer(self._lastMarker)
|
||||
}
|
||||
|
||||
if (lastClick === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
state.selectedElement.setData(undefined)
|
||||
const clickCoor: [number, number] = [lastClick.lat, lastClick.lon]
|
||||
self._lastMarker = L.marker(clickCoor, {
|
||||
icon: L.divIcon({
|
||||
html: iconToShow.ConstructElement(),
|
||||
iconSize: [50, 50],
|
||||
iconAnchor: [25, 50],
|
||||
popupAnchor: [0, -45],
|
||||
}),
|
||||
})
|
||||
|
||||
self._lastMarker.addTo(leafletMap.data)
|
||||
|
||||
self._lastMarker.on("click", () => {
|
||||
if (leafletMap.data.getZoom() < Constants.userJourney.minZoomLevelToAddNewPoints) {
|
||||
leafletMap.data.flyTo(
|
||||
clickCoor,
|
||||
Constants.userJourney.minZoomLevelToAddNewPoints
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
uiToShow.Activate()
|
||||
})
|
||||
})
|
||||
|
||||
state.selectedElement.addCallback(() => {
|
||||
if (self._lastMarker !== undefined) {
|
||||
leafletMap.data.removeLayer(self._lastMarker)
|
||||
this._lastMarker = undefined
|
||||
}
|
||||
})
|
||||
) => {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ export default class SplitAction extends OsmChangeAction {
|
|||
private readonly _splitPointsCoordinates: [number, number][] // lon, lat
|
||||
private _meta: { theme: string; changeType: "split" }
|
||||
private _toleranceInMeters: number
|
||||
private _withNewCoordinates: (coordinates: [number, number][]) => void
|
||||
|
||||
/**
|
||||
* Create a changedescription for splitting a point.
|
||||
|
@ -24,17 +25,20 @@ export default class SplitAction extends OsmChangeAction {
|
|||
* @param splitPointCoordinates: lon, lat
|
||||
* @param meta
|
||||
* @param toleranceInMeters: if a splitpoint closer then this amount of meters to an existing point, the existing point will be used to split the line instead of a new point
|
||||
* @param withNewCoordinates: an optional callback which will leak the new coordinates of the original way
|
||||
*/
|
||||
constructor(
|
||||
wayId: string,
|
||||
splitPointCoordinates: [number, number][],
|
||||
meta: { theme: string },
|
||||
toleranceInMeters = 5
|
||||
toleranceInMeters = 5,
|
||||
withNewCoordinates?: (coordinates: [number, number][]) => void
|
||||
) {
|
||||
super(wayId, true)
|
||||
this.wayId = wayId
|
||||
this._splitPointsCoordinates = splitPointCoordinates
|
||||
this._toleranceInMeters = toleranceInMeters
|
||||
this._withNewCoordinates = withNewCoordinates
|
||||
this._meta = { ...meta, changeType: "split" }
|
||||
}
|
||||
|
||||
|
@ -59,7 +63,7 @@ export default class SplitAction extends OsmChangeAction {
|
|||
const originalElement = <OsmWay>await OsmObject.DownloadObjectAsync(this.wayId)
|
||||
const originalNodes = originalElement.nodes
|
||||
|
||||
// First, calculate splitpoints and remove points close to one another
|
||||
// First, calculate the splitpoints and remove points close to one another
|
||||
const splitInfo = this.CalculateSplitCoordinates(originalElement, this._toleranceInMeters)
|
||||
// Now we have a list with e.g.
|
||||
// [ { originalIndex: 0}, {originalIndex: 1, doSplit: true}, {originalIndex: 2}, {originalIndex: undefined, doSplit: true}, {originalIndex: 3}]
|
||||
|
@ -90,7 +94,7 @@ export default class SplitAction extends OsmChangeAction {
|
|||
}
|
||||
|
||||
const changeDescription: ChangeDescription[] = []
|
||||
// Let's create the new points as needed
|
||||
// Let's create the new nodes as needed
|
||||
for (const element of splitInfo) {
|
||||
if (element.originalIndex >= 0) {
|
||||
continue
|
||||
|
@ -114,17 +118,21 @@ export default class SplitAction extends OsmChangeAction {
|
|||
for (const wayPart of wayParts) {
|
||||
let isOriginal = wayPart === longest
|
||||
if (isOriginal) {
|
||||
// We change the actual element!
|
||||
// We change the existing way
|
||||
const nodeIds = wayPart.map((p) => p.originalIndex)
|
||||
const newCoordinates = wayPart.map((p) => p.lngLat)
|
||||
changeDescription.push({
|
||||
type: "way",
|
||||
id: originalElement.id,
|
||||
changes: {
|
||||
coordinates: wayPart.map((p) => p.lngLat),
|
||||
coordinates: newCoordinates,
|
||||
nodes: nodeIds,
|
||||
},
|
||||
meta: this._meta,
|
||||
})
|
||||
if (this._withNewCoordinates) {
|
||||
this._withNewCoordinates(newCoordinates)
|
||||
}
|
||||
allWayIdsInOrder.push(originalElement.id)
|
||||
allWaysNodesInOrder.push(nodeIds)
|
||||
} else {
|
||||
|
@ -141,6 +149,10 @@ export default class SplitAction extends OsmChangeAction {
|
|||
kv.push({ k: k, v: originalElement.tags[k] })
|
||||
}
|
||||
const nodeIds = wayPart.map((p) => p.originalIndex)
|
||||
if (nodeIds.length <= 1) {
|
||||
console.error("Got a segment with only one node - skipping")
|
||||
continue
|
||||
}
|
||||
changeDescription.push({
|
||||
type: "way",
|
||||
id: id,
|
||||
|
|
|
@ -8,7 +8,7 @@ import { LocalStorageSource } from "../Web/LocalStorageSource"
|
|||
import SimpleMetaTagger from "../SimpleMetaTagger"
|
||||
import FeatureSource from "../FeatureSource/FeatureSource"
|
||||
import { ElementStorage } from "../ElementStorage"
|
||||
import { GeoLocationPointProperties } from "../Actors/GeoLocationHandler"
|
||||
import { GeoLocationPointProperties } from "../State/GeoLocationState"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
import { ChangesetHandler, ChangesetTag } from "./ChangesetHandler"
|
||||
import { OsmConnection } from "./OsmConnection"
|
||||
|
|
144
Logic/State/GeoLocationState.ts
Normal file
144
Logic/State/GeoLocationState.ts
Normal file
|
@ -0,0 +1,144 @@
|
|||
import { UIEventSource } from "../UIEventSource"
|
||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||
|
||||
type GeolocationState = "prompt" | "requested" | "granted" | "denied"
|
||||
|
||||
export interface GeoLocationPointProperties extends GeolocationCoordinates {
|
||||
id: "gps"
|
||||
"user:location": "yes"
|
||||
date: string
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract representation of the current state of the geolocation.
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class GeoLocationState {
|
||||
/**
|
||||
* What do we know about the current state of having access to the GPS?
|
||||
* If 'prompt', then we just started and didn't request access yet
|
||||
* 'requested' means the user tapped the 'locate me' button at least once
|
||||
* 'granted' means that it is granted
|
||||
* 'denied' means that we don't have access
|
||||
*
|
||||
*/
|
||||
public readonly permission: UIEventSource<GeolocationState> = new UIEventSource("prompt")
|
||||
|
||||
public readonly requestMoment: UIEventSource<Date | undefined> = new UIEventSource(undefined)
|
||||
/**
|
||||
* If true: the map will center (and re-center) to this location
|
||||
*/
|
||||
public readonly isLocked: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
|
||||
public readonly currentGPSLocation: UIEventSource<GeolocationCoordinates | undefined> =
|
||||
new UIEventSource<GeolocationCoordinates | undefined>(undefined)
|
||||
|
||||
/**
|
||||
* A small flag on localstorage. If the user previously granted the geolocation, it will be set.
|
||||
* On firefox, the permissions api is broken (probably fingerprint resistiance) and "granted + don't ask again" doesn't stick between sessions.
|
||||
*
|
||||
* Instead, we set this flag. If this flag is set upon loading the page, we start geolocating immediately.
|
||||
* If the user denies the geolocation this time, we unset this flag
|
||||
* @private
|
||||
*/
|
||||
private readonly _previousLocationGrant: UIEventSource<"true" | "false"> = <any>(
|
||||
LocalStorageSource.Get("geolocation-permissions")
|
||||
)
|
||||
|
||||
/**
|
||||
* Used to detect a permission retraction
|
||||
*/
|
||||
private readonly _grantedThisSession: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
constructor() {
|
||||
const self = this
|
||||
|
||||
this.permission.addCallbackAndRunD(async (state) => {
|
||||
if (state === "granted") {
|
||||
self._previousLocationGrant.setData("true")
|
||||
self._grantedThisSession.setData(true)
|
||||
}
|
||||
if (state === "prompt" && self._grantedThisSession.data) {
|
||||
// This is _really_ weird: we had a grant earlier, but it's 'prompt' now?
|
||||
// This means that the rights have been revoked again!
|
||||
// self.permission.setData("denied")
|
||||
self._previousLocationGrant.setData("false")
|
||||
self.permission.setData("denied")
|
||||
self.currentGPSLocation.setData(undefined)
|
||||
console.warn("Detected a downgrade in permissions!")
|
||||
}
|
||||
if (state === "denied") {
|
||||
self._previousLocationGrant.setData("false")
|
||||
}
|
||||
})
|
||||
|
||||
console.log("Previous location grant:", this._previousLocationGrant.data)
|
||||
if (this._previousLocationGrant.data === "true") {
|
||||
// A previous visit successfully granted permission. Chance is high that we are allowed to use it again!
|
||||
|
||||
// We set the flag to false again. If the user only wanted to share their location once, we are not gonna keep bothering them
|
||||
this._previousLocationGrant.setData("false")
|
||||
console.log("Requesting access to GPS as this was previously granted")
|
||||
this.requestPermission()
|
||||
}
|
||||
window["geolocation_state"] = this
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs the listener for updates
|
||||
* @private
|
||||
*/
|
||||
private async startWatching() {
|
||||
const self = this
|
||||
navigator.geolocation.watchPosition(
|
||||
function (position) {
|
||||
self.currentGPSLocation.setData(position.coords)
|
||||
self._previousLocationGrant.setData("true")
|
||||
},
|
||||
function () {
|
||||
console.warn("Could not get location with navigator.geolocation")
|
||||
},
|
||||
{
|
||||
enableHighAccuracy: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the user to allow access to their position.
|
||||
* When granted, will be written to the 'geolocationState'.
|
||||
* This class will start watching
|
||||
*/
|
||||
public requestPermission() {
|
||||
if (typeof navigator === "undefined") {
|
||||
// Not compatible with this browser
|
||||
this.permission.setData("denied")
|
||||
return
|
||||
}
|
||||
if (this.permission.data !== "prompt" && this.permission.data !== "requested") {
|
||||
// If the user denies the first prompt, revokes the deny and then tries again, we have to run the flow as well
|
||||
// Hence that we continue the flow if it is "requested"
|
||||
return
|
||||
}
|
||||
this.requestMoment.setData(new Date())
|
||||
this.permission.setData("requested")
|
||||
try {
|
||||
navigator?.permissions
|
||||
?.query({ name: "geolocation" })
|
||||
.then((status) => {
|
||||
console.log("Status update: received geolocation permission is ", status.state)
|
||||
this.permission.setData(status.state)
|
||||
const self = this
|
||||
status.onchange = function () {
|
||||
self.permission.setData(status.state)
|
||||
}
|
||||
this.permission.setData("requested")
|
||||
// We _must_ call 'startWatching', as that is the actual trigger for the popup...
|
||||
self.startWatching()
|
||||
})
|
||||
.catch((e) => console.error("Could not get geopermission", e))
|
||||
} catch (e) {
|
||||
console.error("Could not get permission:", e)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import { Utils } from "../Utils"
|
||||
|
||||
export default class Constants {
|
||||
public static vNumber = "0.25.0"
|
||||
public static vNumber = "0.25.2"
|
||||
|
||||
public static ImgurApiKey = "7070e7167f0a25a"
|
||||
public static readonly mapillary_client_token_v4 =
|
||||
|
|
|
@ -260,7 +260,7 @@ export interface LayerConfigJson {
|
|||
/**
|
||||
* The type of background picture
|
||||
*/
|
||||
preferredBackground:
|
||||
preferredBackground?:
|
||||
| "osmbasedmap"
|
||||
| "photo"
|
||||
| "historicphoto"
|
||||
|
|
124
UI/Base/Hotkeys.ts
Normal file
124
UI/Base/Hotkeys.ts
Normal file
|
@ -0,0 +1,124 @@
|
|||
import { Utils } from "../../Utils"
|
||||
import Combine from "./Combine"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import Title from "./Title"
|
||||
import Table from "./Table"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { VariableUiElement } from "./VariableUIElement"
|
||||
import doc = Mocha.reporters.doc
|
||||
|
||||
export default class Hotkeys {
|
||||
private static readonly _docs: UIEventSource<
|
||||
{
|
||||
key: { ctrl?: string; shift?: string; alt?: string; nomod?: string; onUp?: boolean }
|
||||
documentation: string
|
||||
}[]
|
||||
> = new UIEventSource<
|
||||
{
|
||||
key: { ctrl?: string; shift?: string; alt?: string; nomod?: string; onUp?: boolean }
|
||||
documentation: string
|
||||
}[]
|
||||
>([])
|
||||
|
||||
private static textElementSelected(): boolean {
|
||||
console.log(document.activeElement)
|
||||
return document?.activeElement?.tagName?.toLowerCase() === "input"
|
||||
}
|
||||
public static RegisterHotkey(
|
||||
key: (
|
||||
| {
|
||||
ctrl: string
|
||||
}
|
||||
| {
|
||||
shift: string
|
||||
}
|
||||
| {
|
||||
alt: string
|
||||
}
|
||||
| {
|
||||
nomod: string
|
||||
}
|
||||
) & {
|
||||
onUp?: boolean
|
||||
},
|
||||
documentation: string,
|
||||
action: () => void
|
||||
) {
|
||||
const type = key["onUp"] ? "keyup" : "keypress"
|
||||
let keycode: string = key["ctrl"] ?? key["shift"] ?? key["alt"] ?? key["nomod"]
|
||||
if (keycode.length == 1) {
|
||||
keycode = keycode.toLowerCase()
|
||||
if (key["shift"] !== undefined) {
|
||||
keycode = keycode.toUpperCase()
|
||||
}
|
||||
}
|
||||
|
||||
this._docs.data.push({ key, documentation })
|
||||
this._docs.ping()
|
||||
if (Utils.runningFromConsole) {
|
||||
return
|
||||
}
|
||||
if (key["ctrl"] !== undefined) {
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.ctrlKey && event.key === keycode) {
|
||||
action()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
} else if (key["shift"] !== undefined) {
|
||||
document.addEventListener(type, function (event) {
|
||||
if (Hotkeys.textElementSelected()) {
|
||||
// A text element is selected, we don't do anything special
|
||||
return
|
||||
}
|
||||
if (event.shiftKey && event.key === keycode) {
|
||||
action()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
} else if (key["alt"] !== undefined) {
|
||||
document.addEventListener(type, function (event) {
|
||||
if (event.altKey && event.key === keycode) {
|
||||
action()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
} else if (key["nomod"] !== undefined) {
|
||||
document.addEventListener(type, function (event) {
|
||||
if (Hotkeys.textElementSelected()) {
|
||||
// A text element is selected, we don't do anything special
|
||||
return
|
||||
}
|
||||
if (event.key === keycode) {
|
||||
action()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static generateDocumentation(): BaseUIElement {
|
||||
return new Combine([
|
||||
new Title("Hotkeys", 1),
|
||||
"MapComplete supports the following keys:",
|
||||
new Table(
|
||||
["Key combination", "Action"],
|
||||
Hotkeys._docs.data
|
||||
.map(({ key, documentation }) => {
|
||||
const modifiers = Object.keys(key).filter(
|
||||
(k) => k !== "nomod" && k !== "onUp"
|
||||
)
|
||||
const keycode: string =
|
||||
key["ctrl"] ?? key["shift"] ?? key["alt"] ?? key["nomod"]
|
||||
modifiers.push(keycode)
|
||||
return [modifiers.join("+"), documentation]
|
||||
})
|
||||
.sort()
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
static generateDocumentationDynamic(): BaseUIElement {
|
||||
return new VariableUiElement(Hotkeys._docs.map((_) => Hotkeys.generateDocumentation()))
|
||||
}
|
||||
}
|
|
@ -14,7 +14,83 @@ import BackgroundMapSwitch from "../BigComponents/BackgroundMapSwitch"
|
|||
import AvailableBaseLayersImplementation from "../../Logic/Actors/AvailableBaseLayersImplementation"
|
||||
import ShowDataLayer from "../ShowDataLayer/ShowDataLayer"
|
||||
import ShowDataLayerImplementation from "../ShowDataLayer/ShowDataLayerImplementation"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import ScrollableFullScreen from "./ScrollableFullScreen"
|
||||
import Constants from "../../Models/Constants"
|
||||
import StrayClickHandler from "../../Logic/Actors/StrayClickHandler"
|
||||
|
||||
/**
|
||||
* The stray-click-hanlders adds a marker to the map if no feature was clicked.
|
||||
* Shows the given uiToShow-element in the messagebox
|
||||
*/
|
||||
export class StrayClickHandlerImplementation {
|
||||
private _lastMarker
|
||||
|
||||
constructor(
|
||||
state: {
|
||||
LastClickLocation: UIEventSource<{ lat: number; lon: number }>
|
||||
selectedElement: UIEventSource<string>
|
||||
filteredLayers: UIEventSource<FilteredLayer[]>
|
||||
leafletMap: UIEventSource<L.Map>
|
||||
},
|
||||
uiToShow: ScrollableFullScreen,
|
||||
iconToShow: BaseUIElement
|
||||
) {
|
||||
const self = this
|
||||
const leafletMap = state.leafletMap
|
||||
state.filteredLayers.data.forEach((filteredLayer) => {
|
||||
filteredLayer.isDisplayed.addCallback((isEnabled) => {
|
||||
if (isEnabled && self._lastMarker && leafletMap.data !== undefined) {
|
||||
// When a layer is activated, we remove the 'last click location' in order to force the user to reclick
|
||||
// This reclick might be at a location where a feature now appeared...
|
||||
state.leafletMap.data.removeLayer(self._lastMarker)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
state.LastClickLocation.addCallback(function (lastClick) {
|
||||
if (self._lastMarker !== undefined) {
|
||||
state.leafletMap.data?.removeLayer(self._lastMarker)
|
||||
}
|
||||
|
||||
if (lastClick === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
state.selectedElement.setData(undefined)
|
||||
const clickCoor: [number, number] = [lastClick.lat, lastClick.lon]
|
||||
self._lastMarker = L.marker(clickCoor, {
|
||||
icon: L.divIcon({
|
||||
html: iconToShow.ConstructElement(),
|
||||
iconSize: [50, 50],
|
||||
iconAnchor: [25, 50],
|
||||
popupAnchor: [0, -45],
|
||||
}),
|
||||
})
|
||||
|
||||
self._lastMarker.addTo(leafletMap.data)
|
||||
|
||||
self._lastMarker.on("click", () => {
|
||||
if (leafletMap.data.getZoom() < Constants.userJourney.minZoomLevelToAddNewPoints) {
|
||||
leafletMap.data.flyTo(
|
||||
clickCoor,
|
||||
Constants.userJourney.minZoomLevelToAddNewPoints
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
uiToShow.Activate()
|
||||
})
|
||||
})
|
||||
|
||||
state.selectedElement.addCallback(() => {
|
||||
if (self._lastMarker !== undefined) {
|
||||
leafletMap.data.removeLayer(self._lastMarker)
|
||||
this._lastMarker = undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
export default class MinimapImplementation extends BaseUIElement implements MinimapObj {
|
||||
private static _nextId = 0
|
||||
public readonly leafletMap: UIEventSource<Map>
|
||||
|
@ -53,6 +129,18 @@ export default class MinimapImplementation extends BaseUIElement implements Mini
|
|||
AvailableBaseLayers.implement(new AvailableBaseLayersImplementation())
|
||||
Minimap.createMiniMap = (options) => new MinimapImplementation(options)
|
||||
ShowDataLayer.actualContstructor = (options) => new ShowDataLayerImplementation(options)
|
||||
StrayClickHandler.construct = (
|
||||
state: {
|
||||
LastClickLocation: UIEventSource<{ lat: number; lon: number }>
|
||||
selectedElement: UIEventSource<string>
|
||||
filteredLayers: UIEventSource<FilteredLayer[]>
|
||||
leafletMap: UIEventSource<L.Map>
|
||||
},
|
||||
uiToShow: ScrollableFullScreen,
|
||||
iconToShow: BaseUIElement
|
||||
) => {
|
||||
return new StrayClickHandlerImplementation(state, uiToShow, iconToShow)
|
||||
}
|
||||
}
|
||||
|
||||
public installBounds(factor: number | BBox, showRange?: boolean) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { UIEventSource } from "../../Logic/UIEventSource"
|
|||
import Hash from "../../Logic/Web/Hash"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import Title from "./Title"
|
||||
import Hotkeys from "./Hotkeys"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -82,12 +83,11 @@ export default class ScrollableFullScreen {
|
|||
}
|
||||
|
||||
private static initEmpty(): FixedUiElement {
|
||||
document.addEventListener("keyup", function (event) {
|
||||
if (event.code === "Escape") {
|
||||
ScrollableFullScreen.collapse()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: "Escape", onUp: true },
|
||||
"Close the sidebar",
|
||||
ScrollableFullScreen.collapse
|
||||
)
|
||||
|
||||
return new FixedUiElement("")
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ export default class ScrollableFullScreen {
|
|||
this._fullscreencomponent.AttachTo("fullscreen")
|
||||
const fs = document.getElementById("fullscreen")
|
||||
ScrollableFullScreen._currentlyOpen = this
|
||||
fs.classList.remove("hidden")
|
||||
fs?.classList?.remove("hidden")
|
||||
}
|
||||
|
||||
private BuildComponent(title: BaseUIElement, content: BaseUIElement): BaseUIElement {
|
||||
|
|
|
@ -24,6 +24,10 @@ export default abstract class BaseUIElement {
|
|||
AttachTo(divId: string) {
|
||||
let element = document.getElementById(divId)
|
||||
if (element === null) {
|
||||
if (Utils.runningFromConsole) {
|
||||
this.ConstructElement()
|
||||
return
|
||||
}
|
||||
throw "SEVERE: could not attach UIElement to " + divId
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import BaseLayer from "../../Models/BaseLayer"
|
|||
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import Hotkeys from "../Base/Hotkeys"
|
||||
|
||||
class SingleLayerSelectionButton extends Toggle {
|
||||
public readonly activate: () => void
|
||||
|
@ -48,13 +49,13 @@ class SingleLayerSelectionButton extends Toggle {
|
|||
let toggle: BaseUIElement = new Toggle(
|
||||
selected,
|
||||
unselected,
|
||||
options.currentBackground.map((bg) => bg.category === options.preferredType)
|
||||
options.currentBackground.map((bg) => bg?.category === options.preferredType)
|
||||
)
|
||||
|
||||
super(
|
||||
toggle,
|
||||
undefined,
|
||||
available.map((av) => av.category === options.preferredType)
|
||||
available.map((av) => av?.category === options.preferredType)
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -174,6 +175,7 @@ export default class BackgroundMapSwitch extends Combine {
|
|||
options?: {
|
||||
preferredCategory?: string
|
||||
allowedCategories?: ("osmbasedmap" | "photo" | "map")[]
|
||||
enableHotkeys?: boolean
|
||||
}
|
||||
) {
|
||||
const allowedCategories = options?.allowedCategories ?? ["osmbasedmap", "photo", "map"]
|
||||
|
@ -183,7 +185,7 @@ export default class BackgroundMapSwitch extends Combine {
|
|||
let activatePrevious: () => void = undefined
|
||||
for (const category of allowedCategories) {
|
||||
let preferredLayer = undefined
|
||||
if (previousLayer.category === category) {
|
||||
if (previousLayer?.category === category) {
|
||||
preferredLayer = previousLayer
|
||||
}
|
||||
|
||||
|
@ -198,6 +200,16 @@ export default class BackgroundMapSwitch extends Combine {
|
|||
if (category === options?.preferredCategory) {
|
||||
button.activate()
|
||||
}
|
||||
|
||||
if (options?.enableHotkeys) {
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: category.charAt(0).toUpperCase() },
|
||||
"Switch to a background layer of category " + category,
|
||||
() => {
|
||||
button.activate()
|
||||
}
|
||||
)
|
||||
}
|
||||
buttons.push(button)
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ export class DownloadPanel extends Toggle {
|
|||
currentBounds: UIEventSource<BBox>
|
||||
}) {
|
||||
const t = Translations.t.general.download
|
||||
const name = State.state.layoutToUse.id
|
||||
const name = state.layoutToUse.id
|
||||
|
||||
const includeMetaToggle = new CheckBoxes([t.includeMetaData])
|
||||
const metaisIncluded = includeMetaToggle.GetValue().map((selected) => selected.length > 0)
|
||||
|
|
|
@ -20,6 +20,7 @@ import FilteredLayer from "../../Models/FilteredLayer"
|
|||
import CopyrightPanel from "./CopyrightPanel"
|
||||
import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"
|
||||
import PrivacyPolicy from "./PrivacyPolicy"
|
||||
import Hotkeys from "../Base/Hotkeys"
|
||||
|
||||
export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
|
||||
public static MoreThemesTabIndex = 1
|
||||
|
@ -126,6 +127,7 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
|
|||
osmcha_link: Utils.OsmChaLinkFor(7),
|
||||
}),
|
||||
"<br/>Version " + Constants.vNumber,
|
||||
Hotkeys.generateDocumentationDynamic(),
|
||||
]).SetClass("link-underline"),
|
||||
})
|
||||
|
||||
|
|
129
UI/BigComponents/GeolocationControl.ts
Normal file
129
UI/BigComponents/GeolocationControl.ts
Normal file
|
@ -0,0 +1,129 @@
|
|||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Svg from "../../Svg"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
import Loc from "../../Models/Loc"
|
||||
import Hotkeys from "../Base/Hotkeys"
|
||||
|
||||
/**
|
||||
* Displays an icon depending on the state of the geolocation.
|
||||
* Will set the 'lock' if clicked twice
|
||||
*/
|
||||
export class GeolocationControl extends VariableUiElement {
|
||||
constructor(
|
||||
geolocationHandler: GeoLocationHandler,
|
||||
state: {
|
||||
locationControl: UIEventSource<Loc>
|
||||
currentBounds: UIEventSource<BBox>
|
||||
}
|
||||
) {
|
||||
const lastClick = new UIEventSource<Date>(undefined)
|
||||
const lastClickWithinThreeSecs = lastClick.map((lastClick) => {
|
||||
if (lastClick === undefined) {
|
||||
return false
|
||||
}
|
||||
const timeDiff = (new Date().getTime() - lastClick.getTime()) / 1000
|
||||
return timeDiff <= 3
|
||||
})
|
||||
const geolocationState = geolocationHandler.geolocationState
|
||||
super(
|
||||
geolocationState.permission.map(
|
||||
(permission) => {
|
||||
if (permission === "denied") {
|
||||
return Svg.location_refused_svg()
|
||||
}
|
||||
if (geolocationState.isLocked.data) {
|
||||
return Svg.location_locked_svg()
|
||||
}
|
||||
|
||||
if (geolocationState.currentGPSLocation.data === undefined) {
|
||||
if (permission === "prompt") {
|
||||
return Svg.location_empty_svg()
|
||||
}
|
||||
// Position not yet found, but permission is either requested or granted: we spin to indicate activity
|
||||
const icon = !geolocationHandler.mapHasMoved.data
|
||||
? Svg.location_svg()
|
||||
: Svg.location_empty_svg()
|
||||
return icon
|
||||
.SetClass("cursor-wait")
|
||||
.SetStyle("animation: spin 4s linear infinite;")
|
||||
}
|
||||
|
||||
// We have a location, so we show a dot in the center
|
||||
|
||||
if (
|
||||
lastClickWithinThreeSecs.data &&
|
||||
geolocationState.permission.data === "granted"
|
||||
) {
|
||||
return Svg.location_unlocked_svg()
|
||||
}
|
||||
|
||||
// We have a location, so we show a dot in the center
|
||||
return Svg.location_svg()
|
||||
},
|
||||
[
|
||||
geolocationState.currentGPSLocation,
|
||||
geolocationState.isLocked,
|
||||
geolocationHandler.mapHasMoved,
|
||||
lastClickWithinThreeSecs,
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
async function handleClick() {
|
||||
if (geolocationState.permission.data !== "granted") {
|
||||
await geolocationState.requestPermission()
|
||||
}
|
||||
|
||||
if (geolocationState.isLocked.data === true) {
|
||||
// Unlock
|
||||
geolocationState.isLocked.setData(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (geolocationState.currentGPSLocation.data === undefined) {
|
||||
// No location is known yet, not much we can do
|
||||
return
|
||||
}
|
||||
|
||||
// A location _is_ known! Let's move to this location
|
||||
const currentLocation = geolocationState.currentGPSLocation.data
|
||||
const inBounds = state.currentBounds.data.contains([
|
||||
currentLocation.longitude,
|
||||
currentLocation.latitude,
|
||||
])
|
||||
geolocationHandler.MoveMapToCurrentLocation()
|
||||
if (inBounds) {
|
||||
const lc = state.locationControl.data
|
||||
state.locationControl.setData({
|
||||
...lc,
|
||||
zoom: lc.zoom + 3,
|
||||
})
|
||||
}
|
||||
|
||||
if (lastClickWithinThreeSecs.data && geolocationState.permission.data === "granted") {
|
||||
geolocationState.isLocked.setData(true)
|
||||
lastClick.setData(undefined)
|
||||
return
|
||||
}
|
||||
|
||||
lastClick.setData(new Date())
|
||||
}
|
||||
|
||||
this.onClick(handleClick)
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: "L" },
|
||||
"Pan the map to the current location or zoom the map to the current location. Requests geopermission",
|
||||
handleClick
|
||||
)
|
||||
|
||||
lastClick.addCallbackAndRunD((_) => {
|
||||
window.setTimeout(() => {
|
||||
if (lastClickWithinThreeSecs.data) {
|
||||
lastClick.ping()
|
||||
}
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ import { VariableUiElement } from "../Base/VariableUIElement"
|
|||
import FeatureInfoBox from "../Popup/FeatureInfoBox"
|
||||
import CopyrightPanel from "./CopyrightPanel"
|
||||
import FeaturePipelineState from "../../Logic/State/FeaturePipelineState"
|
||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||
import Hotkeys from "../Base/Hotkeys"
|
||||
|
||||
export default class LeftControls extends Combine {
|
||||
constructor(
|
||||
|
@ -73,7 +73,7 @@ export default class LeftControls extends Combine {
|
|||
guiState.downloadControlIsOpened.setData(true)
|
||||
)
|
||||
|
||||
const downloadButtonn = new Toggle(
|
||||
const downloadButton = new Toggle(
|
||||
toggledDownload,
|
||||
undefined,
|
||||
state.featureSwitchEnableExport.map(
|
||||
|
@ -94,11 +94,20 @@ export default class LeftControls extends Combine {
|
|||
const toggledFilter = new MapControlButton(Svg.layers_svg()).onClick(() =>
|
||||
guiState.filterViewIsOpened.setData(true)
|
||||
)
|
||||
state.featureSwitchFilter.addCallbackAndRun((f) => {
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ nomod: "B" },
|
||||
"Opens the Background, layers and filters panel",
|
||||
() => {
|
||||
guiState.filterViewIsOpened.setData(!guiState.filterViewIsOpened.data)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
const filterButton = new Toggle(toggledFilter, undefined, state.featureSwitchFilter)
|
||||
|
||||
const mapSwitch = new Toggle(
|
||||
new BackgroundMapSwitch(state, state.backgroundLayer),
|
||||
new BackgroundMapSwitch(state, state.backgroundLayer, { enableHotkeys: true }),
|
||||
undefined,
|
||||
state.featureSwitchBackgroundSelection
|
||||
)
|
||||
|
@ -120,7 +129,7 @@ export default class LeftControls extends Combine {
|
|||
state.featureSwitchWelcomeMessage
|
||||
)
|
||||
|
||||
super([currentViewAction, filterButton, downloadButtonn, copyright, mapSwitch])
|
||||
super([currentViewAction, filterButton, downloadButton, copyright, mapSwitch])
|
||||
|
||||
this.SetClass("flex flex-col")
|
||||
}
|
||||
|
|
|
@ -92,13 +92,13 @@ export default class MoreScreen extends Combine {
|
|||
|
||||
if (onMainScreen) {
|
||||
search.focus()
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.ctrlKey && event.code === "KeyF") {
|
||||
search.focus()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
}
|
||||
document.addEventListener("keydown", function (event) {
|
||||
if (event.ctrlKey && event.code === "KeyF") {
|
||||
search.focus()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
const searchBar = new Combine([
|
||||
Svg.search_svg().SetClass("w-8"),
|
||||
|
|
|
@ -5,18 +5,16 @@ import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"
|
|||
import Svg from "../../Svg"
|
||||
import MapState from "../../Logic/State/MapState"
|
||||
import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline"
|
||||
import { Utils } from "../../Utils"
|
||||
import { TagUtils } from "../../Logic/Tags/TagUtils"
|
||||
import { BBox } from "../../Logic/BBox"
|
||||
import { OsmFeature } from "../../Models/OsmFeature"
|
||||
import LevelSelector from "./LevelSelector"
|
||||
import { GeolocationControl } from "./GeolocationControl"
|
||||
|
||||
export default class RightControls extends Combine {
|
||||
constructor(state: MapState & { featurePipeline: FeaturePipeline }) {
|
||||
const geolocatioHandler = new GeoLocationHandler(state)
|
||||
|
||||
constructor(
|
||||
state: MapState & { featurePipeline: FeaturePipeline },
|
||||
geolocationHandler: GeoLocationHandler
|
||||
) {
|
||||
const geolocationButton = new Toggle(
|
||||
new MapControlButton(geolocatioHandler, {
|
||||
new MapControlButton(new GeolocationControl(geolocationHandler, state), {
|
||||
dontStyle: true,
|
||||
}).SetClass("p-1"),
|
||||
undefined,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import Svg from "../../Svg"
|
||||
import { TextField } from "../Input/TextField"
|
||||
import { Geocoding } from "../../Logic/Osm/Geocoding"
|
||||
|
@ -10,6 +9,7 @@ import Combine from "../Base/Combine"
|
|||
import Locale from "../i18n/Locale"
|
||||
|
||||
export default class SearchAndGo extends Combine {
|
||||
private readonly _searchField: TextField
|
||||
constructor(state: { leafletMap: UIEventSource<any>; selectedElement?: UIEventSource<any> }) {
|
||||
const goButton = Svg.search_ui().SetClass("w-8 h-8 full-rounded border-black float-right")
|
||||
|
||||
|
@ -74,6 +74,11 @@ export default class SearchAndGo extends Combine {
|
|||
}
|
||||
|
||||
searchField.enterPressed.addCallback(runSearch)
|
||||
this._searchField = searchField
|
||||
goButton.onClick(runSearch)
|
||||
}
|
||||
|
||||
focus() {
|
||||
this._searchField.focus()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ export default class ShareScreen extends Combine {
|
|||
includeCurrentBackground.GetValue().map(
|
||||
(includeBG) => {
|
||||
if (includeBG) {
|
||||
return "background=" + currentLayer.data.id
|
||||
return "background=" + currentLayer.data?.id
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ export default class ShareScreen extends Combine {
|
|||
return `<span class='literal-code iframe-code-block'>
|
||||
<iframe src="${url}" allow="geolocation" width="100%" height="100%" style="min-width: 250px; min-height: 250px" title="${
|
||||
layout.title?.txt ?? "MapComplete"
|
||||
} with MapComplete"></iframe>
|
||||
} with MapComplete"></iframe>
|
||||
</span>`
|
||||
})
|
||||
)
|
||||
|
|
|
@ -29,6 +29,10 @@ import Img from "./Base/Img"
|
|||
import UserInformationPanel from "./BigComponents/UserInformation"
|
||||
import { LoginToggle } from "./Popup/LoginButton"
|
||||
import { FixedUiElement } from "./Base/FixedUiElement"
|
||||
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
||||
import { GeoLocationState } from "../Logic/State/GeoLocationState"
|
||||
import Hotkeys from "./Base/Hotkeys"
|
||||
import AvailableBaseLayers from "../Logic/Actors/AvailableBaseLayers"
|
||||
|
||||
/**
|
||||
* The default MapComplete GUI initializer
|
||||
|
@ -38,10 +42,14 @@ import { FixedUiElement } from "./Base/FixedUiElement"
|
|||
export default class DefaultGUI {
|
||||
private readonly guiState: DefaultGuiState
|
||||
private readonly state: FeaturePipelineState
|
||||
private readonly geolocationHandler: GeoLocationHandler | undefined
|
||||
|
||||
constructor(state: FeaturePipelineState, guiState: DefaultGuiState) {
|
||||
this.state = state
|
||||
this.guiState = guiState
|
||||
if (this.state.featureSwitchGeolocation.data) {
|
||||
this.geolocationHandler = new GeoLocationHandler(new GeoLocationState(), state)
|
||||
}
|
||||
}
|
||||
|
||||
public setup() {
|
||||
|
@ -55,6 +63,14 @@ export default class DefaultGUI {
|
|||
Utils.LoadCustomCss(this.state.layoutToUse.customCss)
|
||||
}
|
||||
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ shift: "O" },
|
||||
"Switch to default Mapnik-OpenStreetMap background",
|
||||
() => {
|
||||
this.state.backgroundLayer.setData(AvailableBaseLayers.osmCarto)
|
||||
}
|
||||
)
|
||||
|
||||
Utils.downloadJson("./service-worker-version")
|
||||
.then((data) => console.log("Service worker", data))
|
||||
.catch((_) => console.log("Service worker not active"))
|
||||
|
@ -122,7 +138,7 @@ export default class DefaultGUI {
|
|||
.SetStyle("left: calc( 50% - 15px )") // This is a bit hacky, yes I know!
|
||||
}
|
||||
|
||||
new StrayClickHandler(
|
||||
StrayClickHandler.construct(
|
||||
state,
|
||||
addNewPoint,
|
||||
hasPresets ? new AddNewMarker(state.filteredLayers) : noteMarker
|
||||
|
@ -145,6 +161,9 @@ export default class DefaultGUI {
|
|||
}
|
||||
|
||||
private SetupMap() {
|
||||
if (Utils.runningFromConsole) {
|
||||
return
|
||||
}
|
||||
const state = this.state
|
||||
const guiState = this.guiState
|
||||
|
||||
|
@ -232,18 +251,27 @@ export default class DefaultGUI {
|
|||
.AttachTo("on-small-screen")
|
||||
|
||||
new Combine([
|
||||
Toggle.If(state.featureSwitchSearch, () =>
|
||||
new SearchAndGo(state).SetClass(
|
||||
Toggle.If(state.featureSwitchSearch, () => {
|
||||
const search = new SearchAndGo(state).SetClass(
|
||||
"shadow rounded-full h-min w-full overflow-hidden sm:max-w-sm pointer-events-auto"
|
||||
)
|
||||
),
|
||||
Hotkeys.RegisterHotkey(
|
||||
{ ctrl: "F" },
|
||||
"Select the search bar to search locations",
|
||||
() => {
|
||||
search.focus()
|
||||
}
|
||||
)
|
||||
|
||||
return search
|
||||
}),
|
||||
]).AttachTo("top-right")
|
||||
|
||||
new LeftControls(state, guiState).AttachTo("bottom-left")
|
||||
new RightControls(state).AttachTo("bottom-right")
|
||||
new RightControls(state, this.geolocationHandler).AttachTo("bottom-right")
|
||||
|
||||
new CenterMessageBox(state).AttachTo("centermessage")
|
||||
document.getElementById("centermessage").classList.add("pointer-events-none")
|
||||
document?.getElementById("centermessage")?.classList?.add("pointer-events-none")
|
||||
|
||||
// We have to ping the welcomeMessageIsOpened and other isOpened-stuff to activate the FullScreenMessage if needed
|
||||
for (const state of guiState.allFullScreenStates) {
|
||||
|
|
|
@ -22,8 +22,10 @@ import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
|
|||
import { ElementStorage } from "../../Logic/ElementStorage"
|
||||
import BaseLayer from "../../Models/BaseLayer"
|
||||
import FilteredLayer from "../../Models/FilteredLayer"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
|
||||
export default class SplitRoadWizard extends Toggle {
|
||||
export default class SplitRoadWizard extends Combine {
|
||||
// @ts-ignore
|
||||
private static splitLayerStyling = new LayerConfig(
|
||||
split_point,
|
||||
|
@ -63,6 +65,106 @@ export default class SplitRoadWizard extends Toggle {
|
|||
|
||||
// Toggle variable between show split button and map
|
||||
const splitClicked = new UIEventSource<boolean>(false)
|
||||
|
||||
const leafletMap = new UIEventSource<BaseUIElement>(
|
||||
SplitRoadWizard.setupMapComponent(id, splitPoints, state)
|
||||
)
|
||||
|
||||
// Toggle between splitmap
|
||||
const splitButton = new SubtleButton(
|
||||
Svg.scissors_ui().SetStyle("height: 1.5rem; width: auto"),
|
||||
new Toggle(
|
||||
t.splitAgain.Clone().SetClass("text-lg font-bold"),
|
||||
t.inviteToSplit.Clone().SetClass("text-lg font-bold"),
|
||||
hasBeenSplit
|
||||
)
|
||||
)
|
||||
splitButton.onClick(() => {
|
||||
splitClicked.setData(true)
|
||||
})
|
||||
|
||||
// Only show the splitButton if logged in, else show login prompt
|
||||
const loginBtn = t.loginToSplit
|
||||
.Clone()
|
||||
.onClick(() => state.osmConnection.AttemptLogin())
|
||||
.SetClass("login-button-friendly")
|
||||
const splitToggle = new Toggle(splitButton, loginBtn, state.osmConnection.isLoggedIn)
|
||||
|
||||
// Save button
|
||||
const saveButton = new Button(t.split.Clone(), async () => {
|
||||
hasBeenSplit.setData(true)
|
||||
splitClicked.setData(false)
|
||||
const splitAction = new SplitAction(
|
||||
id,
|
||||
splitPoints.data.map((ff) => ff.feature.geometry.coordinates),
|
||||
{
|
||||
theme: state?.layoutToUse?.id,
|
||||
},
|
||||
5,
|
||||
(coordinates) => {
|
||||
state.allElements.ContainingFeatures.get(id).geometry["coordinates"] =
|
||||
coordinates
|
||||
}
|
||||
)
|
||||
await state.changes.applyAction(splitAction)
|
||||
// We throw away the old map and splitpoints, and create a new map from scratch
|
||||
splitPoints.setData([])
|
||||
leafletMap.setData(SplitRoadWizard.setupMapComponent(id, splitPoints, state))
|
||||
})
|
||||
|
||||
saveButton.SetClass("btn btn-primary mr-3")
|
||||
const disabledSaveButton = new Button("Split", undefined)
|
||||
disabledSaveButton.SetClass("btn btn-disabled mr-3")
|
||||
// Only show the save button if there are split points defined
|
||||
const saveToggle = new Toggle(
|
||||
disabledSaveButton,
|
||||
saveButton,
|
||||
splitPoints.map((data) => data.length === 0)
|
||||
)
|
||||
|
||||
const cancelButton = Translations.t.general.cancel
|
||||
.Clone() // Not using Button() element to prevent full width button
|
||||
.SetClass("btn btn-secondary mr-3")
|
||||
.onClick(() => {
|
||||
splitPoints.setData([])
|
||||
splitClicked.setData(false)
|
||||
})
|
||||
|
||||
cancelButton.SetClass("btn btn-secondary block")
|
||||
|
||||
const splitTitle = new Title(t.splitTitle)
|
||||
|
||||
const mapView = new Combine([
|
||||
splitTitle,
|
||||
new VariableUiElement(leafletMap),
|
||||
new Combine([cancelButton, saveToggle]).SetClass("flex flex-row"),
|
||||
])
|
||||
mapView.SetClass("question")
|
||||
super([
|
||||
Toggle.If(hasBeenSplit, () =>
|
||||
t.hasBeenSplit.Clone().SetClass("font-bold thanks block w-full")
|
||||
),
|
||||
new Toggle(mapView, splitToggle, splitClicked),
|
||||
])
|
||||
this.dialogIsOpened = splitClicked
|
||||
}
|
||||
|
||||
private static setupMapComponent(
|
||||
id: string,
|
||||
splitPoints: UIEventSource<{ feature: any; freshness: Date }[]>,
|
||||
state: {
|
||||
filteredLayers: UIEventSource<FilteredLayer[]>
|
||||
backgroundLayer: UIEventSource<BaseLayer>
|
||||
featureSwitchIsTesting: UIEventSource<boolean>
|
||||
featureSwitchIsDebugging: UIEventSource<boolean>
|
||||
featureSwitchShowAllQuestions: UIEventSource<boolean>
|
||||
osmConnection: OsmConnection
|
||||
featureSwitchUserbadge: UIEventSource<boolean>
|
||||
changes: Changes
|
||||
layoutToUse: LayoutConfig
|
||||
allElements: ElementStorage
|
||||
}
|
||||
): BaseUIElement {
|
||||
// Load the road with given id on the minimap
|
||||
const roadElement = state.allElements.ContainingFeatures.get(id)
|
||||
|
||||
|
@ -96,7 +198,6 @@ export default class SplitRoadWizard extends Toggle {
|
|||
layerToShow: SplitRoadWizard.splitLayerStyling,
|
||||
state,
|
||||
})
|
||||
|
||||
/**
|
||||
* Handles a click on the overleaf map.
|
||||
* Finds the closest intersection with the road and adds a point there, ready to confirm the cut.
|
||||
|
@ -137,67 +238,6 @@ export default class SplitRoadWizard extends Toggle {
|
|||
onMapClick([mouseEvent.latlng.lng, mouseEvent.latlng.lat])
|
||||
})
|
||||
)
|
||||
|
||||
// Toggle between splitmap
|
||||
const splitButton = new SubtleButton(
|
||||
Svg.scissors_ui().SetStyle("height: 1.5rem; width: auto"),
|
||||
t.inviteToSplit.Clone().SetClass("text-lg font-bold")
|
||||
)
|
||||
splitButton.onClick(() => {
|
||||
splitClicked.setData(true)
|
||||
})
|
||||
|
||||
// Only show the splitButton if logged in, else show login prompt
|
||||
const loginBtn = t.loginToSplit
|
||||
.Clone()
|
||||
.onClick(() => state.osmConnection.AttemptLogin())
|
||||
.SetClass("login-button-friendly")
|
||||
const splitToggle = new Toggle(splitButton, loginBtn, state.osmConnection.isLoggedIn)
|
||||
|
||||
// Save button
|
||||
const saveButton = new Button(t.split.Clone(), () => {
|
||||
hasBeenSplit.setData(true)
|
||||
state.changes.applyAction(
|
||||
new SplitAction(
|
||||
id,
|
||||
splitPoints.data.map((ff) => ff.feature.geometry.coordinates),
|
||||
{
|
||||
theme: state?.layoutToUse?.id,
|
||||
}
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
saveButton.SetClass("btn btn-primary mr-3")
|
||||
const disabledSaveButton = new Button("Split", undefined)
|
||||
disabledSaveButton.SetClass("btn btn-disabled mr-3")
|
||||
// Only show the save button if there are split points defined
|
||||
const saveToggle = new Toggle(
|
||||
disabledSaveButton,
|
||||
saveButton,
|
||||
splitPoints.map((data) => data.length === 0)
|
||||
)
|
||||
|
||||
const cancelButton = Translations.t.general.cancel
|
||||
.Clone() // Not using Button() element to prevent full width button
|
||||
.SetClass("btn btn-secondary mr-3")
|
||||
.onClick(() => {
|
||||
splitPoints.setData([])
|
||||
splitClicked.setData(false)
|
||||
})
|
||||
|
||||
cancelButton.SetClass("btn btn-secondary block")
|
||||
|
||||
const splitTitle = new Title(t.splitTitle)
|
||||
|
||||
const mapView = new Combine([
|
||||
splitTitle,
|
||||
miniMap,
|
||||
new Combine([cancelButton, saveToggle]).SetClass("flex flex-row"),
|
||||
])
|
||||
mapView.SetClass("question")
|
||||
const confirm = new Toggle(mapView, splitToggle, splitClicked)
|
||||
super(t.hasBeenSplit.Clone(), confirm, hasBeenSplit)
|
||||
this.dialogIsOpened = splitClicked
|
||||
return miniMap
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Utils } from "../../Utils"
|
||||
import { Feature } from "geojson"
|
||||
import { Point } from "@turf/turf"
|
||||
import { GeoLocationPointProperties } from "../../Logic/Actors/GeoLocationHandler"
|
||||
import { GeoLocationPointProperties } from "../../Logic/State/GeoLocationState"
|
||||
import UploadTraceToOsmUI from "../BigComponents/UploadTraceToOsmUI"
|
||||
import { SpecialVisualization } from "../SpecialVisualization"
|
||||
|
||||
|
|
|
@ -17,7 +17,10 @@ export default class ShowDataLayer {
|
|||
*/
|
||||
constructor(options: ShowDataLayerOptions & { layerToShow: LayerConfig }) {
|
||||
if (ShowDataLayer.actualContstructor === undefined) {
|
||||
throw "Show data layer is called, but it isn't initialized yet. Call ` ShowDataLayer.actualContstructor = (options => new ShowDataLayerImplementation(options)) ` somewhere, e.g. in your init"
|
||||
console.error(
|
||||
"Show data layer is called, but it isn't initialized yet. Call ` ShowDataLayer.actualContstructor = (options => new ShowDataLayerImplementation(options)) ` somewhere, e.g. in your init"
|
||||
)
|
||||
return
|
||||
}
|
||||
ShowDataLayer.actualContstructor(options)
|
||||
}
|
||||
|
|
|
@ -143,6 +143,99 @@
|
|||
"override": {
|
||||
"condition": "amenity!=bank"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cash_out",
|
||||
"question": {
|
||||
"en": "Can you withdraw cash from this ATM?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "cash_out=",
|
||||
"then": {
|
||||
"en": "You can withdraw cash from this ATM"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
{
|
||||
"if": "cash_out=yes",
|
||||
"then": {
|
||||
"en": "You can withdraw cash from this ATM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cash_out=no",
|
||||
"then": {
|
||||
"en": "You cannot withdraw cash from this ATM"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cash_in",
|
||||
"question": {
|
||||
"en": "Can you deposit cash into this ATM?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "cash_in=",
|
||||
"then": {
|
||||
"en": "You probably cannot deposit cash into this ATM"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
{
|
||||
"if": "cash_in=yes",
|
||||
"then": {
|
||||
"en": "You can deposit cash into this ATM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "cash_in=no",
|
||||
"then": {
|
||||
"en": "You cannot deposit cash into this ATM"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "speech_output",
|
||||
"question": {
|
||||
"en": "Does this ATM have speech output for visually impaired users?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "speech_output=yes",
|
||||
"then": {
|
||||
"en": "This ATM has speech output, usually available through a headphone jack"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "speech_output=no",
|
||||
"then": {
|
||||
"en": "This ATM does not have speech output"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "speech_output_language",
|
||||
"condition": "speech_output=yes",
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "language_chooser",
|
||||
"key": "speech_output",
|
||||
"question": {
|
||||
"en": "In which languages does this ATM have speech output?"
|
||||
},
|
||||
"render_list_item": {
|
||||
"en": "This ATM has speech output in {language():font-bold}"
|
||||
},
|
||||
"render_single_language": {
|
||||
"en": "This ATM has speech output in {language():font-bold}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
|
@ -153,5 +246,19 @@
|
|||
"centroid"
|
||||
]
|
||||
}
|
||||
],
|
||||
"filter": [
|
||||
"open_now",
|
||||
{
|
||||
"id": "speech_output",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
"en": "With speech output"
|
||||
},
|
||||
"osmTags": "speech_output=yes"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
{
|
||||
"path": "bench.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"authors": [
|
||||
"Tobias Zwick"
|
||||
],
|
||||
"sources": [
|
||||
"https://github.com/streetcomplete/StreetComplete/"
|
||||
]
|
||||
}
|
||||
]
|
|
@ -314,7 +314,10 @@
|
|||
"cs": "Zde si můžete půjčit cyklistické přilby"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"condition": {
|
||||
"and": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rental_types",
|
||||
|
@ -443,7 +446,9 @@
|
|||
"key": "capacity:bicycle_type",
|
||||
"type": "pnat"
|
||||
},
|
||||
"condition": "rental~.*bicycle_type.*"
|
||||
"condition": {"and":
|
||||
["rental~.*bicycle_type.*"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -554,4 +559,4 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -487,7 +487,14 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"bicycle_rental.*bicycle_rental",
|
||||
{
|
||||
"builtin": "bicycle_rental.*bicycle_rental",
|
||||
"override": {
|
||||
"condition": {
|
||||
"and+": ["service:bicycle:rental=yes"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "bike_repair_second-hand-bikes",
|
||||
"question": {
|
||||
|
@ -783,4 +790,4 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
"osmTags": "emergency=defibrillator"
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_days_since_last_survey=Math.floor(new Date() - new Date(feat.properties['survey:date'])/(1000*60*60*24))",
|
||||
"_days_since_last_survey=Math.floor((new Date() - new Date(feat.properties['survey:date']))/(1000*60*60*24))",
|
||||
"_recently_surveyed=Number(feat.properties._days_since_last_survey) <= 90"
|
||||
],
|
||||
"minzoom": 12,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"osmTags": "amenity=parking_space"
|
||||
},
|
||||
"tagRenderings": [
|
||||
"images",
|
||||
{
|
||||
"id": "type",
|
||||
"question": {
|
||||
|
|
14
assets/layers/recycling/fluorescent_tubes.svg
Normal file
14
assets/layers/recycling/fluorescent_tubes.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="700pt" height="700pt" version="1.1" viewBox="0 0 700 700" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g>
|
||||
<path d="m552.4 181.67c-1.5312 0-3.0078-0.60156-4.1016-1.6953l-98.328-98.328c-1.0938-1.0938-1.6953-2.5156-1.6953-4.1016 0-1.5312 0.60156-3.0078 1.6953-4.1016l27.344-27.344c3.5547-3.5547 8.3125-5.5234 13.344-5.5234h0.054688c5.0312 0 9.7344 1.9688 13.289 5.4688l79.844 79.844c7.3828 7.3828 7.3828 19.359 0 26.688l-27.344 27.344c-1.0938 1.1484-2.5703 1.75-4.1016 1.75zm-91.055-104.12 91.055 91.055 23.68-23.68c3.1172-3.1172 3.1172-8.1484 0-11.266l-79.844-79.844c-1.4766-1.4766-3.4453-2.2969-5.5234-2.2969-2.1328 0-4.1016 0.82031-5.6328 2.3516z"/>
|
||||
<path d="m240.19 484.04-94.227-94.227 313.8-313.8 94.281 94.281zm-78.805-94.227 78.805 78.805 298.32-298.32-78.75-78.859z"/>
|
||||
<path d="m209.34 519.42c-5.0312 0-9.7891-1.9688-13.344-5.5234l-79.844-79.844c-3.5547-3.5547-5.5234-8.3125-5.5234-13.344s1.9688-9.7891 5.5234-13.344l27.344-27.344c1.0938-1.0938 2.5156-1.6953 4.1016-1.6953 1.5312 0 3.0078 0.60156 4.1016 1.6953l98.383 98.383c1.0938 1.0938 1.6953 2.5156 1.6953 4.1016 0 1.5312-0.60156 3.0078-1.6953 4.1016l-27.344 27.344c-3.6641 3.5-8.3672 5.4688-13.398 5.4688zm-61.797-128.08-23.68 23.734c-1.5312 1.5312-2.3516 3.5-2.3516 5.6328 0 2.1328 0.82031 4.1016 2.3516 5.6328l79.844 79.844c1.5312 1.5312 3.5 2.3516 5.6328 2.3516s4.1016-0.82031 5.6328-2.3516l23.68-23.68z"/>
|
||||
<path d="m522.1 79.68-19.523-19.523 21.711-21.711c5.4141-5.4141 14.219-5.4141 19.578 0 2.5703 2.5703 4.0469 6.0156 4.0469 9.6797 0 3.7188-1.4219 7.2188-4.0469 9.8438zm-4.1016-19.523 4.1016 4.1016 14-14c0.54688-0.54687 0.875-1.3125 0.875-2.0781 0-0.4375-0.10937-1.2578-0.82031-1.9688-1.1484-1.1484-3.0078-1.1484-4.1562-0.054688z"/>
|
||||
<path d="m569.84 127.37-19.523-19.523 21.711-21.711c5.3594-5.3047 14.109-5.3047 19.469 0 2.625 2.5703 4.1016 6.0156 4.1016 9.7344s-1.4219 7.2188-4.0469 9.8438zm-4.1016-19.523 4.1016 4.1016 13.945-13.945c0.54688-0.54688 0.875-1.3125 0.875-2.0781 0-0.4375-0.10937-1.2578-0.82031-1.9688-1.1484-1.1484-2.9531-1.1484-4.1562 0z"/>
|
||||
<path d="m165.92 525.6c-3.7188 0-7.1641-1.4219-9.7891-4.0469-2.5703-2.5703-4.0469-6.0156-4.0469-9.6797 0-3.7188 1.4219-7.2188 4.0469-9.8438l21.711-21.711 19.523 19.523-21.711 21.711c-2.5703 2.5703-6.0156 4.0469-9.6797 4.0469h-0.054687zm11.922-29.859-13.945 13.945c-0.54688 0.54688-0.875 1.3125-0.875 2.0781 0 0.4375 0.10937 1.2578 0.82031 1.9688 0.60156 0.60156 1.3125 0.875 2.0781 0.875 0.4375 0 1.2578-0.10938 1.9688-0.82031l14-14z"/>
|
||||
<path d="m118.23 477.91c-3.7188 0-7.1641-1.4219-9.7891-4.0469-2.5703-2.5703-4.0469-6.0156-4.0469-9.6797 0-3.7188 1.4219-7.2188 4.0469-9.8438l21.711-21.711 19.523 19.523-21.711 21.711c-2.5703 2.5703-6.0156 4.0469-9.6797 4.0469h-0.054687zm11.922-29.859-13.945 13.945c-0.54688 0.54688-0.875 1.3125-0.875 2.0781 0 0.4375 0.10937 1.2578 0.82031 1.9688 0.60156 0.60156 1.3125 0.875 2.0781 0.875 0.4375 0 1.2578-0.10938 1.9688-0.82031l14-14z"/>
|
||||
<path d="m297.07 284.02 7.7344 7.7344-16.781 16.781-7.7344-7.7344z"/>
|
||||
<path d="m370.96 210.19 7.7344 7.7344-57.656 57.656-7.7344-7.7344z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
|
@ -60,6 +60,17 @@
|
|||
"https://github.com/streetcomplete/StreetComplete/blob/master/res/graphics/recycling%20icons/engine_oil.svg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "fluorescent_tubes.svg",
|
||||
"license": "CC-BY",
|
||||
"authors": [
|
||||
"Noun Project",
|
||||
"shashank singh"
|
||||
],
|
||||
"sources": [
|
||||
"https://thenounproject.com/icon/tube-fluorescent-light-3756518/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "garden_waste.svg",
|
||||
"license": "CC-BY-SA",
|
||||
|
@ -91,6 +102,17 @@
|
|||
"https://github.com/streetcomplete/StreetComplete/blob/master/res/graphics/recycling%20icons/glass_bottles.svg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "light_bulbs.svg",
|
||||
"license": "CC0",
|
||||
"authors": [
|
||||
"OpenClipArt",
|
||||
"fabiovaleggia"
|
||||
],
|
||||
"sources": [
|
||||
"https://openclipart.org/detail/175842/basic-light-bulb"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "newspaper.svg",
|
||||
"license": "CC-BY-SA",
|
||||
|
|
159
assets/layers/recycling/light_bulbs.svg
Normal file
159
assets/layers/recycling/light_bulbs.svg
Normal file
|
@ -0,0 +1,159 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:svg="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:ns1="http://sozi.baierouge.fr" id="svg2" viewBox="0 0 801 801" version="1.0">
|
||||
<defs id="defs4">
|
||||
<linearGradient id="linearGradient3187">
|
||||
<stop id="stop3189" stop-color="#fff" offset="0"/>
|
||||
<stop id="stop3191" stop-color="#fff" stop-opacity="0" offset="1"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient3175">
|
||||
<stop id="stop3177" offset="0"/>
|
||||
<stop id="stop3179" stop-opacity="0" offset="1"/>
|
||||
</linearGradient>
|
||||
<filter id="filter4712" y="-.18408" width="1.4494" height="1.3682" x="-.22472">
|
||||
<feGaussianBlur id="feGaussianBlur4714" stdDeviation="44.016276"/>
|
||||
</filter>
|
||||
<radialGradient id="radialGradient5307" gradientUnits="userSpaceOnUse" cy="891.75" cx="995.08" gradientTransform="matrix(1.7827 1.8967e-7 -4.1911e-8 .39392 -778.86 540.47)" r="52.236">
|
||||
<stop id="stop4522" offset="0"/>
|
||||
<stop id="stop4524" stop-opacity="0" offset="1"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="radialGradient5309" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="509.03" gradientTransform="matrix(.73643 8.7347e-7 -.0000011447 .96512 152.63 23.39)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5311" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="512.8" gradientTransform="matrix(.48062 -9.5378e-8 1.5922e-7 .80233 316.04 140.73)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5313" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="590.74" gradientTransform="matrix(.45736 -3.8247e-7 8.0707e-7 .96512 319.32 23.391)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5315" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="598.74" gradientTransform="matrix(.30233 3.7735e-8 -1.0014e-7 .80233 428.99 140.73)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5317" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="753.17" gradientTransform="matrix(.68217 -4.4781e-7 6.3355e-7 .96512 122.21 23.391)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5319" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="509.03" gradientTransform="matrix(.72462 8.7347e-7 -.0000011263 .96512 -12.477 15.53)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5321" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="512.8" gradientTransform="matrix(.47291 -9.5378e-8 1.5667e-7 .80233 148.31 132.87)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5323" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="590.74" gradientTransform="matrix(.45108 .0069435 -.014382 .96501 161.23 11.508)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5325" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="598.74" gradientTransform="matrix(.29748 3.7735e-8 -9.8537e-8 .80233 259.44 132.87)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5327" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="753.17" gradientTransform="matrix(.67123 -4.4781e-7 6.2339e-7 .96512 -42.412 15.531)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5329" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="509.03" gradientTransform="matrix(.73642 -.0042366 .0030467 .52973 -17.205 458.52)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5331" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="512.8" gradientTransform="matrix(.48062 .000392 -.00034729 .42594 148.97 528.69)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5333" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="590.74" gradientTransform="matrix(.45736 -.00082768 .00093239 .51491 151.73 463.54)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5335" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="598.74" gradientTransform="matrix(.30232 -.0012309 .0017686 .43441 260.37 520.55)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5337" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="753.17" gradientTransform="matrix(.68199 .015520 -.011766 .51703 -36.145 446.9)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5389" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="509.03" gradientTransform="matrix(.73643 8.7347e-7 -.0000011447 .96512 -18.367 115.54)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5391" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="512.8" gradientTransform="matrix(.48062 -9.5378e-8 1.5922e-7 .80233 145.62 232.86)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5393" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="590.74" gradientTransform="matrix(.45736 -3.8247e-7 8.0707e-7 .96512 149.43 115.52)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5395" xlink:href="#linearGradient3187" gradientUnits="userSpaceOnUse" cy="716.36" cx="598.74" gradientTransform="matrix(.30233 3.7735e-8 -1.0014e-7 .80233 258.58 232.89)" r="64.5"/>
|
||||
<radialGradient id="radialGradient5397" xlink:href="#linearGradient3175" gradientUnits="userSpaceOnUse" cy="717.11" cx="753.17" gradientTransform="matrix(.68217 -4.4781e-7 6.3355e-7 .96512 -47.791 115.52)" r="64.5"/>
|
||||
<radialGradient id="radialGradient2544" gradientUnits="userSpaceOnUse" cy="422.33" cx="1345.1" gradientTransform="matrix(.99128 -.0053344 .027760 5.1585 -.84309 -1759.8)" r="195.88">
|
||||
<stop id="stop4646" stop-color="#66676a" offset="0"/>
|
||||
<stop id="stop4648" stop-color="#66676a" stop-opacity="0" offset="1"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<g id="layer1" transform="translate(-821.7 -56.241)">
|
||||
<path id="path3446" d="m1235.6 199.12c-108.2 0-195.9 87.75-195.9 195.87 0 74.78 62.3 147.32 87.6 172.57 22.8 22.85 5.8 81.09 50.5 109.49l115.6 0.29c41.2-30.97 24.8-84.81 52.7-109.57 29.2-21.4 85.3-98 85.3-172.78 0-108.12-87.7-195.87-195.8-195.87z" stroke="#7f868f" stroke-linecap="round" fill="#fff"/>
|
||||
<path id="path3448" opacity=".29365" filter="url(#filter4712)" d="m1235.6 199.12c-108.2 0-195.9 87.75-195.9 195.87 0 74.78 65.5 149.92 89.3 172.79 24.4 23.39-0.3 77.64 48.8 109.56h115.6c41.2-30.97 24.2-86.49 52.7-109.57 28.6-23.07 85.3-98 85.3-172.78 0-108.12-87.7-195.87-195.8-195.87z" fill="url(#radialGradient2544)"/>
|
||||
<path id="path3450" fill="#fff" d="m1229.7 212.8c-1.1 0-2.2 0.01-3.3 0.03 88.9 11.45 157.6 87.42 157.6 179.34 0 69.04-51.9 139.76-78.8 159.52-25.8 22.85-10.6 72.56-48.7 101.15h-82.3c0.7 0.5 1.5 0.99 2.2 1.48h106.7c38.1-28.6 22.8-78.31 48.7-101.16 26.9-19.76 78.8-90.48 78.8-159.52 0-99.82-81-180.84-180.9-180.84z"/>
|
||||
<g id="g3452" stroke-linecap="round" transform="translate(828.16 .0000025)">
|
||||
<g id="g3454" stroke="#000" transform="matrix(1.0301 0 0 .93888 -654.71 -74.398)">
|
||||
<path id="path3456" d="m1078 891.75a51.736 20.077 0 1 1 -103.52 0 51.736 20.077 0 1 1 103.52 0z" fill="#000051" transform="translate(.77236 -.36379)"/>
|
||||
<path id="path3458" d="m1078 891.75a51.736 20.077 0 1 1 -103.52 0 51.736 20.077 0 1 1 103.52 0z" fill="url(#radialGradient5307)" transform="translate(.77236 -.36379)"/>
|
||||
</g>
|
||||
<g id="g3460" transform="translate(-174.44 -28.235)">
|
||||
<path id="path3462" d="m525.49 705.74h110.02c4.98 0 8.99 1.76 8.99 3.94v11.61c0 2.19-4.01 3.95-8.99 3.95h-110.02c-4.98 0-8.99-1.76-8.99-3.95v-11.61c0-2.18 4.01-3.94 8.99-3.94z" stroke="#000" fill="url(#radialGradient5309)"/>
|
||||
<path id="path3464" d="m525.49 705.74h110.02c4.98 0 8.99 1.76 8.99 3.94v11.61c0 2.19-4.01 3.95-8.99 3.95h-110.02c-4.98 0-8.99-1.76-8.99-3.95v-11.61c0-2.18 4.01-3.94 8.99-3.94z" stroke="#000" fill="url(#radialGradient5311)"/>
|
||||
<path id="path3466" d="m525.49 705.74h110.02c4.98 0 8.99 1.76 8.99 3.94v11.61c0 2.19-4.01 3.95-8.99 3.95h-110.02c-4.98 0-8.99-1.76-8.99-3.95v-11.61c0-2.18 4.01-3.94 8.99-3.94z" stroke="#000" fill="url(#radialGradient5313)"/>
|
||||
<path id="path3468" d="m525.49 705.74h110.02c4.98 0 8.99 1.76 8.99 3.94v11.61c0 2.19-4.01 3.95-8.99 3.95h-110.02c-4.98 0-8.99-1.76-8.99-3.95v-11.61c0-2.18 4.01-3.94 8.99-3.94z" stroke="#000" fill="url(#radialGradient5315)"/>
|
||||
<path id="path3470" d="m525.49 705.74h110.02c4.98 0 8.99 1.76 8.99 3.94v11.61c0 2.19-4.01 3.95-8.99 3.95h-110.02c-4.98 0-8.99-1.76-8.99-3.95v-11.61c0-2.18 4.01-3.94 8.99-3.94z" stroke="#565352" fill="url(#radialGradient5317)"/>
|
||||
</g>
|
||||
<path id="path3472" d="m354.4 697.88h108.26c4.9 0 2.26 0.47 2.54-1.06l0.74 6.46c0 2.19-3.31 3.47-8.21 3.47l-103.33 10.63c-4.9 0-8.84-1.76-8.84-3.95v-11.61c0-2.18 3.94-3.94 8.84-3.94z" stroke="#000" stroke-width=".99195" fill="url(#radialGradient5319)"/>
|
||||
<path id="path3474" d="m354.4 697.88l107.78-0.42c4.9 0 2.91 0.67 2.71-0.8l0.99 6.64c0 2.18-3.4 3.29-8.3 3.29l-103.18 10.79c-4.9 0-8.84-1.76-8.84-3.95v-11.61c0-2.18 3.94-3.94 8.84-3.94z" stroke="#000" stroke-width=".99195" fill="url(#radialGradient5321)"/>
|
||||
<path id="path3476" d="m354.4 697.88h108.26c4.9 0 2.69-3.72 2.69-1.53l0.6 7.34c0 2.18-3.54 2.39-8.44 2.39l-103.11 11.3c-4.9 0-8.84-1.76-8.84-3.95v-11.61c0-2.18 3.94-3.94 8.84-3.94z" stroke="#000" stroke-width=".99195" fill="url(#radialGradient5323)"/>
|
||||
<path id="path3478" d="m354.4 697.88h108.26c4.9 0 3-3.72 3-1.53l-0.34 6.66c0 2.19-3.81 3.23-8.51 3.74l-102.41 10.63c-4.9 0-8.84-1.76-8.84-3.95v-11.61c0-2.18 3.94-3.94 8.84-3.94z" stroke="#000" stroke-width=".99195" fill="url(#radialGradient5325)"/>
|
||||
<path id="path3480" d="m354.4 697.88h108.26c3.82-1.57 3.3-3.87 3.3-1.69l0.16 5.98c0 2.19-3.95 3.95-8.85 3.95l-102.87 11.26c-4.9 0-8.84-1.76-8.84-3.95v-11.61c0-2.18 3.94-3.94 8.84-3.94z" stroke="#4e4b4b" stroke-width=".99195" fill="url(#radialGradient5327)"/>
|
||||
<g id="g3482" transform="matrix(.95599 0 0 1 -333.55 -40.073)">
|
||||
<path id="path3484" d="m825.87 742.05c-0.21 0.01-0.43 0.03-0.65 0.04-0.3 0-0.59 0.01-0.88 0.03l-103.91 6.97c-2.79 0.2-4.79 0.88-6.12 1.78-1.6 0.96-2.53 2.3-2.47 3.97 0.05 1.46 1.11 2.58 2.66 3.37 1.44 0.81 3.4 1.29 5.56 1.31-2.27 0.21-3.98 0.74-5.22 1.44-0.04 0.02-0.09 0.04-0.12 0.06-0.1 0.05-0.2 0.11-0.29 0.16l-0.03 0.03-0.09 0.06c-0.16 0.1-0.32 0.21-0.47 0.32-0.02 0.01-0.04 0.04-0.06 0.06-1.26 0.92-1.99 2.09-1.94 3.56 0.04 1.29 0.87 2.33 2.13 3.09 0.01 0.01 0.01 0.03 0.03 0.04 0.15 0.09 0.33 0.19 0.5 0.28 1.18 0.67 2.72 1.07 4.43 1.22 0.07 0 0.13 0.02 0.19 0.03 0.19 0.02 0.37 0.02 0.56 0.03h0.47c0.42 0.02 0.86-0.02 1.28-0.03h0.07c0.12-0.01 0.25 0.01 0.37 0l103.91-6.97c1.2-0.08 2.32-0.32 3.31-0.69 3.21-0.98 5.09-2.7 4.81-5.09-0.27-2.43-2.54-4.05-5.75-4.5-0.02-0.01-0.04 0-0.06 0-0.05-0.01-0.1-0.03-0.16-0.03-0.03-0.01-0.06 0-0.09 0-0.29-0.04-0.57-0.08-0.87-0.1-0.23-0.01-0.49-0.02-0.72-0.03 0.89-0.09 1.73-0.27 2.5-0.53 3.41-0.97 5.44-2.75 5.15-5.22-0.28-2.48-2.64-4.09-5.97-4.5-0.62-0.09-1.32-0.16-2.06-0.16zm-0.65 21.04c-0.3 0-0.59 0.01-0.88 0.03l-103.91 6.97c-2.73 0.2-4.7 0.85-6.03 1.71-0.03 0.02-0.06 0.05-0.09 0.07l-0.09 0.06c-0.02 0.01-0.02 0.02-0.04 0.03-1.51 0.96-2.39 2.26-2.34 3.88 0.04 1.28 0.85 2.32 2.09 3.09 1.24 0.86 3.02 1.36 5 1.53 0.07 0.01 0.13 0.03 0.19 0.03 0.19 0.02 0.37 0.02 0.56 0.03-2.34 0.26-4.07 0.88-5.28 1.66l-0.09 0.06-0.09 0.06c-0.02 0.01-0.02 0.03-0.04 0.04-1.51 0.95-2.39 2.25-2.34 3.87 0.04 1.29 0.85 2.33 2.09 3.09 1.24 0.87 3.02 1.37 5 1.54 0.07 0 0.13 0.02 0.19 0.03 0.19 0.02 0.37 0.02 0.56 0.03h0.47c0.42 0.02 0.86-0.02 1.28-0.03h0.07c0.12-0.01 0.25 0.01 0.37 0l103.91-6.97c1.2-0.08 2.32-0.32 3.31-0.69 3.21-0.98 5.09-2.73 4.81-5.12-0.27-2.43-2.54-4.02-5.75-4.47-0.02-0.01-0.04 0-0.06 0-0.05-0.01-0.11-0.03-0.16-0.03-0.32-0.05-0.64-0.07-1-0.1-0.13-0.01-0.26-0.03-0.4-0.03 0.92-0.12 1.78-0.33 2.56-0.62 3.21-0.99 5.09-2.74 4.81-5.13-0.27-2.42-2.54-4.01-5.75-4.47-0.02 0-0.04 0.01-0.06 0-0.05-0.01-0.11-0.02-0.16-0.03-0.32-0.05-0.64-0.07-1-0.09-0.13-0.01-0.26-0.03-0.4-0.03-0.1-0.01-0.21 0-0.31 0-0.21-0.01-0.42-0.01-0.63 0-0.12-0.01-0.25-0.01-0.37 0zm0 21.15c-0.3 0-0.59 0.04-0.88 0.06l-8.69 0.6-95.22 6.34c-2.47 0.19-4.31 0.76-5.62 1.5-0.22 0.12-0.43 0.25-0.63 0.38-1.51 0.95-2.39 2.25-2.34 3.87 0.04 1.3 0.87 2.33 2.13 3.1 0.01 0 0.01 0.02 0.03 0.03 0.15 0.09 0.33 0.19 0.5 0.28 1.18 0.67 2.72 1.07 4.43 1.22 0.07 0 0.13 0.02 0.19 0.03 0.19 0.02 0.37 0.02 0.56 0.03h0.47c0.42 0.02 0.86-0.02 1.28-0.03h0.07c0.12-0.01 0.25 0.01 0.37 0l103.91-6.97c1.2-0.08 2.32-0.32 3.31-0.69 3.21-0.98 5.09-2.7 4.81-5.09-0.27-2.42-2.54-4.05-5.75-4.5-0.02-0.01-0.04 0-0.06 0-0.05-0.01-0.1-0.03-0.16-0.03-0.03-0.01-0.06 0-0.09 0-0.3-0.04-0.59-0.08-0.91-0.1-0.4-0.02-0.86-0.04-1.31-0.03h-0.4zm0.65 10.91c-0.17 0-0.35 0.02-0.53 0.03h-0.12c-0.17 0-0.34 0.02-0.5 0.03-0.13 0.01-0.25-0.01-0.38 0l-103.91 6.97c-2.72 0.2-4.67 0.86-6 1.72-0.03 0.02-0.08 0.04-0.12 0.06-1.6 0.96-2.53 2.3-2.47 3.97 0.05 1.46 1.11 2.59 2.66 3.37 1.23 0.7 2.83 1.13 4.62 1.25 0.31 0.03 0.62 0.06 0.94 0.07h0.94c0.14-0.01 0.29-0.02 0.43-0.03h0.07c0.12-0.01 0.25 0 0.37 0l103.91-6.97c1.06-0.07 2.07-0.3 2.97-0.6 3.41-0.96 5.44-2.75 5.15-5.22-0.31-2.71-3.1-4.43-6.93-4.62-0.35-0.02-0.73-0.03-1.1-0.03z" stroke="#000" stroke-width=".71131" fill="#fff"/>
|
||||
<g id="g3486" stroke-width=".73116" transform="matrix(.94643 0 0 1 255.03 -82.084)">
|
||||
<g id="g3488" transform="translate(134.21)">
|
||||
<path id="path3490" d="m357.51 831.16l109.79-6.96c4.98-0.32 9.6 1.57 9.97 4.61s-4.01 5.41-9.31 5.79l-109.79 6.97c-5.64 0.29-9.51-2.3-9.57-4.64-0.06-2.35 2.15-5.29 8.91-5.77z" stroke="#000" fill="url(#radialGradient5329)"/>
|
||||
<path id="path3492" d="m357.91 831.16l109.8-6.96c6.82-0.5 9.32 2.79 9.45 4.88 0.14 2.17-3.82 5.21-8.79 5.52l-109.79 6.97c-4.98 0.31-9.45-1.3-9.82-4.34s2.14-5.5 9.15-6.07z" stroke="#000" fill="url(#radialGradient5331)"/>
|
||||
<path id="path3494" d="m358.37 831.16l109.8-6.97c4.54-0.29 8.02 1.23 8.61 4.23 0.6 3.06-2.98 5.86-7.95 6.18l-109.8 6.96c-4.97 0.32-9.59-1.57-9.96-4.61-0.38-3.04 3.87-5.54 9.3-5.79z" stroke="#000" fill="url(#radialGradient5333)"/>
|
||||
<path id="path3496" d="m357.98 831.16l109.8-6.97c4.97-0.31 8.78 1.35 9.29 4.45 0.52 3.11-3.08 5.35-8.63 5.96l-109.8 6.96c-4.97 0.32-9.47-1.59-9.85-4.63-0.37-3.03 3.23-5.36 9.19-5.77z" stroke="#000" fill="url(#radialGradient5335)"/>
|
||||
<path id="path3498" d="m358.46 831.16l109.79-6.97c4.98-0.32 8.79 1.49 9.17 4.6s-3.1 5.13-8.5 5.8l-109.8 6.97c-4.97 0.32-10.55-1.31-10.67-4.65-0.13-3.42 4.03-5.41 10.01-5.75z" stroke="#565352" fill="url(#radialGradient5337)"/>
|
||||
</g>
|
||||
<g id="g3500" transform="translate(134.21 10.389)">
|
||||
<path id="path3502" d="m357.51 831.16l109.79-6.96c4.98-0.32 9.6 1.57 9.97 4.61s-4.01 5.41-9.31 5.79l-109.79 6.97c-5.64 0.29-9.51-2.3-9.57-4.64-0.06-2.35 2.15-5.29 8.91-5.77z" stroke="#000" fill="url(#radialGradient5329)"/>
|
||||
<path id="path3504" d="m357.91 831.16l109.8-6.96c6.82-0.5 9.32 2.79 9.45 4.88 0.14 2.17-3.82 5.21-8.79 5.52l-109.79 6.97c-4.98 0.31-9.45-1.3-9.82-4.34s2.14-5.5 9.15-6.07z" stroke="#000" fill="url(#radialGradient5331)"/>
|
||||
<path id="path3506" d="m358.37 831.16l109.8-6.97c4.54-0.29 8.02 1.23 8.61 4.23 0.6 3.06-2.98 5.86-7.95 6.18l-109.8 6.96c-4.97 0.32-9.59-1.57-9.96-4.61-0.38-3.04 3.87-5.54 9.3-5.79z" stroke="#000" fill="url(#radialGradient5333)"/>
|
||||
<path id="path3508" d="m357.98 831.16l109.8-6.97c4.97-0.31 8.78 1.35 9.29 4.45 0.52 3.11-3.08 5.35-8.63 5.96l-109.8 6.96c-4.97 0.32-9.47-1.59-9.85-4.63-0.37-3.03 3.23-5.36 9.19-5.77z" stroke="#000" fill="url(#radialGradient5335)"/>
|
||||
<path id="path3510" d="m358.46 831.16l109.79-6.97c4.98-0.32 8.79 1.49 9.17 4.6s-3.1 5.13-8.5 5.8l-109.8 6.97c-4.97 0.32-10.55-1.31-10.67-4.65-0.13-3.42 4.03-5.41 10.01-5.75z" stroke="#565352" fill="url(#radialGradient5337)"/>
|
||||
</g>
|
||||
<g id="g3512" transform="translate(134.21 21.011)">
|
||||
<path id="path3514" d="m357.51 831.16l109.79-6.96c4.98-0.32 9.6 1.57 9.97 4.61s-4.01 5.41-9.31 5.79l-109.79 6.97c-5.64 0.29-9.51-2.3-9.57-4.64-0.06-2.35 2.15-5.29 8.91-5.77z" stroke="#000" fill="url(#radialGradient5329)"/>
|
||||
<path id="path3516" d="m357.91 831.16l109.8-6.96c6.82-0.5 9.32 2.79 9.45 4.88 0.14 2.17-3.82 5.21-8.79 5.52l-109.79 6.97c-4.98 0.31-9.45-1.3-9.82-4.34s2.14-5.5 9.15-6.07z" stroke="#000" fill="url(#radialGradient5331)"/>
|
||||
<path id="path3518" d="m358.37 831.16l109.8-6.97c4.54-0.29 8.02 1.23 8.61 4.23 0.6 3.06-2.98 5.86-7.95 6.18l-109.8 6.96c-4.97 0.32-9.59-1.57-9.96-4.61-0.38-3.04 3.87-5.54 9.3-5.79z" stroke="#000" fill="url(#radialGradient5333)"/>
|
||||
<path id="path3520" d="m357.98 831.16l109.8-6.97c4.97-0.31 8.78 1.35 9.29 4.45 0.52 3.11-3.08 5.35-8.63 5.96l-109.8 6.96c-4.97 0.32-9.47-1.59-9.85-4.63-0.37-3.03 3.23-5.36 9.19-5.77z" stroke="#000" fill="url(#radialGradient5335)"/>
|
||||
<path id="path3522" d="m358.46 831.16l109.79-6.97c4.98-0.32 8.79 1.49 9.17 4.6s-3.1 5.13-8.5 5.8l-109.8 6.97c-4.97 0.32-10.55-1.31-10.67-4.65-0.13-3.42 4.03-5.41 10.01-5.75z" stroke="#565352" fill="url(#radialGradient5337)"/>
|
||||
</g>
|
||||
<g id="g3524" transform="translate(134.21 31.385)">
|
||||
<path id="path3526" d="m357.51 831.16l109.79-6.96c4.98-0.32 9.6 1.57 9.97 4.61s-4.01 5.41-9.31 5.79l-109.79 6.97c-5.64 0.29-9.51-2.3-9.57-4.64-0.06-2.35 2.15-5.29 8.91-5.77z" stroke="#000" fill="url(#radialGradient5329)"/>
|
||||
<path id="path3528" d="m357.91 831.16l109.8-6.96c6.82-0.5 9.32 2.79 9.45 4.88 0.14 2.17-3.82 5.21-8.79 5.52l-109.79 6.97c-4.98 0.31-9.45-1.3-9.82-4.34s2.14-5.5 9.15-6.07z" stroke="#000" fill="url(#radialGradient5331)"/>
|
||||
<path id="path3530" d="m358.37 831.16l109.8-6.97c4.54-0.29 8.02 1.23 8.61 4.23 0.6 3.06-2.98 5.86-7.95 6.18l-109.8 6.96c-4.97 0.32-9.59-1.57-9.96-4.61-0.38-3.04 3.87-5.54 9.3-5.79z" stroke="#000" fill="url(#radialGradient5333)"/>
|
||||
<path id="path3532" d="m357.98 831.16l109.8-6.97c4.97-0.31 8.78 1.35 9.29 4.45 0.52 3.11-3.08 5.35-8.63 5.96l-109.8 6.96c-4.97 0.32-9.47-1.59-9.85-4.63-0.37-3.03 3.23-5.36 9.19-5.77z" stroke="#000" fill="url(#radialGradient5335)"/>
|
||||
<path id="path3534" d="m358.46 831.16l109.79-6.97c4.98-0.32 8.79 1.49 9.17 4.6s-3.1 5.13-8.5 5.8l-109.8 6.97c-4.97 0.32-10.55-1.31-10.67-4.65-0.13-3.42 4.03-5.41 10.01-5.75z" stroke="#565352" fill="url(#radialGradient5337)"/>
|
||||
</g>
|
||||
<g id="g3536" transform="translate(134.21 42.169)">
|
||||
<path id="path3538" d="m357.51 831.16l109.79-6.96c4.98-0.32 9.6 1.57 9.97 4.61s-4.01 5.41-9.31 5.79l-109.79 6.97c-5.64 0.29-9.51-2.3-9.57-4.64-0.06-2.35 2.15-5.29 8.91-5.77z" stroke="#000" fill="url(#radialGradient5329)"/>
|
||||
<path id="path3540" d="m357.91 831.16l109.8-6.96c6.82-0.5 9.32 2.79 9.45 4.88 0.14 2.17-3.82 5.21-8.79 5.52l-109.79 6.97c-4.98 0.31-9.45-1.3-9.82-4.34s2.14-5.5 9.15-6.07z" stroke="#000" fill="url(#radialGradient5331)"/>
|
||||
<path id="path3542" d="m358.37 831.16l109.8-6.97c4.54-0.29 8.02 1.23 8.61 4.23 0.6 3.06-2.98 5.86-7.95 6.18l-109.8 6.96c-4.97 0.32-9.59-1.57-9.96-4.61-0.38-3.04 3.87-5.54 9.3-5.79z" stroke="#000" fill="url(#radialGradient5333)"/>
|
||||
<path id="path3544" d="m357.98 831.16l109.8-6.97c4.97-0.31 8.78 1.35 9.29 4.45 0.52 3.11-3.08 5.35-8.63 5.96l-109.8 6.96c-4.97 0.32-9.47-1.59-9.85-4.63-0.37-3.03 3.23-5.36 9.19-5.77z" stroke="#000" fill="url(#radialGradient5335)"/>
|
||||
<path id="path3546" d="m358.46 831.16l109.79-6.97c4.98-0.32 8.79 1.49 9.17 4.6s-3.1 5.13-8.5 5.8l-109.8 6.97c-4.97 0.32-10.55-1.31-10.67-4.65-0.13-3.42 4.03-5.41 10.01-5.75z" stroke="#565352" fill="url(#radialGradient5337)"/>
|
||||
</g>
|
||||
<g id="g3548" transform="translate(134.21 53.089)">
|
||||
<path id="path3550" d="m357.51 831.16l109.79-6.96c4.98-0.32 9.6 1.57 9.97 4.61s-4.01 5.41-9.31 5.79l-109.79 6.97c-5.64 0.29-9.51-2.3-9.57-4.64-0.06-2.35 2.15-5.29 8.91-5.77z" stroke="#000" fill="url(#radialGradient5329)"/>
|
||||
<path id="path3552" d="m357.91 831.16l109.8-6.96c6.82-0.5 9.32 2.79 9.45 4.88 0.14 2.17-3.82 5.21-8.79 5.52l-109.79 6.97c-4.98 0.31-9.45-1.3-9.82-4.34s2.14-5.5 9.15-6.07z" stroke="#000" fill="url(#radialGradient5331)"/>
|
||||
<path id="path3554" d="m358.37 831.16l109.8-6.97c4.54-0.29 8.02 1.23 8.61 4.23 0.6 3.06-2.98 5.86-7.95 6.18l-109.8 6.96c-4.97 0.32-9.59-1.57-9.96-4.61-0.38-3.04 3.87-5.54 9.3-5.79z" stroke="#000" fill="url(#radialGradient5333)"/>
|
||||
<path id="path3556" d="m357.98 831.16l109.8-6.97c4.97-0.31 8.78 1.35 9.29 4.45 0.52 3.11-3.08 5.35-8.63 5.96l-109.8 6.96c-4.97 0.32-9.47-1.59-9.85-4.63-0.37-3.03 3.23-5.36 9.19-5.77z" stroke="#000" fill="url(#radialGradient5335)"/>
|
||||
<path id="path3558" d="m358.46 831.16l109.79-6.97c4.98-0.32 8.79 1.49 9.17 4.6s-3.1 5.13-8.5 5.8l-109.8 6.97c-4.97 0.32-10.55-1.31-10.67-4.65-0.13-3.42 4.03-5.41 10.01-5.75z" stroke="#565352" fill="url(#radialGradient5337)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g3560" transform="matrix(.23216 0 0 .11037 265.8 686.62)">
|
||||
<path id="path3562" d="m543.29 847.29h110.02c4.98 0 8.68 3.83 8.86 9.68s-3.42 9.21-8.86 9.82h-110.02c-4.98 0-10.44-3.69-10.35-9.95 0.09-6.39 4.37-9.62 10.35-9.55z" stroke="#565352" fill="#fff"/>
|
||||
<g id="g3564" transform="translate(187.8 49.415)">
|
||||
<path id="path3566" d="m354.49 797.88h110.02c4.98 0 9.48 4.09 9.65 9.8 0.18 5.71-4.34 9.62-9.65 9.7h-110.02c-5.64-0.13-9.34-5.41-9.26-9.79 0.09-4.39 2.49-9.62 9.26-9.71z" stroke="#000" fill="url(#radialGradient5389)"/>
|
||||
<path id="path3568" d="m355.07 797.86h110.02c6.83-0.12 9.13 6.31 9.13 10.24 0 4.06-4.15 9.26-9.13 9.26h-110.02c-4.98 0-9.34-3.54-9.52-9.26-0.18-5.71 2.49-10.02 9.52-10.24z" stroke="#000" fill="url(#radialGradient5391)"/>
|
||||
<path id="path3570" d="m355.6 797.87h110.02c4.55 0 7.93 3.25 8.33 8.91 0.41 5.79-3.35 10.59-8.33 10.59h-110.02c-4.98 0-9.47-4.08-9.65-9.8-0.18-5.71 4.21-9.88 9.65-9.7z" stroke="#000" fill="url(#radialGradient5393)"/>
|
||||
<path id="path3572" d="m355.09 797.89h110.02c4.98 0 8.67 3.56 8.99 9.41 0.32 5.86-3.42 9.62-8.99 10.09h-110.02c-4.98 0-9.36-4.1-9.54-9.81-0.17-5.72 3.56-9.62 9.54-9.69z" stroke="#000" fill="url(#radialGradient5395)"/>
|
||||
<path id="path3574" d="m355.49 797.86h110.02c4.98 0 8.67 3.83 8.85 9.68s-3.41 9.21-8.85 9.82h-110.02c-4.98 0-10.45-3.69-10.36-9.95 0.1-6.39 4.38-9.62 10.36-9.55z" stroke="#565352" fill="url(#radialGradient5397)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work>
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
|
||||
<dc:publisher>
|
||||
<cc:Agent rdf:about="http://openclipart.org/">
|
||||
<dc:title>Openclipart</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:title>basic light bulb</dc:title>
|
||||
<dc:date>2007-02-16T04:05:06</dc:date>
|
||||
<dc:description/>
|
||||
<dc:source>https://openclipart.org/detail/175842/Clipart-by-drunken_duck</dc:source>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>drunken_duck</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>light</rdf:li>
|
||||
<rdf:li>bulb</rdf:li>
|
||||
<rdf:li>electricity</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</cc:Work>
|
||||
<cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 24 KiB |
|
@ -128,6 +128,15 @@
|
|||
},
|
||||
"then": "circle:white;./assets/layers/recycling/engine_oil.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"_waste_amount=1",
|
||||
"recycling:fluorescent_tubes=yes"
|
||||
]
|
||||
},
|
||||
"then": "circle:white;./assets/layers/recycling/fluorescent_tubes.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
|
@ -160,6 +169,15 @@
|
|||
},
|
||||
"then": "circle:white;./assets/layers/recycling/garden_waste.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"_waste_amount=1",
|
||||
"recycling:light_bulbs=yes"
|
||||
]
|
||||
},
|
||||
"then": "circle:white;./assets/layers/recycling/light_bulbs.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
|
@ -303,6 +321,15 @@
|
|||
},
|
||||
"then": "circle:white;./assets/layers/recycling/engine_oil.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"_waste_amount>1",
|
||||
"recycling:fluorescent_tubes=yes"
|
||||
]
|
||||
},
|
||||
"then": "circle:white;./assets/layers/recycling/fluorescent_tubes.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
|
@ -335,6 +362,15 @@
|
|||
},
|
||||
"then": "circle:white;./assets/layers/recycling/garden_waste.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"_waste_amount>1",
|
||||
"recycling:light_bulbs=yes"
|
||||
]
|
||||
},
|
||||
"then": "circle:white;./assets/layers/recycling/light_bulbs.svg"
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
|
@ -500,7 +536,9 @@
|
|||
"recycling:clothes=",
|
||||
"recycling:cooking_oil=",
|
||||
"recycling:engine_oil=",
|
||||
"recycling:fluorescent_tubes=",
|
||||
"recycling:green_waste=",
|
||||
"recycling:light_bulbs=",
|
||||
"recycling:organic=",
|
||||
"recycling:glass_bottles=",
|
||||
"recycling:glass=",
|
||||
|
@ -698,6 +736,18 @@
|
|||
"class": "medium"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "recycling:fluorescent_tubes=yes",
|
||||
"ifnot": "recycling:fluorescent_tubes=",
|
||||
"then": {
|
||||
"en": "Fluorescent tubes can be recycled here",
|
||||
"nl": "TL-buizen kunnen hier gerecycled worden"
|
||||
},
|
||||
"icon": {
|
||||
"path": "./assets/layers/recycling/fluorescent_tubes.svg",
|
||||
"class": "medium"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "recycling:green_waste=yes",
|
||||
"ifnot": "recycling:green_waste=",
|
||||
|
@ -761,6 +811,18 @@
|
|||
"class": "medium"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "recycling:light_bulbs=yes",
|
||||
"ifnot": "recycling:light_bulbs=",
|
||||
"then": {
|
||||
"en": "Light bulbs can be recycled here",
|
||||
"nl": "Lampen kunnen hier gerecycled worden"
|
||||
},
|
||||
"icon": {
|
||||
"path": "./assets/layers/recycling/light_bulbs.svg",
|
||||
"class": "medium"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "recycling:newspaper=yes",
|
||||
"ifnot": "recycling:newspaper=",
|
||||
|
@ -1047,6 +1109,13 @@
|
|||
},
|
||||
"osmTags": "recycling:engine_oil=yes"
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Recycling of fluorescent tubes",
|
||||
"nl": "Recycling van tl-buizen"
|
||||
},
|
||||
"osmTags": "recycling:fluorescent_tubes=yes"
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Recycling of green waste",
|
||||
|
@ -1081,6 +1150,13 @@
|
|||
},
|
||||
"osmTags": "recycling:glass=yes"
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Recycling of light bulbs",
|
||||
"nl": "Recycling van lampen"
|
||||
},
|
||||
"osmTags": "recycling:light_bulbs=yes"
|
||||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Recycling of newspapers",
|
||||
|
|
|
@ -528,7 +528,8 @@
|
|||
"de": "eine an einer Wand montierte Überwachungskamera"
|
||||
},
|
||||
"preciseInput": {
|
||||
"snapToLayer": "walls_and_buildings"
|
||||
"snapToLayer": "walls_and_buildings",
|
||||
"preferredBackground": ["photo", "osmbasedmap","map"]
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -597,4 +598,4 @@
|
|||
"nl": "Deze laag toont bewakingscamera's en laat toe om de informatie te verrijken en om nieuwe camera\"s toe te voegen",
|
||||
"de": "Diese Ebene zeigt die Überwachungskameras an und ermöglicht es, Informationen zu aktualisieren und neue Kameras hinzuzufügen"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
"then": {
|
||||
"en": "This ticket validator accepts OV-Chipkaart"
|
||||
},
|
||||
"hideInAnswer": "_country!=nl"
|
||||
"hideInAnswer": true
|
||||
},
|
||||
{
|
||||
"if": "payment:ov-chipkaart=yes",
|
||||
|
@ -76,7 +76,7 @@
|
|||
"then": {
|
||||
"en": "This ticket validator accepts OV-Chipkaart"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
"hideInAnswer": "_country!=nl"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -90,6 +90,9 @@
|
|||
"title": {
|
||||
"en": "a ticket validator",
|
||||
"de": "einen Fahrkartenentwerter"
|
||||
},
|
||||
"description": {
|
||||
"en": "A ticket validator to validate a public transport ticket. This can be either a digital reader, reading a card or ticket, or a machine stamping or punching a ticket."
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -103,4 +106,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"license": "CC-BY",
|
||||
"authors": [
|
||||
"asianson.design",
|
||||
" Pieter Vander Vennet"
|
||||
"Pieter Vander Vennet"
|
||||
],
|
||||
"sources": [
|
||||
"https://thenounproject.com/term/urinal/1307984/"
|
||||
|
@ -22,6 +22,8 @@
|
|||
"path": "wheelchair.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://wiki.openstreetmap.org/wiki/File:Wheelchair_symbol.svg"
|
||||
]
|
||||
}
|
||||
]
|
|
@ -233,7 +233,7 @@
|
|||
"id": "toilet-charge"
|
||||
},
|
||||
{
|
||||
"builtin": "payment-options",
|
||||
"builtin": "payment-options-split",
|
||||
"override": {
|
||||
"condition": "fee=yes"
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
"path": "wheelchair.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://wiki.openstreetmap.org/wiki/File:Wheelchair_symbol.svg"
|
||||
]
|
||||
}
|
||||
]
|
|
@ -32,7 +32,7 @@
|
|||
}
|
||||
},
|
||||
"description": {
|
||||
"en": "This is a public waste basket, thrash can, where you can throw away your thrash.",
|
||||
"en": "This is a public waste basket, trash can, where you can throw away your trash.",
|
||||
"nl": "Dit is een publieke vuilnisbak waar je je afval kan weggooien.",
|
||||
"de": "Dies ist ein öffentlicher Abfalleimer, in den Sie Ihren Müll entsorgen können.",
|
||||
"hu": "Ez egy nyilvános szemétkosár vagy kuka, ahová kidobhatod a szemetedet.",
|
||||
|
@ -369,4 +369,4 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[
|
||||
{
|
||||
"path": "watermill.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
}
|
||||
]
|
|
@ -1,191 +0,0 @@
|
|||
{
|
||||
"id": "watermill",
|
||||
"name": {
|
||||
"nl": "Watermolens",
|
||||
"en": "Watermill",
|
||||
"de": "Wassermühlen",
|
||||
"ru": "Водяная мельница",
|
||||
"id": "Kincir Air",
|
||||
"fr": "Moulin à eau",
|
||||
"ca": "Molí d'aigua",
|
||||
"da": "Vandmølle"
|
||||
},
|
||||
"minzoom": 12,
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"and": [
|
||||
"man_made=watermill"
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"render": {
|
||||
"nl": "Watermolens"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"name:nl~*"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "{name:nl}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"name~*"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "{name}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"nl": "Watermolens"
|
||||
},
|
||||
"tagRenderings": [
|
||||
"images",
|
||||
{
|
||||
"render": {
|
||||
"nl": "De toegankelijkheid van dit gebied is: {access:description}"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Is dit gebied toegankelijk?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "access:description"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"access=yes",
|
||||
"fee="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Vrij toegankelijk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"access=no",
|
||||
"fee="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Niet toegankelijk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"access=private",
|
||||
"fee="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Niet toegankelijk, want privégebied"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"access=permissive",
|
||||
"fee="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Toegankelijk, ondanks dat het privegebied is"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"access=guided",
|
||||
"fee="
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Enkel toegankelijk met een gids of tijdens een activiteit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"access=yes",
|
||||
"fee=yes"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Toegankelijk mits betaling"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": "Access tag"
|
||||
},
|
||||
{
|
||||
"render": {
|
||||
"nl": "Beheer door {operator}"
|
||||
},
|
||||
"question": {
|
||||
"nl": "Wie beheert dit pad?"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "operator"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"operator=Natuurpunt"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Dit gebied wordt beheerd door Natuurpunt"
|
||||
},
|
||||
"icon": {
|
||||
"path": "./assets/themes/buurtnatuur/Natuurpunt.jpg",
|
||||
"class": "small"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"operator~(n|N)atuurpunt.*"
|
||||
]
|
||||
},
|
||||
"then": {
|
||||
"nl": "Dit gebied wordt beheerd door {operator}"
|
||||
},
|
||||
"hideInAnswer": true,
|
||||
"icon": {
|
||||
"path": "./assets/themes/buurtnatuur/Natuurpunt.jpg",
|
||||
"class": "small"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": "Operator tag"
|
||||
}
|
||||
],
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": {
|
||||
"render": "./assets/layers/watermill/watermill.svg"
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "50,50,center"
|
||||
},
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="281px" height="374px" viewBox="0 0 281 374" version="1.1">
|
||||
<g id="surface1">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 173.078125 146.714844 L 281 39.171875 L 269.894531 28.089844 L 257.675781 15.707031 L 159.9375 113.457031 C 154.6875 108.464844 147.746094 105.632812 140.5 105.511719 L 136.058594 105.511719 L 34.617188 4.621094 L 23.511719 15.707031 L 11.105469 27.902344 L 111.066406 127.871094 C 110.085938 130.175781 109.398438 132.597656 109.03125 135.074219 L 107.179688 143.945312 L 0 250.566406 L 11.105469 261.652344 L 23.324219 274.035156 L 94.964844 202.519531 L 66.085938 342.21875 L 45.167969 342.21875 L 45.167969 369.378906 L 240.644531 369.378906 L 240.644531 342.21875 L 218.988281 342.21875 L 193.070312 231.347656 L 246.382812 284.5625 L 257.488281 273.480469 L 269.894531 261.28125 L 178.820312 170.925781 Z M 162.898438 340.183594 L 122.171875 340.183594 L 122.171875 287.152344 C 122.171875 276.03125 131.207031 267.007812 142.351562 267.007812 C 147.765625 266.910156 152.992188 268.992188 156.859375 272.777344 C 160.722656 276.566406 162.898438 281.746094 162.898438 287.152344 Z M 162.898438 340.183594 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.3 KiB |
|
@ -499,12 +499,6 @@
|
|||
"https://www.iconpacks.net/free-icon-pack/gender-107.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "gender_female.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
},
|
||||
{
|
||||
"path": "gender_female.svg",
|
||||
"license": "CC0",
|
||||
|
@ -525,12 +519,6 @@
|
|||
"https://www.iconpacks.net/free-icon-pack/gender-107.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "gender_male.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
},
|
||||
{
|
||||
"path": "gender_male.svg",
|
||||
"license": "CC0",
|
||||
|
@ -551,12 +539,6 @@
|
|||
"https://www.iconpacks.net/free-icon-pack/gender-107.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "gender_trans.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
},
|
||||
{
|
||||
"path": "gender_trans.svg",
|
||||
"license": "CC0",
|
||||
|
@ -899,7 +881,7 @@
|
|||
},
|
||||
{
|
||||
"path": "none.svg",
|
||||
"license": "CC0",
|
||||
"license": "trivial",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
},
|
||||
|
@ -1277,9 +1259,11 @@
|
|||
},
|
||||
{
|
||||
"path": "teardrop_with_hole_green.svg",
|
||||
"license": "CC0",
|
||||
"license": "Creative Commons 4.0 BY-NC",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://pngimg.com/image/46283"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "translate.svg",
|
||||
|
|
|
@ -919,6 +919,7 @@
|
|||
"icon": "./assets/tagRenderings/coins.svg",
|
||||
"then": {
|
||||
"en": "Coins are accepted here",
|
||||
"nl": "Muntgeld wordt hier aanvaard",
|
||||
"de": "Münzen werden hier akzeptiert"
|
||||
}
|
||||
},
|
||||
|
@ -928,6 +929,7 @@
|
|||
"icon": "./assets/tagRenderings/notes.svg",
|
||||
"then": {
|
||||
"en": "Bank notes are accepted here",
|
||||
"nl": "Bankbiljetten worden hier aanvaard",
|
||||
"de": "Geldscheine werden hier akzeptiert"
|
||||
}
|
||||
},
|
||||
|
@ -937,6 +939,7 @@
|
|||
"icon": "./assets/tagRenderings/payment_card.svg",
|
||||
"then": {
|
||||
"en": "Debit cards are accepted here",
|
||||
"nl": "Betalen met debetkaarten kan hier",
|
||||
"de": "Debitkarten werden hier akzeptiert"
|
||||
}
|
||||
},
|
||||
|
@ -946,6 +949,7 @@
|
|||
"icon": "./assets/tagRenderings/payment_card.svg",
|
||||
"then": {
|
||||
"en": "Credit cards are accepted here",
|
||||
"nl": "Betalen met creditkaarten kan hier",
|
||||
"de": "Kreditkarten werden hier akzeptiert"
|
||||
}
|
||||
}
|
||||
|
@ -1664,4 +1668,4 @@
|
|||
"es": "El nombre de red es <b>{internet_access:ssid}</b>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,8 +13,13 @@
|
|||
{
|
||||
"path": "car.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"authors": [
|
||||
"Simon Child",
|
||||
"The Noun Project"
|
||||
],
|
||||
"sources": [
|
||||
"https://thenounproject.com/icon/electric-car-55511/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "logo.svg",
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
"socialImage": "./assets/themes/cyclofix/logo.svg",
|
||||
"layers": [
|
||||
"bike_cafe",
|
||||
"bike_shop",
|
||||
{
|
||||
"builtin": [
|
||||
"bicycle_rental"
|
||||
|
@ -87,7 +88,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"bike_shop",
|
||||
{
|
||||
"builtin": "bicycle_library",
|
||||
"override": {
|
||||
|
@ -130,4 +130,4 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,37 +3,49 @@
|
|||
"path": "bench.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "birdhide.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "drips.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "information.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "information_board.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "nature_reserve.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "natuurpunt.png",
|
||||
|
@ -49,72 +61,88 @@
|
|||
"path": "parking.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "parkingbike.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "parkingmotor.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "parkingwheels.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "picnic_table.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "pushchair.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "toilets.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "trail.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "urinal.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "walk_wheelchair.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
},
|
||||
{
|
||||
"path": "watermill.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "wheelchair.svg",
|
||||
"license": "CC0",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://osoc.be/editions/2021/nature-moves"
|
||||
]
|
||||
}
|
||||
]
|
|
@ -323,24 +323,6 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "watermill",
|
||||
"override": {
|
||||
"minzoom": "14",
|
||||
"source": {
|
||||
"geoJson": "https://raw.githubusercontent.com/pietervdvn/MapComplete-data/main/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson",
|
||||
"geoJsonZoomLevel": 12,
|
||||
"isOsmCache": true
|
||||
},
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": {
|
||||
"render": "circle:#FE6F32;./assets/themes/natuurpunt/watermill.svg"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "gps_track",
|
||||
"override": {
|
||||
|
@ -353,4 +335,4 @@
|
|||
"enableIframePopout": false,
|
||||
"enableBackgroundLayerSelection": false,
|
||||
"enableNoteImports": false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="-10 8 15.18 19.74"
|
||||
version="1.1"
|
||||
id="svg1054"
|
||||
sodipodi:docname="watermill.svg"
|
||||
width="15.18"
|
||||
height="19.74"
|
||||
inkscape:version="1.1.1 (1:1.1+202109281949+c3084ef5ed)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1056"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="6.0407534"
|
||||
inkscape:cx="-31.949657"
|
||||
inkscape:cy="10.594705"
|
||||
inkscape:current-layer="svg1054" />
|
||||
<defs
|
||||
id="defs1048">
|
||||
<style
|
||||
id="style1046">.cls-1{fill:#fff;}</style>
|
||||
</defs>
|
||||
<g
|
||||
id="Layer_2"
|
||||
data-name="Layer 2"
|
||||
transform="matrix(0.58392824,0,0,0.58392824,-6.8420153,12.106628)">
|
||||
<g
|
||||
id="Layer_1-2"
|
||||
data-name="Layer 1">
|
||||
<path
|
||||
class="cls-1"
|
||||
d="M 9.35,7.69 15.18,1.87 14.58,1.27 13.92,0.6 8.64,5.89 A 1.56,1.56 0 0 0 7.59,5.46 H 7.35 L 1.87,0 1.27,0.6 0.6,1.26 6,6.67 A 1.6,1.6 0 0 0 5.89,7.06 v 0 L 5.79,7.54 0,13.31 l 0.6,0.6 0.66,0.67 3.87,-3.87 -1.56,7.56 H 2.44 v 1.47 H 13 v -1.47 h -1.17 l -1.4,-6 2.88,2.88 0.6,-0.6 0.67,-0.66 L 9.66,9 Z M 8.8,18.16 H 6.6 V 15.29 A 1.09,1.09 0 0 1 7.69,14.2 v 0 a 1.09,1.09 0 0 1 1.11,1.09 z"
|
||||
id="path1050" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.6 KiB |
|
@ -189,6 +189,25 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"builtin": "parking_spaces",
|
||||
"override": {
|
||||
"source": {
|
||||
"osmTags": "parking_space=disabled"
|
||||
},
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": {
|
||||
"mappings": null
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"hideTagRenderingsWithLabels": [
|
||||
"type",
|
||||
"capacity"
|
||||
]
|
||||
},
|
||||
{
|
||||
"builtin": "shops",
|
||||
"override": {
|
||||
|
|
|
@ -107,9 +107,11 @@
|
|||
},
|
||||
{
|
||||
"path": "logo.svg",
|
||||
"license": "CC0",
|
||||
"license": "Creative Commons 4.0 BY-NC",
|
||||
"authors": [],
|
||||
"sources": []
|
||||
"sources": [
|
||||
"https://pngimg.com/image/46283"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "observation_platform.svg",
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
{
|
||||
"path": "icon.svg",
|
||||
"license": "CC0; trivial",
|
||||
"authors": [],
|
||||
"authors": [
|
||||
"Pieter Vander Vennet"
|
||||
],
|
||||
"sources": []
|
||||
}
|
||||
]
|
|
@ -913,6 +913,7 @@
|
|||
"inviteToSplit": "Split this road in smaller segments. This allows to give different properties to parts of the road.",
|
||||
"loginToSplit": "You must be logged in to split a road",
|
||||
"split": "Split",
|
||||
"splitAgain": "Split this road again",
|
||||
"splitTitle": "Choose on the map where the properties of this road change"
|
||||
},
|
||||
"translations": {
|
||||
|
|
|
@ -881,31 +881,31 @@
|
|||
"2": {
|
||||
"then": "Ací es poden reciclar llaunes"
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"then": "Ací es poden reciclar residus orgànics"
|
||||
},
|
||||
"8": {
|
||||
"9": {
|
||||
"then": "Ací es poden reciclar ampolles de vidre"
|
||||
},
|
||||
"9": {
|
||||
"10": {
|
||||
"then": "Ací es pot reciclar vidre"
|
||||
},
|
||||
"10": {
|
||||
"12": {
|
||||
"then": "Ací es poden reciclar diaris"
|
||||
},
|
||||
"11": {
|
||||
"13": {
|
||||
"then": "Ací es pot reciclar paper"
|
||||
},
|
||||
"12": {
|
||||
"14": {
|
||||
"then": "Ací es poden reciclar ampolles de plàstic"
|
||||
},
|
||||
"13": {
|
||||
"15": {
|
||||
"then": "Ací es poden reciclar envasos de plàstic"
|
||||
},
|
||||
"14": {
|
||||
"16": {
|
||||
"then": "Ací es pot reciclar plàstic"
|
||||
},
|
||||
"20": {
|
||||
"22": {
|
||||
"then": "Ací es pot reciclar el rebuig"
|
||||
}
|
||||
}
|
||||
|
@ -1052,9 +1052,6 @@
|
|||
"render": "Paperera"
|
||||
}
|
||||
},
|
||||
"watermill": {
|
||||
"name": "Molí d'aigua"
|
||||
},
|
||||
"windturbine": {
|
||||
"title": {
|
||||
"mappings": {
|
||||
|
|
|
@ -6322,37 +6322,37 @@
|
|||
"6": {
|
||||
"question": "Recycling von Motoröl"
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"question": "Recycling von Grünabfällen"
|
||||
},
|
||||
"8": {
|
||||
"9": {
|
||||
"question": "Recycling von Glasflaschen"
|
||||
},
|
||||
"9": {
|
||||
"10": {
|
||||
"question": "Recycling von Glas"
|
||||
},
|
||||
"10": {
|
||||
"12": {
|
||||
"question": "Recycling von Zeitungen"
|
||||
},
|
||||
"11": {
|
||||
"13": {
|
||||
"question": "Recycling von Papier"
|
||||
},
|
||||
"12": {
|
||||
"14": {
|
||||
"question": "Recycling von Plastikflaschen"
|
||||
},
|
||||
"13": {
|
||||
"15": {
|
||||
"question": "Recycling von Kunststoffverpackungen"
|
||||
},
|
||||
"14": {
|
||||
"16": {
|
||||
"question": "Recycling von Kunststoffen"
|
||||
},
|
||||
"15": {
|
||||
"17": {
|
||||
"question": "Recycling von Metallschrott"
|
||||
},
|
||||
"16": {
|
||||
"18": {
|
||||
"question": "Recycling von Elektrokleingeräten"
|
||||
},
|
||||
"17": {
|
||||
"19": {
|
||||
"question": "Recycling von Restabfällen"
|
||||
}
|
||||
}
|
||||
|
@ -6411,49 +6411,49 @@
|
|||
"5": {
|
||||
"then": "Motoröl kann hier recycelt werden"
|
||||
},
|
||||
"6": {
|
||||
"7": {
|
||||
"then": "Grünabfälle können hier recycelt werden"
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"then": "Bio-Abfall kann hier recycelt werden"
|
||||
},
|
||||
"8": {
|
||||
"9": {
|
||||
"then": "Glasflaschen können hier recycelt werden"
|
||||
},
|
||||
"9": {
|
||||
"10": {
|
||||
"then": "Glas kann hier recycelt werden"
|
||||
},
|
||||
"10": {
|
||||
"12": {
|
||||
"then": "Zeitungen können hier recycelt werden"
|
||||
},
|
||||
"11": {
|
||||
"13": {
|
||||
"then": "Papier kann hier recycelt werden"
|
||||
},
|
||||
"12": {
|
||||
"14": {
|
||||
"then": "Plastikflaschen können hier recycelt werden"
|
||||
},
|
||||
"13": {
|
||||
"15": {
|
||||
"then": "Kunststoffverpackungen können hier recycelt werden"
|
||||
},
|
||||
"14": {
|
||||
"16": {
|
||||
"then": "Kunststoff kann hier recycelt werden"
|
||||
},
|
||||
"15": {
|
||||
"17": {
|
||||
"then": "Metallschrott kann hier recycelt werden"
|
||||
},
|
||||
"16": {
|
||||
"18": {
|
||||
"then": "Schuhe können hier recycelt werden"
|
||||
},
|
||||
"17": {
|
||||
"then": "Elektrokleingeräte können hier recycelt werden"
|
||||
},
|
||||
"18": {
|
||||
"then": "Elektrokleingeräte können hier recycelt werden"
|
||||
},
|
||||
"19": {
|
||||
"then": "Nadeln können hier recycelt werden"
|
||||
"then": "Elektrokleingeräte können hier recycelt werden"
|
||||
},
|
||||
"20": {
|
||||
"then": "Elektrokleingeräte können hier recycelt werden"
|
||||
},
|
||||
"21": {
|
||||
"then": "Nadeln können hier recycelt werden"
|
||||
},
|
||||
"22": {
|
||||
"then": "Restmüll kann hier recycelt werden"
|
||||
}
|
||||
},
|
||||
|
@ -8308,9 +8308,6 @@
|
|||
"render": "Mülltonne"
|
||||
}
|
||||
},
|
||||
"watermill": {
|
||||
"name": "Wassermühlen"
|
||||
},
|
||||
"windturbine": {
|
||||
"description": "Moderne Windmühlen zur Stromerzeugung",
|
||||
"name": "Windräder",
|
||||
|
|
|
@ -169,6 +169,15 @@
|
|||
},
|
||||
"atm": {
|
||||
"description": "ATMS to withdraw money",
|
||||
"filter": {
|
||||
"1": {
|
||||
"options": {
|
||||
"0": {
|
||||
"question": "With speech output"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"name": "ATMs",
|
||||
"presets": {
|
||||
"0": {
|
||||
|
@ -186,6 +195,34 @@
|
|||
"question": "What brand is this ATM?",
|
||||
"render": "The brand of this ATM is {brand}"
|
||||
},
|
||||
"cash_in": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "You probably cannot deposit cash into this ATM"
|
||||
},
|
||||
"1": {
|
||||
"then": "You can deposit cash into this ATM"
|
||||
},
|
||||
"2": {
|
||||
"then": "You cannot deposit cash into this ATM"
|
||||
}
|
||||
},
|
||||
"question": "Can you deposit cash into this ATM?"
|
||||
},
|
||||
"cash_out": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "You can withdraw cash from this ATM"
|
||||
},
|
||||
"1": {
|
||||
"then": "You can withdraw cash from this ATM"
|
||||
},
|
||||
"2": {
|
||||
"then": "You cannot withdraw cash from this ATM"
|
||||
}
|
||||
},
|
||||
"question": "Can you withdraw cash from this ATM?"
|
||||
},
|
||||
"name": {
|
||||
"render": "The name of this ATM is {name}"
|
||||
},
|
||||
|
@ -195,6 +232,26 @@
|
|||
},
|
||||
"question": "What company operates this ATM?",
|
||||
"render": "The ATM is operated by {operator}"
|
||||
},
|
||||
"speech_output": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "This ATM has speech output, usually available through a headphone jack"
|
||||
},
|
||||
"1": {
|
||||
"then": "This ATM does not have speech output"
|
||||
}
|
||||
},
|
||||
"question": "Does this ATM have speech output for visually impaired users?"
|
||||
},
|
||||
"speech_output_language": {
|
||||
"render": {
|
||||
"special": {
|
||||
"question": "In which languages does this ATM have speech output?",
|
||||
"render_list_item": "This ATM has speech output in {language():font-bold}",
|
||||
"render_single_language": "This ATM has speech output in {language():font-bold}"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
|
@ -6323,36 +6380,42 @@
|
|||
"question": "Recycling of engine oil"
|
||||
},
|
||||
"7": {
|
||||
"question": "Recycling of green waste"
|
||||
"question": "Recycling of fluorescent tubes"
|
||||
},
|
||||
"8": {
|
||||
"question": "Recycling of glass bottles"
|
||||
"question": "Recycling of green waste"
|
||||
},
|
||||
"9": {
|
||||
"question": "Recycling of glass"
|
||||
"question": "Recycling of glass bottles"
|
||||
},
|
||||
"10": {
|
||||
"question": "Recycling of newspapers"
|
||||
"question": "Recycling of glass"
|
||||
},
|
||||
"11": {
|
||||
"question": "Recycling of paper"
|
||||
"question": "Recycling of light bulbs"
|
||||
},
|
||||
"12": {
|
||||
"question": "Recycling of plastic bottles"
|
||||
"question": "Recycling of newspapers"
|
||||
},
|
||||
"13": {
|
||||
"question": "Recycling of plastic packaging"
|
||||
"question": "Recycling of paper"
|
||||
},
|
||||
"14": {
|
||||
"question": "Recycling of plastic"
|
||||
"question": "Recycling of plastic bottles"
|
||||
},
|
||||
"15": {
|
||||
"question": "Recycling of scrap metal"
|
||||
"question": "Recycling of plastic packaging"
|
||||
},
|
||||
"16": {
|
||||
"question": "Recycling of small electrical appliances"
|
||||
"question": "Recycling of plastic"
|
||||
},
|
||||
"17": {
|
||||
"question": "Recycling of scrap metal"
|
||||
},
|
||||
"18": {
|
||||
"question": "Recycling of small electrical appliances"
|
||||
},
|
||||
"19": {
|
||||
"question": "Recycling of residual waste"
|
||||
}
|
||||
}
|
||||
|
@ -6412,48 +6475,54 @@
|
|||
"then": "Engine oil can be recycled here"
|
||||
},
|
||||
"6": {
|
||||
"then": "Green waste can be recycled here"
|
||||
"then": "Fluorescent tubes can be recycled here"
|
||||
},
|
||||
"7": {
|
||||
"then": "Organic waste can be recycled here"
|
||||
"then": "Green waste can be recycled here"
|
||||
},
|
||||
"8": {
|
||||
"then": "Glass bottles can be recycled here"
|
||||
"then": "Organic waste can be recycled here"
|
||||
},
|
||||
"9": {
|
||||
"then": "Glass can be recycled here"
|
||||
"then": "Glass bottles can be recycled here"
|
||||
},
|
||||
"10": {
|
||||
"then": "Newspapers can be recycled here"
|
||||
"then": "Glass can be recycled here"
|
||||
},
|
||||
"11": {
|
||||
"then": "Paper can be recycled here"
|
||||
"then": "Light bulbs can be recycled here"
|
||||
},
|
||||
"12": {
|
||||
"then": "Plastic bottles can be recycled here"
|
||||
"then": "Newspapers can be recycled here"
|
||||
},
|
||||
"13": {
|
||||
"then": "Plastic packaging can be recycled here"
|
||||
"then": "Paper can be recycled here"
|
||||
},
|
||||
"14": {
|
||||
"then": "Plastic can be recycled here"
|
||||
"then": "Plastic bottles can be recycled here"
|
||||
},
|
||||
"15": {
|
||||
"then": "Scrap metal can be recycled here"
|
||||
"then": "Plastic packaging can be recycled here"
|
||||
},
|
||||
"16": {
|
||||
"then": "Shoes can be recycled here"
|
||||
"then": "Plastic can be recycled here"
|
||||
},
|
||||
"17": {
|
||||
"then": "Small electrical appliances can be recycled here"
|
||||
"then": "Scrap metal can be recycled here"
|
||||
},
|
||||
"18": {
|
||||
"then": "Small electrical appliances can be recycled here"
|
||||
"then": "Shoes can be recycled here"
|
||||
},
|
||||
"19": {
|
||||
"then": "Needles can be recycled here"
|
||||
"then": "Small electrical appliances can be recycled here"
|
||||
},
|
||||
"20": {
|
||||
"then": "Small electrical appliances can be recycled here"
|
||||
},
|
||||
"21": {
|
||||
"then": "Needles can be recycled here"
|
||||
},
|
||||
"22": {
|
||||
"then": "Residual waste can be recycled here"
|
||||
}
|
||||
},
|
||||
|
@ -7407,6 +7476,7 @@
|
|||
"name": "Ticket Validators",
|
||||
"presets": {
|
||||
"0": {
|
||||
"description": "A ticket validator to validate a public transport ticket. This can be either a digital reader, reading a card or ticket, or a machine stamping or punching a ticket.",
|
||||
"title": "a ticket validator"
|
||||
}
|
||||
},
|
||||
|
@ -8308,9 +8378,6 @@
|
|||
"render": "Waste Disposal"
|
||||
}
|
||||
},
|
||||
"watermill": {
|
||||
"name": "Watermill"
|
||||
},
|
||||
"windturbine": {
|
||||
"description": "Modern windmills generating electricity",
|
||||
"name": "wind turbine",
|
||||
|
|
|
@ -3189,28 +3189,28 @@
|
|||
"6": {
|
||||
"question": "Reciclaje de aceite de motor"
|
||||
},
|
||||
"8": {
|
||||
"9": {
|
||||
"question": "Reciclaje de botellas de cristal"
|
||||
},
|
||||
"9": {
|
||||
"10": {
|
||||
"question": "Reciclaje de cristal"
|
||||
},
|
||||
"10": {
|
||||
"12": {
|
||||
"question": "Reciclaje de periódicos"
|
||||
},
|
||||
"11": {
|
||||
"13": {
|
||||
"question": "Reciclaje de papel"
|
||||
},
|
||||
"12": {
|
||||
"14": {
|
||||
"question": "Reciclaje de botellas de papel"
|
||||
},
|
||||
"13": {
|
||||
"15": {
|
||||
"question": "Reciclaje de embalajes plásticos"
|
||||
},
|
||||
"14": {
|
||||
"16": {
|
||||
"question": "Reciclaje de plástico"
|
||||
},
|
||||
"15": {
|
||||
"17": {
|
||||
"question": "Reciclaje de chatarra"
|
||||
}
|
||||
}
|
||||
|
@ -3266,34 +3266,34 @@
|
|||
"5": {
|
||||
"then": "Aquí se puede reciclar aceite de motor"
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"then": "Aquí se pueden reciclar residuos orgánicos"
|
||||
},
|
||||
"8": {
|
||||
"9": {
|
||||
"then": "Aquí se pueden reciclar botellas de cristal"
|
||||
},
|
||||
"9": {
|
||||
"10": {
|
||||
"then": "Aquí se puede reciclar cristal"
|
||||
},
|
||||
"10": {
|
||||
"12": {
|
||||
"then": "Aquí se pueden reciclar periódicos"
|
||||
},
|
||||
"11": {
|
||||
"13": {
|
||||
"then": "Aquí se puede reciclar papel"
|
||||
},
|
||||
"12": {
|
||||
"14": {
|
||||
"then": "Aquí se pueden reciclar botellas de plástico"
|
||||
},
|
||||
"13": {
|
||||
"15": {
|
||||
"then": "Aquí se pueden reciclar embalajes plásticos"
|
||||
},
|
||||
"14": {
|
||||
"16": {
|
||||
"then": "Aquí se puede reciclar plástico"
|
||||
},
|
||||
"15": {
|
||||
"17": {
|
||||
"then": "Aquí se puede reciclar chatarra"
|
||||
},
|
||||
"16": {
|
||||
"18": {
|
||||
"then": "Aquí se pueden reciclar zapatos"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1766,37 +1766,37 @@
|
|||
"6": {
|
||||
"question": "Riciclo di olio da motore"
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"question": "Riciclo di umido"
|
||||
},
|
||||
"8": {
|
||||
"9": {
|
||||
"question": "Riciclo di bottiglie di vetro"
|
||||
},
|
||||
"9": {
|
||||
"10": {
|
||||
"question": "Riciclo di vetro"
|
||||
},
|
||||
"10": {
|
||||
"12": {
|
||||
"question": "Riciclo di giornali"
|
||||
},
|
||||
"11": {
|
||||
"13": {
|
||||
"question": "Riciclo di carta"
|
||||
},
|
||||
"12": {
|
||||
"14": {
|
||||
"question": "Riciclo di bottiglie di plastica"
|
||||
},
|
||||
"13": {
|
||||
"15": {
|
||||
"question": "Riciclo di confezioni di plastica"
|
||||
},
|
||||
"14": {
|
||||
"16": {
|
||||
"question": "Riciclo di plastica"
|
||||
},
|
||||
"15": {
|
||||
"17": {
|
||||
"question": "Riciclo di rottami metallici"
|
||||
},
|
||||
"16": {
|
||||
"18": {
|
||||
"question": "Riciclo di piccoli elettrodomestici"
|
||||
},
|
||||
"17": {
|
||||
"19": {
|
||||
"question": "Riciclo di secco"
|
||||
}
|
||||
}
|
||||
|
@ -1855,49 +1855,49 @@
|
|||
"5": {
|
||||
"then": "Olio di motore"
|
||||
},
|
||||
"6": {
|
||||
"7": {
|
||||
"then": "Verde"
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"then": "Umido"
|
||||
},
|
||||
"8": {
|
||||
"9": {
|
||||
"then": "Bottiglie di vetro"
|
||||
},
|
||||
"9": {
|
||||
"10": {
|
||||
"then": "Vetro"
|
||||
},
|
||||
"10": {
|
||||
"12": {
|
||||
"then": "Giornali"
|
||||
},
|
||||
"11": {
|
||||
"13": {
|
||||
"then": "Carta"
|
||||
},
|
||||
"12": {
|
||||
"14": {
|
||||
"then": "Bottiglie di platica"
|
||||
},
|
||||
"13": {
|
||||
"15": {
|
||||
"then": "Confezioni di plastica"
|
||||
},
|
||||
"14": {
|
||||
"16": {
|
||||
"then": "Plastica"
|
||||
},
|
||||
"15": {
|
||||
"17": {
|
||||
"then": "Rottami metallici"
|
||||
},
|
||||
"16": {
|
||||
"18": {
|
||||
"then": "Scarpe"
|
||||
},
|
||||
"17": {
|
||||
"then": "Piccoli elettrodomestici"
|
||||
},
|
||||
"18": {
|
||||
"then": "Piccoli elettrodomestici"
|
||||
},
|
||||
"19": {
|
||||
"then": "Aghi e oggetti appuntiti"
|
||||
"then": "Piccoli elettrodomestici"
|
||||
},
|
||||
"20": {
|
||||
"then": "Piccoli elettrodomestici"
|
||||
},
|
||||
"21": {
|
||||
"then": "Aghi e oggetti appuntiti"
|
||||
},
|
||||
"22": {
|
||||
"then": "Secco"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -5988,36 +5988,42 @@
|
|||
"question": "Recycling van motorolie"
|
||||
},
|
||||
"7": {
|
||||
"question": "Recycling van groen afval"
|
||||
"question": "Recycling van tl-buizen"
|
||||
},
|
||||
"8": {
|
||||
"question": "Recycling van glazen flessen"
|
||||
"question": "Recycling van groen afval"
|
||||
},
|
||||
"9": {
|
||||
"question": "Recycling van glas"
|
||||
"question": "Recycling van glazen flessen"
|
||||
},
|
||||
"10": {
|
||||
"question": "Recycling van kranten"
|
||||
"question": "Recycling van glas"
|
||||
},
|
||||
"11": {
|
||||
"question": "Recycling van papier"
|
||||
"question": "Recycling van lampen"
|
||||
},
|
||||
"12": {
|
||||
"question": "Recycling van plastic flessen"
|
||||
"question": "Recycling van kranten"
|
||||
},
|
||||
"13": {
|
||||
"question": "Recycling van plastic verpakking"
|
||||
"question": "Recycling van papier"
|
||||
},
|
||||
"14": {
|
||||
"question": "Recycling van plastic"
|
||||
"question": "Recycling van plastic flessen"
|
||||
},
|
||||
"15": {
|
||||
"question": "Recycling van oud metaal"
|
||||
"question": "Recycling van plastic verpakking"
|
||||
},
|
||||
"16": {
|
||||
"question": "Recycling van kleine elektrische apparaten"
|
||||
"question": "Recycling van plastic"
|
||||
},
|
||||
"17": {
|
||||
"question": "Recycling van oud metaal"
|
||||
},
|
||||
"18": {
|
||||
"question": "Recycling van kleine elektrische apparaten"
|
||||
},
|
||||
"19": {
|
||||
"question": "Recycling van restafval"
|
||||
}
|
||||
}
|
||||
|
@ -6077,48 +6083,54 @@
|
|||
"then": "Motorolie kan hier gerecycled worden"
|
||||
},
|
||||
"6": {
|
||||
"then": "Groen afval kan hier gerecycled worden"
|
||||
"then": "TL-buizen kunnen hier gerecycled worden"
|
||||
},
|
||||
"7": {
|
||||
"then": "Organisch afval kan hier gerecycled worden"
|
||||
"then": "Groen afval kan hier gerecycled worden"
|
||||
},
|
||||
"8": {
|
||||
"then": "Glazen flessen kunnen hier gerecycled worden"
|
||||
"then": "Organisch afval kan hier gerecycled worden"
|
||||
},
|
||||
"9": {
|
||||
"then": "Glas kan hier gerecycled worden"
|
||||
"then": "Glazen flessen kunnen hier gerecycled worden"
|
||||
},
|
||||
"10": {
|
||||
"then": "Kranten kunnen hier gerecycled worden"
|
||||
"then": "Glas kan hier gerecycled worden"
|
||||
},
|
||||
"11": {
|
||||
"then": "Papier kan hier gerecycled worden"
|
||||
"then": "Lampen kunnen hier gerecycled worden"
|
||||
},
|
||||
"12": {
|
||||
"then": "Plastic flessen kunnen hier gerecycled worden"
|
||||
"then": "Kranten kunnen hier gerecycled worden"
|
||||
},
|
||||
"13": {
|
||||
"then": "Plastic verpakking kan hier gerecycled worden"
|
||||
"then": "Papier kan hier gerecycled worden"
|
||||
},
|
||||
"14": {
|
||||
"then": "Plastic kan hier gerecycled worden"
|
||||
"then": "Plastic flessen kunnen hier gerecycled worden"
|
||||
},
|
||||
"15": {
|
||||
"then": "Oud metaal kan hier gerecycled worden"
|
||||
"then": "Plastic verpakking kan hier gerecycled worden"
|
||||
},
|
||||
"16": {
|
||||
"then": "Schoenen kunnen hier gerecycled worden"
|
||||
"then": "Plastic kan hier gerecycled worden"
|
||||
},
|
||||
"17": {
|
||||
"then": "Kleine elektrische apparaten kunnen hier gerecycled worden"
|
||||
"then": "Oud metaal kan hier gerecycled worden"
|
||||
},
|
||||
"18": {
|
||||
"then": "Kleine elektrische apparaten kunnen hier gerecycled worden"
|
||||
"then": "Schoenen kunnen hier gerecycled worden"
|
||||
},
|
||||
"19": {
|
||||
"then": "Injectienaalden kunnen hier gerecycled worden"
|
||||
"then": "Kleine elektrische apparaten kunnen hier gerecycled worden"
|
||||
},
|
||||
"20": {
|
||||
"then": "Kleine elektrische apparaten kunnen hier gerecycled worden"
|
||||
},
|
||||
"21": {
|
||||
"then": "Injectienaalden kunnen hier gerecycled worden"
|
||||
},
|
||||
"22": {
|
||||
"then": "Restafval kan hier gerecycled worden"
|
||||
}
|
||||
},
|
||||
|
@ -7872,59 +7884,6 @@
|
|||
"render": "Afvalbak"
|
||||
}
|
||||
},
|
||||
"watermill": {
|
||||
"description": "Watermolens",
|
||||
"name": "Watermolens",
|
||||
"tagRenderings": {
|
||||
"Access tag": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Vrij toegankelijk"
|
||||
},
|
||||
"1": {
|
||||
"then": "Niet toegankelijk"
|
||||
},
|
||||
"2": {
|
||||
"then": "Niet toegankelijk, want privégebied"
|
||||
},
|
||||
"3": {
|
||||
"then": "Toegankelijk, ondanks dat het privegebied is"
|
||||
},
|
||||
"4": {
|
||||
"then": "Enkel toegankelijk met een gids of tijdens een activiteit"
|
||||
},
|
||||
"5": {
|
||||
"then": "Toegankelijk mits betaling"
|
||||
}
|
||||
},
|
||||
"question": "Is dit gebied toegankelijk?",
|
||||
"render": "De toegankelijkheid van dit gebied is: {access:description}"
|
||||
},
|
||||
"Operator tag": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Dit gebied wordt beheerd door Natuurpunt"
|
||||
},
|
||||
"1": {
|
||||
"then": "Dit gebied wordt beheerd door {operator}"
|
||||
}
|
||||
},
|
||||
"question": "Wie beheert dit pad?",
|
||||
"render": "Beheer door {operator}"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "{name:nl}"
|
||||
},
|
||||
"1": {
|
||||
"then": "{name}"
|
||||
}
|
||||
},
|
||||
"render": "Watermolens"
|
||||
}
|
||||
},
|
||||
"windturbine": {
|
||||
"description": "Windturbines (moderne windmolens die elektriciteit genereren)",
|
||||
"name": "windturbine",
|
||||
|
|
|
@ -179,6 +179,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"payment-options-split": {
|
||||
"override": {
|
||||
"mappings+": {
|
||||
"0": {
|
||||
"then": "Muntgeld wordt hier aanvaard"
|
||||
},
|
||||
"1": {
|
||||
"then": "Bankbiljetten worden hier aanvaard"
|
||||
},
|
||||
"2": {
|
||||
"then": "Betalen met debetkaarten kan hier"
|
||||
},
|
||||
"3": {
|
||||
"then": "Betalen met creditkaarten kan hier"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"phone": {
|
||||
"question": "Wat is het telefoonnummer van {title()}?"
|
||||
},
|
||||
|
|
|
@ -443,14 +443,14 @@
|
|||
},
|
||||
"onwheels": {
|
||||
"layers": {
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "Estadístiques"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -680,14 +680,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "Statistikker"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -909,14 +909,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "Statistik"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -909,14 +909,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "Statistics"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -888,14 +888,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "Statistiques"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -441,14 +441,14 @@
|
|||
},
|
||||
"onwheels": {
|
||||
"layers": {
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "Statistikk"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -1036,14 +1036,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "Statistieken"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
|
@ -168,14 +168,14 @@
|
|||
},
|
||||
"onwheels": {
|
||||
"layers": {
|
||||
"18": {
|
||||
"19": {
|
||||
"override": {
|
||||
"=title": {
|
||||
"render": "انکڑے"
|
||||
}
|
||||
}
|
||||
},
|
||||
"19": {
|
||||
"20": {
|
||||
"override": {
|
||||
"+tagRenderings": {
|
||||
"0": {
|
||||
|
|
4119
package-lock.json
generated
4119
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "mapcomplete",
|
||||
"version": "0.0.5",
|
||||
"version": "0.25.1",
|
||||
"repository": "https://github.com/pietervdvn/MapComplete",
|
||||
"description": "A small website to edit OSM easily",
|
||||
"bugs": "https://github.com/pietervdvn/MapComplete/issues",
|
||||
|
|
|
@ -16,7 +16,13 @@ import SharedTagRenderings from "../Customizations/SharedTagRenderings"
|
|||
import { writeFile } from "fs"
|
||||
import Translations from "../UI/i18n/Translations"
|
||||
import * as themeOverview from "../assets/generated/theme_overview.json"
|
||||
|
||||
import DefaultGUI from "../UI/DefaultGUI"
|
||||
import FeaturePipelineState from "../Logic/State/FeaturePipelineState"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
||||
import * as bookcases from "../assets/generated/themes/bookcases.json"
|
||||
import { DefaultGuiState } from "../UI/DefaultGuiState"
|
||||
import * as fakedom from "fake-dom"
|
||||
import Hotkeys from "../UI/Base/Hotkeys"
|
||||
function WriteFile(
|
||||
filename,
|
||||
html: BaseUIElement,
|
||||
|
@ -217,5 +223,13 @@ WriteFile("./Docs/URL_Parameters.md", QueryParameterDocumentation.GenerateQueryP
|
|||
"Logic/Web/QueryParameters.ts",
|
||||
"UI/QueryParameterDocumentation.ts",
|
||||
])
|
||||
if (fakedom === undefined || window === undefined) {
|
||||
throw "FakeDom not initialized"
|
||||
}
|
||||
new DefaultGUI(
|
||||
new FeaturePipelineState(new LayoutConfig(<any>bookcases)),
|
||||
new DefaultGuiState()
|
||||
).setup()
|
||||
|
||||
WriteFile("./Docs/Hotkeys.md", Hotkeys.generateDocumentation(), [])
|
||||
console.log("Generated docs")
|
||||
|
|
|
@ -279,7 +279,23 @@ function main(args: string[]) {
|
|||
const invalidLicenses = licenseInfos
|
||||
.filter((l) => (l.license ?? "") === "")
|
||||
.map((l) => `License for artwork ${l.path} is empty string or undefined`)
|
||||
|
||||
let invalid = 0
|
||||
for (const licenseInfo of licenseInfos) {
|
||||
const isTrivial =
|
||||
licenseInfo.license
|
||||
.split(";")
|
||||
.map((l) => l.trim().toLowerCase())
|
||||
.indexOf("trivial") >= 0
|
||||
if (licenseInfo.sources.length + licenseInfo.authors.length == 0 && !isTrivial) {
|
||||
invalid++
|
||||
invalidLicenses.push(
|
||||
"Invalid license: No sources nor authors given in the license for " +
|
||||
JSON.stringify(licenseInfo)
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
for (const source of licenseInfo.sources) {
|
||||
if (source == "") {
|
||||
invalidLicenses.push(
|
||||
|
@ -294,7 +310,7 @@ function main(args: string[]) {
|
|||
}
|
||||
}
|
||||
|
||||
if (missingLicenses.length > 0) {
|
||||
if (missingLicenses.length > 0 || invalidLicenses.length) {
|
||||
const msg = `There are ${missingLicenses.length} licenses missing and ${invalidLicenses.length} invalid licenses.`
|
||||
console.log(missingLicenses.concat(invalidLicenses).join("\n"))
|
||||
console.error(msg)
|
||||
|
|
|
@ -7594,7 +7594,7 @@ describe("GenerateCache", () => {
|
|||
}
|
||||
mkdirSync(dir + "np-cache")
|
||||
initDownloads(
|
||||
"(nwr%5B%22amenity%22%3D%22toilets%22%5D%3Bnwr%5B%22amenity%22%3D%22parking%22%5D%3Bnwr%5B%22amenity%22%3D%22bench%22%5D%3Bnwr%5B%22id%22%3D%22location_track%22%5D%3Bnwr%5B%22id%22%3D%22gps%22%5D%3Bnwr%5B%22information%22%3D%22board%22%5D%3Bnwr%5B%22leisure%22%3D%22picnic_table%22%5D%3Bnwr%5B%22man_made%22%3D%22watermill%22%5D%3Bnwr%5B%22selected%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Ahome%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Alocation%22%3D%22yes%22%5D%3Bnwr%5B%22leisure%22%3D%22nature_reserve%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22boundary%22%3D%22protected_area%22%5D%5B%22protect_class%22!%3D%2298%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22visitor_centre%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22office%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*foot.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*hiking.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*bycicle.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*horse.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22leisure%22%3D%22bird_hide%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22amenity%22%3D%22drinking_water%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3Bnwr%5B%22drinking_water%22%3D%22yes%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3B)%3Bout%20body%3Bout%20meta%3B%3E%3Bout%20skel%20qt%3B"
|
||||
"(nwr%5B%22amenity%22%3D%22toilets%22%5D%3Bnwr%5B%22amenity%22%3D%22parking%22%5D%3Bnwr%5B%22amenity%22%3D%22bench%22%5D%3Bnwr%5B%22id%22%3D%22location_track%22%5D%3Bnwr%5B%22id%22%3D%22gps%22%5D%3Bnwr%5B%22information%22%3D%22board%22%5D%3Bnwr%5B%22leisure%22%3D%22picnic_table%22%5D%3Bnwr%5B%22selected%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Ahome%22%3D%22yes%22%5D%3Bnwr%5B%22user%3Alocation%22%3D%22yes%22%5D%3Bnwr%5B%22leisure%22%3D%22nature_reserve%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22boundary%22%3D%22protected_area%22%5D%5B%22protect_class%22!%3D%2298%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22visitor_centre%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22information%22%3D%22office%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*foot.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*hiking.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*bycicle.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22route%22~%22%5E(.*horse.*)%24%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22leisure%22%3D%22bird_hide%22%5D%5B%22operator%22~%22%5E(.*%5BnN%5Datuurpunt.*)%24%22%5D%3Bnwr%5B%22amenity%22%3D%22drinking_water%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3Bnwr%5B%22drinking_water%22%3D%22yes%22%5D%5B%22man_made%22!%3D%22reservoir_covered%22%5D%5B%22access%22!%3D%22permissive%22%5D%5B%22access%22!%3D%22private%22%5D%3B)%3Bout%20body%3Bout%20meta%3B%3E%3Bout%20skel%20qt%3B"
|
||||
)
|
||||
await main([
|
||||
"natuurpunt",
|
||||
|
|
Loading…
Reference in a new issue