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 {BBox} from "./Logic/GeoOperations";
|
||||
import StaticFeatureSource from "./Logic/FeatureSource/Sources/StaticFeatureSource";
|
||||
import FilterConfig from "./Models/ThemeConfig/FilterConfig";
|
||||
import FilteredLayer from "./Models/FilteredLayer";
|
||||
|
||||
export class InitUiElements {
|
||||
static InitAll(
|
||||
|
@ -406,8 +408,10 @@ export class InitUiElements {
|
|||
|
||||
private static InitLayers(): void {
|
||||
const state = State.state;
|
||||
const empty = []
|
||||
|
||||
state.filteredLayers = state.layoutToUse.map((layoutToUse) => {
|
||||
const flayers = [];
|
||||
const flayers: FilteredLayer[] = [];
|
||||
|
||||
for (const layer of layoutToUse.layers) {
|
||||
const isDisplayed = QueryParameters.GetQueryParameter(
|
||||
|
@ -422,30 +426,47 @@ export class InitUiElements {
|
|||
const flayer = {
|
||||
isDisplayed: isDisplayed,
|
||||
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);
|
||||
}
|
||||
return flayers;
|
||||
});
|
||||
|
||||
|
||||
const layers = State.state.layoutToUse.data.layers
|
||||
const clusterShow = Math.min(...layers.map(layer => layer.minzoom))
|
||||
|
||||
|
||||
|
||||
const clusterCounter = TileHierarchyAggregator.createHierarchy()
|
||||
new ShowDataLayer({
|
||||
features: clusterCounter.getCountsForZoom(State.state.locationControl, State.state.layoutToUse.data.clustering.minNeededElements),
|
||||
leafletMap: State.state.leafletMap,
|
||||
layerToShow: ShowTileInfo.styling,
|
||||
doShowLayer: layers.length === 1 ? undefined : State.state.locationControl.map(l => l.zoom < clusterShow)
|
||||
})
|
||||
|
||||
State.state.featurePipeline = new FeaturePipeline(
|
||||
source => {
|
||||
|
||||
clusterCounter.addTile(source)
|
||||
|
||||
|
||||
const clustering = State.state.layoutToUse.data.clustering
|
||||
const doShowFeatures = source.features.map(
|
||||
f => {
|
||||
|
@ -489,7 +510,7 @@ export class InitUiElements {
|
|||
return true
|
||||
}, [State.state.locationControl, State.state.currentBounds]
|
||||
)
|
||||
|
||||
|
||||
new ShowDataLayer(
|
||||
{
|
||||
features: source,
|
||||
|
|
|
@ -5,13 +5,14 @@ import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
|
|||
import Hash from "../../Web/Hash";
|
||||
import {BBox} from "../../GeoOperations";
|
||||
|
||||
export default class FilteringFeatureSource implements FeatureSourceForLayer , Tiled {
|
||||
export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled {
|
||||
public features: UIEventSource<{ feature: any; freshness: Date }[]> =
|
||||
new UIEventSource<{ feature: any; freshness: Date }[]>([]);
|
||||
public readonly name;
|
||||
public readonly layer: FilteredLayer;
|
||||
public readonly tileIndex : number
|
||||
public readonly bbox : BBox
|
||||
public readonly tileIndex: number
|
||||
public readonly bbox: BBox
|
||||
|
||||
constructor(
|
||||
state: {
|
||||
locationControl: UIEventSource<{ zoom: number }>,
|
||||
|
@ -21,7 +22,7 @@ public readonly tileIndex : number
|
|||
upstream: FeatureSourceForLayer
|
||||
) {
|
||||
const self = this;
|
||||
this.name = "FilteringFeatureSource("+upstream.name+")"
|
||||
this.name = "FilteringFeatureSource(" + upstream.name + ")"
|
||||
this.tileIndex = tileIndex
|
||||
this.bbox = BBox.fromTileIndex(tileIndex)
|
||||
|
||||
|
@ -50,12 +51,15 @@ public readonly tileIndex : number
|
|||
}
|
||||
|
||||
const tagsFilter = layer.appliedFilters.data;
|
||||
if (tagsFilter) {
|
||||
if (!tagsFilter.matchesProperties(f.feature.properties)) {
|
||||
for (const filter of tagsFilter ?? []) {
|
||||
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
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!layer.isDisplayed) {
|
||||
// The layer itself is either disabled or hidden due to zoom constraints
|
||||
// We should return true, but it might still match some other layer
|
||||
|
@ -80,7 +84,7 @@ public readonly tileIndex : number
|
|||
});
|
||||
|
||||
layer.appliedFilters.addCallback(_ => {
|
||||
if(!layer.isDisplayed.data){
|
||||
if (!layer.isDisplayed.data) {
|
||||
// Currently not shown.
|
||||
// Note that a change in 'isSHown' will trigger an update as well, so we don't have to watch it another time
|
||||
return;
|
||||
|
|
|
@ -150,6 +150,7 @@ export default class MetaTagging {
|
|||
for (const f of functions) {
|
||||
f(params, feature);
|
||||
}
|
||||
State.state.allElements.getEventSourceById(feature.properties.id).ping();
|
||||
} catch (e) {
|
||||
console.error("While calculating a tag value: ", e)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import {Utils} from "../Utils";
|
|||
|
||||
export default class Constants {
|
||||
|
||||
public static vNumber = "0.10.0-alpha-2";
|
||||
public static vNumber = "0.10.0-alpha-3";
|
||||
public static ImgurApiKey = '7070e7167f0a25a'
|
||||
|
||||
// The user journey states thresholds when a new feature gets unlocked
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import {UIEventSource} from "../Logic/UIEventSource";
|
||||
import LayerConfig from "./ThemeConfig/LayerConfig";
|
||||
import {And} from "../Logic/Tags/And";
|
||||
import FilterConfig from "./ThemeConfig/FilterConfig";
|
||||
|
||||
export default interface FilteredLayer {
|
||||
readonly isDisplayed: UIEventSource<boolean>;
|
||||
readonly appliedFilters: UIEventSource<And>;
|
||||
readonly appliedFilters: UIEventSource<{filter: FilterConfig, selected: number}[]>;
|
||||
readonly layerDef: LayerConfig;
|
||||
}
|
|
@ -5,7 +5,8 @@ import Translations from "../../UI/i18n/Translations";
|
|||
import {TagUtils} from "../../Logic/Tags/TagUtils";
|
||||
|
||||
export default class FilterConfig {
|
||||
readonly options: {
|
||||
public readonly id: string
|
||||
public readonly options: {
|
||||
question: Translation;
|
||||
osmTags: TagsFilter;
|
||||
}[];
|
||||
|
@ -14,11 +15,18 @@ export default class FilterConfig {
|
|||
if (json.options === undefined) {
|
||||
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) {
|
||||
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) => {
|
||||
const question = Translations.T(
|
||||
option.question,
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import {AndOrTagConfigJson} from "./TagConfigJson";
|
||||
|
||||
export default interface FilterConfigJson {
|
||||
/**
|
||||
* An id/name for this filter, used to set the URL parameters
|
||||
*/
|
||||
id: string,
|
||||
/**
|
||||
* The options for a filter
|
||||
* 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 {Translation} from "../i18n/Translation";
|
||||
import Svg from "../../Svg";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import {And} from "../../Logic/Tags/And";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import State from "../../State";
|
||||
|
@ -16,11 +14,6 @@ import FilteredLayer from "../../Models/FilteredLayer";
|
|||
import BackgroundSelector from "./BackgroundSelector";
|
||||
import FilterConfig from "../../Models/ThemeConfig/FilterConfig";
|
||||
|
||||
|
||||
/**
|
||||
* Shows the filter
|
||||
*/
|
||||
|
||||
export default class FilterView extends VariableUiElement {
|
||||
constructor(filteredLayer: UIEventSource<FilteredLayer[]>) {
|
||||
const backgroundSelector = new Toggle(
|
||||
|
@ -101,26 +94,52 @@ export default class FilterView extends VariableUiElement {
|
|||
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
|
||||
);
|
||||
|
||||
const update = () => {
|
||||
let listTagsFilters = Utils.NoNull(
|
||||
listFilterElements.map((input) => input[1].data)
|
||||
);
|
||||
flayer.appliedFilters.setData(new And(listTagsFilters));
|
||||
};
|
||||
listFilterElements.forEach((inputElement, i) =>
|
||||
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.forEach((inputElement) =>
|
||||
inputElement[1].addCallback((_) => update())
|
||||
console.log(listTagsFilters, oldValue)
|
||||
flayer.appliedFilters.setData(listTagsFilters);
|
||||
})
|
||||
);
|
||||
|
||||
flayer.appliedFilters.addCallbackAndRun(appliedFilters => {
|
||||
if (appliedFilters === undefined || appliedFilters.and.length === 0) {
|
||||
listFilterElements.forEach(filter => filter[1].setData(undefined))
|
||||
return
|
||||
for (let i = 0; i < layer.filters.length; i++){
|
||||
const filter = layer.filters[i];
|
||||
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")))
|
||||
|
@ -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) {
|
||||
let option = filterConfig.options[0];
|
||||
|
||||
|
@ -142,20 +161,36 @@ export default class FilterView extends VariableUiElement {
|
|||
.ToggleOnClick()
|
||||
.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;
|
||||
|
||||
const values = options.map((f, i) => ({
|
||||
filter: filterConfig, selected: i
|
||||
}))
|
||||
const radio = new RadioButton(
|
||||
options.map(
|
||||
(option) =>
|
||||
new FixedInputElement(option.question.Clone(), option.osmTags)
|
||||
(option, i) =>
|
||||
new FixedInputElement(option.question.Clone(), i)
|
||||
),
|
||||
{
|
||||
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")
|
||||
).onClick(() => {
|
||||
preset.layerToAddTo.appliedFilters.setData(new And([]))
|
||||
preset.layerToAddTo.appliedFilters.setData([])
|
||||
cancel()
|
||||
})
|
||||
|
||||
const disableFiltersOrConfirm = new Toggle(
|
||||
openLayerOrConfirm,
|
||||
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,
|
||||
"filter": [
|
||||
{
|
||||
"id": "wheelchair",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -275,6 +276,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "shelter",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -170,6 +170,7 @@
|
|||
],
|
||||
"filter": [
|
||||
{
|
||||
"id": "opened-now",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -2627,6 +2627,7 @@
|
|||
"wayHandling": 1,
|
||||
"filter": [
|
||||
{
|
||||
"id": "vehicle-type",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -2656,6 +2657,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "working",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -2671,6 +2673,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "connection_type",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -648,6 +648,7 @@
|
|||
"wayHandling": 1,
|
||||
"filter": [
|
||||
{
|
||||
"id": "vehicle-type",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -677,6 +678,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "working",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -242,6 +242,7 @@ function run(file, protojson) {
|
|||
})
|
||||
|
||||
proto["filter"].push({
|
||||
id:"connection_type",
|
||||
options: filterOptions
|
||||
})
|
||||
|
||||
|
|
|
@ -560,6 +560,7 @@
|
|||
],
|
||||
"filter": [
|
||||
{
|
||||
"id": "opened-now",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -571,6 +572,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "vegetarian",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -589,6 +591,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "vegan",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -605,6 +608,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "halal",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -423,6 +423,7 @@
|
|||
],
|
||||
"filter": [
|
||||
{
|
||||
"id": "access",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -433,6 +434,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "dogs",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -444,6 +444,7 @@
|
|||
},
|
||||
"filter": [
|
||||
{
|
||||
"id": "kid-books",
|
||||
"options": [
|
||||
{
|
||||
"question": "Kinderboeken aanwezig?",
|
||||
|
@ -452,6 +453,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "adult-books",
|
||||
"options": [
|
||||
{
|
||||
"question": "Boeken voor volwassenen aanwezig?",
|
||||
|
@ -460,6 +462,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "inside",
|
||||
"options": [
|
||||
{
|
||||
"question": "Binnen of buiten",
|
||||
|
|
|
@ -411,6 +411,7 @@
|
|||
],
|
||||
"filter": [
|
||||
{
|
||||
"id": "wheelchair",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -421,6 +422,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "changing_table",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
@ -431,6 +433,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "free",
|
||||
"options": [
|
||||
{
|
||||
"question": {
|
||||
|
|
|
@ -143,6 +143,7 @@
|
|||
},
|
||||
"filter": [
|
||||
{
|
||||
"id": "name-alt",
|
||||
"options": [
|
||||
{
|
||||
"question": "Name contains 'alt'",
|
||||
|
@ -151,6 +152,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "name-wenslijn",
|
||||
"options": [
|
||||
{
|
||||
"question": "Name contains 'wenslijn'",
|
||||
|
@ -159,6 +161,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "name-omleiding",
|
||||
"options": [
|
||||
{
|
||||
"question": "Name contains 'omleiding'",
|
||||
|
@ -167,6 +170,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id":"ref-alt",
|
||||
"options": [
|
||||
{
|
||||
"question": "Reference contains 'alt'",
|
||||
|
@ -175,6 +179,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "missing_link",
|
||||
"options": [
|
||||
{
|
||||
"question": "No filter"
|
||||
|
@ -194,6 +199,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"id": "proposed",
|
||||
"options": [
|
||||
{
|
||||
"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://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",
|
||||
"icon": "./assets/themes/uk_addresses/housenumber_unknown.svg",
|
||||
"version": "2021-09-17",
|
||||
"startLat": -0.08528530407,
|
||||
"startLon": 51.52103754846,
|
||||
"startZoom": 18,
|
||||
"widenFactor": 1.5,
|
||||
"startLat": -0.08706,
|
||||
"startLon": 51.52224,
|
||||
"startZoom": 17,
|
||||
"widenFactor": 1.01,
|
||||
"socialImage": "",
|
||||
"clustering": {
|
||||
"minNeededFeatures": 25,
|
||||
"maxZoom": 17
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"id": "to_import",
|
||||
|
@ -34,21 +38,21 @@
|
|||
"minzoom": 12,
|
||||
"wayHandling": 1,
|
||||
"icon": {
|
||||
"render": "./assets/themes/uk_addresses/housenumber_unknown.svg"
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center",
|
||||
"render": "./assets/themes/uk_addresses/housenumber_unknown.svg",
|
||||
"mappings": [
|
||||
{
|
||||
"if": "_embedding_object:id~*",
|
||||
"then": "15,15,center"
|
||||
"then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg"
|
||||
},
|
||||
{
|
||||
"if": "_imported=yes",
|
||||
"then": "8,8,center"
|
||||
"then": "./assets/themes/uk_addresses/housenumber_unknown_small.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"title": {
|
||||
"render": "Address to be determined"
|
||||
},
|
||||
|
@ -73,6 +77,22 @@
|
|||
"_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: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",
|
||||
() => {
|
||||
const bbox = BBox.fromTile(16, 32754, 21785)
|
||||
equal(-0.0714111328125, bbox.minLon)
|
||||
equal(-0.076904296875, bbox.maxLon)
|
||||
equal(51.53266860674158, bbox.minLat)
|
||||
equal(51.5292513551899, bbox.maxLat)
|
||||
equal(-0.076904296875, bbox.minLon)
|
||||
equal(-0.0714111328125, bbox.maxLon)
|
||||
equal(51.5292513551899, bbox.minLat)
|
||||
equal(51.53266860674158, bbox.maxLat)
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue