forked from MapComplete/MapComplete
Add search previews on the map
This commit is contained in:
parent
1c46a65c84
commit
4f52483a98
19 changed files with 315 additions and 87 deletions
|
@ -356,9 +356,32 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"#": "ignore-image-in-then",
|
||||||
|
"if": "osm_id~*",
|
||||||
|
"then": {
|
||||||
|
"special": {
|
||||||
|
"type": "link",
|
||||||
|
"text": "<img alt='on osm' textmode='🗺️' src='./assets/svg/osm-logo-us.svg'/>",
|
||||||
|
"href": "https://www.openstreetmap.org/{osm_id}",
|
||||||
|
"arialabel": {
|
||||||
|
"en": "Open on openstreetmap.org",
|
||||||
|
"nl": "Bekijk op openstreetmap.org",
|
||||||
|
"de": "Auf openstreetmap.org öffnen",
|
||||||
|
"pl": "Otwórz na openstreetmap.org",
|
||||||
|
"da": "Åbn på openstreetmap.org"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"condition": "id~(node|way|relation)/[0-9]*"
|
"condition": {
|
||||||
|
"or": [
|
||||||
|
"id~(node|way|relation)/[0-9]*",
|
||||||
|
"osm_id~*"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "rating",
|
"id": "rating",
|
||||||
|
|
66
assets/layers/search/search.json
Normal file
66
assets/layers/search/search.json
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"id": "search",
|
||||||
|
"description": {
|
||||||
|
"en": "Priviliged layer showing the search results"
|
||||||
|
},
|
||||||
|
"source": "special",
|
||||||
|
"title": "{display_name}",
|
||||||
|
"tagRenderings": [
|
||||||
|
{
|
||||||
|
"id": "intro",
|
||||||
|
"render": {
|
||||||
|
"en": "Search result"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "osm",
|
||||||
|
"render": {
|
||||||
|
"*": "<a href='https://openstreetmap.org/{osm_type}/{osm_id}'>On OpenStreetMap</a>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"all_tags"
|
||||||
|
],
|
||||||
|
"pointRendering": [
|
||||||
|
{
|
||||||
|
"location": [
|
||||||
|
"point",
|
||||||
|
"centroid"
|
||||||
|
],
|
||||||
|
"marker": [
|
||||||
|
{
|
||||||
|
"icon": "circle",
|
||||||
|
"color": "white"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon": {
|
||||||
|
"render": "globe_alt",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"if": "category~city|locality|county",
|
||||||
|
"then": "building_office_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "category=train_station",
|
||||||
|
"then": "train"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "category=airport",
|
||||||
|
"then": "airport"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "category=house",
|
||||||
|
"then": "house"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": "category=shop",
|
||||||
|
"then": "building_storefront"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"label": "{display_name}",
|
||||||
|
"labelCssClasses": "bg-white rounded p-2 no-wrap"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -89,7 +89,7 @@
|
||||||
"generate:contributor-list": "vite-node scripts/generateContributors.ts",
|
"generate:contributor-list": "vite-node scripts/generateContributors.ts",
|
||||||
"generate:service-worker": "tsc src/service-worker.ts --outFile public/service-worker.js && git_hash=$(git rev-parse HEAD) && sed -i.bak \"s/GITHUB-COMMIT/$git_hash/\" public/service-worker.js && rm public/service-worker.js.bak",
|
"generate:service-worker": "tsc src/service-worker.ts --outFile public/service-worker.js && git_hash=$(git rev-parse HEAD) && sed -i.bak \"s/GITHUB-COMMIT/$git_hash/\" public/service-worker.js && rm public/service-worker.js.bak",
|
||||||
"reset:layeroverview": "npm run prep:layeroverview && npm run generate:layeroverview && npm run refresh:layeroverview",
|
"reset:layeroverview": "npm run prep:layeroverview && npm run generate:layeroverview && npm run refresh:layeroverview",
|
||||||
"prep:layeroverview": "mkdir -p ./src/assets/generated/layers; echo {\\\"themes\\\":[]} > ./src/assets/generated/known_themes.json && echo {\\\"layers\\\": []} > ./src/assets/generated/known_layers.json && rm -f ./src/assets/generated/layers/*.json && rm -f ./src/assets/generated/themes/*.json && cp ./assets/layers/usersettings/usersettings.json ./src/assets/generated/layers/usersettings.json && echo '{}' > ./src/assets/generated/layers/favourite.json && echo '{}' > ./src/assets/generated/layers/summary.json && echo '{}' > ./src/assets/generated/layers/last_click.json && echo '[]' > ./src/assets/generated/theme_overview.json",
|
"prep:layeroverview": "mkdir -p ./src/assets/generated/layers; echo {\\\"themes\\\":[]} > ./src/assets/generated/known_themes.json && echo {\\\"layers\\\": []} > ./src/assets/generated/known_layers.json && rm -f ./src/assets/generated/layers/*.json && rm -f ./src/assets/generated/themes/*.json && cp ./assets/layers/usersettings/usersettings.json ./src/assets/generated/layers/usersettings.json && echo '{}' > ./src/assets/generated/layers/favourite.json && echo '{}' > ./src/assets/generated/layers/summary.json && echo '{}' > ./src/assets/generated/layers/last_click.json && echo '[]' > ./src/assets/generated/theme_overview.json && echo '{}' > ./src/assets/generated/layers/search.json",
|
||||||
"generate": "npm run generate:licenses && npm run generate:images && npm run generate:charging-stations && npm run generate:translations && npm run refresh:layeroverview && npm run generate:service-worker",
|
"generate": "npm run generate:licenses && npm run generate:images && npm run generate:charging-stations && npm run generate:translations && npm run refresh:layeroverview && npm run generate:service-worker",
|
||||||
"generate:charging-stations": "cd ./assets/layers/charging_station && vite-node csvToJson.ts && cd -",
|
"generate:charging-stations": "cd ./assets/layers/charging_station && vite-node csvToJson.ts && cd -",
|
||||||
"clean:tests": "find . -type f -name \"*.doctest.ts\" | xargs -r rm",
|
"clean:tests": "find . -type f -name \"*.doctest.ts\" | xargs -r rm",
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default class TitleHandler {
|
||||||
if (selected === undefined) {
|
if (selected === undefined) {
|
||||||
return defaultTitle
|
return defaultTitle
|
||||||
}
|
}
|
||||||
const layer = state.layout.getMatchingLayer(selected.properties)
|
const layer = state.getMatchingLayer(selected.properties)
|
||||||
if (layer === undefined) {
|
if (layer === undefined) {
|
||||||
return defaultTitle
|
return defaultTitle
|
||||||
}
|
}
|
||||||
|
|
41
src/Logic/Geocoding/GeocodingFeatureSource.ts
Normal file
41
src/Logic/Geocoding/GeocodingFeatureSource.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { GeoCodeResult } from "./GeocodingProvider"
|
||||||
|
import { Store } from "../UIEventSource"
|
||||||
|
import { FeatureSource } from "../FeatureSource/FeatureSource"
|
||||||
|
import { Feature, Geometry } from "geojson"
|
||||||
|
|
||||||
|
export default class GeocodingFeatureSource implements FeatureSource {
|
||||||
|
public features: Store<Feature<Geometry, Record<string, string>>[]>
|
||||||
|
|
||||||
|
constructor(provider: Store<GeoCodeResult[]>) {
|
||||||
|
this.features = provider.mapD(geocoded => {
|
||||||
|
const features: Feature[] = []
|
||||||
|
|
||||||
|
for (const gc of geocoded) {
|
||||||
|
if (gc.lat === undefined || gc.lon === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
features.push({
|
||||||
|
type: "Feature",
|
||||||
|
properties: {
|
||||||
|
id: "search_result_" + gc.osm_type + "/" + gc.osm_id,
|
||||||
|
category: gc.category,
|
||||||
|
description: gc.description,
|
||||||
|
display_name: gc.display_name,
|
||||||
|
osm_id: gc.osm_type + "/" + gc.osm_id,
|
||||||
|
osm_key: gc.feature?.properties?.osm_key,
|
||||||
|
osm_value: gc.feature?.properties?.osm_value
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: "Point",
|
||||||
|
coordinates: [gc.lon, gc.lat]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return features
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,8 +2,10 @@ import { BBox } from "../BBox"
|
||||||
import { Feature, Geometry } from "geojson"
|
import { Feature, Geometry } from "geojson"
|
||||||
import { DefaultPinIcon } from "../../Models/Constants"
|
import { DefaultPinIcon } from "../../Models/Constants"
|
||||||
import { Store } from "../UIEventSource"
|
import { Store } from "../UIEventSource"
|
||||||
|
import * as search from "../../assets/generated/layers/search.json"
|
||||||
export type GeocodingCategory = "coordinate" | "city" | "house" | "street" | "locality" | "country" | "train_station" | "county" | "airport"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
|
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
|
export type GeocodingCategory = "coordinate" | "city" | "house" | "street" | "locality" | "country" | "train_station" | "county" | "airport" | "shop"
|
||||||
|
|
||||||
export type GeoCodeResult = {
|
export type GeoCodeResult = {
|
||||||
/**
|
/**
|
||||||
|
@ -66,6 +68,8 @@ export interface ReverseGeocodingProvider {
|
||||||
|
|
||||||
export class GeocodingUtils {
|
export class GeocodingUtils {
|
||||||
|
|
||||||
|
public static searchLayer= new LayerConfig(<LayerConfigJson> search, "search")
|
||||||
|
|
||||||
public static categoryToZoomLevel: Record<GeocodingCategory, number> = {
|
public static categoryToZoomLevel: Record<GeocodingCategory, number> = {
|
||||||
city: 12,
|
city: 12,
|
||||||
county: 10,
|
county: 10,
|
||||||
|
@ -75,7 +79,8 @@ export class GeocodingUtils {
|
||||||
locality: 14,
|
locality: 14,
|
||||||
street: 15,
|
street: 15,
|
||||||
train_station: 14,
|
train_station: 14,
|
||||||
airport: 13
|
airport: 13,
|
||||||
|
shop:16
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +94,8 @@ export class GeocodingUtils {
|
||||||
street: "globe_alt",
|
street: "globe_alt",
|
||||||
train_station: "train",
|
train_station: "train",
|
||||||
county: "building_office_2",
|
county: "building_office_2",
|
||||||
airport: "airport"
|
airport: "airport",
|
||||||
|
shop: "building_storefront"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,9 @@ export default class PhotonSearch implements GeocodingProvider, ReverseGeocoding
|
||||||
|
|
||||||
private getCategory(entry: Feature) {
|
private getCategory(entry: Feature) {
|
||||||
const p = entry.properties
|
const p = entry.properties
|
||||||
|
if(p.osm_key === "shop"){
|
||||||
|
return "shop"
|
||||||
|
}
|
||||||
if (p.osm_value === "train_station" || p.osm_key === "railway") {
|
if (p.osm_value === "train_station" || p.osm_key === "railway") {
|
||||||
return "train_station"
|
return "train_station"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,41 @@ export class RecentSearch {
|
||||||
public readonly seenThisSession: Store<GeoCodeResult[]>
|
public readonly seenThisSession: Store<GeoCodeResult[]>
|
||||||
|
|
||||||
constructor(state: { layout: LayoutConfig, osmConnection: OsmConnection, selectedElement: Store<Feature> }) {
|
constructor(state: { layout: LayoutConfig, osmConnection: OsmConnection, selectedElement: Store<Feature> }) {
|
||||||
// const prefs = state.osmConnection.preferencesHandler.GetLongPreference("previous-searches")
|
const prefs = state.osmConnection.preferencesHandler.GetLongPreference("previous-searches")
|
||||||
|
prefs.addCallbackAndRunD(prev => console.trace("Previous searches are:", prev))
|
||||||
|
prefs.set(null)
|
||||||
this._seenThisSession = new UIEventSource<GeoCodeResult[]>([])//UIEventSource.asObject<GeoCodeResult[]>(prefs, [])
|
this._seenThisSession = new UIEventSource<GeoCodeResult[]>([])//UIEventSource.asObject<GeoCodeResult[]>(prefs, [])
|
||||||
this.seenThisSession = this._seenThisSession
|
this.seenThisSession = this._seenThisSession
|
||||||
|
|
||||||
|
prefs.addCallbackAndRunD(prefs => {
|
||||||
|
if(prefs === ""){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const simpleArr = <GeoCodeResult[]> JSON.parse(prefs)
|
||||||
|
if(simpleArr.length > 0){
|
||||||
|
this._seenThisSession.set(simpleArr)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.seenThisSession.stabilized(2500).addCallbackAndRunD(seen => {
|
||||||
|
const results= []
|
||||||
|
for (let i = 0; i < Math.min(3, seen.length); i++) {
|
||||||
|
const gc = seen[i]
|
||||||
|
const simple = {
|
||||||
|
category: gc.category,
|
||||||
|
description: gc.description,
|
||||||
|
display_name: gc.display_name,
|
||||||
|
lat: gc.lat, lon: gc.lon,
|
||||||
|
osm_id: gc.osm_id,
|
||||||
|
osm_type: gc.osm_type
|
||||||
|
}
|
||||||
|
results.push(simple)
|
||||||
|
}
|
||||||
|
console.log("Setting", results)
|
||||||
|
prefs.setData(JSON.stringify(results))
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
state.selectedElement.addCallbackAndRunD(selected => {
|
state.selectedElement.addCallbackAndRunD(selected => {
|
||||||
|
|
||||||
|
@ -23,6 +54,10 @@ export class RecentSearch {
|
||||||
if(!osm_id){
|
if(!osm_id){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
console.log("Selected element is", selected)
|
||||||
|
if(["node","way","relation"].indexOf(osm_type) < 0){
|
||||||
|
return
|
||||||
|
}
|
||||||
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
|
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
|
||||||
const entry = <GeoCodeResult>{
|
const entry = <GeoCodeResult>{
|
||||||
feature: selected,
|
feature: selected,
|
||||||
|
@ -46,6 +81,7 @@ export class RecentSearch {
|
||||||
seenIds.add(id)
|
seenIds.add(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(">>>",arr)
|
||||||
this._seenThisSession.set(arr)
|
this._seenThisSession.set(arr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ import { UIEventSource } from "../UIEventSource"
|
||||||
import UserDetails, { OsmConnection } from "./OsmConnection"
|
import UserDetails, { OsmConnection } from "./OsmConnection"
|
||||||
import { Utils } from "../../Utils"
|
import { Utils } from "../../Utils"
|
||||||
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
import { LocalStorageSource } from "../Web/LocalStorageSource"
|
||||||
// @ts-ignore
|
import OSMAuthInstance = OSMAuth.osmAuth
|
||||||
import { osmAuth } from "osm-auth"
|
|
||||||
import OSMAuthInstance = OSMAuth.OSMAuthInstance
|
|
||||||
|
|
||||||
export class OsmPreferences {
|
export class OsmPreferences {
|
||||||
/**
|
/**
|
||||||
|
@ -53,7 +51,7 @@ export class OsmPreferences {
|
||||||
const subOptions = { prefix: "" }
|
const subOptions = { prefix: "" }
|
||||||
// Gives the number of combined preferences
|
// Gives the number of combined preferences
|
||||||
const length = this.GetPreference(allStartWith + "-length", "", subOptions)
|
const length = this.GetPreference(allStartWith + "-length", "", subOptions)
|
||||||
|
const preferences = this.preferences
|
||||||
if ((allStartWith + "-length").length > 255) {
|
if ((allStartWith + "-length").length > 255) {
|
||||||
throw (
|
throw (
|
||||||
"This preference key is too long, it has " +
|
"This preference key is too long, it has " +
|
||||||
|
@ -64,7 +62,6 @@ export class OsmPreferences {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const self = this
|
|
||||||
source.addCallback((str) => {
|
source.addCallback((str) => {
|
||||||
if (str === undefined || str === "") {
|
if (str === undefined || str === "") {
|
||||||
return
|
return
|
||||||
|
@ -74,9 +71,9 @@ export class OsmPreferences {
|
||||||
const count = parseInt(length.data)
|
const count = parseInt(length.data)
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
// Delete all the preferences
|
// Delete all the preferences
|
||||||
self.GetPreference(allStartWith + "-" + i, "", subOptions).setData("")
|
this.GetPreference(allStartWith + "-" + i, "", subOptions).setData("")
|
||||||
}
|
}
|
||||||
self.GetPreference(allStartWith + "-length", "", subOptions).setData("")
|
this.GetPreference(allStartWith + "-length", "", subOptions).setData("")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +96,7 @@ export class OsmPreferences {
|
||||||
if (i > 100) {
|
if (i > 100) {
|
||||||
throw "This long preference is getting very long... "
|
throw "This long preference is getting very long... "
|
||||||
}
|
}
|
||||||
self.GetPreference(allStartWith + "-" + i, "", subOptions).setData(
|
this.GetPreference(allStartWith + "-" + i, "", subOptions).setData(
|
||||||
str.substr(0, 255)
|
str.substr(0, 255)
|
||||||
)
|
)
|
||||||
str = str.substr(255)
|
str = str.substr(255)
|
||||||
|
@ -108,8 +105,9 @@ export class OsmPreferences {
|
||||||
length.setData("" + i) // We use I, the number of preference fields used
|
length.setData("" + i) // We use I, the number of preference fields used
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
function updateData(l: number) {
|
function updateData(l: number) {
|
||||||
if (Object.keys(self.preferences.data).length === 0) {
|
if (Object.keys(preferences.data).length === 0) {
|
||||||
// The preferences are still empty - they are not yet updated, so we delay updating for now
|
// The preferences are still empty - they are not yet updated, so we delay updating for now
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -120,15 +118,21 @@ export class OsmPreferences {
|
||||||
let str = ""
|
let str = ""
|
||||||
for (let i = 0; i < prefsCount; i++) {
|
for (let i = 0; i < prefsCount; i++) {
|
||||||
const key = allStartWith + "-" + i
|
const key = allStartWith + "-" + i
|
||||||
if (self.preferences.data[key] === undefined) {
|
if (preferences.data[key] === undefined) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"Detected a broken combined preference:",
|
"Detected a broken combined preference:",
|
||||||
key,
|
key,
|
||||||
"is undefined",
|
"is undefined",
|
||||||
self.preferences
|
preferences
|
||||||
)
|
)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
str += self.preferences.data[key] ?? ""
|
const v = preferences.data[key]
|
||||||
|
if(v === "undefined"){
|
||||||
|
delete preferences.data[key]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
str += preferences.data[key] ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
source.setData(str)
|
source.setData(str)
|
||||||
|
@ -137,7 +141,7 @@ export class OsmPreferences {
|
||||||
length.addCallback((l) => {
|
length.addCallback((l) => {
|
||||||
updateData(Number(l))
|
updateData(Number(l))
|
||||||
})
|
})
|
||||||
this.preferences.addCallbackAndRun((_) => {
|
this.preferences.addCallbackAndRun(() => {
|
||||||
updateData(Number(length.data))
|
updateData(Number(length.data))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -159,7 +163,7 @@ export class OsmPreferences {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
key = prefix + key
|
key = prefix + key
|
||||||
key = key.replace(/[:\\\/"' {}.%]/g, "")
|
key = key.replace(/[:/"' {}.%\\]/g, "")
|
||||||
if (key.length >= 255) {
|
if (key.length >= 255) {
|
||||||
throw "Preferences: key length to big"
|
throw "Preferences: key length to big"
|
||||||
}
|
}
|
||||||
|
@ -193,7 +197,6 @@ export class OsmPreferences {
|
||||||
|
|
||||||
public ClearPreferences() {
|
public ClearPreferences() {
|
||||||
let isRunning = false
|
let isRunning = false
|
||||||
const self = this
|
|
||||||
this.preferences.addCallback((prefs) => {
|
this.preferences.addCallback((prefs) => {
|
||||||
console.log("Cleaning preferences...")
|
console.log("Cleaning preferences...")
|
||||||
if (Object.keys(prefs).length == 0) {
|
if (Object.keys(prefs).length == 0) {
|
||||||
|
@ -208,7 +211,7 @@ export class OsmPreferences {
|
||||||
const matches = prefixes.some((prefix) => key.startsWith(prefix))
|
const matches = prefixes.some((prefix) => key.startsWith(prefix))
|
||||||
if (matches) {
|
if (matches) {
|
||||||
console.log("Clearing ", key)
|
console.log("Clearing ", key)
|
||||||
self.GetPreference(key, "", { prefix: "" }).setData("")
|
this.GetPreference(key, "", { prefix: "" }).setData("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isRunning = false
|
isRunning = false
|
||||||
|
@ -227,7 +230,6 @@ export class OsmPreferences {
|
||||||
}
|
}
|
||||||
|
|
||||||
private UpdatePreferences(forceUpdate?: boolean) {
|
private UpdatePreferences(forceUpdate?: boolean) {
|
||||||
const self = this
|
|
||||||
if (this._fakeUser) {
|
if (this._fakeUser) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -236,7 +238,7 @@ export class OsmPreferences {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/api/0.6/user/preferences",
|
path: "/api/0.6/user/preferences",
|
||||||
},
|
},
|
||||||
function (error, value: XMLDocument) {
|
(error, value: XMLDocument) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log("Could not load preferences", error)
|
console.log("Could not load preferences", error)
|
||||||
return
|
return
|
||||||
|
@ -246,34 +248,33 @@ export class OsmPreferences {
|
||||||
for (let i = 0; i < prefs.length; i++) {
|
for (let i = 0; i < prefs.length; i++) {
|
||||||
const pref = prefs[i]
|
const pref = prefs[i]
|
||||||
const k = pref.getAttribute("k")
|
const k = pref.getAttribute("k")
|
||||||
const v = pref.getAttribute("v")
|
this.preferences.data[k] = pref.getAttribute("v")
|
||||||
self.preferences.data[k] = v
|
|
||||||
seenKeys.add(k)
|
seenKeys.add(k)
|
||||||
}
|
}
|
||||||
if (forceUpdate) {
|
if (forceUpdate) {
|
||||||
for (let key in self.preferences.data) {
|
for (const key in this.preferences.data) {
|
||||||
if (seenKeys.has(key)) {
|
if (seenKeys.has(key)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
console.log("Deleting key", key, "as we didn't find it upstream")
|
console.log("Deleting key", key, "as we didn't find it upstream")
|
||||||
delete self.preferences.data[key]
|
delete this.preferences.data[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We merge all the preferences: new keys are uploaded
|
// We merge all the preferences: new keys are uploaded
|
||||||
// For differing values, the server overrides local changes
|
// For differing values, the server overrides local changes
|
||||||
self.preferenceSources.forEach((preference, key) => {
|
this.preferenceSources.forEach((preference, key) => {
|
||||||
const osmValue = self.preferences.data[key]
|
const osmValue = this.preferences.data[key]
|
||||||
if (osmValue === undefined && preference.data !== undefined) {
|
if (osmValue === undefined && preference.data !== undefined) {
|
||||||
// OSM doesn't know this value yet
|
// OSM doesn't know this value yet
|
||||||
self.UploadPreference(key, preference.data)
|
this.UploadPreference(key, preference.data)
|
||||||
} else {
|
} else {
|
||||||
// OSM does have a value - set it
|
// OSM does have a value - set it
|
||||||
preference.setData(osmValue)
|
preference.setData(osmValue)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.preferences.ping()
|
this.preferences.ping()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -287,7 +288,6 @@ export class OsmPreferences {
|
||||||
if (this.preferences.data[k] === v) {
|
if (this.preferences.data[k] === v) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const self = this
|
|
||||||
console.debug("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15))
|
console.debug("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15))
|
||||||
if (this._fakeUser) {
|
if (this._fakeUser) {
|
||||||
return
|
return
|
||||||
|
@ -299,13 +299,13 @@ export class OsmPreferences {
|
||||||
path: "/api/0.6/user/preferences/" + encodeURIComponent(k),
|
path: "/api/0.6/user/preferences/" + encodeURIComponent(k),
|
||||||
headers: { "Content-Type": "text/plain" },
|
headers: { "Content-Type": "text/plain" },
|
||||||
},
|
},
|
||||||
function (error) {
|
(error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.warn("Could not remove preference", error)
|
console.warn("Could not remove preference", error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delete self.preferences.data[k]
|
delete this.preferences.data[k]
|
||||||
self.preferences.ping()
|
this.preferences.ping()
|
||||||
console.debug("Preference ", k, "removed!")
|
console.debug("Preference ", k, "removed!")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -319,13 +319,13 @@ export class OsmPreferences {
|
||||||
headers: { "Content-Type": "text/plain" },
|
headers: { "Content-Type": "text/plain" },
|
||||||
content: v,
|
content: v,
|
||||||
},
|
},
|
||||||
function (error) {
|
(error)=> {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.warn(`Could not set preference "${k}"'`, error)
|
console.warn(`Could not set preference "${k}"'`, error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.preferences.data[k] = v
|
this.preferences.data[k] = v
|
||||||
self.preferences.ping()
|
this.preferences.ping()
|
||||||
console.debug(`Preference ${k} written!`)
|
console.debug(`Preference ${k} written!`)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -351,8 +351,10 @@ export default class UserRelatedState {
|
||||||
const key = k.substring(0, k.length - "length".length)
|
const key = k.substring(0, k.length - "length".length)
|
||||||
let combined = ""
|
let combined = ""
|
||||||
for (let i = 0; i < l; i++) {
|
for (let i = 0; i < l; i++) {
|
||||||
combined += newPrefs[key + i]
|
console.log("Building preference:",key,i,">>>", newPrefs[key + i], "<<<", newPrefs, )
|
||||||
|
combined += (newPrefs[key + i])
|
||||||
}
|
}
|
||||||
|
console.log("Combined",key,">>>",combined)
|
||||||
amendedPrefs.data[key.substring(0, key.length - "-combined-".length)] = combined
|
amendedPrefs.data[key.substring(0, key.length - "-combined-".length)] = combined
|
||||||
} else {
|
} else {
|
||||||
amendedPrefs.data[k] = newPrefs[k]
|
amendedPrefs.data[k] = newPrefs[k]
|
||||||
|
@ -456,11 +458,15 @@ export default class UserRelatedState {
|
||||||
amendedPrefs.addCallbackD((tags) => {
|
amendedPrefs.addCallbackD((tags) => {
|
||||||
for (const key in tags) {
|
for (const key in tags) {
|
||||||
if (key.startsWith("_") || key === "mapcomplete-language") {
|
if (key.startsWith("_") || key === "mapcomplete-language") {
|
||||||
// Language is managed seperately
|
// Language is managed separately
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (tags[key + "-combined-0"]) {
|
if (tags[key + "-combined-0"]) {
|
||||||
// A combined value exists
|
// A combined value exists
|
||||||
|
if(tags[key].startsWith("undefined")){
|
||||||
|
// Sometimes, a long string of 'undefined' will show up, we ignore them
|
||||||
|
continue
|
||||||
|
}
|
||||||
this.osmConnection.GetLongPreference(key, "").setData(tags[key])
|
this.osmConnection.GetLongPreference(key, "").setData(tags[key])
|
||||||
} else {
|
} else {
|
||||||
this.osmConnection
|
this.osmConnection
|
||||||
|
|
|
@ -91,6 +91,20 @@ export class Stores {
|
||||||
})
|
})
|
||||||
return stable
|
return stable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Constructs a new store, but tries to keep the value 'defined'
|
||||||
|
* If a defined value was in the stream once, a defined value will be returned
|
||||||
|
* @param store
|
||||||
|
*/
|
||||||
|
static holdDefined<T>(store: Store<T | undefined>): Store<T | undefined> {
|
||||||
|
const newStore = new UIEventSource(store.data)
|
||||||
|
store.addCallbackD(t => {
|
||||||
|
newStore.setData(t)
|
||||||
|
})
|
||||||
|
return newStore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class Store<T> implements Readable<T> {
|
export abstract class Store<T> implements Readable<T> {
|
||||||
|
|
|
@ -26,6 +26,7 @@ export default class Constants {
|
||||||
"last_click",
|
"last_click",
|
||||||
"favourite",
|
"favourite",
|
||||||
"summary",
|
"summary",
|
||||||
|
"search"
|
||||||
] as const
|
] as const
|
||||||
/**
|
/**
|
||||||
* Special layers which are not included in a theme by default
|
* Special layers which are not included in a theme by default
|
||||||
|
@ -38,7 +39,7 @@ export default class Constants {
|
||||||
"import_candidate",
|
"import_candidate",
|
||||||
"usersettings",
|
"usersettings",
|
||||||
"icons",
|
"icons",
|
||||||
"filters",
|
"filters"
|
||||||
] as const
|
] as const
|
||||||
/**
|
/**
|
||||||
* Layer IDs of layers which have special properties through built-in hooks
|
* Layer IDs of layers which have special properties through built-in hooks
|
||||||
|
@ -126,6 +127,7 @@ export default class Constants {
|
||||||
"brick_wall_round",
|
"brick_wall_round",
|
||||||
"brick_wall_square",
|
"brick_wall_square",
|
||||||
"building_office_2",
|
"building_office_2",
|
||||||
|
"building_storefront",
|
||||||
"bug",
|
"bug",
|
||||||
"checkmark",
|
"checkmark",
|
||||||
"checkmark",
|
"checkmark",
|
||||||
|
|
|
@ -340,7 +340,7 @@ export default class LayoutConfig implements LayoutInformation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("Fallthrough", this, tags)
|
console.trace("Fallthrough: could not find the appropraite layer for an object with tags", tags, "within layout", this)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ export default class LayoutConfig implements LayoutInformation {
|
||||||
...json,
|
...json,
|
||||||
layers: json.layers.filter((l) => l["id"] !== "favourite"),
|
layers: json.layers.filter((l) => l["id"] !== "favourite"),
|
||||||
}
|
}
|
||||||
const usedImages = json._usedImages
|
const usedImages = jsonNoFavourites._usedImages
|
||||||
usedImages.sort()
|
usedImages.sort()
|
||||||
|
|
||||||
this.usedImages = Utils.Dedup(usedImages)
|
this.usedImages = Utils.Dedup(usedImages)
|
||||||
|
|
|
@ -68,7 +68,7 @@ import Locale from "../UI/i18n/Locale"
|
||||||
import Hash from "../Logic/Web/Hash"
|
import Hash from "../Logic/Web/Hash"
|
||||||
import { GeoOperations } from "../Logic/GeoOperations"
|
import { GeoOperations } from "../Logic/GeoOperations"
|
||||||
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
||||||
import GeocodingProvider from "../Logic/Geocoding/GeocodingProvider"
|
import GeocodingProvider, { GeocodingUtils } from "../Logic/Geocoding/GeocodingProvider"
|
||||||
import CombinedSearcher from "../Logic/Geocoding/CombinedSearcher"
|
import CombinedSearcher from "../Logic/Geocoding/CombinedSearcher"
|
||||||
import CoordinateSearch from "../Logic/Geocoding/CoordinateSearch"
|
import CoordinateSearch from "../Logic/Geocoding/CoordinateSearch"
|
||||||
import LocalElementSearch from "../Logic/Geocoding/LocalElementSearch"
|
import LocalElementSearch from "../Logic/Geocoding/LocalElementSearch"
|
||||||
|
@ -774,6 +774,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
favourite: this.favourites,
|
favourite: this.favourites,
|
||||||
summary: this.featureSummary,
|
summary: this.featureSummary,
|
||||||
last_click: this.lastClickObject,
|
last_click: this.lastClickObject,
|
||||||
|
search: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closestFeatures.registerSource(specialLayers.favourite, "favourite")
|
this.closestFeatures.registerSource(specialLayers.favourite, "favourite")
|
||||||
|
@ -910,6 +911,34 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
this.selectedElement.setData(this.currentView.features?.data?.[0])
|
this.selectedElement.setData(this.currentView.features?.data?.[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches the appropriate layer - will first try if a special layer matches; if not, a normal layer will be used by delegating to the layout
|
||||||
|
* @param tags
|
||||||
|
*/
|
||||||
|
public getMatchingLayer(properties: Record<string, string>){
|
||||||
|
|
||||||
|
const id = properties.id
|
||||||
|
|
||||||
|
if (id.startsWith("summary_")) {
|
||||||
|
// We don't select 'summary'-objects
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id === "settings") {
|
||||||
|
return UserRelatedState.usersettingsConfig
|
||||||
|
}
|
||||||
|
if (id.startsWith(LastClickFeatureSource.newPointElementId)) {
|
||||||
|
return this.layout.layers.find((l) => l.id === "last_click")
|
||||||
|
}
|
||||||
|
if (id.startsWith("search_result")) {
|
||||||
|
return GeocodingUtils.searchLayer
|
||||||
|
}
|
||||||
|
if (id === "location_track") {
|
||||||
|
return this.layout.layers.find((l) => l.id === "gps_track")
|
||||||
|
}
|
||||||
|
return this.layout.getMatchingLayer(properties)
|
||||||
|
}
|
||||||
|
|
||||||
public async reportError(message: string | Error | XMLHttpRequest) {
|
public async reportError(message: string | Error | XMLHttpRequest) {
|
||||||
const isTesting = this.featureSwitchIsTesting.data
|
const isTesting = this.featureSwitchIsTesting.data
|
||||||
console.log(
|
console.log(
|
||||||
|
|
|
@ -7,23 +7,17 @@
|
||||||
import { LastClickFeatureSource } from "../../Logic/FeatureSource/Sources/LastClickFeatureSource"
|
import { LastClickFeatureSource } from "../../Logic/FeatureSource/Sources/LastClickFeatureSource"
|
||||||
import Loading from "./Loading.svelte"
|
import Loading from "./Loading.svelte"
|
||||||
import { onDestroy } from "svelte"
|
import { onDestroy } from "svelte"
|
||||||
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
|
import { GeocodingUtils } from "../../Logic/Geocoding/GeocodingProvider"
|
||||||
|
import ThemeViewState from "../../Models/ThemeViewState"
|
||||||
|
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
export let selected: Feature
|
export let selected: Feature
|
||||||
let tags = state.featureProperties.getStore(selected.properties.id)
|
let tags = state.featureProperties.getStore(selected.properties.id)
|
||||||
|
|
||||||
export let absolute = true
|
export let absolute = true
|
||||||
function getLayer(properties: Record<string, string>) {
|
function getLayer(properties: Record<string, string>): LayerConfig {
|
||||||
if (properties.id === "settings") {
|
return state.getMatchingLayer(properties)
|
||||||
return UserRelatedState.usersettingsConfig
|
|
||||||
}
|
|
||||||
if (properties.id.startsWith(LastClickFeatureSource.newPointElementId)) {
|
|
||||||
return state.layout.layers.find((l) => l.id === "last_click")
|
|
||||||
}
|
|
||||||
if (properties.id === "location_track") {
|
|
||||||
return state.layout.layers.find((l) => l.id === "gps_track")
|
|
||||||
}
|
|
||||||
return state.layout.getMatchingLayer(properties)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let layer = getLayer(selected.properties)
|
let layer = getLayer(selected.properties)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import type { Feature } from "geojson"
|
import type { Feature } from "geojson"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import Loading from "../Base/Loading.svelte"
|
import Loading from "../Base/Loading.svelte"
|
||||||
|
@ -17,10 +17,14 @@
|
||||||
import type GeocodingProvider from "../../Logic/Geocoding/GeocodingProvider"
|
import type GeocodingProvider from "../../Logic/Geocoding/GeocodingProvider"
|
||||||
|
|
||||||
import SearchResults from "./SearchResults.svelte"
|
import SearchResults from "./SearchResults.svelte"
|
||||||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
|
||||||
import MoreScreen from "./MoreScreen"
|
import MoreScreen from "./MoreScreen"
|
||||||
import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig"
|
||||||
import { focusWithArrows } from "../../Utils/focusWithArrows"
|
import { focusWithArrows } from "../../Utils/focusWithArrows"
|
||||||
|
import ShowDataLayer from "../Map/ShowDataLayer"
|
||||||
|
import ThemeViewState from "../../Models/ThemeViewState"
|
||||||
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
|
import GeocodingFeatureSource from "../../Logic/Geocoding/GeocodingFeatureSource"
|
||||||
|
import type { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson.js"
|
||||||
|
|
||||||
export let perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer> | undefined = undefined
|
export let perLayer: ReadonlyMap<string, GeoIndexedStoreForLayer> | undefined = undefined
|
||||||
export let bounds: UIEventSource<BBox>
|
export let bounds: UIEventSource<BBox>
|
||||||
|
@ -29,11 +33,11 @@
|
||||||
export let geolocationState: GeoLocationState | undefined = undefined
|
export let geolocationState: GeoLocationState | undefined = undefined
|
||||||
export let clearAfterView: boolean = true
|
export let clearAfterView: boolean = true
|
||||||
export let searcher: GeocodingProvider = new NominatimGeocoding()
|
export let searcher: GeocodingProvider = new NominatimGeocoding()
|
||||||
export let state: SpecialVisualizationState
|
export let state: ThemeViewState
|
||||||
let searchContents: UIEventSource<string> = new UIEventSource<string>("")
|
let searchContents: UIEventSource<string> = new UIEventSource<string>("")
|
||||||
export let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined)
|
export let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined)
|
||||||
onDestroy(
|
onDestroy(
|
||||||
triggerSearch.addCallback((_) => {
|
triggerSearch.addCallback(() => {
|
||||||
performSearch()
|
performSearch()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -139,7 +143,18 @@
|
||||||
if (search.length === 0) {
|
if (search.length === 0) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return searcher.suggest(search, { bbox: bounds.data })
|
return Stores.holdDefined(bounds.bindD(bbox => searcher.suggest(search, { bbox, limit: 15 })))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
let geocededFeatures= new GeocodingFeatureSource(suggestions.stabilized(250))
|
||||||
|
state.featureProperties.trackFeatureSource(geocededFeatures)
|
||||||
|
|
||||||
|
new ShowDataLayer(
|
||||||
|
state.map,
|
||||||
|
{
|
||||||
|
layer: GeocodingUtils.searchLayer,
|
||||||
|
features: geocededFeatures,
|
||||||
|
selectedElement: state.selectedElement
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -147,7 +162,7 @@
|
||||||
|
|
||||||
function checkFocus() {
|
function checkFocus() {
|
||||||
window.requestAnimationFrame(() => {
|
window.requestAnimationFrame(() => {
|
||||||
if (geosearch.contains(document.activeElement)) {
|
if (geosearch?.contains(document.activeElement)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
isFocused.setData(false)
|
isFocused.setData(false)
|
||||||
|
@ -159,7 +174,6 @@
|
||||||
}, true /* use 'capturing' instead of bubbling, needed for focus-events*/)
|
}, true /* use 'capturing' instead of bubbling, needed for focus-events*/)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={geosearch} use:focusWithArrows={"searchresult"}>
|
<div bind:this={geosearch} use:focusWithArrows={"searchresult"}>
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
import BuildingOffice2 from "@babeard/svelte-heroicons/outline/BuildingOffice2"
|
import BuildingOffice2 from "@babeard/svelte-heroicons/outline/BuildingOffice2"
|
||||||
import Train from "../../assets/svg/Train.svelte"
|
import Train from "../../assets/svg/Train.svelte"
|
||||||
import Airport from "../../assets/svg/Airport.svelte"
|
import Airport from "../../assets/svg/Airport.svelte"
|
||||||
|
import BuildingStorefront from "@babeard/svelte-heroicons/outline/BuildingStorefront"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a single icon.
|
* Renders a single icon.
|
||||||
|
@ -159,6 +160,8 @@
|
||||||
<Train {color} class={clss}/>
|
<Train {color} class={clss}/>
|
||||||
{:else if icon === "airport"}
|
{:else if icon === "airport"}
|
||||||
<Airport {color} class={clss}/>
|
<Airport {color} class={clss}/>
|
||||||
|
{:else if icon === "building_storefront"}
|
||||||
|
<BuildingStorefront {color} class={clss}/>
|
||||||
{:else if Utils.isEmoji(icon)}
|
{:else if Utils.isEmoji(icon)}
|
||||||
<span style={`font-size: ${emojiHeight}px; line-height: ${emojiHeight}px`}>
|
<span style={`font-size: ${emojiHeight}px; line-height: ${emojiHeight}px`}>
|
||||||
{icon}
|
{icon}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import LayoutConfig, { MinimalLayoutInformation } from "../Models/ThemeConfig/La
|
||||||
import {
|
import {
|
||||||
FeatureSource,
|
FeatureSource,
|
||||||
IndexedFeatureSource,
|
IndexedFeatureSource,
|
||||||
WritableFeatureSource,
|
WritableFeatureSource
|
||||||
} from "../Logic/FeatureSource/FeatureSource"
|
} from "../Logic/FeatureSource/FeatureSource"
|
||||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||||
import { Changes } from "../Logic/Osm/Changes"
|
import { Changes } from "../Logic/Osm/Changes"
|
||||||
|
@ -97,8 +97,10 @@ export interface SpecialVisualizationState {
|
||||||
readonly geolocation: GeoLocationHandler
|
readonly geolocation: GeoLocationHandler
|
||||||
readonly recentlySearched: RecentSearch
|
readonly recentlySearched: RecentSearch
|
||||||
|
|
||||||
|
getMatchingLayer(properties: Record<string, string>);
|
||||||
|
|
||||||
showCurrentLocationOn(map: Store<MlMap>): ShowDataLayer
|
showCurrentLocationOn(map: Store<MlMap>): ShowDataLayer
|
||||||
|
|
||||||
reportError(message: string): Promise<void>
|
reportError(message: string): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
HeartIcon,
|
HeartIcon,
|
||||||
MenuIcon,
|
MenuIcon,
|
||||||
XCircleIcon,
|
XCircleIcon
|
||||||
} from "@rgossiaux/svelte-heroicons/solid"
|
} from "@rgossiaux/svelte-heroicons/solid"
|
||||||
import Tr from "./Base/Tr.svelte"
|
import Tr from "./Base/Tr.svelte"
|
||||||
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"
|
import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"
|
||||||
|
@ -72,6 +72,7 @@
|
||||||
import HotkeyTable from "./BigComponents/HotkeyTable.svelte"
|
import HotkeyTable from "./BigComponents/HotkeyTable.svelte"
|
||||||
import SelectedElementPanel from "./Base/SelectedElementPanel.svelte"
|
import SelectedElementPanel from "./Base/SelectedElementPanel.svelte"
|
||||||
import type { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
|
import type { LayerConfigJson } from "../Models/ThemeConfig/Json/LayerConfigJson"
|
||||||
|
import { GeocodingUtils } from "../Logic/Geocoding/GeocodingProvider"
|
||||||
|
|
||||||
export let state: ThemeViewState
|
export let state: ThemeViewState
|
||||||
let layout = state.layout
|
let layout = state.layout
|
||||||
|
@ -98,22 +99,10 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
let selectedLayer: Store<LayerConfig> = state.selectedElement.mapD((element) => {
|
let selectedLayer: Store<LayerConfig> = state.selectedElement.mapD((element) => {
|
||||||
const id = element.properties.id
|
if (element.properties.id.startsWith("current_view")) {
|
||||||
if (id.startsWith("current_view")) {
|
|
||||||
return currentViewLayer
|
return currentViewLayer
|
||||||
}
|
}
|
||||||
if (id.startsWith("summary_")) {
|
return state.getMatchingLayer(element.properties)
|
||||||
console.log("Not selecting a summary object. The summary object is", element)
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (id.startsWith(LastClickFeatureSource.newPointElementId)) {
|
|
||||||
return layout.layers.find((l) => l.id === "last_click")
|
|
||||||
}
|
|
||||||
if (id === "location_track") {
|
|
||||||
return layout.layers.find((l) => l.id === "gps_track")
|
|
||||||
}
|
|
||||||
|
|
||||||
return state.layout.getMatchingLayer(element.properties)
|
|
||||||
})
|
})
|
||||||
let currentZoom = state.mapProperties.zoom
|
let currentZoom = state.mapProperties.zoom
|
||||||
let showCrosshair = state.userRelatedState.showCrosshair
|
let showCrosshair = state.userRelatedState.showCrosshair
|
||||||
|
@ -144,7 +133,7 @@
|
||||||
const bottomRight = mlmap.unproject([rect.right, rect.bottom])
|
const bottomRight = mlmap.unproject([rect.right, rect.bottom])
|
||||||
const bbox = new BBox([
|
const bbox = new BBox([
|
||||||
[topLeft.lng, topLeft.lat],
|
[topLeft.lng, topLeft.lat],
|
||||||
[bottomRight.lng, bottomRight.lat],
|
[bottomRight.lng, bottomRight.lat]
|
||||||
])
|
])
|
||||||
state.visualFeedbackViewportBounds.setData(bbox)
|
state.visualFeedbackViewportBounds.setData(bbox)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue