forked from MapComplete/MapComplete
		
	Fix bbox bug, add ids to filters, add filter state to the URL
This commit is contained in:
		
							parent
							
								
									38037014b0
								
							
						
					
					
						commit
						0a9e7c0b36
					
				
					 23 changed files with 248 additions and 59 deletions
				
			
		|  | @ -42,6 +42,8 @@ import {Tiles} from "./Models/TileRange"; | ||||||
| import {TileHierarchyAggregator} from "./UI/ShowDataLayer/PerTileCountAggregator"; | import {TileHierarchyAggregator} from "./UI/ShowDataLayer/PerTileCountAggregator"; | ||||||
| import {BBox} from "./Logic/GeoOperations"; | import {BBox} from "./Logic/GeoOperations"; | ||||||
| import StaticFeatureSource from "./Logic/FeatureSource/Sources/StaticFeatureSource"; | import StaticFeatureSource from "./Logic/FeatureSource/Sources/StaticFeatureSource"; | ||||||
|  | import FilterConfig from "./Models/ThemeConfig/FilterConfig"; | ||||||
|  | import FilteredLayer from "./Models/FilteredLayer"; | ||||||
| 
 | 
 | ||||||
| export class InitUiElements { | export class InitUiElements { | ||||||
|     static InitAll( |     static InitAll( | ||||||
|  | @ -406,8 +408,10 @@ export class InitUiElements { | ||||||
| 
 | 
 | ||||||
|     private static InitLayers(): void { |     private static InitLayers(): void { | ||||||
|         const state = State.state; |         const state = State.state; | ||||||
|  |         const empty = [] | ||||||
|  | 
 | ||||||
|         state.filteredLayers = state.layoutToUse.map((layoutToUse) => { |         state.filteredLayers = state.layoutToUse.map((layoutToUse) => { | ||||||
|             const flayers = []; |             const flayers: FilteredLayer[] = []; | ||||||
| 
 | 
 | ||||||
|             for (const layer of layoutToUse.layers) { |             for (const layer of layoutToUse.layers) { | ||||||
|                 const isDisplayed = QueryParameters.GetQueryParameter( |                 const isDisplayed = QueryParameters.GetQueryParameter( | ||||||
|  | @ -422,23 +426,40 @@ export class InitUiElements { | ||||||
|                 const flayer = { |                 const flayer = { | ||||||
|                     isDisplayed: isDisplayed, |                     isDisplayed: isDisplayed, | ||||||
|                     layerDef: layer, |                     layerDef: layer, | ||||||
|                     appliedFilters: new UIEventSource<TagsFilter>(undefined), |                     appliedFilters: new UIEventSource<{ filter: FilterConfig, selected: number }[]>([]), | ||||||
|                 }; |                 }; | ||||||
|  | 
 | ||||||
|  |                 if (layer.filters.length > 0) { | ||||||
|  |                     const filtersPerName = new Map<string, FilterConfig>() | ||||||
|  |                     layer.filters.forEach(f => filtersPerName.set(f.id, f)) | ||||||
|  |                     const qp = QueryParameters.GetQueryParameter("filter-" + layer.id, "","Filtering state for a layer") | ||||||
|  |                     flayer.appliedFilters.map(filters => { | ||||||
|  |                         filters = filters ?? [] | ||||||
|  |                         return filters.map(f => f.filter.id + "." + f.selected).join(",") | ||||||
|  |                     }, [], textual => { | ||||||
|  |                         if(textual.length === 0){ | ||||||
|  |                             return empty | ||||||
|  |                         } | ||||||
|  |                         return textual.split(",").map(part => { | ||||||
|  |                             const [filterId, selected] = part.split("."); | ||||||
|  |                             return {filter: filtersPerName.get(filterId), selected: Number(selected)} | ||||||
|  |                         }).filter(f => f.filter !== undefined && !isNaN(f.selected)) | ||||||
|  |                     }).syncWith(qp, true) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 flayers.push(flayer); |                 flayers.push(flayer); | ||||||
|             } |             } | ||||||
|             return flayers; |             return flayers; | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         const layers = State.state.layoutToUse.data.layers |  | ||||||
|         const clusterShow = Math.min(...layers.map(layer => layer.minzoom)) |  | ||||||
| 
 | 
 | ||||||
|  |         const layers = State.state.layoutToUse.data.layers | ||||||
| 
 | 
 | ||||||
|         const clusterCounter = TileHierarchyAggregator.createHierarchy() |         const clusterCounter = TileHierarchyAggregator.createHierarchy() | ||||||
|         new ShowDataLayer({ |         new ShowDataLayer({ | ||||||
|             features: clusterCounter.getCountsForZoom(State.state.locationControl, State.state.layoutToUse.data.clustering.minNeededElements), |             features: clusterCounter.getCountsForZoom(State.state.locationControl, State.state.layoutToUse.data.clustering.minNeededElements), | ||||||
|             leafletMap: State.state.leafletMap, |             leafletMap: State.state.leafletMap, | ||||||
|             layerToShow: ShowTileInfo.styling, |             layerToShow: ShowTileInfo.styling, | ||||||
|             doShowLayer: layers.length === 1 ? undefined : State.state.locationControl.map(l => l.zoom < clusterShow) |  | ||||||
|         }) |         }) | ||||||
| 
 | 
 | ||||||
|         State.state.featurePipeline = new FeaturePipeline( |         State.state.featurePipeline = new FeaturePipeline( | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer , T | ||||||
|     public readonly layer: FilteredLayer; |     public readonly layer: FilteredLayer; | ||||||
|     public readonly tileIndex: number |     public readonly tileIndex: number | ||||||
|     public readonly bbox: BBox |     public readonly bbox: BBox | ||||||
|  | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         state: { |         state: { | ||||||
|             locationControl: UIEventSource<{ zoom: number }>, |             locationControl: UIEventSource<{ zoom: number }>, | ||||||
|  | @ -50,12 +51,15 @@ public readonly tileIndex : number | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 const tagsFilter = layer.appliedFilters.data; |                 const tagsFilter = layer.appliedFilters.data; | ||||||
|                 if (tagsFilter) { |                 for (const filter of tagsFilter ?? []) { | ||||||
|                     if (!tagsFilter.matchesProperties(f.feature.properties)) { |                     const neededTags = filter.filter.options[filter.selected].osmTags | ||||||
|  |                     if (!neededTags.matchesProperties(f.feature.properties)) { | ||||||
|                         // Hidden by the filter on the layer itself - we want to hide it no matter wat
 |                         // Hidden by the filter on the layer itself - we want to hide it no matter wat
 | ||||||
|                         return false; |                         return false; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|                 if (!layer.isDisplayed) { |                 if (!layer.isDisplayed) { | ||||||
|                     // The layer itself is either disabled or hidden due to zoom constraints
 |                     // The layer itself is either disabled or hidden due to zoom constraints
 | ||||||
|                     // We should return true, but it might still match some other layer
 |                     // We should return true, but it might still match some other layer
 | ||||||
|  |  | ||||||
|  | @ -150,6 +150,7 @@ export default class MetaTagging { | ||||||
|                 for (const f of functions) { |                 for (const f of functions) { | ||||||
|                     f(params, feature); |                     f(params, feature); | ||||||
|                 } |                 } | ||||||
|  |                  State.state.allElements.getEventSourceById(feature.properties.id).ping(); | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.error("While calculating a tag value: ", e) |                 console.error("While calculating a tag value: ", e) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import {Utils} from "../Utils"; | ||||||
| 
 | 
 | ||||||
| export default class Constants { | export default class Constants { | ||||||
| 
 | 
 | ||||||
|     public static vNumber = "0.10.0-alpha-2"; |     public static vNumber = "0.10.0-alpha-3"; | ||||||
|     public static ImgurApiKey = '7070e7167f0a25a' |     public static ImgurApiKey = '7070e7167f0a25a' | ||||||
| 
 | 
 | ||||||
|     // The user journey states thresholds when a new feature gets unlocked
 |     // The user journey states thresholds when a new feature gets unlocked
 | ||||||
|  |  | ||||||
|  | @ -1,9 +1,10 @@ | ||||||
| import {UIEventSource} from "../Logic/UIEventSource"; | import {UIEventSource} from "../Logic/UIEventSource"; | ||||||
| import LayerConfig from "./ThemeConfig/LayerConfig"; | import LayerConfig from "./ThemeConfig/LayerConfig"; | ||||||
| import {And} from "../Logic/Tags/And"; | import {And} from "../Logic/Tags/And"; | ||||||
|  | import FilterConfig from "./ThemeConfig/FilterConfig"; | ||||||
| 
 | 
 | ||||||
| export default interface FilteredLayer { | export default interface FilteredLayer { | ||||||
|     readonly isDisplayed: UIEventSource<boolean>; |     readonly isDisplayed: UIEventSource<boolean>; | ||||||
|     readonly appliedFilters: UIEventSource<And>; |     readonly appliedFilters: UIEventSource<{filter: FilterConfig, selected: number}[]>; | ||||||
|     readonly layerDef: LayerConfig; |     readonly layerDef: LayerConfig; | ||||||
| } | } | ||||||
|  | @ -5,7 +5,8 @@ import Translations from "../../UI/i18n/Translations"; | ||||||
| import {TagUtils} from "../../Logic/Tags/TagUtils"; | import {TagUtils} from "../../Logic/Tags/TagUtils"; | ||||||
| 
 | 
 | ||||||
| export default class FilterConfig { | export default class FilterConfig { | ||||||
|     readonly options: { |     public readonly id: string | ||||||
|  |     public readonly options: { | ||||||
|         question: Translation; |         question: Translation; | ||||||
|         osmTags: TagsFilter; |         osmTags: TagsFilter; | ||||||
|     }[]; |     }[]; | ||||||
|  | @ -14,11 +15,18 @@ export default class FilterConfig { | ||||||
|         if (json.options === undefined) { |         if (json.options === undefined) { | ||||||
|             throw `A filter without options was given at ${context}` |             throw `A filter without options was given at ${context}` | ||||||
|         } |         } | ||||||
|  |         if (json.id === undefined) { | ||||||
|  |             throw `A filter without id was found at ${context}` | ||||||
|  |         } | ||||||
|  |         if(json.id.match(/^[a-zA-Z0-9_-]*$/) === null){ | ||||||
|  |             throw `A filter with invalid id was found at ${context}. Ids should only contain letters, numbers or - _` | ||||||
|  | 
 | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (json.options.map === undefined) { |         if (json.options.map === undefined) { | ||||||
|             throw `A filter was given where the options aren't a list at ${context}` |             throw `A filter was given where the options aren't a list at ${context}` | ||||||
|         } |         } | ||||||
| 
 |         this.id = json.id; | ||||||
|         this.options = json.options.map((option, i) => { |         this.options = json.options.map((option, i) => { | ||||||
|             const question = Translations.T( |             const question = Translations.T( | ||||||
|                 option.question, |                 option.question, | ||||||
|  |  | ||||||
|  | @ -1,6 +1,10 @@ | ||||||
| import {AndOrTagConfigJson} from "./TagConfigJson"; | import {AndOrTagConfigJson} from "./TagConfigJson"; | ||||||
| 
 | 
 | ||||||
| export default interface FilterConfigJson { | export default interface FilterConfigJson { | ||||||
|  |     /** | ||||||
|  |      * An id/name for this filter, used to set the URL parameters | ||||||
|  |      */ | ||||||
|  |     id: string, | ||||||
|     /** |     /** | ||||||
|      * The options for a filter |      * The options for a filter | ||||||
|      * If there are multiple options these will be a list of radio buttons |      * If there are multiple options these will be a list of radio buttons | ||||||
|  |  | ||||||
|  | @ -7,8 +7,6 @@ import Combine from "../Base/Combine"; | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations"; | ||||||
| import {Translation} from "../i18n/Translation"; | import {Translation} from "../i18n/Translation"; | ||||||
| import Svg from "../../Svg"; | import Svg from "../../Svg"; | ||||||
| import {TagsFilter} from "../../Logic/Tags/TagsFilter"; |  | ||||||
| import {And} from "../../Logic/Tags/And"; |  | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement"; | ||||||
| import State from "../../State"; | import State from "../../State"; | ||||||
|  | @ -16,11 +14,6 @@ import FilteredLayer from "../../Models/FilteredLayer"; | ||||||
| import BackgroundSelector from "./BackgroundSelector"; | import BackgroundSelector from "./BackgroundSelector"; | ||||||
| import FilterConfig from "../../Models/ThemeConfig/FilterConfig"; | import FilterConfig from "../../Models/ThemeConfig/FilterConfig"; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Shows the filter |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| export default class FilterView extends VariableUiElement { | export default class FilterView extends VariableUiElement { | ||||||
|     constructor(filteredLayer: UIEventSource<FilteredLayer[]>) { |     constructor(filteredLayer: UIEventSource<FilteredLayer[]>) { | ||||||
|         const backgroundSelector = new Toggle( |         const backgroundSelector = new Toggle( | ||||||
|  | @ -101,26 +94,52 @@ export default class FilterView extends VariableUiElement { | ||||||
|             return undefined; |             return undefined; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let listFilterElements: [BaseUIElement, UIEventSource<TagsFilter>][] = layer.filters.map( |         const filterIndexes = new Map<string, number>() | ||||||
|  |         layer.filters.forEach((f, i) => filterIndexes.set(f.id, i)) | ||||||
|  | 
 | ||||||
|  |         let listFilterElements: [BaseUIElement, UIEventSource<{ filter: FilterConfig, selected: number }>][] = layer.filters.map( | ||||||
|             FilterView.createFilter |             FilterView.createFilter | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         const update = () => { |         listFilterElements.forEach((inputElement, i) => | ||||||
|             let listTagsFilters = Utils.NoNull( |             inputElement[1].addCallback((changed) => { | ||||||
|  |                 const oldValue = flayer.appliedFilters.data | ||||||
|  |                  | ||||||
|  |                 if(changed === undefined){ | ||||||
|  |                     // Lets figure out which filter should be removed
 | ||||||
|  |                     // We know this inputElement corresponds with layer.filters[i]
 | ||||||
|  |                     // SO, if there is a value in 'oldValue' with this filter, we have to recalculated
 | ||||||
|  |                     if(!oldValue.some(f => f.filter === layer.filters[i])){ | ||||||
|  |                         // The filter to remove is already gone, we can stop
 | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  |                 }else if(oldValue.some(f => f.filter === changed.filter && f.selected === changed.selected)){ | ||||||
|  |                     // The changed value is already there
 | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                 const listTagsFilters = Utils.NoNull( | ||||||
|                     listFilterElements.map((input) => input[1].data) |                     listFilterElements.map((input) => input[1].data) | ||||||
|                 ); |                 ); | ||||||
|             flayer.appliedFilters.setData(new And(listTagsFilters)); |  | ||||||
|         }; |  | ||||||
| 
 | 
 | ||||||
|         listFilterElements.forEach((inputElement) => |                 console.log(listTagsFilters, oldValue) | ||||||
|             inputElement[1].addCallback((_) => update()) |                 flayer.appliedFilters.setData(listTagsFilters); | ||||||
|  |             }) | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         flayer.appliedFilters.addCallbackAndRun(appliedFilters => { |         flayer.appliedFilters.addCallbackAndRun(appliedFilters => { | ||||||
|             if (appliedFilters === undefined || appliedFilters.and.length === 0) { |             for (let i = 0; i < layer.filters.length; i++){ | ||||||
|                 listFilterElements.forEach(filter => filter[1].setData(undefined)) |                 const filter = layer.filters[i]; | ||||||
|                 return |                 let foundMatch = undefined | ||||||
|  |                 for (const appliedFilter of appliedFilters) { | ||||||
|  |                     if(appliedFilter.filter === filter){ | ||||||
|  |                         foundMatch = appliedFilter | ||||||
|  |                      break;    | ||||||
|                     } |                     } | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 listFilterElements[i][1].setData(foundMatch) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|         }) |         }) | ||||||
| 
 | 
 | ||||||
|         return new Combine(listFilterElements.map(input => input[0].SetClass("mt-3"))) |         return new Combine(listFilterElements.map(input => input[0].SetClass("mt-3"))) | ||||||
|  | @ -128,7 +147,7 @@ export default class FilterView extends VariableUiElement { | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static createFilter(filterConfig: FilterConfig): [BaseUIElement, UIEventSource<TagsFilter>] { |     private static createFilter(filterConfig: FilterConfig): [BaseUIElement, UIEventSource<{ filter: FilterConfig, selected: number }>] { | ||||||
|         if (filterConfig.options.length === 1) { |         if (filterConfig.options.length === 1) { | ||||||
|             let option = filterConfig.options[0]; |             let option = filterConfig.options[0]; | ||||||
| 
 | 
 | ||||||
|  | @ -142,20 +161,36 @@ export default class FilterView extends VariableUiElement { | ||||||
|                 .ToggleOnClick() |                 .ToggleOnClick() | ||||||
|                 .SetClass("block m-1") |                 .SetClass("block m-1") | ||||||
| 
 | 
 | ||||||
|             return [toggle, toggle.isEnabled.map(enabled => enabled ? option.osmTags : undefined, [], tags => tags !== undefined)] |             const selected = { | ||||||
|  |                 filter: filterConfig, | ||||||
|  |                 selected: 0 | ||||||
|  |             } | ||||||
|  |             return [toggle, toggle.isEnabled.map(enabled => enabled ? selected : undefined, [], | ||||||
|  |                 f => f?.filter === filterConfig && f?.selected === 0) | ||||||
|  |             ] | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let options = filterConfig.options; |         let options = filterConfig.options; | ||||||
| 
 | 
 | ||||||
|  |         const values = options.map((f, i) => ({ | ||||||
|  |            filter: filterConfig, selected: i  | ||||||
|  |         })) | ||||||
|         const radio = new RadioButton( |         const radio = new RadioButton( | ||||||
|             options.map( |             options.map( | ||||||
|                 (option) => |                 (option, i) => | ||||||
|                     new FixedInputElement(option.question.Clone(), option.osmTags) |                     new FixedInputElement(option.question.Clone(), i) | ||||||
|             ), |             ), | ||||||
|             { |             { | ||||||
|                 dontStyle: true |                 dontStyle: true | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
|         return [radio, radio.GetValue()] |         return [radio,  | ||||||
|  |             radio.GetValue().map( | ||||||
|  |             i => values[i],  | ||||||
|  |                 [], | ||||||
|  |             selected => { | ||||||
|  |                 return selected?.selected | ||||||
|  |             } | ||||||
|  |         )] | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -223,14 +223,14 @@ export default class SimpleAddUI extends Toggle { | ||||||
|                 ] |                 ] | ||||||
|             ).SetClass("flex flex-col") |             ).SetClass("flex flex-col") | ||||||
|         ).onClick(() => { |         ).onClick(() => { | ||||||
|             preset.layerToAddTo.appliedFilters.setData(new And([])) |             preset.layerToAddTo.appliedFilters.setData([]) | ||||||
|             cancel() |             cancel() | ||||||
|         }) |         }) | ||||||
| 
 | 
 | ||||||
|         const disableFiltersOrConfirm = new Toggle( |         const disableFiltersOrConfirm = new Toggle( | ||||||
|             openLayerOrConfirm, |             openLayerOrConfirm, | ||||||
|             disableFilter, |             disableFilter, | ||||||
|             preset.layerToAddTo.appliedFilters.map(filters => filters === undefined || filters.normalize().and.length === 0) |             preset.layerToAddTo.appliedFilters.map(filters => filters === undefined || filters.length === 0) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -258,6 +258,7 @@ | ||||||
|     "wayHandling": 1, |     "wayHandling": 1, | ||||||
|     "filter": [ |     "filter": [ | ||||||
|         { |         { | ||||||
|  |             "id": "wheelchair", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -275,6 +276,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "shelter", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  |  | ||||||
|  | @ -170,6 +170,7 @@ | ||||||
|     ], |     ], | ||||||
|     "filter": [ |     "filter": [ | ||||||
|         { |         { | ||||||
|  |             "id": "opened-now", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  |  | ||||||
|  | @ -2627,6 +2627,7 @@ | ||||||
|     "wayHandling": 1, |     "wayHandling": 1, | ||||||
|     "filter": [ |     "filter": [ | ||||||
|         { |         { | ||||||
|  |             "id": "vehicle-type", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -2656,6 +2657,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "working", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -2671,6 +2673,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "connection_type", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  |  | ||||||
|  | @ -648,6 +648,7 @@ | ||||||
|   "wayHandling": 1, |   "wayHandling": 1, | ||||||
|   "filter": [ |   "filter": [ | ||||||
|     { |     { | ||||||
|  |       "id": "vehicle-type", | ||||||
|       "options": [ |       "options": [ | ||||||
|         { |         { | ||||||
|           "question": { |           "question": { | ||||||
|  | @ -677,6 +678,7 @@ | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|  |       "id": "working", | ||||||
|       "options": [ |       "options": [ | ||||||
|         { |         { | ||||||
|           "question": { |           "question": { | ||||||
|  |  | ||||||
|  | @ -242,6 +242,7 @@ function run(file, protojson) { | ||||||
|     }) |     }) | ||||||
|      |      | ||||||
|     proto["filter"].push({ |     proto["filter"].push({ | ||||||
|  |         id:"connection_type", | ||||||
|         options: filterOptions |         options: filterOptions | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -560,6 +560,7 @@ | ||||||
|     ], |     ], | ||||||
|     "filter": [ |     "filter": [ | ||||||
|         { |         { | ||||||
|  |             "id": "opened-now", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -571,6 +572,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "vegetarian", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -589,6 +591,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "vegan", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -605,6 +608,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "halal", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  |  | ||||||
|  | @ -423,6 +423,7 @@ | ||||||
|     ], |     ], | ||||||
|     "filter": [ |     "filter": [ | ||||||
|         { |         { | ||||||
|  |             "id": "access", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -433,6 +434,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "dogs", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  |  | ||||||
|  | @ -444,6 +444,7 @@ | ||||||
|     }, |     }, | ||||||
|     "filter": [ |     "filter": [ | ||||||
|         { |         { | ||||||
|  |             "id": "kid-books", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": "Kinderboeken aanwezig?", |                     "question": "Kinderboeken aanwezig?", | ||||||
|  | @ -452,6 +453,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "adult-books", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": "Boeken voor volwassenen aanwezig?", |                     "question": "Boeken voor volwassenen aanwezig?", | ||||||
|  | @ -460,6 +462,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "inside", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": "Binnen of buiten", |                     "question": "Binnen of buiten", | ||||||
|  |  | ||||||
|  | @ -411,6 +411,7 @@ | ||||||
|     ], |     ], | ||||||
|     "filter": [ |     "filter": [ | ||||||
|         { |         { | ||||||
|  |             "id": "wheelchair", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -421,6 +422,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "changing_table", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  | @ -431,6 +433,7 @@ | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |             "id": "free", | ||||||
|             "options": [ |             "options": [ | ||||||
|                 { |                 { | ||||||
|                     "question": { |                     "question": { | ||||||
|  |  | ||||||
|  | @ -143,6 +143,7 @@ | ||||||
|       }, |       }, | ||||||
|       "filter": [ |       "filter": [ | ||||||
|         { |         { | ||||||
|  |           "id": "name-alt", | ||||||
|           "options": [ |           "options": [ | ||||||
|             { |             { | ||||||
|               "question": "Name contains 'alt'", |               "question": "Name contains 'alt'", | ||||||
|  | @ -151,6 +152,7 @@ | ||||||
|           ] |           ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |           "id": "name-wenslijn", | ||||||
|           "options": [ |           "options": [ | ||||||
|             { |             { | ||||||
|               "question": "Name contains 'wenslijn'", |               "question": "Name contains 'wenslijn'", | ||||||
|  | @ -159,6 +161,7 @@ | ||||||
|           ] |           ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |           "id": "name-omleiding", | ||||||
|           "options": [ |           "options": [ | ||||||
|             { |             { | ||||||
|               "question": "Name contains 'omleiding'", |               "question": "Name contains 'omleiding'", | ||||||
|  | @ -167,6 +170,7 @@ | ||||||
|           ] |           ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |           "id":"ref-alt", | ||||||
|           "options": [ |           "options": [ | ||||||
|             { |             { | ||||||
|               "question": "Reference contains 'alt'", |               "question": "Reference contains 'alt'", | ||||||
|  | @ -175,6 +179,7 @@ | ||||||
|           ] |           ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |           "id": "missing_link", | ||||||
|           "options": [ |           "options": [ | ||||||
|             { |             { | ||||||
|               "question": "No filter" |               "question": "No filter" | ||||||
|  | @ -194,6 +199,7 @@ | ||||||
|           ] |           ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|  |           "id": "proposed", | ||||||
|           "options": [ |           "options": [ | ||||||
|             { |             { | ||||||
|               "question": "No filter" |               "question": "No filter" | ||||||
|  |  | ||||||
							
								
								
									
										60
									
								
								assets/themes/uk_addresses/housenumber_unknown_small.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								assets/themes/uk_addresses/housenumber_unknown_small.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <svg | ||||||
|  |    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||||
|  |    xmlns:cc="http://creativecommons.org/ns#" | ||||||
|  |    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    version="1.1" | ||||||
|  |    viewBox="0 0 87.992996 87.883003" | ||||||
|  |    id="svg12" | ||||||
|  |    sodipodi:docname="housenumber_unknown_small.svg" | ||||||
|  |    inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)" | ||||||
|  |    width="87.992996" | ||||||
|  |    height="87.883003"> | ||||||
|  |   <metadata | ||||||
|  |      id="metadata18"> | ||||||
|  |     <rdf:RDF> | ||||||
|  |       <cc:Work | ||||||
|  |          rdf:about=""> | ||||||
|  |         <dc:format>image/svg+xml</dc:format> | ||||||
|  |         <dc:type | ||||||
|  |            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||||
|  |       </cc:Work> | ||||||
|  |     </rdf:RDF> | ||||||
|  |   </metadata> | ||||||
|  |   <defs | ||||||
|  |      id="defs16" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      pagecolor="#ffffff" | ||||||
|  |      bordercolor="#666666" | ||||||
|  |      borderopacity="1" | ||||||
|  |      objecttolerance="10" | ||||||
|  |      gridtolerance="10" | ||||||
|  |      guidetolerance="10" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pageshadow="2" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="1043" | ||||||
|  |      id="namedview14" | ||||||
|  |      showgrid="false" | ||||||
|  |      inkscape:zoom="7.375" | ||||||
|  |      inkscape:cx="-1.3561062" | ||||||
|  |      inkscape:cy="19.621117" | ||||||
|  |      inkscape:window-x="0" | ||||||
|  |      inkscape:window-y="0" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:current-layer="svg12" /> | ||||||
|  |   <path | ||||||
|  |      d="m 42.372766,41.559418 h 3.247468 c 0.421762,0 0.76133,0.339541 0.76133,0.761329 v 3.241506 c 0,0.421761 -0.339541,0.761329 -0.76133,0.761329 h -3.247468 c -0.421762,0 -0.76133,-0.339541 -0.76133,-0.761329 v -3.241506 c 0,-0.421761 0.339541,-0.761329 0.76133,-0.761329 z" | ||||||
|  |      style="fill:#495aad;stroke-width:0.0542103;paint-order:normal" | ||||||
|  |      id="path6" | ||||||
|  |      inkscape:connector-curvature="0" /> | ||||||
|  |   <path | ||||||
|  |      d="m 42.085614,42.793949 v 2.289464 c 0.381581,0 0.763173,0.381581 0.763173,0.763173 h 2.289463 c 0,-0.381581 0.381581,-0.763173 0.763173,-0.763173 v -2.289464 c -0.381581,0 -0.763173,-0.381581 -0.763173,-0.763172 h -2.289463 c 0,0.38158 -0.381581,0.763172 -0.763173,0.763172 z" | ||||||
|  |      id="path8" | ||||||
|  |      inkscape:connector-curvature="0" | ||||||
|  |      style="fill:none;stroke:#ffffff;stroke-width:0.27187553" /> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 2.3 KiB | 
|  | @ -39,5 +39,13 @@ | ||||||
|       "https://github.com/streetcomplete/StreetComplete/tree/master/res/graphics", |       "https://github.com/streetcomplete/StreetComplete/tree/master/res/graphics", | ||||||
|       "https://f-droid.org/packages/de.westnordost.streetcomplete/" |       "https://f-droid.org/packages/de.westnordost.streetcomplete/" | ||||||
|     ] |     ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     "path": "housenumber_unknown_small.svg", | ||||||
|  |     "license": "CC0", | ||||||
|  |     "authors": [ | ||||||
|  |       "Pieter Vander Vennet" | ||||||
|  |     ], | ||||||
|  |     "sources": [] | ||||||
|   } |   } | ||||||
| ] | ] | ||||||
|  | @ -15,11 +15,15 @@ | ||||||
|   "maintainer": "Pieter Vander Vennet, Rob Nickerson, Russ Garrett", |   "maintainer": "Pieter Vander Vennet, Rob Nickerson, Russ Garrett", | ||||||
|   "icon": "./assets/themes/uk_addresses/housenumber_unknown.svg", |   "icon": "./assets/themes/uk_addresses/housenumber_unknown.svg", | ||||||
|   "version": "2021-09-17", |   "version": "2021-09-17", | ||||||
|   "startLat": -0.08528530407, |   "startLat": -0.08706, | ||||||
|   "startLon": 51.52103754846, |   "startLon": 51.52224, | ||||||
|   "startZoom": 18, |   "startZoom": 17, | ||||||
|   "widenFactor": 1.5, |   "widenFactor": 1.01, | ||||||
|   "socialImage": "", |   "socialImage": "", | ||||||
|  |   "clustering": { | ||||||
|  |     "minNeededFeatures": 25, | ||||||
|  |     "maxZoom": 17 | ||||||
|  |   }, | ||||||
|   "layers": [ |   "layers": [ | ||||||
|     { |     { | ||||||
|       "id": "to_import", |       "id": "to_import", | ||||||
|  | @ -34,21 +38,21 @@ | ||||||
|       "minzoom": 12, |       "minzoom": 12, | ||||||
|       "wayHandling": 1, |       "wayHandling": 1, | ||||||
|       "icon": { |       "icon": { | ||||||
|         "render": "./assets/themes/uk_addresses/housenumber_unknown.svg" |         "render": "./assets/themes/uk_addresses/housenumber_unknown.svg", | ||||||
|       }, |  | ||||||
|       "iconSize": { |  | ||||||
|         "render": "40,40,center", |  | ||||||
|         "mappings": [ |         "mappings": [ | ||||||
|           { |           { | ||||||
|             "if": "_embedding_object:id~*", |             "if": "_embedding_object:id~*", | ||||||
|             "then": "15,15,center" |             "then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg" | ||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
|             "if": "_imported=yes", |             "if": "_imported=yes", | ||||||
|             "then": "8,8,center" |             "then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg" | ||||||
|           } |           } | ||||||
|         ] |         ] | ||||||
|       }, |       }, | ||||||
|  |       "iconSize": { | ||||||
|  |         "render": "40,40,center" | ||||||
|  |       }, | ||||||
|       "title": { |       "title": { | ||||||
|         "render": "Address to be determined" |         "render": "Address to be determined" | ||||||
|       }, |       }, | ||||||
|  | @ -73,6 +77,22 @@ | ||||||
|         "_embedding_object:addr:housenumber=JSON.parse(feat.properties._embedding_object)?.['addr:housenumber']", |         "_embedding_object:addr:housenumber=JSON.parse(feat.properties._embedding_object)?.['addr:housenumber']", | ||||||
|         "_embedding_object:addr:street=JSON.parse(feat.properties._embedding_object)?.['addr:street']", |         "_embedding_object:addr:street=JSON.parse(feat.properties._embedding_object)?.['addr:street']", | ||||||
|         "_embedding_object:id=JSON.parse(feat.properties._embedding_object)?.id" |         "_embedding_object:id=JSON.parse(feat.properties._embedding_object)?.id" | ||||||
|  |       ], | ||||||
|  |       "filter": [ | ||||||
|  |         { | ||||||
|  |           "id": "to_handle", | ||||||
|  |           "options": [ | ||||||
|  |             { | ||||||
|  |               "question": "Only show non-matched objects", | ||||||
|  |               "osmTags": { | ||||||
|  |                 "and": [ | ||||||
|  |                   "_imported=", | ||||||
|  |                   "_embedding_object:id=" | ||||||
|  |                 ] | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           ] | ||||||
|  |         } | ||||||
|       ] |       ] | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -181,10 +181,10 @@ export default class GeoOperationsSpec extends T { | ||||||
|                 ["bbox bounds test", |                 ["bbox bounds test", | ||||||
|                     () => { |                     () => { | ||||||
|                         const bbox = BBox.fromTile(16, 32754, 21785) |                         const bbox = BBox.fromTile(16, 32754, 21785) | ||||||
|                         equal(-0.0714111328125, bbox.minLon) |                         equal(-0.076904296875, bbox.minLon) | ||||||
|                         equal(-0.076904296875, bbox.maxLon) |                         equal(-0.0714111328125, bbox.maxLon) | ||||||
|                         equal(51.53266860674158, bbox.minLat) |                         equal(51.5292513551899, bbox.minLat) | ||||||
|                         equal(51.5292513551899, bbox.maxLat) |                         equal(51.53266860674158, bbox.maxLat) | ||||||
|                     } |                     } | ||||||
|                 ] |                 ] | ||||||
|             ] |             ] | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue