From b535f7cf1e7be3fe11012021d4d98239f54e0fc9 Mon Sep 17 00:00:00 2001 From: Ward Date: Tue, 20 Jul 2021 15:14:51 +0200 Subject: [PATCH 1/6] start creating filter --- InitUiElements.ts | 30 +- State.ts | 612 ++++++++++++++++++++------------- Svg.ts | 12 +- UI/BigComponents/FilterView.ts | 39 +++ assets/svg/arrow-left-thin.svg | 3 + assets/svg/filter.svg | 3 + assets/svg/license_info.json | 6 + 7 files changed, 460 insertions(+), 245 deletions(-) create mode 100644 UI/BigComponents/FilterView.ts create mode 100644 assets/svg/arrow-left-thin.svg create mode 100644 assets/svg/filter.svg diff --git a/InitUiElements.ts b/InitUiElements.ts index 5be908fad5..b2f8fe09a1 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -41,6 +41,7 @@ import FeatureSource from "./Logic/FeatureSource/FeatureSource"; import AllKnownLayers from "./Customizations/AllKnownLayers"; import LayerConfig from "./Customizations/JSON/LayerConfig"; import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers"; +import FilterView from "./UI/BigComponents/FilterView"; export class InitUiElements { static InitAll( @@ -205,7 +206,7 @@ export class InitUiElements { Img.AsImageElement(Svg.plus_zoom, "", "width:1.25rem;height:1.25rem") ) ).onClick(() => { - State.state.locationControl.data.zoom++; + State.state.locationControl.data.zoom++; State.state.locationControl.ping(); }); @@ -353,6 +354,7 @@ export class InitUiElements { const layerControlPanel = new LayerControlPanel( State.state.layerControlIsOpened ).SetClass("block p-1 rounded-full"); + const layerControlButton = new Toggle( layerControlPanel, new MapControlButton(Svg.layers_svg()), @@ -365,7 +367,31 @@ export class InitUiElements { State.state.featureSwitchLayers ); - new Combine([copyrightButton, layerControl]).AttachTo("bottom-left"); + const filterView = new FilterView(State.state.FilterIsOpened).SetClass( + "block p-1 rounded-full" + ); + + const filterMapControlButton = new MapControlButton( + new CenterFlexedElement( + Img.AsImageElement(Svg.filter, "", "width:1.25rem;height:1.25rem") + ) + ); + + const filterButton = new Toggle( + filterView, + filterMapControlButton, + State.state.FilterIsOpened + ).ToggleOnClick(); + + const filterControl = new Toggle( + filterButton, + "", + State.state.featureSwitchFilter + ); + + new Combine([copyrightButton, layerControl, filterControl]).AttachTo( + "bottom-left" + ); State.state.locationControl.addCallback(() => { // Close the layer selection when the map is moved diff --git a/State.ts b/State.ts index 8e4322d654..c4169d50ff 100644 --- a/State.ts +++ b/State.ts @@ -1,13 +1,13 @@ -import {Utils} from "./Utils"; -import {ElementStorage} from "./Logic/ElementStorage"; -import {Changes} from "./Logic/Osm/Changes"; -import {OsmConnection} from "./Logic/Osm/OsmConnection"; +import { Utils } from "./Utils"; +import { ElementStorage } from "./Logic/ElementStorage"; +import { Changes } from "./Logic/Osm/Changes"; +import { OsmConnection } from "./Logic/Osm/OsmConnection"; import Locale from "./UI/i18n/Locale"; -import {UIEventSource} from "./Logic/UIEventSource"; -import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; -import {QueryParameters} from "./Logic/Web/QueryParameters"; +import { UIEventSource } from "./Logic/UIEventSource"; +import { LocalStorageSource } from "./Logic/Web/LocalStorageSource"; +import { QueryParameters } from "./Logic/Web/QueryParameters"; import LayoutConfig from "./Customizations/JSON/LayoutConfig"; -import {MangroveIdentity} from "./Logic/Web/MangroveReviews"; +import { MangroveIdentity } from "./Logic/Web/MangroveReviews"; import InstalledThemes from "./Logic/Actors/InstalledThemes"; import BaseLayer from "./Models/BaseLayer"; import Loc from "./Models/Loc"; @@ -17,7 +17,7 @@ import OverpassFeatureSource from "./Logic/Actors/OverpassFeatureSource"; import LayerConfig from "./Customizations/JSON/LayerConfig"; import TitleHandler from "./Logic/Actors/TitleHandler"; import PendingChangesUploader from "./Logic/Actors/PendingChangesUploader"; -import {Relation} from "./Logic/Osm/ExtractRelations"; +import { Relation } from "./Logic/Osm/ExtractRelations"; import OsmApiFeatureSource from "./Logic/FeatureSource/OsmApiFeatureSource"; /** @@ -25,274 +25,402 @@ import OsmApiFeatureSource from "./Logic/FeatureSource/OsmApiFeatureSource"; */ export default class State { + // The singleton of the global state + public static state: State; - // The singleton of the global state - public static state: State; + public readonly layoutToUse = new UIEventSource(undefined); - - public readonly layoutToUse = new UIEventSource(undefined); - - /** + /** The mapping from id -> UIEventSource */ - public allElements: ElementStorage; - /** + public allElements: ElementStorage; + /** THe change handler */ - public changes: Changes; - /** + public changes: Changes; + /** The leaflet instance of the big basemap */ - public leafletMap = new UIEventSource(undefined); - /** - * Background layer id - */ - public availableBackgroundLayers: UIEventSource; - /** + public leafletMap = new UIEventSource(undefined); + /** + * Background layer id + */ + public availableBackgroundLayers: UIEventSource; + /** The user credentials */ - public osmConnection: OsmConnection; + public osmConnection: OsmConnection; - public mangroveIdentity: MangroveIdentity; + public mangroveIdentity: MangroveIdentity; - public favouriteLayers: UIEventSource; + public favouriteLayers: UIEventSource; - public layerUpdater: OverpassFeatureSource; - - public osmApiFeatureSource : OsmApiFeatureSource ; + public layerUpdater: OverpassFeatureSource; + public osmApiFeatureSource: OsmApiFeatureSource; - public filteredLayers: UIEventSource<{ - readonly isDisplayed: UIEventSource, - readonly layerDef: LayerConfig; - }[]> = new UIEventSource<{ - readonly isDisplayed: UIEventSource, - readonly layerDef: LayerConfig; - }[]>([]) + public filteredLayers: UIEventSource< + { + readonly isDisplayed: UIEventSource; + readonly layerDef: LayerConfig; + }[] + > = new UIEventSource< + { + readonly isDisplayed: UIEventSource; + readonly layerDef: LayerConfig; + }[] + >([]); - - /** + /** The latest element that was selected */ - public readonly selectedElement = new UIEventSource(undefined, "Selected element") + public readonly selectedElement = new UIEventSource( + undefined, + "Selected element" + ); - /** - * Keeps track of relations: which way is part of which other way? - * Set by the overpass-updater; used in the metatagging - */ - public readonly knownRelations = new UIEventSource>(undefined, "Relation memberships") + /** + * Keeps track of relations: which way is part of which other way? + * Set by the overpass-updater; used in the metatagging + */ + public readonly knownRelations = new UIEventSource< + Map + >(undefined, "Relation memberships"); - public readonly featureSwitchUserbadge: UIEventSource; - public readonly featureSwitchSearch: UIEventSource; - public readonly featureSwitchLayers: UIEventSource; - public readonly featureSwitchAddNew: UIEventSource; - public readonly featureSwitchWelcomeMessage: UIEventSource; - public readonly featureSwitchIframe: UIEventSource; - public readonly featureSwitchMoreQuests: UIEventSource; - public readonly featureSwitchShareScreen: UIEventSource; - public readonly featureSwitchGeolocation: UIEventSource; - public readonly featureSwitchIsTesting: UIEventSource; - public readonly featureSwitchIsDebugging: UIEventSource; - public readonly featureSwitchShowAllQuestions: UIEventSource; - public readonly featureSwitchApiURL: UIEventSource; + public readonly featureSwitchUserbadge: UIEventSource; + public readonly featureSwitchSearch: UIEventSource; + public readonly featureSwitchLayers: UIEventSource; + public readonly featureSwitchAddNew: UIEventSource; + public readonly featureSwitchWelcomeMessage: UIEventSource; + public readonly featureSwitchIframe: UIEventSource; + public readonly featureSwitchMoreQuests: UIEventSource; + public readonly featureSwitchShareScreen: UIEventSource; + public readonly featureSwitchGeolocation: UIEventSource; + public readonly featureSwitchIsTesting: UIEventSource; + public readonly featureSwitchIsDebugging: UIEventSource; + public readonly featureSwitchShowAllQuestions: UIEventSource; + public readonly featureSwitchApiURL: UIEventSource; + public readonly featureSwitchFilter: UIEventSource; + /** + * The map location: currently centered lat, lon and zoom + */ + public readonly locationControl = new UIEventSource(undefined); + public backgroundLayer; + public readonly backgroundLayerId: UIEventSource; - /** - * The map location: currently centered lat, lon and zoom - */ - public readonly locationControl = new UIEventSource(undefined); - public backgroundLayer; - public readonly backgroundLayerId: UIEventSource; + /* Last location where a click was registered + */ + public readonly LastClickLocation: UIEventSource<{ + lat: number; + lon: number; + }> = new UIEventSource<{ lat: number; lon: number }>(undefined); - /* Last location where a click was registered - */ - public readonly LastClickLocation: UIEventSource<{ lat: number, lon: number }> = new UIEventSource<{ lat: number, lon: number }>(undefined) + /** + * The location as delivered by the GPS + */ + public currentGPSLocation: UIEventSource<{ + latlng: { lat: number; lng: number }; + accuracy: number; + }> = new UIEventSource<{ + latlng: { lat: number; lng: number }; + accuracy: number; + }>(undefined); + public layoutDefinition: string; + public installedThemes: UIEventSource< + { layout: LayoutConfig; definition: string }[] + >; - /** - * The location as delivered by the GPS - */ - public currentGPSLocation: UIEventSource<{ - latlng: { lat: number, lng: number }, - accuracy: number - }> = new UIEventSource<{ latlng: { lat: number, lng: number }, accuracy: number }>(undefined); - public layoutDefinition: string; - public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; - - public layerControlIsOpened: UIEventSource = - QueryParameters.GetQueryParameter("layer-control-toggle", "false", "Whether or not the layer control is shown") - .map((str) => str !== "false", [], b => "" + b) - - public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`).map( - str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n + public layerControlIsOpened: UIEventSource = + QueryParameters.GetQueryParameter( + "layer-control-toggle", + "false", + "Whether or not the layer control is shown" + ).map( + (str) => str !== "false", + [], + (b) => "" + b ); - - constructor(layoutToUse: LayoutConfig) { - const self = this; - this.layoutToUse.setData(layoutToUse); + public FilterIsOpened: UIEventSource = + QueryParameters.GetQueryParameter( + "filter-toggle", + "false", + "Whether or not the filter is shown" + ).map( + (str) => str !== "false", + [], + (b) => "" + b + ); - // -- Location control initialization - { - const zoom = State.asFloat( - QueryParameters.GetQueryParameter("z", "" + (layoutToUse?.startZoom ?? 1), "The initial/current zoom level") - .syncWith(LocalStorageSource.Get("zoom"))); - const lat = State.asFloat(QueryParameters.GetQueryParameter("lat", "" + (layoutToUse?.startLat ?? 0), "The initial/current latitude") - .syncWith(LocalStorageSource.Get("lat"))); - const lon = State.asFloat(QueryParameters.GetQueryParameter("lon", "" + (layoutToUse?.startLon ?? 0), "The initial/current longitude of the app") - .syncWith(LocalStorageSource.Get("lon"))); + public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter( + "tab", + "0", + `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)` + ).map( + (str) => (isNaN(Number(str)) ? 0 : Number(str)), + [], + (n) => "" + n + ); + constructor(layoutToUse: LayoutConfig) { + const self = this; - this.locationControl = new UIEventSource({ - zoom: Utils.asFloat(zoom.data), - lat: Utils.asFloat(lat.data), - lon: Utils.asFloat(lon.data), - }).addCallback((latlonz) => { - zoom.setData(latlonz.zoom); - lat.setData(latlonz.lat); - lon.setData(latlonz.lon); - }); + this.layoutToUse.setData(layoutToUse); - this.layoutToUse.addCallback(layoutToUse => { - const lcd = self.locationControl.data; - lcd.zoom = lcd.zoom ?? layoutToUse?.startZoom; - lcd.lat = lcd.lat ?? layoutToUse?.startLat; - lcd.lon = lcd.lon ?? layoutToUse?.startLon; - self.locationControl.ping(); - }); + // -- Location control initialization + { + const zoom = State.asFloat( + QueryParameters.GetQueryParameter( + "z", + "" + (layoutToUse?.startZoom ?? 1), + "The initial/current zoom level" + ).syncWith(LocalStorageSource.Get("zoom")) + ); + const lat = State.asFloat( + QueryParameters.GetQueryParameter( + "lat", + "" + (layoutToUse?.startLat ?? 0), + "The initial/current latitude" + ).syncWith(LocalStorageSource.Get("lat")) + ); + const lon = State.asFloat( + QueryParameters.GetQueryParameter( + "lon", + "" + (layoutToUse?.startLon ?? 0), + "The initial/current longitude of the app" + ).syncWith(LocalStorageSource.Get("lon")) + ); - } - - // Helper function to initialize feature switches - function featSw(key: string, deflt: (layout: LayoutConfig) => boolean, documentation: string): UIEventSource { - const queryParameterSource = QueryParameters.GetQueryParameter(key, undefined, documentation); - // I'm so sorry about someone trying to decipher this - - // It takes the current layout, extracts the default value for this query parameter. A query parameter event source is then retrieved and flattened - return UIEventSource.flatten( - self.layoutToUse.map((layout) => { - const defaultValue = deflt(layout); - const queryParam = QueryParameters.GetQueryParameter(key, "" + defaultValue, documentation) - return queryParam.map((str) => str === undefined ? defaultValue : (str !== "false")); - }), [queryParameterSource]); - } - - // Feature switch initialization - not as a function as the UIEventSources are readonly - { - - this.featureSwitchUserbadge = featSw("fs-userbadge", (layoutToUse) => layoutToUse?.enableUserBadge ?? true, - "Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode."); - this.featureSwitchSearch = featSw("fs-search", (layoutToUse) => layoutToUse?.enableSearch ?? true, - "Disables/Enables the search bar"); - this.featureSwitchLayers = featSw("fs-layers", (layoutToUse) => layoutToUse?.enableLayers ?? true, - "Disables/Enables the layer control"); - this.featureSwitchAddNew = featSw("fs-add-new", (layoutToUse) => layoutToUse?.enableAddNewPoints ?? true, - "Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place)"); - this.featureSwitchWelcomeMessage = featSw("fs-welcome-message", () => true, - "Disables/enables the help menu or welcome message"); - this.featureSwitchIframe = featSw("fs-iframe", () => false, - "Disables/Enables the iframe-popup"); - this.featureSwitchMoreQuests = featSw("fs-more-quests", (layoutToUse) => layoutToUse?.enableMoreQuests ?? true, - "Disables/Enables the 'More Quests'-tab in the welcome message"); - this.featureSwitchShareScreen = featSw("fs-share-screen", (layoutToUse) => layoutToUse?.enableShareScreen ?? true, - "Disables/Enables the 'Share-screen'-tab in the welcome message"); - this.featureSwitchGeolocation = featSw("fs-geolocation", (layoutToUse) => layoutToUse?.enableGeolocation ?? true, - "Disables/Enables the geolocation button"); - this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, - "Always show all questions"); - - this.featureSwitchIsTesting = QueryParameters.GetQueryParameter("test", "false", - "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org") - .map(str => str === "true", [], b => "" + b); - - this.featureSwitchIsDebugging = QueryParameters.GetQueryParameter("debug","false", - "If true, shows some extra debugging help such as all the available tags on every object") - .map(str => str === "true", [], b => "" + b) - - this.featureSwitchApiURL = QueryParameters.GetQueryParameter("backend","osm", - "The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test'") - - } - { - // Some other feature switches - const customCssQP = QueryParameters.GetQueryParameter("custom-css", "", "If specified, the custom css from the given link will be loaded additionaly"); - if (customCssQP.data !== undefined && customCssQP.data !== "") { - Utils.LoadCustomCss(customCssQP.data); - } - - - this.backgroundLayerId = QueryParameters.GetQueryParameter("background", - layoutToUse?.defaultBackgroundId ?? "osm", - "The id of the background layer to start with") - - } - - - if(Utils.runningFromConsole){ - return; - } - - this.osmConnection = new OsmConnection( - this.featureSwitchIsTesting.data, - QueryParameters.GetQueryParameter("oauth_token", undefined, - "Used to complete the login"), - layoutToUse?.id, - true, - // @ts-ignore - this.featureSwitchApiURL.data - ); - - - this.allElements = new ElementStorage(); - this.changes = new Changes(); - this.osmApiFeatureSource = new OsmApiFeatureSource() - - new PendingChangesUploader(this.changes, this.selectedElement); - - this.mangroveIdentity = new MangroveIdentity( - this.osmConnection.GetLongPreference("identity", "mangrove") - ); - - - this.installedThemes = new InstalledThemes(this.osmConnection).installedThemes; - - // Important: the favourite layers are initialized _after_ the installed themes, as these might contain an installedTheme - this.favouriteLayers = LocalStorageSource.Get("favouriteLayers") - .syncWith(this.osmConnection.GetLongPreference("favouriteLayers")) - .map( - str => Utils.Dedup(str?.split(";")) ?? [], - [], layers => Utils.Dedup(layers)?.join(";") - ); - - Locale.language.syncWith(this.osmConnection.GetPreference("language")); - - - Locale.language.addCallback((currentLanguage) => { - const layoutToUse = self.layoutToUse.data; - if (layoutToUse === undefined) { - return; - } - if (this.layoutToUse.data.language.indexOf(currentLanguage) < 0) { - console.log("Resetting language to", layoutToUse.language[0], "as", currentLanguage, " is unsupported") - // The current language is not supported -> switch to a supported one - Locale.language.setData(layoutToUse.language[0]); - } - }).ping() - - new TitleHandler(this.layoutToUse, this.selectedElement, this.allElements); + this.locationControl = new UIEventSource({ + zoom: Utils.asFloat(zoom.data), + lat: Utils.asFloat(lat.data), + lon: Utils.asFloat(lon.data), + }).addCallback((latlonz) => { + zoom.setData(latlonz.zoom); + lat.setData(latlonz.lat); + lon.setData(latlonz.lon); + }); + this.layoutToUse.addCallback((layoutToUse) => { + const lcd = self.locationControl.data; + lcd.zoom = lcd.zoom ?? layoutToUse?.startZoom; + lcd.lat = lcd.lat ?? layoutToUse?.startLat; + lcd.lon = lcd.lon ?? layoutToUse?.startLon; + self.locationControl.ping(); + }); } - private static asFloat(source: UIEventSource): UIEventSource { - return source.map(str => { - let parsed = parseFloat(str); - return isNaN(parsed) ? undefined : parsed; - }, [], fl => { - if (fl === undefined || isNaN(fl)) { - return undefined; - } - return ("" + fl).substr(0, 8); - }) + // Helper function to initialize feature switches + function featSw( + key: string, + deflt: (layout: LayoutConfig) => boolean, + documentation: string + ): UIEventSource { + const queryParameterSource = QueryParameters.GetQueryParameter( + key, + undefined, + documentation + ); + // I'm so sorry about someone trying to decipher this + + // It takes the current layout, extracts the default value for this query parameter. A query parameter event source is then retrieved and flattened + return UIEventSource.flatten( + self.layoutToUse.map((layout) => { + const defaultValue = deflt(layout); + const queryParam = QueryParameters.GetQueryParameter( + key, + "" + defaultValue, + documentation + ); + return queryParam.map((str) => + str === undefined ? defaultValue : str !== "false" + ); + }), + [queryParameterSource] + ); } + // Feature switch initialization - not as a function as the UIEventSources are readonly + { + this.featureSwitchUserbadge = featSw( + "fs-userbadge", + (layoutToUse) => layoutToUse?.enableUserBadge ?? true, + "Disables/Enables the user information pill (userbadge) at the top left. Disabling this disables logging in and thus disables editing all together, effectively putting MapComplete into read-only mode." + ); + this.featureSwitchSearch = featSw( + "fs-search", + (layoutToUse) => layoutToUse?.enableSearch ?? true, + "Disables/Enables the search bar" + ); + this.featureSwitchLayers = featSw( + "fs-layers", + (layoutToUse) => layoutToUse?.enableLayers ?? true, + "Disables/Enables the layer control" + ); + this.featureSwitchFilter = featSw( + "fs-filter", + (layoutToUse) => layoutToUse?.enableLayers ?? true, + "Disables/Enables the filter" + ); + this.featureSwitchAddNew = featSw( + "fs-add-new", + (layoutToUse) => layoutToUse?.enableAddNewPoints ?? true, + "Disables/Enables the 'add new feature'-popup. (A theme without presets might not have it in the first place)" + ); + this.featureSwitchWelcomeMessage = featSw( + "fs-welcome-message", + () => true, + "Disables/enables the help menu or welcome message" + ); + this.featureSwitchIframe = featSw( + "fs-iframe", + () => false, + "Disables/Enables the iframe-popup" + ); + this.featureSwitchMoreQuests = featSw( + "fs-more-quests", + (layoutToUse) => layoutToUse?.enableMoreQuests ?? true, + "Disables/Enables the 'More Quests'-tab in the welcome message" + ); + this.featureSwitchShareScreen = featSw( + "fs-share-screen", + (layoutToUse) => layoutToUse?.enableShareScreen ?? true, + "Disables/Enables the 'Share-screen'-tab in the welcome message" + ); + this.featureSwitchGeolocation = featSw( + "fs-geolocation", + (layoutToUse) => layoutToUse?.enableGeolocation ?? true, + "Disables/Enables the geolocation button" + ); + this.featureSwitchShowAllQuestions = featSw( + "fs-all-questions", + (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, + "Always show all questions" + ); + this.featureSwitchIsTesting = QueryParameters.GetQueryParameter( + "test", + "false", + "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org" + ).map( + (str) => str === "true", + [], + (b) => "" + b + ); + + this.featureSwitchIsDebugging = QueryParameters.GetQueryParameter( + "debug", + "false", + "If true, shows some extra debugging help such as all the available tags on every object" + ).map( + (str) => str === "true", + [], + (b) => "" + b + ); + + this.featureSwitchApiURL = QueryParameters.GetQueryParameter( + "backend", + "osm", + "The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test'" + ); + } + { + // Some other feature switches + const customCssQP = QueryParameters.GetQueryParameter( + "custom-css", + "", + "If specified, the custom css from the given link will be loaded additionaly" + ); + if (customCssQP.data !== undefined && customCssQP.data !== "") { + Utils.LoadCustomCss(customCssQP.data); + } + + this.backgroundLayerId = QueryParameters.GetQueryParameter( + "background", + layoutToUse?.defaultBackgroundId ?? "osm", + "The id of the background layer to start with" + ); + } + + if (Utils.runningFromConsole) { + return; + } + + this.osmConnection = new OsmConnection( + this.featureSwitchIsTesting.data, + QueryParameters.GetQueryParameter( + "oauth_token", + undefined, + "Used to complete the login" + ), + layoutToUse?.id, + true, + // @ts-ignore + this.featureSwitchApiURL.data + ); + + this.allElements = new ElementStorage(); + this.changes = new Changes(); + this.osmApiFeatureSource = new OsmApiFeatureSource(); + + new PendingChangesUploader(this.changes, this.selectedElement); + + this.mangroveIdentity = new MangroveIdentity( + this.osmConnection.GetLongPreference("identity", "mangrove") + ); + + this.installedThemes = new InstalledThemes( + this.osmConnection + ).installedThemes; + + // Important: the favourite layers are initialized _after_ the installed themes, as these might contain an installedTheme + this.favouriteLayers = LocalStorageSource.Get("favouriteLayers") + .syncWith(this.osmConnection.GetLongPreference("favouriteLayers")) + .map( + (str) => Utils.Dedup(str?.split(";")) ?? [], + [], + (layers) => Utils.Dedup(layers)?.join(";") + ); + + Locale.language.syncWith(this.osmConnection.GetPreference("language")); + + Locale.language + .addCallback((currentLanguage) => { + const layoutToUse = self.layoutToUse.data; + if (layoutToUse === undefined) { + return; + } + if (this.layoutToUse.data.language.indexOf(currentLanguage) < 0) { + console.log( + "Resetting language to", + layoutToUse.language[0], + "as", + currentLanguage, + " is unsupported" + ); + // The current language is not supported -> switch to a supported one + Locale.language.setData(layoutToUse.language[0]); + } + }) + .ping(); + + new TitleHandler(this.layoutToUse, this.selectedElement, this.allElements); + } + + private static asFloat(source: UIEventSource): UIEventSource { + return source.map( + (str) => { + let parsed = parseFloat(str); + return isNaN(parsed) ? undefined : parsed; + }, + [], + (fl) => { + if (fl === undefined || isNaN(fl)) { + return undefined; + } + return ("" + fl).substr(0, 8); + } + ); + } } diff --git a/Svg.ts b/Svg.ts index 0ebc3f924e..22ea0e1158 100644 --- a/Svg.ts +++ b/Svg.ts @@ -29,6 +29,11 @@ export default class Svg { public static arrow_left_smooth_svg() { return new Img(Svg.arrow_left_smooth, true);} public static arrow_left_smooth_ui() { return new FixedUiElement(Svg.arrow_left_smooth_img);} + public static arrow_left_thin = " " + public static arrow_left_thin_img = Img.AsImageElement(Svg.arrow_left_thin) + public static arrow_left_thin_svg() { return new Img(Svg.arrow_left_thin, true);} + public static arrow_left_thin_ui() { return new FixedUiElement(Svg.arrow_left_thin_img);} + public static arrow_right_smooth = " image/svg+xml " public static arrow_right_smooth_img = Img.AsImageElement(Svg.arrow_right_smooth) public static arrow_right_smooth_svg() { return new Img(Svg.arrow_right_smooth, true);} @@ -134,6 +139,11 @@ export default class Svg { public static envelope_svg() { return new Img(Svg.envelope, true);} public static envelope_ui() { return new FixedUiElement(Svg.envelope_img);} + public static filter = " " + public static filter_img = Img.AsImageElement(Svg.filter) + public static filter_svg() { return new Img(Svg.filter, true);} + public static filter_ui() { return new FixedUiElement(Svg.filter_img);} + public static floppy = " " public static floppy_img = Img.AsImageElement(Svg.floppy) public static floppy_svg() { return new Img(Svg.floppy, true);} @@ -349,4 +359,4 @@ export default class Svg { public static wikipedia_svg() { return new Img(Svg.wikipedia, true);} public static wikipedia_ui() { return new FixedUiElement(Svg.wikipedia_img);} -public static All = {"SocialImageForeground.svg": Svg.SocialImageForeground,"add.svg": Svg.add,"addSmall.svg": Svg.addSmall,"ampersand.svg": Svg.ampersand,"arrow-left-smooth.svg": Svg.arrow_left_smooth,"arrow-right-smooth.svg": Svg.arrow_right_smooth,"back.svg": Svg.back,"bug.svg": Svg.bug,"camera-plus.svg": Svg.camera_plus,"checkmark.svg": Svg.checkmark,"circle.svg": Svg.circle,"clock.svg": Svg.clock,"close.svg": Svg.close,"compass.svg": Svg.compass,"cross_bottom_right.svg": Svg.cross_bottom_right,"crosshair-blue-center.svg": Svg.crosshair_blue_center,"crosshair-blue.svg": Svg.crosshair_blue,"crosshair.svg": Svg.crosshair,"delete_icon.svg": Svg.delete_icon,"direction.svg": Svg.direction,"direction_gradient.svg": Svg.direction_gradient,"direction_masked.svg": Svg.direction_masked,"direction_outline.svg": Svg.direction_outline,"direction_stroke.svg": Svg.direction_stroke,"down.svg": Svg.down,"envelope.svg": Svg.envelope,"floppy.svg": Svg.floppy,"gear.svg": Svg.gear,"help.svg": Svg.help,"home.svg": Svg.home,"home_white_bg.svg": Svg.home_white_bg,"josm_logo.svg": Svg.josm_logo,"layers.svg": Svg.layers,"layersAdd.svg": Svg.layersAdd,"location.svg": Svg.location,"logo.svg": Svg.logo,"logout.svg": Svg.logout,"mapcomplete_logo.svg": Svg.mapcomplete_logo,"mapillary.svg": Svg.mapillary,"mapillary_black.svg": Svg.mapillary_black,"min-zoom.svg": Svg.min_zoom,"min.svg": Svg.min,"no_checkmark.svg": Svg.no_checkmark,"or.svg": Svg.or,"osm-copyright.svg": Svg.osm_copyright,"osm-logo-us.svg": Svg.osm_logo_us,"osm-logo.svg": Svg.osm_logo,"pencil.svg": Svg.pencil,"phone.svg": Svg.phone,"pin.svg": Svg.pin,"plus-zoom.svg": Svg.plus_zoom,"plus.svg": Svg.plus,"pop-out.svg": Svg.pop_out,"reload.svg": Svg.reload,"ring.svg": Svg.ring,"search.svg": Svg.search,"send_email.svg": Svg.send_email,"share.svg": Svg.share,"square.svg": Svg.square,"star.svg": Svg.star,"star_half.svg": Svg.star_half,"star_outline.svg": Svg.star_outline,"star_outline_half.svg": Svg.star_outline_half,"statistics.svg": Svg.statistics,"translate.svg": Svg.translate,"up.svg": Svg.up,"wikidata.svg": Svg.wikidata,"wikimedia-commons-white.svg": Svg.wikimedia_commons_white,"wikipedia.svg": Svg.wikipedia};} +public static All = {"SocialImageForeground.svg": Svg.SocialImageForeground,"add.svg": Svg.add,"addSmall.svg": Svg.addSmall,"ampersand.svg": Svg.ampersand,"arrow-left-smooth.svg": Svg.arrow_left_smooth,"arrow-left-thin.svg": Svg.arrow_left_thin,"arrow-right-smooth.svg": Svg.arrow_right_smooth,"back.svg": Svg.back,"bug.svg": Svg.bug,"camera-plus.svg": Svg.camera_plus,"checkmark.svg": Svg.checkmark,"circle.svg": Svg.circle,"clock.svg": Svg.clock,"close.svg": Svg.close,"compass.svg": Svg.compass,"cross_bottom_right.svg": Svg.cross_bottom_right,"crosshair-blue-center.svg": Svg.crosshair_blue_center,"crosshair-blue.svg": Svg.crosshair_blue,"crosshair.svg": Svg.crosshair,"delete_icon.svg": Svg.delete_icon,"direction.svg": Svg.direction,"direction_gradient.svg": Svg.direction_gradient,"direction_masked.svg": Svg.direction_masked,"direction_outline.svg": Svg.direction_outline,"direction_stroke.svg": Svg.direction_stroke,"down.svg": Svg.down,"envelope.svg": Svg.envelope,"filter.svg": Svg.filter,"floppy.svg": Svg.floppy,"gear.svg": Svg.gear,"help.svg": Svg.help,"home.svg": Svg.home,"home_white_bg.svg": Svg.home_white_bg,"josm_logo.svg": Svg.josm_logo,"layers.svg": Svg.layers,"layersAdd.svg": Svg.layersAdd,"location.svg": Svg.location,"logo.svg": Svg.logo,"logout.svg": Svg.logout,"mapcomplete_logo.svg": Svg.mapcomplete_logo,"mapillary.svg": Svg.mapillary,"mapillary_black.svg": Svg.mapillary_black,"min-zoom.svg": Svg.min_zoom,"min.svg": Svg.min,"no_checkmark.svg": Svg.no_checkmark,"or.svg": Svg.or,"osm-copyright.svg": Svg.osm_copyright,"osm-logo-us.svg": Svg.osm_logo_us,"osm-logo.svg": Svg.osm_logo,"pencil.svg": Svg.pencil,"phone.svg": Svg.phone,"pin.svg": Svg.pin,"plus-zoom.svg": Svg.plus_zoom,"plus.svg": Svg.plus,"pop-out.svg": Svg.pop_out,"reload.svg": Svg.reload,"ring.svg": Svg.ring,"search.svg": Svg.search,"send_email.svg": Svg.send_email,"share.svg": Svg.share,"square.svg": Svg.square,"star.svg": Svg.star,"star_half.svg": Svg.star_half,"star_outline.svg": Svg.star_outline,"star_outline_half.svg": Svg.star_outline_half,"statistics.svg": Svg.statistics,"translate.svg": Svg.translate,"up.svg": Svg.up,"wikidata.svg": Svg.wikidata,"wikimedia-commons-white.svg": Svg.wikimedia_commons_white,"wikipedia.svg": Svg.wikipedia};} diff --git a/UI/BigComponents/FilterView.ts b/UI/BigComponents/FilterView.ts new file mode 100644 index 0000000000..b2ee12c16b --- /dev/null +++ b/UI/BigComponents/FilterView.ts @@ -0,0 +1,39 @@ +import { FixedUiElement } from "./../Base/FixedUiElement"; +import { LayerConfigJson } from "./../../Customizations/JSON/LayerConfigJson"; +import { UIEventSource } from "../../Logic/UIEventSource"; +import { VariableUiElement } from "../Base/VariableUIElement"; +import State from "../../State"; +import Toggle from "../Input/Toggle"; +import Combine from "../Base/Combine"; +import Translations from "../i18n/Translations"; +import LayerConfig from "../../Customizations/JSON/LayerConfig"; +import BaseUIElement from "../BaseUIElement"; +import { Translation } from "../i18n/Translation"; +import ScrollableFullScreen from "../Base/ScrollableFullScreen"; + +/** + * Shows the filter + */ +export default class FilterView extends ScrollableFullScreen { + constructor(isShown: UIEventSource) { + super(FilterView.GenTitle, FilterView.Generatecontent, "filter", isShown); + } + + private static GenTitle(): BaseUIElement { + return new FixedUiElement(`Filter`).SetClass( + "text-2xl break-words font-bold p-2" + ); + } + + private static Generatecontent(): BaseUIElement { + let filterPanel: BaseUIElement = new FixedUiElement("more stuff"); + + if (State.state.filteredLayers.data.length > 1) { + let layers = State.state.filteredLayers; + console.log(layers); + filterPanel = new Combine(["layerssss", "
", filterPanel]); + } + + return filterPanel; + } +} diff --git a/assets/svg/arrow-left-thin.svg b/assets/svg/arrow-left-thin.svg new file mode 100644 index 0000000000..e4329b6151 --- /dev/null +++ b/assets/svg/arrow-left-thin.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/filter.svg b/assets/svg/filter.svg new file mode 100644 index 0000000000..a6783b2484 --- /dev/null +++ b/assets/svg/filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 82c1793bab..fa3d1d13ec 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -490,5 +490,11 @@ "path": "plus-zoom.svg", "license": "CC0", "sources": [] + }, + { + "authors": ["Hannah Declerck"], + "path": "filter.svg", + "license": "CC0", + "sources": [] } ] From ec10a0fbe1daee0ac0cc33dc00fe2f3ba570c31a Mon Sep 17 00:00:00 2001 From: karelleketers Date: Tue, 20 Jul 2021 16:23:44 +0200 Subject: [PATCH 2/6] Changed icons and adjusted zoom levels --- assets/layers/bench/bench.json | 6 +- assets/layers/bench/bench.svg | 1 + assets/layers/bench/license_info.json | 8 + assets/layers/birdhide/birdhide.json | 2 +- .../information_board/information_board.json | 3 - assets/layers/parking/parking.json | 8 +- assets/layers/picnic_table/picnic_table.json | 4 - assets/layers/toilet/toilet.json | 2 +- assets/layers/trail/trail.json | 5 +- .../visitor_information_centre.json | 4 - assets/layers/watermill/license_info.json | 8 + assets/layers/watermill/watermill.json | 6 +- assets/layers/watermill/watermill.svg | 1 + assets/svg/license_info.json | 232 +++++++++++++----- assets/themes/natuurpunt/bench.svg | 1 + assets/themes/natuurpunt/birdhide.svg | 1 + assets/themes/natuurpunt/drips.svg | 1 + assets/themes/natuurpunt/information.svg | 1 + .../themes/natuurpunt/information_board.svg | 1 + assets/themes/natuurpunt/license_info.json | 90 +++++++ assets/themes/natuurpunt/nature_reserve.svg | 1 + assets/themes/natuurpunt/natuurpunt.json | 151 ++++++++++-- assets/themes/natuurpunt/parking.svg | 1 + assets/themes/natuurpunt/picnic_table.svg | 1 + assets/themes/natuurpunt/pushchair.svg | 1 + assets/themes/natuurpunt/toilets.svg | 1 + assets/themes/natuurpunt/trail.svg | 1 + assets/themes/natuurpunt/urinal.svg | 1 + assets/themes/natuurpunt/walk_wheelchair.svg | 1 + assets/themes/natuurpunt/watermill.svg | 1 + assets/themes/natuurpunt/wheelchair.svg | 1 + 31 files changed, 445 insertions(+), 101 deletions(-) create mode 100644 assets/layers/bench/bench.svg create mode 100644 assets/layers/bench/license_info.json create mode 100644 assets/layers/watermill/license_info.json create mode 100644 assets/layers/watermill/watermill.svg create mode 100644 assets/themes/natuurpunt/bench.svg create mode 100644 assets/themes/natuurpunt/birdhide.svg create mode 100644 assets/themes/natuurpunt/drips.svg create mode 100644 assets/themes/natuurpunt/information.svg create mode 100644 assets/themes/natuurpunt/information_board.svg create mode 100644 assets/themes/natuurpunt/nature_reserve.svg create mode 100644 assets/themes/natuurpunt/parking.svg create mode 100644 assets/themes/natuurpunt/picnic_table.svg create mode 100644 assets/themes/natuurpunt/pushchair.svg create mode 100644 assets/themes/natuurpunt/toilets.svg create mode 100644 assets/themes/natuurpunt/trail.svg create mode 100644 assets/themes/natuurpunt/urinal.svg create mode 100644 assets/themes/natuurpunt/walk_wheelchair.svg create mode 100644 assets/themes/natuurpunt/watermill.svg create mode 100644 assets/themes/natuurpunt/wheelchair.svg diff --git a/assets/layers/bench/bench.json b/assets/layers/bench/bench.json index fca4ca579e..f55874b0ff 100644 --- a/assets/layers/bench/bench.json +++ b/assets/layers/bench/bench.json @@ -520,11 +520,7 @@ ], "hideUnderlayingFeaturesMinPercentage": 0, "icon": { - "render": "./assets/themes/benches/bench_poi.svg", - "mappings": [] - }, - "width": { - "render": "8" + "render": "circle:#FE6F32;./assets/layers/bench/bench.svg" }, "iconSize": { "render": "35,35,center" diff --git a/assets/layers/bench/bench.svg b/assets/layers/bench/bench.svg new file mode 100644 index 0000000000..dc4fc07882 --- /dev/null +++ b/assets/layers/bench/bench.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/layers/bench/license_info.json b/assets/layers/bench/license_info.json new file mode 100644 index 0000000000..2e404ab20d --- /dev/null +++ b/assets/layers/bench/license_info.json @@ -0,0 +1,8 @@ +[ + { + "authors": [], + "path": "bench.svg", + "license": "CC0", + "sources": [] + } +] \ No newline at end of file diff --git a/assets/layers/birdhide/birdhide.json b/assets/layers/birdhide/birdhide.json index 71a80d88d1..08ff0f22f5 100644 --- a/assets/layers/birdhide/birdhide.json +++ b/assets/layers/birdhide/birdhide.json @@ -241,5 +241,5 @@ } } ], - "wayHandling": 2 + "wayHandling": 1 } \ No newline at end of file diff --git a/assets/layers/information_board/information_board.json b/assets/layers/information_board/information_board.json index 017f3aeb63..db4b5dfcd8 100644 --- a/assets/layers/information_board/information_board.json +++ b/assets/layers/information_board/information_board.json @@ -33,9 +33,6 @@ "icon": { "render": "./assets/layers/information_board/board.svg" }, - "width": { - "render": "8" - }, "iconSize": { "render": "40,40,center" }, diff --git a/assets/layers/parking/parking.json b/assets/layers/parking/parking.json index a8ad2767d5..c6e5f57f0e 100644 --- a/assets/layers/parking/parking.json +++ b/assets/layers/parking/parking.json @@ -167,13 +167,9 @@ ] } ], - "hideUnderlayingFeaturesMinPercentage": 10, - "wayHandling": 2, - "width": { - "render": "5" - }, + "wayHandling": 1, "iconSize": { - "render": "50,50,center" + "render": "30,30,center" }, "color": { "render": "#E1AD01" diff --git a/assets/layers/picnic_table/picnic_table.json b/assets/layers/picnic_table/picnic_table.json index 672e41f07f..ac46da5363 100644 --- a/assets/layers/picnic_table/picnic_table.json +++ b/assets/layers/picnic_table/picnic_table.json @@ -72,13 +72,9 @@ ] } ], - "hideUnderlayingFeaturesMinPercentage": 0, "icon": { "render": "circle:#e6cf39;./assets/layers/picnic_table/picnic_table.svg" }, - "width": { - "render": "8" - }, "iconSize": { "render": "35,35,center" }, diff --git a/assets/layers/toilet/toilet.json b/assets/layers/toilet/toilet.json index b7a44457e2..cbdd19d286 100644 --- a/assets/layers/toilet/toilet.json +++ b/assets/layers/toilet/toilet.json @@ -38,7 +38,7 @@ "color": { "render": "#0000ff" }, - "wayHandling": 2, + "wayHandling": 1, "presets": [ { "title": { diff --git a/assets/layers/trail/trail.json b/assets/layers/trail/trail.json index d1236bc896..5a031f02e5 100644 --- a/assets/layers/trail/trail.json +++ b/assets/layers/trail/trail.json @@ -393,7 +393,7 @@ }, "wayHandling": 2, "width": { - "render": "5" + "render": "3" }, "iconSize": { "render": "35,35,center" @@ -401,6 +401,9 @@ "color": { "render": "#335D9F" }, + "dashArray": { + "render": "5 5" + }, "presets": [ { "tags": [ diff --git a/assets/layers/visitor_information_centre/visitor_information_centre.json b/assets/layers/visitor_information_centre/visitor_information_centre.json index 07f28942c0..10c3cd0de1 100644 --- a/assets/layers/visitor_information_centre/visitor_information_centre.json +++ b/assets/layers/visitor_information_centre/visitor_information_centre.json @@ -51,13 +51,9 @@ "nl": "Een bezoekerscentrum biedt informatie over een specifieke attractie of bezienswaardigheid waar het is gevestigd." }, "tagRenderings": [], - "hideUnderlayingFeaturesMinPercentage": 0, "icon": { "render": "./assets/layers/visitor_information_centre/information.svg" }, - "width": { - "render": "8" - }, "iconSize": { "render": "40,40,center" }, diff --git a/assets/layers/watermill/license_info.json b/assets/layers/watermill/license_info.json new file mode 100644 index 0000000000..44bc785297 --- /dev/null +++ b/assets/layers/watermill/license_info.json @@ -0,0 +1,8 @@ +[ + { + "authors": [], + "path": "watermill.svg", + "license": "CC0", + "sources": [] + } +] \ No newline at end of file diff --git a/assets/layers/watermill/watermill.json b/assets/layers/watermill/watermill.json index 5789202d5e..ffa2f0dc9a 100644 --- a/assets/layers/watermill/watermill.json +++ b/assets/layers/watermill/watermill.json @@ -160,9 +160,9 @@ } ], "hideUnderlayingFeaturesMinPercentage": 10, - "wayHandling": 2, - "width": { - "render": "10" + "wayHandling": 1, + "icon": { + "render": "./assets/layers/watermill/watermill.svg" }, "iconSize": { "render": "50,50,center" diff --git a/assets/layers/watermill/watermill.svg b/assets/layers/watermill/watermill.svg new file mode 100644 index 0000000000..05528d3c4d --- /dev/null +++ b/assets/layers/watermill/watermill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 82c1793bab..41272b2d58 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -1,36 +1,50 @@ [ { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "direction_masked.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "direction_outline.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "direction_stroke.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "SocialImageForeground.svg", "license": "CC-BY-SA", - "sources": ["https://mapcomplete.osm.be"] + "sources": [ + "https://mapcomplete.osm.be" + ] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "add.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "addSmall.svg", "license": "CC0", "sources": [] @@ -42,25 +56,33 @@ "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "arrow-left-smooth.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "arrow-right-smooth.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "back.svg", "license": "CC0", "sources": [] }, { - "authors": ["Github"], + "authors": [ + "Github" + ], "path": "bug.svg", "license": "MIT", "sources": [ @@ -71,26 +93,35 @@ { "path": "camera-plus.svg", "license": "CC-BY-SA 3.0", - "authors": ["Dave Gandy", "Pieter Vander Vennet"], + "authors": [ + "Dave Gandy", + "Pieter Vander Vennet" + ], "sources": [ "https://fontawesome.com/", "https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg" ] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "checkmark.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "circle.svg", "license": "CC0", "sources": [] }, { - "authors": ["Pieter Vander Vennet"], + "authors": [ + "Pieter Vander Vennet" + ], "path": "clock.svg", "license": "CC0", "sources": [] @@ -132,7 +163,9 @@ "sources": [] }, { - "authors": ["Dave Gandy"], + "authors": [ + "Dave Gandy" + ], "path": "delete_icon.svg", "license": "CC-BY-SA", "sources": [ @@ -164,7 +197,9 @@ "sources": [] }, { - "authors": ["The Tango Desktop Project"], + "authors": [ + "The Tango Desktop Project" + ], "path": "floppy.svg", "license": "CC0", "sources": [ @@ -185,19 +220,29 @@ "sources": [] }, { - "authors": ["Timothy Miller"], + "authors": [ + "Timothy Miller" + ], "path": "home.svg", "license": "CC-BY-SA 3.0", - "sources": ["https://commons.wikimedia.org/wiki/File:Home-icon.svg"] + "sources": [ + "https://commons.wikimedia.org/wiki/File:Home-icon.svg" + ] }, { - "authors": ["Timothy Miller"], + "authors": [ + "Timothy Miller" + ], "path": "home_white_bg.svg", "license": "CC-BY-SA 3.0", - "sources": ["https://commons.wikimedia.org/wiki/File:Home-icon.svg"] + "sources": [ + "https://commons.wikimedia.org/wiki/File:Home-icon.svg" + ] }, { - "authors": ["JOSM Team"], + "authors": [ + "JOSM Team" + ], "path": "josm_logo.svg", "license": "CC0", "sources": [ @@ -220,7 +265,9 @@ { "path": "Ornament-Horiz-0.svg", "license": "CC-BY", - "authors": ["Nightwolfdezines"], + "authors": [ + "Nightwolfdezines" + ], "sources": [ "https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes" ] @@ -228,7 +275,9 @@ { "path": "Ornament-Horiz-1.svg", "license": "CC-BY", - "authors": ["Nightwolfdezines"], + "authors": [ + "Nightwolfdezines" + ], "sources": [ "https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes" ] @@ -236,7 +285,9 @@ { "path": "Ornament-Horiz-2.svg", "license": "CC-BY", - "authors": ["Nightwolfdezines"], + "authors": [ + "Nightwolfdezines" + ], "sources": [ "https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes" ] @@ -244,7 +295,9 @@ { "path": "Ornament-Horiz-3.svg", "license": "CC-BY", - "authors": ["Nightwolfdezines"], + "authors": [ + "Nightwolfdezines" + ], "sources": [ "https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes" ] @@ -252,7 +305,9 @@ { "path": "Ornament-Horiz-4.svg", "license": "CC-BY", - "authors": ["Nightwolfdezines"], + "authors": [ + "Nightwolfdezines" + ], "sources": [ "https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes" ] @@ -260,7 +315,9 @@ { "path": "Ornament-Horiz-5.svg", "license": "CC-BY", - "authors": ["Nightwolfdezines"], + "authors": [ + "Nightwolfdezines" + ], "sources": [ "https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes" ] @@ -268,7 +325,9 @@ { "path": "Ornament-Horiz-6.svg", "license": "CC-BY", - "authors": ["Nightwolfdezines"], + "authors": [ + "Nightwolfdezines" + ], "sources": [ "https://www.vecteezy.com/vector-art/226361-ornaments-and-flourishes" ] @@ -310,16 +369,25 @@ "sources": [] }, { - "authors": ["Pieter Vander Vennet", " OSM"], + "authors": [ + "Pieter Vander Vennet", + " OSM" + ], "path": "mapcomplete_logo.svg", "license": "Logo; CC-BY-SA", - "sources": ["https://mapcomplete.osm.be"] + "sources": [ + "https://mapcomplete.osm.be" + ] }, { - "authors": ["Mapillary"], + "authors": [ + "Mapillary" + ], "path": "mapillary.svg", "license": "Logo; All rights reserved", - "sources": ["https://mapillary.com/"] + "sources": [ + "https://mapillary.com/" + ] }, { "authors": [], @@ -343,22 +411,32 @@ "authors": [], "path": "osm-copyright.svg", "license": "logo; all rights reserved", - "sources": ["https://www.OpenStreetMap.org"] + "sources": [ + "https://www.OpenStreetMap.org" + ] }, { - "authors": ["OpenStreetMap U.S. Chapter"], + "authors": [ + "OpenStreetMap U.S. Chapter" + ], "path": "osm-logo-us.svg", "license": "Logo", - "sources": ["https://www.openstreetmap.us/"] + "sources": [ + "https://www.openstreetmap.us/" + ] }, { "authors": [], "path": "osm-logo.svg", "license": "logo; all rights reserved", - "sources": ["https://www.OpenStreetMap.org"] + "sources": [ + "https://www.OpenStreetMap.org" + ] }, { - "authors": ["GitHub Octicons"], + "authors": [ + "GitHub Octicons" + ], "path": "pencil.svg", "license": "MIT", "sources": [ @@ -367,10 +445,14 @@ ] }, { - "authors": ["@ tyskrat"], + "authors": [ + "@ tyskrat" + ], "path": "phone.svg", "license": "CC-BY 3.0", - "sources": ["https://www.onlinewebfonts.com/icon/1059"] + "sources": [ + "https://www.onlinewebfonts.com/icon/1059" + ] }, { "authors": [], @@ -385,10 +467,14 @@ "sources": [] }, { - "authors": ["@fatih"], + "authors": [ + "@fatih" + ], "path": "pop-out.svg", "license": "CC-BY 3.0", - "sources": ["https://www.onlinewebfonts.com/icon/2151"] + "sources": [ + "https://www.onlinewebfonts.com/icon/2151" + ] }, { "authors": [], @@ -403,7 +489,9 @@ "sources": [] }, { - "authors": ["OOjs UI Team and other contributors"], + "authors": [ + "OOjs UI Team and other contributors" + ], "path": "search.svg", "license": "MIT", "sources": [ @@ -430,13 +518,19 @@ "sources": [] }, { - "authors": ["@felpgrc"], + "authors": [ + "@felpgrc" + ], "path": "statistics.svg", "license": "CC-BY 3.0", - "sources": ["https://www.onlinewebfonts.com/icon/197818"] + "sources": [ + "https://www.onlinewebfonts.com/icon/197818" + ] }, { - "authors": ["MGalloway (WMF)"], + "authors": [ + "MGalloway (WMF)" + ], "path": "translate.svg", "license": "CC-BY-SA 3.0", "sources": [ @@ -450,45 +544,67 @@ "sources": [] }, { - "authors": ["Wikidata"], + "authors": [ + "Wikidata" + ], "path": "wikidata.svg", "license": "Logo; All rights reserved", - "sources": ["https://www.wikidata.org"] + "sources": [ + "https://www.wikidata.org" + ] }, { - "authors": ["Wikimedia"], + "authors": [ + "Wikimedia" + ], "path": "wikimedia-commons-white.svg", "license": "Logo; All rights reserved", - "sources": ["https://commons.wikimedia.org"] + "sources": [ + "https://commons.wikimedia.org" + ] }, { - "authors": ["Wikipedia"], + "authors": [ + "Wikipedia" + ], "path": "wikipedia.svg", "license": "Logo; All rights reserved", - "sources": ["https://www.wikipedia.org/"] + "sources": [ + "https://www.wikipedia.org/" + ] }, { - "authors": ["Mapillary"], + "authors": [ + "Mapillary" + ], "path": "mapillary_black.svg", "license": "Logo; All rights reserved", - "sources": ["https://www.mapillary.com/"] + "sources": [ + "https://www.mapillary.com/" + ] }, { - "authors": ["Hannah Declerck"], + "authors": [ + "Hannah Declerck" + ], "path": "location.svg", "license": "CC0", "sources": [] }, { - "authors": ["Hannah Declerck"], + "authors": [ + "Hannah Declerck" + ], "path": "min-zoom.svg", "license": "CC0", "sources": [] }, { - "authors": ["Hannah Declerck"], + "authors": [ + "Hannah Declerck" + ], "path": "plus-zoom.svg", "license": "CC0", "sources": [] } -] +] \ No newline at end of file diff --git a/assets/themes/natuurpunt/bench.svg b/assets/themes/natuurpunt/bench.svg new file mode 100644 index 0000000000..ddab90ca99 --- /dev/null +++ b/assets/themes/natuurpunt/bench.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/birdhide.svg b/assets/themes/natuurpunt/birdhide.svg new file mode 100644 index 0000000000..730e3f712f --- /dev/null +++ b/assets/themes/natuurpunt/birdhide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/drips.svg b/assets/themes/natuurpunt/drips.svg new file mode 100644 index 0000000000..94517d71eb --- /dev/null +++ b/assets/themes/natuurpunt/drips.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/information.svg b/assets/themes/natuurpunt/information.svg new file mode 100644 index 0000000000..248cbccb52 --- /dev/null +++ b/assets/themes/natuurpunt/information.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/information_board.svg b/assets/themes/natuurpunt/information_board.svg new file mode 100644 index 0000000000..42d2b07459 --- /dev/null +++ b/assets/themes/natuurpunt/information_board.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/license_info.json b/assets/themes/natuurpunt/license_info.json index 29b7ace4ba..c24e4be1c2 100644 --- a/assets/themes/natuurpunt/license_info.json +++ b/assets/themes/natuurpunt/license_info.json @@ -8,5 +8,95 @@ "sources": [ "https://www.natuurpunt.be/" ] + }, + { + "authors": [], + "path": "bench.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "watermill.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "information.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "trail.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "toilets.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "urinal.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "wheelchair.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "walk_wheelchair.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "information_board.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "pushchair.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "picnic_table.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "parking.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "nature_reserve.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "drips.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [], + "path": "birdhide.svg", + "license": "CC0", + "sources": [] } ] \ No newline at end of file diff --git a/assets/themes/natuurpunt/nature_reserve.svg b/assets/themes/natuurpunt/nature_reserve.svg new file mode 100644 index 0000000000..e1085da76c --- /dev/null +++ b/assets/themes/natuurpunt/nature_reserve.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/natuurpunt.json b/assets/themes/natuurpunt/natuurpunt.json index f14c42a8cf..06d30fd7c4 100644 --- a/assets/themes/natuurpunt/natuurpunt.json +++ b/assets/themes/natuurpunt/natuurpunt.json @@ -27,8 +27,24 @@ "layers": [ { "builtin": [ - "nature_reserve", - "trail", + "nature_reserve" + ], + "override": { + "source": { + "osmTags": { + "+and": [ + "operator~.*[nN]atuurpunt.*" + ] + } + }, + "minzoom": "8", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/nature_reserve.svg" + } + } + }, + { + "builtin": [ "visitor_information_centre" ], "override": { @@ -37,33 +53,138 @@ "+and": [ "operator~.*[nN]atuurpunt.*" ] - }, - "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", - "geoJsonZoomLevel": 8, - "isOsmCache": true + } + }, + "minzoom": "8", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/information.svg" } } }, { "builtin": [ - "birdhide", - "toilet", - "drinking_water", - "picnic_table" + "trail" ], "override": { - "minzoom": "14" + "source": { + "osmTags": { + "+and": [ + "operator~.*[nN]atuurpunt.*" + ] + } + }, + "minzoom": "13", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/trail.svg", + "mappings": [ + { + "if": "wheelchair=yes", + "then": "circle:#FE6F32;./assets/themes/natuurpunt/walk_wheelchair.svg" + }, + { + "if": "pushchair=yes", + "then": "circle:#FE6F32;./assets/themes/natuurpunt/pushchair.svg" + } + ] + } + } + }, + { + "builtin": [ + "toilet" + ], + "override": { + "minzoom": "15", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/toilets.svg", + "mappings": [ + { + "if": "wheelchair=yes", + "then": "circle:#FE6F32;./assets/themes/natuurpunt/wheelchair.svg" + }, + { + "if": "toilets:position=urinals", + "then": "circle:#FE6F32;./assets/themes/natuurpunt/urinal.svg" + } + ] + } + } + }, + { + "builtin": [ + "birdhide" + ], + "override": { + "minzoom": "15", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/birdhide.svg" + } + } + }, + { + "builtin": [ + "picnic_table" + ], + "override": { + "minzoom": "16", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/picnic_table.svg" + } + } + }, + { + "builtin": [ + "drinking_water" + ], + "override": { + "minzoom": "16", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/drips.svg" + } + } + }, + { + "builtin": [ + "bench" + ], + "override": { + "minzoom": "18", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/bench.svg" + } + } + }, + { + "builtin": [ + "watermill" + ], + "override": { + "minzoom": "18", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/watermill.svg" + } + } + }, + { + "builtin": [ + "parking" + ], + "override": { + "minzoom": "18", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/parking.svg" + } } }, { "builtin": [ - "bench", - "watermill", - "parking", "information_board" ], "override": { - "minzoom": "17" + "minzoom": "18", + "icon": { + "render": "circle:#FE6F32;./assets/themes/natuurpunt/information_board.svg" + } } } ], diff --git a/assets/themes/natuurpunt/parking.svg b/assets/themes/natuurpunt/parking.svg new file mode 100644 index 0000000000..fceb3f23f7 --- /dev/null +++ b/assets/themes/natuurpunt/parking.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/picnic_table.svg b/assets/themes/natuurpunt/picnic_table.svg new file mode 100644 index 0000000000..6629c237ef --- /dev/null +++ b/assets/themes/natuurpunt/picnic_table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/pushchair.svg b/assets/themes/natuurpunt/pushchair.svg new file mode 100644 index 0000000000..725e1dee32 --- /dev/null +++ b/assets/themes/natuurpunt/pushchair.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/toilets.svg b/assets/themes/natuurpunt/toilets.svg new file mode 100644 index 0000000000..006dcceca5 --- /dev/null +++ b/assets/themes/natuurpunt/toilets.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/trail.svg b/assets/themes/natuurpunt/trail.svg new file mode 100644 index 0000000000..3839ed493b --- /dev/null +++ b/assets/themes/natuurpunt/trail.svg @@ -0,0 +1 @@ + diff --git a/assets/themes/natuurpunt/urinal.svg b/assets/themes/natuurpunt/urinal.svg new file mode 100644 index 0000000000..90038efb6a --- /dev/null +++ b/assets/themes/natuurpunt/urinal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/walk_wheelchair.svg b/assets/themes/natuurpunt/walk_wheelchair.svg new file mode 100644 index 0000000000..6f2e46fe9c --- /dev/null +++ b/assets/themes/natuurpunt/walk_wheelchair.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/watermill.svg b/assets/themes/natuurpunt/watermill.svg new file mode 100644 index 0000000000..1c62cd1473 --- /dev/null +++ b/assets/themes/natuurpunt/watermill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/wheelchair.svg b/assets/themes/natuurpunt/wheelchair.svg new file mode 100644 index 0000000000..9a7124a876 --- /dev/null +++ b/assets/themes/natuurpunt/wheelchair.svg @@ -0,0 +1 @@ + \ No newline at end of file From 2c9f737cbd702e4a1fdddd7ca7aeeee99a01231f Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 22 Jul 2021 10:52:07 +0200 Subject: [PATCH 3/6] Enable caching, add different background --- assets/svg/license_info.json | 4 +- assets/themes/natuurpunt/natuurpunt.json | 51 ++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 560b9d1435..2f85396c2b 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -608,7 +608,9 @@ "sources": [] }, { - "authors": ["Hannah Declerck"], + "authors": [ + "Hannah Declerck" + ], "path": "filter.svg", "license": "CC0", "sources": [] diff --git a/assets/themes/natuurpunt/natuurpunt.json b/assets/themes/natuurpunt/natuurpunt.json index 06d30fd7c4..ffdf377fdb 100644 --- a/assets/themes/natuurpunt/natuurpunt.json +++ b/assets/themes/natuurpunt/natuurpunt.json @@ -24,6 +24,7 @@ "startZoom": 12, "widenFactor": 0.05, "socialImage": "", + "defaultBackgroundId": "CartoDB.Positron", "layers": [ { "builtin": [ @@ -35,7 +36,10 @@ "+and": [ "operator~.*[nN]atuurpunt.*" ] - } + }, + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true }, "minzoom": "8", "icon": { @@ -53,7 +57,10 @@ "+and": [ "operator~.*[nN]atuurpunt.*" ] - } + }, + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true }, "minzoom": "8", "icon": { @@ -71,7 +78,10 @@ "+and": [ "operator~.*[nN]atuurpunt.*" ] - } + }, + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true }, "minzoom": "13", "icon": { @@ -95,6 +105,11 @@ ], "override": { "minzoom": "15", + "source": { + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true + }, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/toilets.svg", "mappings": [ @@ -116,6 +131,11 @@ ], "override": { "minzoom": "15", + "source": { + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true + }, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/birdhide.svg" } @@ -127,6 +147,11 @@ ], "override": { "minzoom": "16", + "source": { + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true + }, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/picnic_table.svg" } @@ -138,6 +163,11 @@ ], "override": { "minzoom": "16", + "source": { + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true + }, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/drips.svg" } @@ -160,6 +190,11 @@ ], "override": { "minzoom": "18", + "source": { + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true + }, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/watermill.svg" } @@ -171,6 +206,11 @@ ], "override": { "minzoom": "18", + "source": { + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true + }, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/parking.svg" } @@ -182,6 +222,11 @@ ], "override": { "minzoom": "18", + "source": { + "geoJson": "https://pietervdvn.github.io/natuurpunt_cache/natuurpunt_{layer}_{z}_{x}_{y}.geojson", + "geoJsonZoomLevel": 12, + "isOsmCache": true + }, "icon": { "render": "circle:#FE6F32;./assets/themes/natuurpunt/information_board.svg" } From 34b87e7b7efd17f0ebc03982c3975bcffdc1d25e Mon Sep 17 00:00:00 2001 From: Ward Date: Tue, 20 Jul 2021 16:29:48 +0200 Subject: [PATCH 4/6] more custom filter on layers --- Svg.ts | 12 +++++++- UI/BigComponents/FilterView.ts | 53 ++++++++++++++++++++++++++++++---- assets/svg/checkbox-empty.svg | 3 ++ assets/svg/checkbox-filled.svg | 4 +++ assets/svg/license_info.json | 24 +++++++++++++++ 5 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 assets/svg/checkbox-empty.svg create mode 100644 assets/svg/checkbox-filled.svg diff --git a/Svg.ts b/Svg.ts index 22ea0e1158..ab5ef6569a 100644 --- a/Svg.ts +++ b/Svg.ts @@ -54,6 +54,16 @@ export default class Svg { public static camera_plus_svg() { return new Img(Svg.camera_plus, true);} public static camera_plus_ui() { return new FixedUiElement(Svg.camera_plus_img);} + public static checkbox_empty = " " + public static checkbox_empty_img = Img.AsImageElement(Svg.checkbox_empty) + public static checkbox_empty_svg() { return new Img(Svg.checkbox_empty, true);} + public static checkbox_empty_ui() { return new FixedUiElement(Svg.checkbox_empty_img);} + + public static checkbox_filled = " " + public static checkbox_filled_img = Img.AsImageElement(Svg.checkbox_filled) + public static checkbox_filled_svg() { return new Img(Svg.checkbox_filled, true);} + public static checkbox_filled_ui() { return new FixedUiElement(Svg.checkbox_filled_img);} + public static checkmark = "" public static checkmark_img = Img.AsImageElement(Svg.checkmark) public static checkmark_svg() { return new Img(Svg.checkmark, true);} @@ -359,4 +369,4 @@ export default class Svg { public static wikipedia_svg() { return new Img(Svg.wikipedia, true);} public static wikipedia_ui() { return new FixedUiElement(Svg.wikipedia_img);} -public static All = {"SocialImageForeground.svg": Svg.SocialImageForeground,"add.svg": Svg.add,"addSmall.svg": Svg.addSmall,"ampersand.svg": Svg.ampersand,"arrow-left-smooth.svg": Svg.arrow_left_smooth,"arrow-left-thin.svg": Svg.arrow_left_thin,"arrow-right-smooth.svg": Svg.arrow_right_smooth,"back.svg": Svg.back,"bug.svg": Svg.bug,"camera-plus.svg": Svg.camera_plus,"checkmark.svg": Svg.checkmark,"circle.svg": Svg.circle,"clock.svg": Svg.clock,"close.svg": Svg.close,"compass.svg": Svg.compass,"cross_bottom_right.svg": Svg.cross_bottom_right,"crosshair-blue-center.svg": Svg.crosshair_blue_center,"crosshair-blue.svg": Svg.crosshair_blue,"crosshair.svg": Svg.crosshair,"delete_icon.svg": Svg.delete_icon,"direction.svg": Svg.direction,"direction_gradient.svg": Svg.direction_gradient,"direction_masked.svg": Svg.direction_masked,"direction_outline.svg": Svg.direction_outline,"direction_stroke.svg": Svg.direction_stroke,"down.svg": Svg.down,"envelope.svg": Svg.envelope,"filter.svg": Svg.filter,"floppy.svg": Svg.floppy,"gear.svg": Svg.gear,"help.svg": Svg.help,"home.svg": Svg.home,"home_white_bg.svg": Svg.home_white_bg,"josm_logo.svg": Svg.josm_logo,"layers.svg": Svg.layers,"layersAdd.svg": Svg.layersAdd,"location.svg": Svg.location,"logo.svg": Svg.logo,"logout.svg": Svg.logout,"mapcomplete_logo.svg": Svg.mapcomplete_logo,"mapillary.svg": Svg.mapillary,"mapillary_black.svg": Svg.mapillary_black,"min-zoom.svg": Svg.min_zoom,"min.svg": Svg.min,"no_checkmark.svg": Svg.no_checkmark,"or.svg": Svg.or,"osm-copyright.svg": Svg.osm_copyright,"osm-logo-us.svg": Svg.osm_logo_us,"osm-logo.svg": Svg.osm_logo,"pencil.svg": Svg.pencil,"phone.svg": Svg.phone,"pin.svg": Svg.pin,"plus-zoom.svg": Svg.plus_zoom,"plus.svg": Svg.plus,"pop-out.svg": Svg.pop_out,"reload.svg": Svg.reload,"ring.svg": Svg.ring,"search.svg": Svg.search,"send_email.svg": Svg.send_email,"share.svg": Svg.share,"square.svg": Svg.square,"star.svg": Svg.star,"star_half.svg": Svg.star_half,"star_outline.svg": Svg.star_outline,"star_outline_half.svg": Svg.star_outline_half,"statistics.svg": Svg.statistics,"translate.svg": Svg.translate,"up.svg": Svg.up,"wikidata.svg": Svg.wikidata,"wikimedia-commons-white.svg": Svg.wikimedia_commons_white,"wikipedia.svg": Svg.wikipedia};} +public static All = {"SocialImageForeground.svg": Svg.SocialImageForeground,"add.svg": Svg.add,"addSmall.svg": Svg.addSmall,"ampersand.svg": Svg.ampersand,"arrow-left-smooth.svg": Svg.arrow_left_smooth,"arrow-left-thin.svg": Svg.arrow_left_thin,"arrow-right-smooth.svg": Svg.arrow_right_smooth,"back.svg": Svg.back,"bug.svg": Svg.bug,"camera-plus.svg": Svg.camera_plus,"checkbox-empty.svg": Svg.checkbox_empty,"checkbox-filled.svg": Svg.checkbox_filled,"checkmark.svg": Svg.checkmark,"circle.svg": Svg.circle,"clock.svg": Svg.clock,"close.svg": Svg.close,"compass.svg": Svg.compass,"cross_bottom_right.svg": Svg.cross_bottom_right,"crosshair-blue-center.svg": Svg.crosshair_blue_center,"crosshair-blue.svg": Svg.crosshair_blue,"crosshair.svg": Svg.crosshair,"delete_icon.svg": Svg.delete_icon,"direction.svg": Svg.direction,"direction_gradient.svg": Svg.direction_gradient,"direction_masked.svg": Svg.direction_masked,"direction_outline.svg": Svg.direction_outline,"direction_stroke.svg": Svg.direction_stroke,"down.svg": Svg.down,"envelope.svg": Svg.envelope,"filter.svg": Svg.filter,"floppy.svg": Svg.floppy,"gear.svg": Svg.gear,"help.svg": Svg.help,"home.svg": Svg.home,"home_white_bg.svg": Svg.home_white_bg,"josm_logo.svg": Svg.josm_logo,"layers.svg": Svg.layers,"layersAdd.svg": Svg.layersAdd,"location.svg": Svg.location,"logo.svg": Svg.logo,"logout.svg": Svg.logout,"mapcomplete_logo.svg": Svg.mapcomplete_logo,"mapillary.svg": Svg.mapillary,"mapillary_black.svg": Svg.mapillary_black,"min-zoom.svg": Svg.min_zoom,"min.svg": Svg.min,"no_checkmark.svg": Svg.no_checkmark,"or.svg": Svg.or,"osm-copyright.svg": Svg.osm_copyright,"osm-logo-us.svg": Svg.osm_logo_us,"osm-logo.svg": Svg.osm_logo,"pencil.svg": Svg.pencil,"phone.svg": Svg.phone,"pin.svg": Svg.pin,"plus-zoom.svg": Svg.plus_zoom,"plus.svg": Svg.plus,"pop-out.svg": Svg.pop_out,"reload.svg": Svg.reload,"ring.svg": Svg.ring,"search.svg": Svg.search,"send_email.svg": Svg.send_email,"share.svg": Svg.share,"square.svg": Svg.square,"star.svg": Svg.star,"star_half.svg": Svg.star_half,"star_outline.svg": Svg.star_outline,"star_outline_half.svg": Svg.star_outline_half,"statistics.svg": Svg.statistics,"translate.svg": Svg.translate,"up.svg": Svg.up,"wikidata.svg": Svg.wikidata,"wikimedia-commons-white.svg": Svg.wikimedia_commons_white,"wikipedia.svg": Svg.wikipedia};} diff --git a/UI/BigComponents/FilterView.ts b/UI/BigComponents/FilterView.ts index b2ee12c16b..1aff3d6f89 100644 --- a/UI/BigComponents/FilterView.ts +++ b/UI/BigComponents/FilterView.ts @@ -10,6 +10,7 @@ import LayerConfig from "../../Customizations/JSON/LayerConfig"; import BaseUIElement from "../BaseUIElement"; import { Translation } from "../i18n/Translation"; import ScrollableFullScreen from "../Base/ScrollableFullScreen"; +import Svg from "../../Svg"; /** * Shows the filter @@ -26,14 +27,54 @@ export default class FilterView extends ScrollableFullScreen { } private static Generatecontent(): BaseUIElement { - let filterPanel: BaseUIElement = new FixedUiElement("more stuff"); + let filterPanel: BaseUIElement = new FixedUiElement(""); if (State.state.filteredLayers.data.length > 1) { - let layers = State.state.filteredLayers; - console.log(layers); - filterPanel = new Combine(["layerssss", "
", filterPanel]); - } + let activeLayers = State.state.filteredLayers; - return filterPanel; + if (activeLayers === undefined) { + throw "ActiveLayers should be defined..."; + } + + const checkboxes: BaseUIElement[] = []; + + for (const layer of activeLayers.data) { + const icon = new Combine([Svg.checkbox_filled]).SetStyle( + "width:1.5rem;height:1.5rem" + ); + const iconUnselected = new Combine([Svg.checkbox_empty]).SetStyle( + "width:1.5rem;height:1.5rem" + ); + + if (layer.layerDef.name === undefined) { + continue; + } + + const style = "display:flex;align-items:center;color:#007759"; + + const name: Translation = Translations.WT(layer.layerDef.name)?.Clone(); + name.SetStyle("font-size:large;"); + + const layerChecked = new Combine([icon, name.Clone()]).SetStyle(style); + + const layerNotChecked = new Combine([ + iconUnselected, + name.Clone(), + ]).SetStyle(style); + + checkboxes.push( + new Toggle(layerChecked, layerNotChecked, layer.isDisplayed) + .ToggleOnClick() + .SetStyle("margin:0.3em;") + ); + } + + let combinedCheckboxes = new Combine(checkboxes); + combinedCheckboxes.SetStyle("display:flex;flex-direction:column;"); + + filterPanel = new Combine([combinedCheckboxes]); + + return filterPanel; + } } } diff --git a/assets/svg/checkbox-empty.svg b/assets/svg/checkbox-empty.svg new file mode 100644 index 0000000000..e4a9dc8663 --- /dev/null +++ b/assets/svg/checkbox-empty.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/svg/checkbox-filled.svg b/assets/svg/checkbox-filled.svg new file mode 100644 index 0000000000..166f917855 --- /dev/null +++ b/assets/svg/checkbox-filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 2f85396c2b..ccdac7acf7 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -614,5 +614,29 @@ "path": "filter.svg", "license": "CC0", "sources": [] + }, + { + "authors": [ + "Hannah Declerck" + ], + "path": "checkbox-empty.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [ + "Hannah Declerck" + ], + "path": "checkbox-filled.svg", + "license": "CC0", + "sources": [] + }, + { + "authors": [ + "Hannah Declerck" + ], + "path": "arrow-left-thin.svg", + "license": "CC0", + "sources": [] } ] \ No newline at end of file From 3fd059311bd1eb9cb5c9353ab440847026e6f745 Mon Sep 17 00:00:00 2001 From: Ward Date: Thu, 22 Jul 2021 11:29:09 +0200 Subject: [PATCH 5/6] start extra filter functionality --- Customizations/JSON/FilterConfig.ts | 27 + Customizations/JSON/FilterConfigJson.ts | 11 + Customizations/JSON/LayerConfig.ts | 963 +++++++++++++----------- Customizations/JSON/LayerConfigJson.ts | 7 + UI/BigComponents/FilterView.ts | 23 +- 5 files changed, 579 insertions(+), 452 deletions(-) create mode 100644 Customizations/JSON/FilterConfig.ts create mode 100644 Customizations/JSON/FilterConfigJson.ts diff --git a/Customizations/JSON/FilterConfig.ts b/Customizations/JSON/FilterConfig.ts new file mode 100644 index 0000000000..4993baf4e3 --- /dev/null +++ b/Customizations/JSON/FilterConfig.ts @@ -0,0 +1,27 @@ +import { TagsFilter } from "../../Logic/Tags/TagsFilter"; +import { Translation } from "../../UI/i18n/Translation"; +import Translations from "../../UI/i18n/Translations"; +import FilterConfigJson from "./FilterConfigJson"; +import { FromJSON } from "./FromJSON"; + +export default class FilterConfig { + readonly options: { + question: Translation; + osmTags: TagsFilter; + }[]; + + constructor(json: FilterConfigJson, context: string) { + this.options = json.options.map((option, i) => { + const question = Translations.T( + option.question, + context + ".options-[" + i + "].question" + ); + const osmTags = FromJSON.Tag( + option.osmTags, + `${context}.options-[${i}].osmTags` + ); + + return { question: question, osmTags: osmTags }; + }); + } +} diff --git a/Customizations/JSON/FilterConfigJson.ts b/Customizations/JSON/FilterConfigJson.ts new file mode 100644 index 0000000000..082fd7fe0a --- /dev/null +++ b/Customizations/JSON/FilterConfigJson.ts @@ -0,0 +1,11 @@ +import { AndOrTagConfigJson } from "./TagConfigJson"; + +export default interface FilterConfigJson { + /** + * The options for a filter + * If there are multiple options these will be a list of radio buttons + * If there is only one option this will be a checkbox + * Filtering is done based on the given osmTags that are compared to the objects in that layer. + */ + options: { question: string | any; osmTags: AndOrTagConfigJson | string }[]; +} diff --git a/Customizations/JSON/LayerConfig.ts b/Customizations/JSON/LayerConfig.ts index 0acf8198f1..994b4c37c5 100644 --- a/Customizations/JSON/LayerConfig.ts +++ b/Customizations/JSON/LayerConfig.ts @@ -1,489 +1,562 @@ import Translations from "../../UI/i18n/Translations"; import TagRenderingConfig from "./TagRenderingConfig"; -import {LayerConfigJson} from "./LayerConfigJson"; -import {FromJSON} from "./FromJSON"; +import { LayerConfigJson } from "./LayerConfigJson"; +import { FromJSON } from "./FromJSON"; import SharedTagRenderings from "../SharedTagRenderings"; -import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; -import {Translation} from "../../UI/i18n/Translation"; +import { TagRenderingConfigJson } from "./TagRenderingConfigJson"; +import { Translation } from "../../UI/i18n/Translation"; import Svg from "../../Svg"; -import {Utils} from "../../Utils"; +import { Utils } from "../../Utils"; import Combine from "../../UI/Base/Combine"; -import {VariableUiElement} from "../../UI/Base/VariableUIElement"; -import {UIEventSource} from "../../Logic/UIEventSource"; -import {FixedUiElement} from "../../UI/Base/FixedUiElement"; +import { VariableUiElement } from "../../UI/Base/VariableUIElement"; +import { UIEventSource } from "../../Logic/UIEventSource"; +import { FixedUiElement } from "../../UI/Base/FixedUiElement"; import SourceConfig from "./SourceConfig"; -import {TagsFilter} from "../../Logic/Tags/TagsFilter"; -import {Tag} from "../../Logic/Tags/Tag"; +import { TagsFilter } from "../../Logic/Tags/TagsFilter"; +import { Tag } from "../../Logic/Tags/Tag"; import BaseUIElement from "../../UI/BaseUIElement"; -import {Unit} from "./Denomination"; +import { Unit } from "./Denomination"; import DeleteConfig from "./DeleteConfig"; +import FilterConfig from "./FilterConfig"; export default class LayerConfig { + static WAYHANDLING_DEFAULT = 0; + static WAYHANDLING_CENTER_ONLY = 1; + static WAYHANDLING_CENTER_AND_WAY = 2; + id: string; + name: Translation; + description: Translation; + source: SourceConfig; + calculatedTags: [string, string][]; + doNotDownload: boolean; + passAllFeatures: boolean; + isShown: TagRenderingConfig; + minzoom: number; + maxzoom: number; + title?: TagRenderingConfig; + titleIcons: TagRenderingConfig[]; + icon: TagRenderingConfig; + iconOverlays: { if: TagsFilter; then: TagRenderingConfig; badge: boolean }[]; + iconSize: TagRenderingConfig; + label: TagRenderingConfig; + rotation: TagRenderingConfig; + color: TagRenderingConfig; + width: TagRenderingConfig; + dashArray: TagRenderingConfig; + wayHandling: number; + public readonly units: Unit[]; + public readonly deletion: DeleteConfig | null; - static WAYHANDLING_DEFAULT = 0; - static WAYHANDLING_CENTER_ONLY = 1; - static WAYHANDLING_CENTER_AND_WAY = 2; + presets: { + title: Translation; + tags: Tag[]; + description?: Translation; + }[]; - id: string; - name: Translation - description: Translation; - source: SourceConfig; - calculatedTags: [string, string][] - doNotDownload: boolean; - passAllFeatures: boolean; - isShown: TagRenderingConfig; - minzoom: number; - maxzoom: number; - title?: TagRenderingConfig; - titleIcons: TagRenderingConfig[]; - icon: TagRenderingConfig; - iconOverlays: { if: TagsFilter, then: TagRenderingConfig, badge: boolean }[] - iconSize: TagRenderingConfig; - label: TagRenderingConfig; - rotation: TagRenderingConfig; - color: TagRenderingConfig; - width: TagRenderingConfig; - dashArray: TagRenderingConfig; - wayHandling: number; - public readonly units: Unit[]; - public readonly deletion: DeleteConfig | null + tagRenderings: TagRenderingConfig[]; + filters: FilterConfig[]; - presets: { - title: Translation, - tags: Tag[], - description?: Translation, - }[]; + constructor( + json: LayerConfigJson, + units?: Unit[], + context?: string, + official: boolean = true + ) { + this.units = units ?? []; + context = context + "." + json.id; + const self = this; + this.id = json.id; + this.name = Translations.T(json.name, context + ".name"); - tagRenderings: TagRenderingConfig []; - - constructor(json: LayerConfigJson, - units?:Unit[], - context?: string, - official: boolean = true,) { - this.units = units ?? []; - context = context + "." + json.id; - const self = this; - this.id = json.id; - this.name = Translations.T(json.name, context + ".name"); - - if(json.description !== undefined){ - if(Object.keys(json.description).length === 0){ - json.description = undefined; - } - } - - this.description =Translations.T(json.description, context + ".description") ; - - let legacy = undefined; - if (json["overpassTags"] !== undefined) { - // @ts-ignore - legacy = FromJSON.Tag(json["overpassTags"], context + ".overpasstags"); - } - if (json.source !== undefined) { - if (legacy !== undefined) { - throw context + "Both the legacy 'layer.overpasstags' and the new 'layer.source'-field are defined" - } - - let osmTags: TagsFilter = legacy; - if (json.source["osmTags"]) { - osmTags = FromJSON.Tag(json.source["osmTags"], context + "source.osmTags"); - } - - if(json.source["geoJsonSource"] !== undefined){ - throw context + "Use 'geoJson' instead of 'geoJsonSource'" - } - - this.source = new SourceConfig({ - osmTags: osmTags, - geojsonSource: json.source["geoJson"], - geojsonSourceLevel: json.source["geoJsonZoomLevel"], - overpassScript: json.source["overpassScript"], - isOsmCache: json.source["isOsmCache"] - }, this.id); - } else { - this.source = new SourceConfig({ - osmTags: legacy - }) - } - - - this.calculatedTags = undefined; - if (json.calculatedTags !== undefined) { - if (!official) { - console.warn(`Unofficial theme ${this.id} with custom javascript! This is a security risk`) - } - this.calculatedTags = []; - for (const kv of json.calculatedTags) { - - const index = kv.indexOf("=") - const key = kv.substring(0, index); - const code = kv.substring(index + 1); - - this.calculatedTags.push([key, code]) - } - } - - this.doNotDownload = json.doNotDownload ?? false; - this.passAllFeatures = json.passAllFeatures ?? false; - this.minzoom = json.minzoom ?? 0; - this.maxzoom = json.maxzoom ?? 1000; - this.wayHandling = json.wayHandling ?? 0; - this.presets = (json.presets ?? []).map((pr, i) => - ({ - title: Translations.T(pr.title, `${context}.presets[${i}].title`), - tags: pr.tags.map(t => FromJSON.SimpleTag(t)), - description: Translations.T(pr.description, `${context}.presets[${i}].description`) - })) - - - /** Given a key, gets the corresponding property from the json (or the default if not found - * - * The found value is interpreted as a tagrendering and fetched/parsed - * */ - function tr(key: string, deflt) { - const v = json[key]; - if (v === undefined || v === null) { - if (deflt === undefined) { - return undefined; - } - return new TagRenderingConfig(deflt, self.source.osmTags, `${context}.${key}.default value`); - } - if (typeof v === "string") { - const shared = SharedTagRenderings.SharedTagRendering.get(v); - if (shared) { - return shared; - } - } - return new TagRenderingConfig(v, self.source.osmTags, `${context}.${key}`); - } - - /** - * Converts a list of tagRenderingCOnfigJSON in to TagRenderingConfig - * A string is interpreted as a name to call - */ - function trs(tagRenderings?: (string | TagRenderingConfigJson)[], readOnly = false) { - if (tagRenderings === undefined) { - return []; - } - - return Utils.NoNull(tagRenderings.map( - (renderingJson, i) => { - if (typeof renderingJson === "string") { - - if (renderingJson === "questions") { - if (readOnly) { - throw `A tagrendering has a question, but asking a question does not make sense here: is it a title icon or a geojson-layer? ${context}. The offending tagrendering is ${JSON.stringify(renderingJson)}` - } - - return new TagRenderingConfig("questions", undefined) - } - - - const shared = SharedTagRenderings.SharedTagRendering.get(renderingJson); - if (shared !== undefined) { - return shared; - } - - const keys = Array.from(SharedTagRenderings.SharedTagRendering.keys()) - - if(Utils.runningFromConsole){ - return undefined; - } - - throw `Predefined tagRendering ${renderingJson} not found in ${context}.\n Try one of ${(keys.join(", "))}\n If you intent to output this text literally, use {\"render\": } instead"}`; - } - return new TagRenderingConfig(renderingJson, self.source.osmTags, `${context}.tagrendering[${i}]`); - })); - } - - this.tagRenderings = trs(json.tagRenderings, false); - - - const titleIcons = []; - const defaultIcons = ["phonelink", "emaillink", "wikipedialink", "osmlink", "sharelink"]; - for (const icon of (json.titleIcons ?? defaultIcons)) { - if (icon === "defaults") { - titleIcons.push(...defaultIcons); - } else { - titleIcons.push(icon); - } - } - - this.titleIcons = trs(titleIcons, true); - - - this.title = tr("title", undefined); - this.icon = tr("icon", ""); - this.iconOverlays = (json.iconOverlays ?? []).map((overlay, i) => { - let tr = new TagRenderingConfig(overlay.then, self.source.osmTags, `iconoverlays.${i}`); - if (typeof overlay.then === "string" && SharedTagRenderings.SharedIcons.get(overlay.then) !== undefined) { - tr = SharedTagRenderings.SharedIcons.get(overlay.then); - } - return { - if: FromJSON.Tag(overlay.if), - then: tr, - badge: overlay.badge ?? false - } - }); - - const iconPath = this.icon.GetRenderValue({id: "node/-1"}).txt; - if (iconPath.startsWith(Utils.assets_path)) { - const iconKey = iconPath.substr(Utils.assets_path.length); - if (Svg.All[iconKey] === undefined) { - throw "Builtin SVG asset not found: " + iconPath - } - } - this.isShown = tr("isShown", "yes"); - this.iconSize = tr("iconSize", "40,40,center"); - this.label = tr("label", "") - this.color = tr("color", "#0000ff"); - this.width = tr("width", "7"); - this.rotation = tr("rotation", "0"); - this.dashArray = tr("dashArray", ""); - - this.deletion = null; - if(json.deletion === true){ - json.deletion = { - } - } - if(json.deletion !== undefined && json.deletion !== false){ - this.deletion = new DeleteConfig(json.deletion, `${context}.deletion`) - } - - - if (json["showIf"] !== undefined) { - throw "Invalid key on layerconfig " + this.id + ": showIf. Did you mean 'isShown' instead?"; - } + if (json.description !== undefined) { + if (Object.keys(json.description).length === 0) { + json.description = undefined; + } } - public CustomCodeSnippets(): string[] { - if (this.calculatedTags === undefined) { - return [] - } + this.description = Translations.T( + json.description, + context + ".description" + ); - return this.calculatedTags.map(code => code[1]); + let legacy = undefined; + if (json["overpassTags"] !== undefined) { + // @ts-ignore + legacy = FromJSON.Tag(json["overpassTags"], context + ".overpasstags"); } + if (json.source !== undefined) { + if (legacy !== undefined) { + throw ( + context + + "Both the legacy 'layer.overpasstags' and the new 'layer.source'-field are defined" + ); + } - public AddRoamingRenderings(addAll: { - tagRenderings: TagRenderingConfig[], - titleIcons: TagRenderingConfig[], - iconOverlays: { "if": TagsFilter, then: TagRenderingConfig, badge: boolean }[] + let osmTags: TagsFilter = legacy; + if (json.source["osmTags"]) { + osmTags = FromJSON.Tag( + json.source["osmTags"], + context + "source.osmTags" + ); + } - }): LayerConfig { + if (json.source["geoJsonSource"] !== undefined) { + throw context + "Use 'geoJson' instead of 'geoJsonSource'"; + } - let insertionPoint = this.tagRenderings.map(tr => tr.IsQuestionBoxElement()).indexOf(true) - if (insertionPoint < 0) { - // No 'questions' defined - we just add them all to the end - insertionPoint = this.tagRenderings.length; - } - this.tagRenderings.splice(insertionPoint, 0, ...addAll.tagRenderings); - - - this.iconOverlays.push(...addAll.iconOverlays); - for (const icon of addAll.titleIcons) { - this.titleIcons.splice(0, 0, icon); - } - return this; - } - - public GetRoamingRenderings(): { - tagRenderings: TagRenderingConfig[], - titleIcons: TagRenderingConfig[], - iconOverlays: { "if": TagsFilter, then: TagRenderingConfig, badge: boolean }[] - - } { - - const tagRenderings = this.tagRenderings.filter(tr => tr.roaming); - const titleIcons = this.titleIcons.filter(tr => tr.roaming); - const iconOverlays = this.iconOverlays.filter(io => io.then.roaming) - - return { - tagRenderings: tagRenderings, - titleIcons: titleIcons, - iconOverlays: iconOverlays - } - - } - - public GenerateLeafletStyle(tags: UIEventSource, clickable: boolean, widthHeight= "100%"): + this.source = new SourceConfig( { - icon: - { - html: BaseUIElement, - iconSize: [number, number], - iconAnchor: [number, number], - popupAnchor: [number, number], - iconUrl: string, - className: string - }, - color: string, - weight: number, - dashArray: number[] - } { + osmTags: osmTags, + geojsonSource: json.source["geoJson"], + geojsonSourceLevel: json.source["geoJsonZoomLevel"], + overpassScript: json.source["overpassScript"], + isOsmCache: json.source["isOsmCache"], + }, + this.id + ); + } else { + this.source = new SourceConfig({ + osmTags: legacy, + }); + } - function num(str, deflt = 40) { - const n = Number(str); - if (isNaN(n)) { - return deflt; - } - return n; + this.calculatedTags = undefined; + if (json.calculatedTags !== undefined) { + if (!official) { + console.warn( + `Unofficial theme ${this.id} with custom javascript! This is a security risk` + ); + } + this.calculatedTags = []; + for (const kv of json.calculatedTags) { + const index = kv.indexOf("="); + const key = kv.substring(0, index); + const code = kv.substring(index + 1); + + this.calculatedTags.push([key, code]); + } + } + + this.doNotDownload = json.doNotDownload ?? false; + this.passAllFeatures = json.passAllFeatures ?? false; + this.minzoom = json.minzoom ?? 0; + this.maxzoom = json.maxzoom ?? 1000; + this.wayHandling = json.wayHandling ?? 0; + this.presets = (json.presets ?? []).map((pr, i) => ({ + title: Translations.T(pr.title, `${context}.presets[${i}].title`), + tags: pr.tags.map((t) => FromJSON.SimpleTag(t)), + description: Translations.T( + pr.description, + `${context}.presets[${i}].description` + ), + })); + + /** Given a key, gets the corresponding property from the json (or the default if not found + * + * The found value is interpreted as a tagrendering and fetched/parsed + * */ + function tr(key: string, deflt) { + const v = json[key]; + if (v === undefined || v === null) { + if (deflt === undefined) { + return undefined; } - - function rendernum(tr: TagRenderingConfig, deflt: number) { - const str = Number(render(tr, "" + deflt)); - const n = Number(str); - if (isNaN(n)) { - return deflt; - } - return n; + return new TagRenderingConfig( + deflt, + self.source.osmTags, + `${context}.${key}.default value` + ); + } + if (typeof v === "string") { + const shared = SharedTagRenderings.SharedTagRendering.get(v); + if (shared) { + return shared; } + } + return new TagRenderingConfig( + v, + self.source.osmTags, + `${context}.${key}` + ); + } - function render(tr: TagRenderingConfig, deflt?: string) { - const str = (tr?.GetRenderValue(tags.data)?.txt ?? deflt); - return Utils.SubstituteKeys(str, tags.data).replace(/{.*}/g, ""); - } + /** + * Converts a list of tagRenderingCOnfigJSON in to TagRenderingConfig + * A string is interpreted as a name to call + */ + function trs( + tagRenderings?: (string | TagRenderingConfigJson)[], + readOnly = false + ) { + if (tagRenderings === undefined) { + return []; + } - const iconSize = render(this.iconSize, "40,40,center").split(","); - const dashArray = render(this.dashArray).split(" ").map(Number); - let color = render(this.color, "#00f"); + return Utils.NoNull( + tagRenderings.map((renderingJson, i) => { + if (typeof renderingJson === "string") { + if (renderingJson === "questions") { + if (readOnly) { + throw `A tagrendering has a question, but asking a question does not make sense here: is it a title icon or a geojson-layer? ${context}. The offending tagrendering is ${JSON.stringify( + renderingJson + )}`; + } - if (color.startsWith("--")) { - color = getComputedStyle(document.body).getPropertyValue("--catch-detail-color") - } - - const weight = rendernum(this.width, 5); - - const iconW = num(iconSize[0]); - let iconH = num(iconSize[1]); - const mode = iconSize[2]?.trim()?.toLowerCase() ?? "center" - - let anchorW = iconW / 2; - let anchorH = iconH / 2; - if (mode === "left") { - anchorW = 0; - } - if (mode === "right") { - anchorW = iconW; - } - - if (mode === "top") { - anchorH = 0; - } - if (mode === "bottom") { - anchorH = iconH; - } - - const iconUrlStatic = render(this.icon); - const self = this; - const mappedHtml = tags.map(tgs => { - function genHtmlFromString(sourcePart: string): BaseUIElement { - - const style = `width:100%;height:100%;transform: rotate( ${rotation} );display:block;position: absolute; top: 0; left: 0`; - let html: BaseUIElement = new FixedUiElement(``); - const match = sourcePart.match(/([a-zA-Z0-9_]*):([^;]*)/) - if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) { - html = new Combine([ - (Svg.All[match[1] + ".svg"] as string) - .replace(/#000000/g, match[2]) - ]).SetStyle(style); - } - return html; + return new TagRenderingConfig("questions", undefined); } - - // What do you mean, 'tgs' is never read? - // It is read implicitly in the 'render' method - const iconUrl = render(self.icon); - const rotation = render(self.rotation, "0deg"); - - let htmlParts: BaseUIElement[] = []; - let sourceParts = Utils.NoNull(iconUrl.split(";").filter(prt => prt != "")); - for (const sourcePart of sourceParts) { - htmlParts.push(genHtmlFromString(sourcePart)) + const shared = + SharedTagRenderings.SharedTagRendering.get(renderingJson); + if (shared !== undefined) { + return shared; } - let badges = []; - for (const iconOverlay of self.iconOverlays) { - if (!iconOverlay.if.matchesProperties(tgs)) { - continue; - } - if (iconOverlay.badge) { - const badgeParts: BaseUIElement[] = []; - const partDefs = iconOverlay.then.GetRenderValue(tgs).txt.split(";").filter(prt => prt != ""); + const keys = Array.from( + SharedTagRenderings.SharedTagRendering.keys() + ); - for (const badgePartStr of partDefs) { - badgeParts.push(genHtmlFromString(badgePartStr)) - } - - const badgeCompound = new Combine(badgeParts) - .SetStyle("display:flex;position:relative;width:100%;height:100%;"); - - badges.push(badgeCompound) - - } else { - htmlParts.push(genHtmlFromString( - iconOverlay.then.GetRenderValue(tgs).txt)); - } + if (Utils.runningFromConsole) { + return undefined; } - if (badges.length > 0) { - const badgesComponent = new Combine(badges) - .SetStyle("display:flex;height:50%;width:100%;position:absolute;top:50%;left:50%;"); - htmlParts.push(badgesComponent) - } - - if (sourceParts.length == 0) { - iconH = 0 - } - try { - - const label = self.label?.GetRenderValue(tgs)?.Subs(tgs) - ?.SetClass("block text-center") - ?.SetStyle("margin-top: " + (iconH + 2) + "px") - if (label !== undefined) { - htmlParts.push(new Combine([label]).SetClass("flex flex-col items-center")) - } - } catch (e) { - console.error(e, tgs) - } - return new Combine(htmlParts); + throw `Predefined tagRendering ${renderingJson} not found in ${context}.\n Try one of ${keys.join( + ", " + )}\n If you intent to output this text literally, use {\"render\": } instead"}`; + } + return new TagRenderingConfig( + renderingJson, + self.source.osmTags, + `${context}.tagrendering[${i}]` + ); }) - - - return { - icon: - { - html: new VariableUiElement(mappedHtml), - iconSize: [iconW, iconH], - iconAnchor: [anchorW, anchorH], - popupAnchor: [0, 3 - anchorH], - iconUrl: iconUrlStatic, - className: clickable ? "leaflet-div-icon" : "leaflet-div-icon unclickable" - }, - color: color, - weight: weight, - dashArray: dashArray - }; + ); } - public ExtractImages(): Set { - const parts: Set[] = [] - parts.push(...this.tagRenderings?.map(tr => tr.ExtractImages(false))) - parts.push(...this.titleIcons?.map(tr => tr.ExtractImages(true))) - parts.push(this.icon?.ExtractImages(true)) - parts.push(...this.iconOverlays?.map(overlay => overlay.then.ExtractImages(true))) - for (const preset of this.presets) { - parts.push(new Set(preset.description?.ExtractImages(false))) - } + this.tagRenderings = trs(json.tagRenderings, false); - const allIcons = new Set(); - for (const part of parts) { - part?.forEach(allIcons.add, allIcons) - } + this.filters = (json.filter ?? []).map((option, i) => { + return new FilterConfig(option, `${context}.filter-[${i}]`) + }); - return allIcons; + const titleIcons = []; + const defaultIcons = [ + "phonelink", + "emaillink", + "wikipedialink", + "osmlink", + "sharelink", + ]; + for (const icon of json.titleIcons ?? defaultIcons) { + if (icon === "defaults") { + titleIcons.push(...defaultIcons); + } else { + titleIcons.push(icon); + } } -} \ No newline at end of file + this.titleIcons = trs(titleIcons, true); + + this.title = tr("title", undefined); + this.icon = tr("icon", ""); + this.iconOverlays = (json.iconOverlays ?? []).map((overlay, i) => { + let tr = new TagRenderingConfig( + overlay.then, + self.source.osmTags, + `iconoverlays.${i}` + ); + if ( + typeof overlay.then === "string" && + SharedTagRenderings.SharedIcons.get(overlay.then) !== undefined + ) { + tr = SharedTagRenderings.SharedIcons.get(overlay.then); + } + return { + if: FromJSON.Tag(overlay.if), + then: tr, + badge: overlay.badge ?? false, + }; + }); + + const iconPath = this.icon.GetRenderValue({ id: "node/-1" }).txt; + if (iconPath.startsWith(Utils.assets_path)) { + const iconKey = iconPath.substr(Utils.assets_path.length); + if (Svg.All[iconKey] === undefined) { + throw "Builtin SVG asset not found: " + iconPath; + } + } + this.isShown = tr("isShown", "yes"); + this.iconSize = tr("iconSize", "40,40,center"); + this.label = tr("label", ""); + this.color = tr("color", "#0000ff"); + this.width = tr("width", "7"); + this.rotation = tr("rotation", "0"); + this.dashArray = tr("dashArray", ""); + + this.deletion = null; + if (json.deletion === true) { + json.deletion = {}; + } + if (json.deletion !== undefined && json.deletion !== false) { + this.deletion = new DeleteConfig(json.deletion, `${context}.deletion`); + } + + if (json["showIf"] !== undefined) { + throw ( + "Invalid key on layerconfig " + + this.id + + ": showIf. Did you mean 'isShown' instead?" + ); + } + } + + public CustomCodeSnippets(): string[] { + if (this.calculatedTags === undefined) { + return []; + } + + return this.calculatedTags.map((code) => code[1]); + } + + public AddRoamingRenderings(addAll: { + tagRenderings: TagRenderingConfig[]; + titleIcons: TagRenderingConfig[]; + iconOverlays: { + if: TagsFilter; + then: TagRenderingConfig; + badge: boolean; + }[]; + }): LayerConfig { + let insertionPoint = this.tagRenderings + .map((tr) => tr.IsQuestionBoxElement()) + .indexOf(true); + if (insertionPoint < 0) { + // No 'questions' defined - we just add them all to the end + insertionPoint = this.tagRenderings.length; + } + this.tagRenderings.splice(insertionPoint, 0, ...addAll.tagRenderings); + + this.iconOverlays.push(...addAll.iconOverlays); + for (const icon of addAll.titleIcons) { + this.titleIcons.splice(0, 0, icon); + } + return this; + } + + public GetRoamingRenderings(): { + tagRenderings: TagRenderingConfig[]; + titleIcons: TagRenderingConfig[]; + iconOverlays: { + if: TagsFilter; + then: TagRenderingConfig; + badge: boolean; + }[]; + } { + const tagRenderings = this.tagRenderings.filter((tr) => tr.roaming); + const titleIcons = this.titleIcons.filter((tr) => tr.roaming); + const iconOverlays = this.iconOverlays.filter((io) => io.then.roaming); + + return { + tagRenderings: tagRenderings, + titleIcons: titleIcons, + iconOverlays: iconOverlays, + }; + } + + public GenerateLeafletStyle( + tags: UIEventSource, + clickable: boolean, + widthHeight = "100%" + ): { + icon: { + html: BaseUIElement; + iconSize: [number, number]; + iconAnchor: [number, number]; + popupAnchor: [number, number]; + iconUrl: string; + className: string; + }; + color: string; + weight: number; + dashArray: number[]; + } { + function num(str, deflt = 40) { + const n = Number(str); + if (isNaN(n)) { + return deflt; + } + return n; + } + + function rendernum(tr: TagRenderingConfig, deflt: number) { + const str = Number(render(tr, "" + deflt)); + const n = Number(str); + if (isNaN(n)) { + return deflt; + } + return n; + } + + function render(tr: TagRenderingConfig, deflt?: string) { + const str = tr?.GetRenderValue(tags.data)?.txt ?? deflt; + return Utils.SubstituteKeys(str, tags.data).replace(/{.*}/g, ""); + } + + const iconSize = render(this.iconSize, "40,40,center").split(","); + const dashArray = render(this.dashArray).split(" ").map(Number); + let color = render(this.color, "#00f"); + + if (color.startsWith("--")) { + color = getComputedStyle(document.body).getPropertyValue( + "--catch-detail-color" + ); + } + + const weight = rendernum(this.width, 5); + + const iconW = num(iconSize[0]); + let iconH = num(iconSize[1]); + const mode = iconSize[2]?.trim()?.toLowerCase() ?? "center"; + + let anchorW = iconW / 2; + let anchorH = iconH / 2; + if (mode === "left") { + anchorW = 0; + } + if (mode === "right") { + anchorW = iconW; + } + + if (mode === "top") { + anchorH = 0; + } + if (mode === "bottom") { + anchorH = iconH; + } + + const iconUrlStatic = render(this.icon); + const self = this; + const mappedHtml = tags.map((tgs) => { + function genHtmlFromString(sourcePart: string): BaseUIElement { + const style = `width:100%;height:100%;transform: rotate( ${rotation} );display:block;position: absolute; top: 0; left: 0`; + let html: BaseUIElement = new FixedUiElement( + `` + ); + const match = sourcePart.match(/([a-zA-Z0-9_]*):([^;]*)/); + if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) { + html = new Combine([ + (Svg.All[match[1] + ".svg"] as string).replace( + /#000000/g, + match[2] + ), + ]).SetStyle(style); + } + return html; + } + + // What do you mean, 'tgs' is never read? + // It is read implicitly in the 'render' method + const iconUrl = render(self.icon); + const rotation = render(self.rotation, "0deg"); + + let htmlParts: BaseUIElement[] = []; + let sourceParts = Utils.NoNull( + iconUrl.split(";").filter((prt) => prt != "") + ); + for (const sourcePart of sourceParts) { + htmlParts.push(genHtmlFromString(sourcePart)); + } + + let badges = []; + for (const iconOverlay of self.iconOverlays) { + if (!iconOverlay.if.matchesProperties(tgs)) { + continue; + } + if (iconOverlay.badge) { + const badgeParts: BaseUIElement[] = []; + const partDefs = iconOverlay.then + .GetRenderValue(tgs) + .txt.split(";") + .filter((prt) => prt != ""); + + for (const badgePartStr of partDefs) { + badgeParts.push(genHtmlFromString(badgePartStr)); + } + + const badgeCompound = new Combine(badgeParts).SetStyle( + "display:flex;position:relative;width:100%;height:100%;" + ); + + badges.push(badgeCompound); + } else { + htmlParts.push( + genHtmlFromString(iconOverlay.then.GetRenderValue(tgs).txt) + ); + } + } + + if (badges.length > 0) { + const badgesComponent = new Combine(badges).SetStyle( + "display:flex;height:50%;width:100%;position:absolute;top:50%;left:50%;" + ); + htmlParts.push(badgesComponent); + } + + if (sourceParts.length == 0) { + iconH = 0; + } + try { + const label = self.label + ?.GetRenderValue(tgs) + ?.Subs(tgs) + ?.SetClass("block text-center") + ?.SetStyle("margin-top: " + (iconH + 2) + "px"); + if (label !== undefined) { + htmlParts.push( + new Combine([label]).SetClass("flex flex-col items-center") + ); + } + } catch (e) { + console.error(e, tgs); + } + return new Combine(htmlParts); + }); + + return { + icon: { + html: new VariableUiElement(mappedHtml), + iconSize: [iconW, iconH], + iconAnchor: [anchorW, anchorH], + popupAnchor: [0, 3 - anchorH], + iconUrl: iconUrlStatic, + className: clickable + ? "leaflet-div-icon" + : "leaflet-div-icon unclickable", + }, + color: color, + weight: weight, + dashArray: dashArray, + }; + } + + public ExtractImages(): Set { + const parts: Set[] = []; + parts.push(...this.tagRenderings?.map((tr) => tr.ExtractImages(false))); + parts.push(...this.titleIcons?.map((tr) => tr.ExtractImages(true))); + parts.push(this.icon?.ExtractImages(true)); + parts.push( + ...this.iconOverlays?.map((overlay) => overlay.then.ExtractImages(true)) + ); + for (const preset of this.presets) { + parts.push(new Set(preset.description?.ExtractImages(false))); + } + + const allIcons = new Set(); + for (const part of parts) { + part?.forEach(allIcons.add, allIcons); + } + + return allIcons; + } +} diff --git a/Customizations/JSON/LayerConfigJson.ts b/Customizations/JSON/LayerConfigJson.ts index d81307fd9f..a3ae740801 100644 --- a/Customizations/JSON/LayerConfigJson.ts +++ b/Customizations/JSON/LayerConfigJson.ts @@ -1,6 +1,7 @@ import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; import {AndOrTagConfigJson} from "./TagConfigJson"; import {DeleteConfigJson} from "./DeleteConfigJson"; +import FilterConfigJson from "./FilterConfigJson"; /** * Configuration for a single layer @@ -233,6 +234,12 @@ export interface LayerConfigJson { */ tagRenderings?: (string | TagRenderingConfigJson) [], + + /** + * All the extra questions for filtering + */ + filter?: (FilterConfigJson) [], + /** * This block defines under what circumstances the delete dialog is shown for objects of this layer. * If set, a dialog is shown to the user to (soft) delete the point. diff --git a/UI/BigComponents/FilterView.ts b/UI/BigComponents/FilterView.ts index 1aff3d6f89..9b5b79386c 100644 --- a/UI/BigComponents/FilterView.ts +++ b/UI/BigComponents/FilterView.ts @@ -39,11 +39,11 @@ export default class FilterView extends ScrollableFullScreen { const checkboxes: BaseUIElement[] = []; for (const layer of activeLayers.data) { - const icon = new Combine([Svg.checkbox_filled]).SetStyle( - "width:1.5rem;height:1.5rem" - ); + const iconStyle = "width:1.5rem;height:1.5rem;margin-left:1.25rem"; + + const icon = new Combine([Svg.checkbox_filled]).SetStyle(iconStyle); const iconUnselected = new Combine([Svg.checkbox_empty]).SetStyle( - "width:1.5rem;height:1.5rem" + iconStyle ); if (layer.layerDef.name === undefined) { @@ -53,13 +53,22 @@ export default class FilterView extends ScrollableFullScreen { const style = "display:flex;align-items:center;color:#007759"; const name: Translation = Translations.WT(layer.layerDef.name)?.Clone(); - name.SetStyle("font-size:large;"); - const layerChecked = new Combine([icon, name.Clone()]).SetStyle(style); + const styledNameChecked = name + .Clone() + .SetStyle("font-size:large;padding-left:1.25rem"); + + const styledNameUnChecked = name + .Clone() + .SetStyle("font-size:large;padding-left:1.25rem"); + + const layerChecked = new Combine([icon, styledNameChecked]).SetStyle( + style + ); const layerNotChecked = new Combine([ iconUnselected, - name.Clone(), + styledNameUnChecked, ]).SetStyle(style); checkboxes.push( From 1e07c8c44cbef3ca7dbe9e78155a0d3837e6c017 Mon Sep 17 00:00:00 2001 From: karelleketers Date: Thu, 22 Jul 2021 13:22:31 +0200 Subject: [PATCH 6/6] Added parking badges --- .DS_Store | Bin 0 -> 10244 bytes assets/.DS_Store | Bin 0 -> 10244 bytes assets/layers/parking/parking.json | 30 ++++----- assets/layers/watermill/watermill.json | 2 +- assets/svg/license_info.json | 4 +- assets/themes/.DS_Store | Bin 0 -> 10244 bytes assets/themes/natuurpunt/license_info.json | 18 ++++++ assets/themes/natuurpunt/natuurpunt.json | 68 +++++++++++++-------- assets/themes/natuurpunt/parkingbike.svg | 1 + assets/themes/natuurpunt/parkingmotor.svg | 1 + assets/themes/natuurpunt/parkingwheels.svg | 1 + 11 files changed, 83 insertions(+), 42 deletions(-) create mode 100644 .DS_Store create mode 100644 assets/.DS_Store create mode 100644 assets/themes/.DS_Store create mode 100644 assets/themes/natuurpunt/parkingbike.svg create mode 100644 assets/themes/natuurpunt/parkingmotor.svg create mode 100644 assets/themes/natuurpunt/parkingwheels.svg diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e1002670c385ff367426fadd455d9cfc0cb128db GIT binary patch literal 10244 zcmeHM&2HO95FX01OxccO7XcC=D8NgA0Cfc?Hj3m>K>kBuAT5e0Ne}&TBukdrP^2MI zQ5x5Q?sN2_sji2*XXr=7V7myzCM15*fOaqD_U2_aL1{?#90mp!2;3_hJZ#Fl7$w=2b z1{?#9flCH>eF$)|tY>m;q%0liWD5XU#%*aBV;>-xAd~e>j*S#3Y?|GJmqER3i{TkK zo(HTBSE8& zcJtfV&kv|WDf$}s2T^j=ijo$PTx{F8YX3>Yi0B6P{-^khfH{PILPI*D6O2Phwphc{ zn7TPTA98jouyZ-H*7ZK0rP~?}PBZ`hY@J5oAl=yb+bhkL=PL`ozvwSsTl}eUl8hQ@ zGaU|gn*AU6*LThIq?L`ICP{QTZnmC>ozdayjolE?0?5d5%Q|hkE0~+G6>fks0CR$n%?1w4$TpQF_572=n(=GQiJw&bhzA=_B^x`#2qotX@X&;xrS_3 ztit!)oty>mtSsDuKIiK|`0mP*W*>82ER$w&d|k+ENNPA4JB?9YQlSK@xF!ywu!8LiJq(DOQ5)xUe3yYWnnpIVM^UdWb!j7oV})Iq;`18 zKL&eUGkcD2j+kv>6*KqYGgkr27?!vmrsN#gg~G2)#ZRmeg{{&PWZ*XKAx8U{u}5v~ ztwhN7b^)Fp!Osx07VJws{A0z%M{cKxNs2d`^eN@4u=Oj#B2YG7Z5w5Ii^4j^>yFZ^Ug%AWpm1tiUa$~_cVSLTKUGcsJEN?1P+v}NX3>G;s$n4!Wa#hG(f=~oar&h$3C z?rYo3r_#k|z%|E!W56-s7;p@H3IlTn94tZZPyhe_r%d6njseHO6=%RJ?=|*z;N->W zQ{G=bYY%X}z{QRA#zqPRogBwQ%5gk?@NxWIT&%mnk{ibLOpcAj9kl=dp8+$^S=1if f?f>}%VaD!A?V$PO!R`NB$m#58T^rtE#KMnklQ> zL?lY>`c0w&5n1R=^OrF6X}r$8rwt@Cv!DX{L?K1AK%ZiiJGy<;w!KKpPpGe`ahBr=p0?$__L#vJ;Tyec9^>V^u}HiyganD4CcCe(tf*gs1RI z`MIxba2^}VMjwAw7Qanp@fv*y3oTlKMibPB4aTlY6?hhc)86f2J%(TXY;s=HHm4!Q z@6)03BS1EHVTE(jRu)h1h%)i1oTe?!sGFo3aIs;J@!@zm&sEsu-0=I?*DICnw5@SO zBoULgRX(xQUz_uq)}A^?yQ1v)@UE{NmGiWnK}58leT!6H`$#zlQ7icZe{@>D7sZQ< zzledsp{ItQwyY6rWNhSaWltVdVmod}B|F^ar!_m?a}s_-O88nza}Fu z_GGZNqjrzoW;xiE*pWS0ZShic#|F(p;YAy1332U)HRZ7aM^LTu80ynYrToiIhdxQ2;8mL!VKH zzM}8w5&b|v(QotzJr-kPM!X=di+S;icuf>VS-dAc5Fd$kv90w7x;f?2n`)wtha{)_ zl`!ySz@?6*$MAXb2fMDy2p4qzvEYK0DUMv2#N||B8iwW`2R_x}JfpSF2BL;yQXpE0uV|8Uzdi1_6VBLBJqz;SdeB2VKL7s(F`WFk literal 0 HcmV?d00001 diff --git a/assets/layers/parking/parking.json b/assets/layers/parking/parking.json index c6e5f57f0e..56da2650a2 100644 --- a/assets/layers/parking/parking.json +++ b/assets/layers/parking/parking.json @@ -1,7 +1,7 @@ { "id": "parking", "name": { - "nl": "parking" + "nl": "Parking" }, "minzoom": 12, "source": { @@ -10,7 +10,8 @@ { "or": [ "amenity=parking", - "amenity=motorcycle_parking" + "amenity=motorcycle_parking", + "amenity=bicycle_parking" ] } ] @@ -22,23 +23,21 @@ }, "mappings": [ { - "if": { - "and": [ - "name:nl~*" - ] - }, + "if": "amenity=parking", "then": { - "nl": "{name:nl}" + "nl": "Auto Parking" } }, { - "if": { - "and": [ - "name~*" - ] - }, + "if": "amenity=motorcycle_parking", "then": { - "nl": "{name}" + "nl": "Motorfiets Parking" + } + }, + { + "if": "amenity=bicycle_parking", + "then": { + "nl": "Fietsenstalling" } } ] @@ -169,7 +168,7 @@ ], "wayHandling": 1, "iconSize": { - "render": "30,30,center" + "render": "36,36,center" }, "color": { "render": "#E1AD01" @@ -179,6 +178,7 @@ "tags": [ "amenity=parking", "amenity=motorcycle_parking", + "amenity=bicycle_parking", "fixme=Toegevoegd met MapComplete, geometry nog uit te tekenen" ], "title": { diff --git a/assets/layers/watermill/watermill.json b/assets/layers/watermill/watermill.json index ffa2f0dc9a..1ff9b488df 100644 --- a/assets/layers/watermill/watermill.json +++ b/assets/layers/watermill/watermill.json @@ -1,7 +1,7 @@ { "id": "watermill", "name": { - "nl": "watermolens" + "nl": "Watermolens" }, "minzoom": 12, "source": { diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 560b9d1435..2f85396c2b 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -608,7 +608,9 @@ "sources": [] }, { - "authors": ["Hannah Declerck"], + "authors": [ + "Hannah Declerck" + ], "path": "filter.svg", "license": "CC0", "sources": [] diff --git a/assets/themes/.DS_Store b/assets/themes/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7d02d7d4e6d1f607628cf4f4b378aba7f837bb80 GIT binary patch literal 10244 zcmeHM&2AG(5bk#VCbsjl5>obpG?ztth)^IA+C8k~4eSAl1Cr5lfW?d%6Ay7_tnnDH zH=D?Jo?!RDEASjV0OBpUa|+*AGqHMl0!M;Gx7A%eGxb&Vd{y0@o+zdC{y4m$l&_TX zP$@T?Xf7yx&RQw8;?6Zl4ZKR8bq7foSDO`Gcf&E@7;p?Y1{?#9fp3EW?Aa_{BbTmq z3^)cH19JwrKKQ7VtwPRnDN6?$IRZc~;|g`DLQcTjW=h0LM4IAZAH z?4WZvp0^79SuS(9(&8C*3eUPYq3Gi1p?y(Tx|K`UItCmARR(x=Ur>SSsqpTgbbkLG zPp+Ry5!ec}QkAKRN+1s{?Kc(eE^Nl?nd(E1%G&y>rM;oLDuV75bpZVi+6ebj@j127 zuPpSIpbrIigwe&oW-`hM{R3DV;W|K#_|&rY(XzG*YYBdb7)tRx@V{#U!7OxjtHjYs=I`iNKegRI{z z`VW$1Fz*N5Kcn8Hvw7uq5@$ga_fi2zVGk;gA4YMQO!kv;9FD|JJAdGLtKMp7^T*@k zy`Mp11#_ zS0UzQJBbWvnI!UsiKy3&L~MxuSP-2#8IHDs2@JkV`VDvpV0!>L6)pq3e^zErgY^<> z5fdW7WVA*@hD&)4f-=Nlr_;^|>y!hrm?E!3nNU4PNmTRhEPp3oUaX#8rYm z7YP|**{3jU;yvgy>gTy*y^pYK>aUA8E-}RAWTmP0c1WxvcguI*zahHkfJF(l6Y9Ft}e6 z9N#0urZJS \ No newline at end of file diff --git a/assets/themes/natuurpunt/parkingmotor.svg b/assets/themes/natuurpunt/parkingmotor.svg new file mode 100644 index 0000000000..0fc18d9a68 --- /dev/null +++ b/assets/themes/natuurpunt/parkingmotor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/themes/natuurpunt/parkingwheels.svg b/assets/themes/natuurpunt/parkingwheels.svg new file mode 100644 index 0000000000..3e08f733bb --- /dev/null +++ b/assets/themes/natuurpunt/parkingwheels.svg @@ -0,0 +1 @@ + \ No newline at end of file