forked from MapComplete/MapComplete
Feat: Use panoramax to upload to. Will contain bugs
This commit is contained in:
parent
cf74296d23
commit
0bdc1aec61
19 changed files with 325 additions and 193 deletions
|
@ -498,75 +498,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "picture-license",
|
||||
"description": "This question is not meant to be placed on an OpenStreetMap-element; however it is used in the user information panel to ask which license the user wants",
|
||||
"question": {
|
||||
"en": "Under what license do you want to publish your pictures?",
|
||||
"de": "Unter welcher Lizenz möchten Sie Ihre Bilder veröffentlichen?",
|
||||
"nl": "Met welke licentie wil je je afbeeldingen toevoegen?",
|
||||
"ca": "Sota quina llicència vols publicar les teves fotos?",
|
||||
"pt": "Sob que licença você deseja publicar suas fotos?",
|
||||
"cs": "Pod jakou licencí chcete své fotografie zveřejnit?",
|
||||
"da": "Under hvilken licens vil du frigive dine billeder?"
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "mapcomplete-pictures-license=",
|
||||
"icon": "./assets/layers/usersettings/scale.svg",
|
||||
"then": {
|
||||
"en": "Pictures you take will be licensed with <b>CC0</b> and added to the public domain. This means that everyone can use your pictures for any purpose. <span class='subtle'>This is the default choice.</span>",
|
||||
"de": "Die von Ihnen aufgenommenen Bilder werden mit <b>CC0</b> lizenziert und der Public Domain hinzugefügt. Das bedeutet, dass jeder Ihre Bilder für jeden Zweck verwenden kann. <span class='subtle'>Dies ist die Standardeinstellung.</span>",
|
||||
"nl": "Afbeeldingen die je toevoegt zullen gepubliceerd worden met de <b>CC0</b>-licentie en dus aan het publieke domein toegevoegd worden. Dit betekent dat iedereen je afbeeldingen kan gebruiken voor elk mogelijks gebruik. <span class='subtle'>Dit is de standaard-instelling</span>",
|
||||
"cs": "Pořízené fotografie budou licencovány pod <b>CC0</b> a přidány do veřejné domény. To znamená, že kdokoli může vaše snímky použít k jakémukoli účelu. <span class='subtle'>Toto je výchozí volba.</span>",
|
||||
"ca": "Les imatges que feu tindran llicència <b>CC0</b> i s'afegiran al domini públic. Això vol dir que tothom pot utilitzar les vostres imatges per a qualsevol propòsit. <span class='subtle'>Aquesta és l'opció predeterminada. </span>",
|
||||
"pt": "As fotos que você tirar serão licenciadas com <b>CC0</b> e adicionadas ao domínio público. Isso significa que todos podem usar suas fotos para qualquer finalidade. <span class='subtle'>Esta é a escolha padrão.</span>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
{
|
||||
"if": "mapcomplete-pictures-license=CC0",
|
||||
"icon": "./assets/layers/usersettings/scale.svg",
|
||||
"then": {
|
||||
"en": "Pictures you take will be licensed with <b>CC0</b> and added to the public domain. This means that everyone can use your pictures for any purpose.",
|
||||
"de": "Ihre aufgenommenen Bilder werden mit <b>CC0</b> lizenziert und der Public Domain hinzugefügt. Das bedeutet, dass jeder Ihre Bilder für jeden Zweck verwenden kann.",
|
||||
"nl": "Afbeeldingen die je toevoegt zullen gepubliceerd worden met de <b>CC0</b>-licentie en dus aan het publieke domein toegevoegd worden. Dit betekent dat iedereen je afbeeldingen kan gebruiken voor elk mogelijks gebruik.",
|
||||
"ru": "Изображения будут опубликованы под лицензией <b>CC0</b> и перейдут в общественное достояние. Это значит, что кто угодно имеет право использовать их без ограничений.",
|
||||
"cs": "Pořízené fotografie budou licencovány pod <b>CC0</b> a přidány do veřejné domény. To znamená, že kdokoli může vaše snímky použít k jakémukoli účelu.",
|
||||
"ca": "Les imatges que feu tindran llicència <b>CC0</b> i s'afegiran al domini públic. Això vol dir que tothom pot utilitzar les vostres imatges per a qualsevol propòsit.",
|
||||
"es": "Las fotografías que tome tendrán una licencia con <b>CC0</b> y se agregarán al dominio público. Esto significa que todos pueden usar sus imágenes para cualquier propósito.",
|
||||
"pt": "As fotos que você tirar serão licenciadas com <b>CC0</b> e adicionadas ao domínio público. Isso significa que todos podem usar suas fotos para qualquer finalidade.",
|
||||
"da": "Billeder, som du har taget, vil blive udgivet under <b>CC0</b>-licensen og lagt ud i fælleseje. Det betyder, at alle kan bruge dine billeder til ethvert formål.",
|
||||
"fr": "Les photos que vous avez ajoutées seront sous licence <b>CC0</b> et mises dans le domaine public. Cela signifie que n'importe qui pourra les utiliser, quel qu'en soit l'usage."
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "mapcomplete-pictures-license=CC-BY 4.0",
|
||||
"icon": "./assets/layers/usersettings/scale.svg",
|
||||
"then": {
|
||||
"en": "Pictures you take will be licensed with <b>CC-BY 4.0</b> which requires everyone using your picture that they have to attribute you",
|
||||
"ca": "Les fotografies que facis es publicaran sota <b>CC-BY 4.0</b> que requereix que qualsevol que utilitzi la vostra imatge us ha de donar crèdits",
|
||||
"de": "Die von Ihnen aufgenommenen Bilder werden mit <b>CC-BY 4.0</b> lizenziert, was bedeutet, dass jeder, der Ihr Bild verwendet, Sie als Urheber nennen muss",
|
||||
"nl": "Afbeeldingen die je toevoegt zullen gepubliceerd worden met de <b>CC-BY 4.0</b>-licentie. Dit betekent dat iedereen je afbeelding mag gebruiken voor elke toepassing mits het vermelden van je naam",
|
||||
"cs": "Pořízené fotografie budou licencovány pod <b>CC-BY 4.0</b>, což vyžaduje, aby vás uvedl každý, kdo použije vaší fotku",
|
||||
"pt": "As fotos que você tirar serão licenciadas com <b>CC-BY 4.0</b>, que exige que todos que usam sua foto atribuam a você"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "mapcomplete-pictures-license=CC-BY-SA 4.0",
|
||||
"icon": "./assets/layers/usersettings/scale.svg",
|
||||
"then": {
|
||||
"en": "Pictures you take will be licensed with <b>CC-BY-SA 4.0</b> which means that everyone using your picture must attribute you and that derivatives of your picture must be reshared with the same license.",
|
||||
"de": "Die von Ihnen aufgenommenen Bilder werden mit <b>CC-BY-SA 4.0</b> lizenziert, was bedeutet, dass jeder, der Ihr Bild verwendet, Sie als Urheber nennen muss und dass Ableitungen Ihres Bildes mit der gleichen Lizenz weitergegeben werden müssen.",
|
||||
"nl": "Afbeeldingen die je toevoegt zullen gepubliceerd worden met de <b>CC-BY-SA 4.0</b>-licentie. Dit betekent dat iedereen je afbeelding mag gebruiken voor elke toepassing mits het vermelden van je naam en dat afgeleide werken van je afbeelding ook ondere deze licentie moeten gepubliceerd worden.",
|
||||
"cs": "Pořízené fotografie budou licencovány pod <b>CC-BY-SA 4.0</b>, což vyžaduje, aby vás uvedl každý, kdo použije vaší fotku a že odvozené fotky musí být dále sdíleny se stejnou licencí.",
|
||||
"ca": "Les imatges que feu tindran una llicència amb <b>CC-BY-SA 4.0</b> el que significa que tothom que utilitzi la vostra imatge us ha d'atribuir i que els derivats de la vostra imatge s'han de tornar a compartir amb la mateixa llicència.",
|
||||
"fr": "Les photos que vous prenez seront sous la licence <b>CC-BY-SA 4.0</b> ce qui signifie que quiconque utilisant votre photo doit vous créditer et que les modifications apportées à votre photo doivent être repartagées avec la même licence.",
|
||||
"pt": "As fotos que você tirar serão licenciadas com <b>CC-BY-SA 4.0</b>, o que significa que todos que usarem sua foto devem atribuí-lo e que os derivados de sua foto devem ser compartilhados novamente com a mesma licença."
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"id": "show_tags",
|
||||
"question": {
|
||||
|
|
|
@ -577,7 +577,7 @@
|
|||
"title": "Nearby streetview imagery"
|
||||
},
|
||||
"pleaseLogin": "Please log in to add a picture",
|
||||
"respectPrivacy": "Do not photograph people nor license plates. Do not upload Google Maps, Google Streetview or other copyrighted sources.",
|
||||
"respectPrivacy": "Do not upload Google Maps, Google Streetview or other copyrighted sources.",
|
||||
"toBig": "Your image is too large as it is {actual_size}. Please use images of at most {max_size}",
|
||||
"upload": {
|
||||
"failReasons": "You might have lost connection to the internet",
|
||||
|
|
84
package-lock.json
generated
84
package-lock.json
generated
|
@ -39,6 +39,7 @@
|
|||
"dompurify": "^3.0.5",
|
||||
"email-validator": "^2.0.4",
|
||||
"escape-html": "^1.0.3",
|
||||
"exifreader": "^4.23.5",
|
||||
"fake-dom": "^1.0.4",
|
||||
"flowbite-svelte": "^0.46.2",
|
||||
"follow-redirects": "^1.15.6",
|
||||
|
@ -62,6 +63,7 @@
|
|||
"opening_hours": "^3.6.0",
|
||||
"osm-auth": "^2.5.0",
|
||||
"osmtogeojson": "^3.0.0-beta.5",
|
||||
"panoramax-js": "^0.1.1",
|
||||
"panzoom": "^9.4.3",
|
||||
"papaparse": "^5.3.1",
|
||||
"pbf": "^3.2.1",
|
||||
|
@ -4908,6 +4910,19 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@ogcapi-js/features": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ogcapi-js/features/-/features-1.1.1.tgz",
|
||||
"integrity": "sha512-/w6kFvAXWO+F0/nLC5m11tuOw0LX+gVz/OCLiDkElXO9ko9F9OA3AbzKZxJaE5Buu0KUGn+TRxS6w1xhZc4KRA==",
|
||||
"dependencies": {
|
||||
"@ogcapi-js/shared": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@ogcapi-js/shared": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ogcapi-js/shared/-/shared-1.1.1.tgz",
|
||||
"integrity": "sha512-EQ6T4iVXwIMnBcdpR2C0YnNNCxtNWHpWg0Hs9uEvH4BPZI2xT87gV+WRw8/hYAe8EtrK6j57iluBoSyHiAQweQ=="
|
||||
},
|
||||
"node_modules/@parcel/service-worker": {
|
||||
"version": "2.8.2",
|
||||
"dev": true,
|
||||
|
@ -10048,6 +10063,24 @@
|
|||
"node": ">=0.8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/exifreader": {
|
||||
"version": "4.23.5",
|
||||
"resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.23.5.tgz",
|
||||
"integrity": "sha512-Gy9FXSBW+4ivu4aNtthGHAPEfVJ72z4aN9Iusr3YiIOy+ZCh7NWfoswCXZV/CH8MpOJE2Ij4hmmKQPGvo4Vf9g==",
|
||||
"hasInstallScript": true,
|
||||
"optionalDependencies": {
|
||||
"@xmldom/xmldom": "^0.8.10"
|
||||
}
|
||||
},
|
||||
"node_modules/exifreader/node_modules/@xmldom/xmldom": {
|
||||
"version": "0.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/expand-template": {
|
||||
"version": "2.0.3",
|
||||
"dev": true,
|
||||
|
@ -15960,6 +15993,17 @@
|
|||
"version": "1.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/panoramax-js": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.1.1.tgz",
|
||||
"integrity": "sha512-6R/Bo89Nwln92zG0TwqxGhtjn6dyDrxMEO/lTTtgTZc1lkEF2znHfDXKJa4YfTPUz14FtNVOV1IWmPsp/YULYw==",
|
||||
"dependencies": {
|
||||
"@ogcapi-js/features": "^1.1.1",
|
||||
"@ogcapi-js/shared": "^1.1.1",
|
||||
"@types/geojson": "^7946.0.14",
|
||||
"json-schema": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/panzoom": {
|
||||
"version": "9.4.3",
|
||||
"license": "MIT",
|
||||
|
@ -24679,6 +24723,19 @@
|
|||
"fastq": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"@ogcapi-js/features": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ogcapi-js/features/-/features-1.1.1.tgz",
|
||||
"integrity": "sha512-/w6kFvAXWO+F0/nLC5m11tuOw0LX+gVz/OCLiDkElXO9ko9F9OA3AbzKZxJaE5Buu0KUGn+TRxS6w1xhZc4KRA==",
|
||||
"requires": {
|
||||
"@ogcapi-js/shared": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"@ogcapi-js/shared": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ogcapi-js/shared/-/shared-1.1.1.tgz",
|
||||
"integrity": "sha512-EQ6T4iVXwIMnBcdpR2C0YnNNCxtNWHpWg0Hs9uEvH4BPZI2xT87gV+WRw8/hYAe8EtrK6j57iluBoSyHiAQweQ=="
|
||||
},
|
||||
"@parcel/service-worker": {
|
||||
"version": "2.8.2",
|
||||
"dev": true
|
||||
|
@ -28120,6 +28177,22 @@
|
|||
"events": {
|
||||
"version": "3.3.0"
|
||||
},
|
||||
"exifreader": {
|
||||
"version": "4.23.5",
|
||||
"resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.23.5.tgz",
|
||||
"integrity": "sha512-Gy9FXSBW+4ivu4aNtthGHAPEfVJ72z4aN9Iusr3YiIOy+ZCh7NWfoswCXZV/CH8MpOJE2Ij4hmmKQPGvo4Vf9g==",
|
||||
"requires": {
|
||||
"@xmldom/xmldom": "^0.8.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@xmldom/xmldom": {
|
||||
"version": "0.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"expand-template": {
|
||||
"version": "2.0.3",
|
||||
"dev": true
|
||||
|
@ -31982,6 +32055,17 @@
|
|||
"packet-reader": {
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"panoramax-js": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.1.1.tgz",
|
||||
"integrity": "sha512-6R/Bo89Nwln92zG0TwqxGhtjn6dyDrxMEO/lTTtgTZc1lkEF2znHfDXKJa4YfTPUz14FtNVOV1IWmPsp/YULYw==",
|
||||
"requires": {
|
||||
"@ogcapi-js/features": "^1.1.1",
|
||||
"@ogcapi-js/shared": "^1.1.1",
|
||||
"@types/geojson": "^7946.0.14",
|
||||
"json-schema": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"panzoom": {
|
||||
"version": "9.4.3",
|
||||
"requires": {
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
"imgur": "7070e7167f0a25a",
|
||||
"mapillary_v4": "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
|
||||
},
|
||||
"panoramax": {
|
||||
"url": "https://panoramax.mapcomplete.org",
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnZW92aXNpbyIsInN1YiI6IjU5ZjgzOGI0LTM4ZjAtNDdjYi04OWYyLTM3NDQ3MWMxNTUxOCJ9.0rBioZS_48NTjnkIyN9497c3fQdTqtGgH1HDqlz1bWs"
|
||||
},
|
||||
"default_overpass_urls": [
|
||||
"https://overpass-api.de/api/interpreter",
|
||||
"https://overpass.private.coffee/api/interpreter",
|
||||
|
@ -177,6 +181,7 @@
|
|||
"dompurify": "^3.0.5",
|
||||
"email-validator": "^2.0.4",
|
||||
"escape-html": "^1.0.3",
|
||||
"exifreader": "^4.23.5",
|
||||
"fake-dom": "^1.0.4",
|
||||
"flowbite-svelte": "^0.46.2",
|
||||
"follow-redirects": "^1.15.6",
|
||||
|
@ -200,6 +205,7 @@
|
|||
"opening_hours": "^3.6.0",
|
||||
"osm-auth": "^2.5.0",
|
||||
"osmtogeojson": "^3.0.0-beta.5",
|
||||
"panoramax-js": "^0.1.1",
|
||||
"panzoom": "^9.4.3",
|
||||
"papaparse": "^5.3.1",
|
||||
"pbf": "^3.2.1",
|
||||
|
|
|
@ -5,6 +5,7 @@ import GenericImageProvider from "./GenericImageProvider"
|
|||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import ImageProvider, { ProvidedImage } from "./ImageProvider"
|
||||
import { WikidataImageProvider } from "./WikidataImageProvider"
|
||||
import Panoramax from "./Panoramax"
|
||||
|
||||
/**
|
||||
* A generic 'from the interwebz' image picker, without attribution
|
||||
|
@ -28,6 +29,7 @@ export default class AllImageProviders {
|
|||
Mapillary.singleton,
|
||||
WikidataImageProvider.singleton,
|
||||
WikimediaImageProvider.singleton,
|
||||
Panoramax.singleton,
|
||||
AllImageProviders.genericImageProvider,
|
||||
]
|
||||
public static apiUrls: string[] = [].concat(
|
||||
|
@ -41,6 +43,7 @@ export default class AllImageProviders {
|
|||
mapillary: Mapillary.singleton,
|
||||
wikidata: WikidataImageProvider.singleton,
|
||||
wikimedia: WikimediaImageProvider.singleton,
|
||||
panoramax: Panoramax.singleton
|
||||
}
|
||||
private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<
|
||||
string,
|
||||
|
@ -66,6 +69,9 @@ export default class AllImageProviders {
|
|||
return AllImageProviders.genericImageProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to extract all image data for this image
|
||||
*/
|
||||
public static LoadImagesFor(
|
||||
tags: Store<Record<string, string>>,
|
||||
tagKey?: string[]
|
||||
|
|
|
@ -36,7 +36,7 @@ export default abstract class ImageProvider {
|
|||
prefixes?: string[]
|
||||
}
|
||||
): UIEventSource<ProvidedImage[]> {
|
||||
const prefixes = options?.prefixes ?? this.defaultKeyPrefixes
|
||||
const prefixes = Utils.Dedup(options?.prefixes ?? this.defaultKeyPrefixes)
|
||||
if (prefixes === undefined) {
|
||||
throw "No `defaultKeyPrefixes` defined by this image provider"
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ export default abstract class ImageProvider {
|
|||
const seenValues = new Set<string>()
|
||||
allTags.addCallbackAndRunD((tags) => {
|
||||
for (const key in tags) {
|
||||
if(key === "panoramax"){
|
||||
console.log("Inspecting", key,"against", prefixes)
|
||||
}
|
||||
if (!prefixes.some((prefix) => key.startsWith(prefix))) {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import { Changes } from "../Osm/Changes"
|
|||
import Translations from "../../UI/i18n/Translations"
|
||||
import NoteCommentElement from "../../UI/Popup/Notes/NoteCommentElement"
|
||||
import { Translation } from "../../UI/i18n/Translation"
|
||||
import { IndexedFeatureSource } from "../FeatureSource/FeatureSource"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
|
||||
/**
|
||||
* The ImageUploadManager has a
|
||||
|
@ -17,7 +19,8 @@ export class ImageUploadManager {
|
|||
private readonly _uploader: ImageUploader
|
||||
private readonly _featureProperties: FeaturePropertiesStore
|
||||
private readonly _layout: LayoutConfig
|
||||
|
||||
private readonly _indexedFeatures: IndexedFeatureSource
|
||||
private readonly _gps: Store<GeolocationCoordinates | undefined>
|
||||
private readonly _uploadStarted: Map<string, UIEventSource<number>> = new Map()
|
||||
private readonly _uploadFinished: Map<string, UIEventSource<number>> = new Map()
|
||||
private readonly _uploadFailed: Map<string, UIEventSource<number>> = new Map()
|
||||
|
@ -32,13 +35,17 @@ export class ImageUploadManager {
|
|||
uploader: ImageUploader,
|
||||
featureProperties: FeaturePropertiesStore,
|
||||
osmConnection: OsmConnection,
|
||||
changes: Changes
|
||||
changes: Changes,
|
||||
gpsLocation: Store<GeolocationCoordinates | undefined>,
|
||||
allFeatures: IndexedFeatureSource,
|
||||
) {
|
||||
this._uploader = uploader
|
||||
this._featureProperties = featureProperties
|
||||
this._layout = layout
|
||||
this._osmConnection = osmConnection
|
||||
this._changes = changes
|
||||
this._indexedFeatures = allFeatures
|
||||
this._gps = gpsLocation
|
||||
|
||||
const failed = this.getCounterFor(this._uploadFailed, "*")
|
||||
const done = this.getCounterFor(this._uploadFinished, "*")
|
||||
|
@ -47,7 +54,7 @@ export class ImageUploadManager {
|
|||
(startedCount) => {
|
||||
return startedCount > failed.data + done.data
|
||||
},
|
||||
[failed, done]
|
||||
[failed, done],
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -96,7 +103,7 @@ export class ImageUploadManager {
|
|||
public async uploadImageAndApply(
|
||||
file: File,
|
||||
tagsStore: UIEventSource<OsmTags>,
|
||||
targetKey?: string
|
||||
targetKey?: string,
|
||||
): Promise<void> {
|
||||
const canBeUploaded = this.canBeUploaded(file)
|
||||
if (canBeUploaded !== true) {
|
||||
|
@ -105,28 +112,15 @@ export class ImageUploadManager {
|
|||
|
||||
const tags = tagsStore.data
|
||||
const featureId = <OsmId>tags.id
|
||||
const licenseStore = this._osmConnection?.GetPreference("pictures-license", "CC0")
|
||||
const license = licenseStore?.data ?? "CC0"
|
||||
|
||||
const matchingLayer = this._layout?.getMatchingLayer(tags)
|
||||
|
||||
const title =
|
||||
matchingLayer?.title?.GetRenderValue(tags)?.Subs(tags)?.textFor("en") ??
|
||||
tags.name ??
|
||||
"https//osm.org/" + tags.id
|
||||
const description = [
|
||||
"author:" + this._osmConnection.userDetails.data.name,
|
||||
"license:" + license,
|
||||
"osmid:" + tags.id,
|
||||
].join("\n")
|
||||
const author = this._osmConnection.userDetails.data.name
|
||||
|
||||
const action = await this.uploadImageWithLicense(
|
||||
featureId,
|
||||
title,
|
||||
description,
|
||||
author,
|
||||
file,
|
||||
targetKey,
|
||||
tags?.data?.["_orig_theme"]
|
||||
tags?.data?.["_orig_theme"],
|
||||
)
|
||||
|
||||
if (!action) {
|
||||
|
@ -146,23 +140,30 @@ export class ImageUploadManager {
|
|||
|
||||
private async uploadImageWithLicense(
|
||||
featureId: OsmId,
|
||||
title: string,
|
||||
description: string,
|
||||
author: string,
|
||||
blob: File,
|
||||
targetKey: string | undefined,
|
||||
theme?: string
|
||||
theme?: string,
|
||||
): Promise<LinkImageAction> {
|
||||
this.increaseCountFor(this._uploadStarted, featureId)
|
||||
const properties = this._featureProperties.getStore(featureId)
|
||||
let key: string
|
||||
let value: string
|
||||
let location: [number, number] = undefined
|
||||
if (this._gps.data) {
|
||||
location = [this._gps.data.longitude, this._gps.data.latitude]
|
||||
}
|
||||
if (location === undefined || location?.some(l => l === undefined)) {
|
||||
const feature = this._indexedFeatures.featuresById.data.get(featureId)
|
||||
location = GeoOperations.centerpointCoordinates(feature)
|
||||
}
|
||||
try {
|
||||
;({ key, value } = await this._uploader.uploadImage(title, description, blob))
|
||||
;({ key, value } = await this._uploader.uploadImage(blob, location, author))
|
||||
} catch (e) {
|
||||
this.increaseCountFor(this._uploadRetried, featureId)
|
||||
console.error("Could not upload image, trying again:", e)
|
||||
try {
|
||||
;({ key, value } = await this._uploader.uploadImage(title, description, blob))
|
||||
;({ key, value } = await this._uploader.uploadImage(blob, location, author))
|
||||
this.increaseCountFor(this._uploadRetriedSuccess, featureId)
|
||||
} catch (e) {
|
||||
console.error("Could again not upload image due to", e)
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import { Feature } from "geojson"
|
||||
|
||||
export interface ImageUploader {
|
||||
maxFileSizeInMegabytes?: number
|
||||
/**
|
||||
* Uploads the 'blob' as image, with some metadata.
|
||||
* Returns the URL to be linked + the appropriate key to add this to OSM
|
||||
* @param title
|
||||
* @param description
|
||||
* @param blob
|
||||
*/
|
||||
uploadImage(
|
||||
title: string,
|
||||
description: string,
|
||||
blob: File
|
||||
blob: File,
|
||||
currentGps: [number,number],
|
||||
author: string
|
||||
): Promise<{ key: string; value: string }>
|
||||
}
|
||||
|
|
|
@ -3,14 +3,12 @@ import BaseUIElement from "../../UI/BaseUIElement"
|
|||
import { Utils } from "../../Utils"
|
||||
import Constants from "../../Models/Constants"
|
||||
import { LicenseInfo } from "./LicenseInfo"
|
||||
import { ImageUploader } from "./ImageUploader"
|
||||
|
||||
export class Imgur extends ImageProvider implements ImageUploader {
|
||||
export class Imgur extends ImageProvider {
|
||||
public static readonly defaultValuePrefix = ["https://i.imgur.com"]
|
||||
public static readonly singleton = new Imgur()
|
||||
public readonly name = "Imgur"
|
||||
public readonly defaultKeyPrefixes: string[] = ["image"]
|
||||
public readonly maxFileSizeInMegabytes = 10
|
||||
public static readonly apiUrl = "https://api.imgur.com/3/image"
|
||||
public static readonly supportingUrls = ["https://i.imgur.com"]
|
||||
private constructor() {
|
||||
|
@ -21,40 +19,6 @@ export class Imgur extends ImageProvider implements ImageUploader {
|
|||
return [Imgur.apiUrl]
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an image, returns the URL where to find the image
|
||||
* @param title
|
||||
* @param description
|
||||
* @param blob
|
||||
*/
|
||||
public async uploadImage(
|
||||
title: string,
|
||||
description: string,
|
||||
blob: File
|
||||
): Promise<{ key: string; value: string }> {
|
||||
const apiUrl = Imgur.apiUrl
|
||||
const apiKey = Constants.ImgurApiKey
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append("image", blob)
|
||||
formData.append("title", title)
|
||||
formData.append("description", description)
|
||||
|
||||
const settings: RequestInit = {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
redirect: "follow",
|
||||
headers: new Headers({
|
||||
Authorization: `Client-ID ${apiKey}`,
|
||||
Accept: "application/json",
|
||||
}),
|
||||
}
|
||||
|
||||
// Response contains stringified JSON
|
||||
const response = await fetch(apiUrl, settings)
|
||||
const content = await response.json()
|
||||
return { key: "image", value: content.data.link }
|
||||
}
|
||||
|
||||
SourceIcon(): BaseUIElement {
|
||||
return undefined
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
export class LicenseInfo {
|
||||
title: string = ""
|
||||
title?: string = ""
|
||||
artist: string = ""
|
||||
license: string = undefined
|
||||
licenseShortName: string = ""
|
||||
usageTerms: string = ""
|
||||
attributionRequired: boolean = false
|
||||
copyrighted: boolean = false
|
||||
credit: string = ""
|
||||
description: string = ""
|
||||
informationLocation: URL = undefined
|
||||
license?: string = undefined
|
||||
licenseShortName?: string = ""
|
||||
usageTerms?: string = ""
|
||||
attributionRequired?: boolean = false
|
||||
copyrighted?: boolean = false
|
||||
credit?: string = ""
|
||||
description?: string = ""
|
||||
informationLocation?: URL = undefined
|
||||
date?: Date
|
||||
views?: number
|
||||
}
|
||||
|
|
158
src/Logic/ImageProviders/Panoramax.ts
Normal file
158
src/Logic/ImageProviders/Panoramax.ts
Normal file
|
@ -0,0 +1,158 @@
|
|||
import { ImageUploader } from "./ImageUploader"
|
||||
import { AuthorizedPanoramax } from "panoramax-js/dist"
|
||||
import ExifReader from "exifreader"
|
||||
import ImageProvider, { ProvidedImage } from "./ImageProvider"
|
||||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
import { LicenseInfo } from "./LicenseInfo"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Feature, FeatureCollection, Point } from "geojson"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
|
||||
type ImageData = Feature<Point, { "geovisio:producer": string, "geovisio:license": string, "datetime": string }> & {
|
||||
id: string,
|
||||
assets: { hd: { href: string }, sd: { href: string } },
|
||||
providers: {name: string}[]
|
||||
}
|
||||
|
||||
export default class PanoramaxImageProvider extends ImageProvider {
|
||||
|
||||
public static readonly singleton = new PanoramaxImageProvider()
|
||||
|
||||
public defaultKeyPrefixes: string[] = ["panoramax", "image"]
|
||||
public readonly name: string = "panoramax"
|
||||
|
||||
private static knownMeta: Record<string, ImageData> = {}
|
||||
|
||||
public SourceIcon(id?: string, location?: { lon: number; lat: number; }): BaseUIElement {
|
||||
return undefined
|
||||
}
|
||||
|
||||
public addKnownMeta(meta: ImageData){
|
||||
console.log("Adding known meta for", meta.id)
|
||||
PanoramaxImageProvider.knownMeta[meta.id] = meta
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the entry from the mapcomplete-panoramax instance. Might return undefined
|
||||
* @param id
|
||||
* @private
|
||||
*/
|
||||
private async getInfoFromMapComplete(id: string): Promise<{ data: ImageData, url: string }> {
|
||||
const sequence = "6e702976-580b-419c-8fb3-cf7bd364e6f8" // We always reuse this sequence
|
||||
const url = `https://panoramax.mapcomplete.org/api/collections/${sequence}/items/${id}`
|
||||
const data = <any> await Utils.downloadJsonCached(url, 60 * 60 * 1000)
|
||||
return {url, data}
|
||||
}
|
||||
|
||||
private async getInfoFromXYZ(imageId: string): Promise<{ data: ImageData, url: string }> {
|
||||
const url = "https://api.panoramax.xyz/api/search?limit=1&ids=" + imageId
|
||||
const metaAll = await Utils.downloadJsonCached<FeatureCollection<Point>>(url, 1000 * 60 * 60)
|
||||
const data= <any>metaAll.features[0]
|
||||
return {data, url}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a geovisio-somewhat-looking-like-geojson object and converts it to a provided image
|
||||
* @param meta
|
||||
* @private
|
||||
*/
|
||||
private featureToImage(info: {data: ImageData, url: string}) {
|
||||
const meta = info.data
|
||||
const url = info.url
|
||||
if (!meta) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
function makeAbsolute(s: string){
|
||||
if(!s.startsWith("https://") && !s.startsWith("http://")){
|
||||
const parsed = new URL(url)
|
||||
return parsed.protocol+"//"+parsed.host+s
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
const [lon, lat] = GeoOperations.centerpointCoordinates(meta)
|
||||
return <ProvidedImage>{
|
||||
id: meta.id,
|
||||
url: makeAbsolute(meta.assets.sd.href),
|
||||
url_hd: makeAbsolute(meta.assets.hd.href),
|
||||
lon, lat,
|
||||
key: "panoramax",
|
||||
provider: this,
|
||||
rotation: Number(meta.properties["view:azimuth"]),
|
||||
date: new Date(meta.properties.datetime),
|
||||
}
|
||||
}
|
||||
|
||||
private async getInfoFor(id: string): Promise<{ data: ImageData, url: string }> {
|
||||
const cached= PanoramaxImageProvider.knownMeta[id]
|
||||
console.log("Cached version", id, cached)
|
||||
if(cached){
|
||||
return {data: cached, url: undefined}
|
||||
}
|
||||
try {
|
||||
return await this.getInfoFromMapComplete(id)
|
||||
} catch (e) {
|
||||
return await this.getInfoFromXYZ(id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
|
||||
return [this.getInfoFor(value).then(r => this.featureToImage(<any>r))]
|
||||
}
|
||||
|
||||
public async DownloadAttribution(providedImage: { url: string; id: string; }): Promise<LicenseInfo> {
|
||||
const meta = await this.getInfoFor(providedImage.id)
|
||||
|
||||
return {
|
||||
artist: meta.data.providers.at(-1).name, // We take the last provider, as that one probably contain the username of the uploader
|
||||
date: new Date(meta.data.properties["datetime"]),
|
||||
licenseShortName: meta.data.properties["geovisio:license"],
|
||||
}
|
||||
}
|
||||
|
||||
public apiUrls(): string[] {
|
||||
return ["https://panoramax.mapcomplete.org", "https://panoramax.xyz"]
|
||||
}
|
||||
}
|
||||
|
||||
export class PanoramaxUploader implements ImageUploader {
|
||||
private readonly _panoramax: AuthorizedPanoramax
|
||||
|
||||
constructor(url: string, token: string) {
|
||||
this._panoramax = new AuthorizedPanoramax(url, token)
|
||||
}
|
||||
|
||||
async uploadImage(blob: File, currentGps: [number, number], author: string): Promise<{
|
||||
key: string;
|
||||
value: string;
|
||||
}> {
|
||||
|
||||
const tags = await ExifReader.load(blob)
|
||||
const hasDate = tags.DateTime !== undefined
|
||||
const hasGPS = tags.GPSLatitude !== undefined && tags.GPSLongitude !== undefined
|
||||
|
||||
const [lon, lat] = currentGps
|
||||
|
||||
const p = this._panoramax
|
||||
const defaultSequence = (await p.mySequences())[0]
|
||||
const img = <ImageData> await p.addImage(blob, defaultSequence, {
|
||||
lat: !hasGPS ? lat : undefined,
|
||||
lon: !hasGPS ? lon : undefined,
|
||||
datetime: !hasDate ? new Date().toISOString() : undefined,
|
||||
exifOverride: {
|
||||
Artist: author,
|
||||
},
|
||||
|
||||
})
|
||||
PanoramaxImageProvider.singleton.addKnownMeta(img)
|
||||
await Utils.waitFor(1250)
|
||||
return {
|
||||
key: "panoramax",
|
||||
value: img.id,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { OsmNode, OsmObject, OsmRelation, OsmWay } from "./OsmObject"
|
||||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import { UIEventSource } from "../UIEventSource"
|
||||
import Constants from "../../Models/Constants"
|
||||
import OsmChangeAction from "./Actions/OsmChangeAction"
|
||||
import { ChangeDescription, ChangeDescriptionTools } from "./Actions/ChangeDescription"
|
||||
|
@ -11,7 +11,6 @@ import { GeoLocationPointProperties } from "../State/GeoLocationState"
|
|||
import { GeoOperations } from "../GeoOperations"
|
||||
import { ChangesetHandler, ChangesetTag } from "./ChangesetHandler"
|
||||
import { OsmConnection } from "./OsmConnection"
|
||||
import FeaturePropertiesStore from "../FeatureSource/Actors/FeaturePropertiesStore"
|
||||
import OsmObjectDownloader from "./OsmObjectDownloader"
|
||||
import ChangeLocationAction from "./Actions/ChangeLocationAction"
|
||||
import ChangeTagAction from "./Actions/ChangeTagAction"
|
||||
|
@ -62,9 +61,9 @@ export class Changes {
|
|||
this.backend = state.osmConnection.Backend()
|
||||
this._reportError = reportError
|
||||
this._changesetHandler = new ChangesetHandler(
|
||||
state.dryRun,
|
||||
state.featureSwitches.featureSwitchIsTesting,
|
||||
state.osmConnection,
|
||||
state.featurePropertiesStore,
|
||||
state.featureProperties,
|
||||
this,
|
||||
(e, extramessage: string) => this._reportError(e, extramessage)
|
||||
)
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { GeoOperations } from "./GeoOperations"
|
||||
import { Utils } from "../Utils"
|
||||
import opening_hours from "opening_hours"
|
||||
import Combine from "../UI/Base/Combine"
|
||||
import BaseUIElement from "../UI/BaseUIElement"
|
||||
import Title from "../UI/Base/Title"
|
||||
import { FixedUiElement } from "../UI/Base/FixedUiElement"
|
||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||
import { CountryCoder } from "latlon2country"
|
||||
import Constants from "../Models/Constants"
|
||||
|
|
|
@ -291,6 +291,8 @@ export default class NameSuggestionIndex {
|
|||
if (location === undefined) {
|
||||
return true
|
||||
}
|
||||
console.log("Resolving location", i.locationSet)
|
||||
/*
|
||||
const resolvedSet = NameSuggestionIndex.loco.resolveLocationSet(i.locationSet)
|
||||
|
||||
if (resolvedSet) {
|
||||
|
@ -299,7 +301,7 @@ export default class NameSuggestionIndex {
|
|||
const setFeature: Feature<MultiPolygon> = resolvedSet.feature
|
||||
return turf.booleanPointInPolygon(location, setFeature.geometry)
|
||||
}
|
||||
|
||||
*/
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ export default class Constants {
|
|||
...Constants.added_by_default,
|
||||
...Constants.no_include,
|
||||
] as const
|
||||
|
||||
public static panoramax: { url: string, token: string } = packagefile.config.panoramax
|
||||
|
||||
// The user journey states thresholds when a new feature gets unlocked
|
||||
public static userJourney = {
|
||||
moreScreenUnlock: 1,
|
||||
|
|
|
@ -2,11 +2,7 @@ import LayoutConfig from "./ThemeConfig/LayoutConfig"
|
|||
import { SpecialVisualizationState } from "../UI/SpecialVisualization"
|
||||
import { Changes } from "../Logic/Osm/Changes"
|
||||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||
import {
|
||||
FeatureSource,
|
||||
IndexedFeatureSource,
|
||||
WritableFeatureSource
|
||||
} from "../Logic/FeatureSource/FeatureSource"
|
||||
import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"
|
||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||
import { ExportableMap, MapProperties } from "./MapProperties"
|
||||
import LayerState from "../Logic/State/LayerState"
|
||||
|
@ -50,13 +46,10 @@ import BackgroundLayerResetter from "../Logic/Actors/BackgroundLayerResetter"
|
|||
import SaveFeatureSourceToLocalStorage from "../Logic/FeatureSource/Actors/SaveFeatureSourceToLocalStorage"
|
||||
import BBoxFeatureSource from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
|
||||
import ThemeViewStateHashActor from "../Logic/Web/ThemeViewStateHashActor"
|
||||
import NoElementsInViewDetector, {
|
||||
FeatureViewState
|
||||
} from "../Logic/Actors/NoElementsInViewDetector"
|
||||
import NoElementsInViewDetector, { FeatureViewState } from "../Logic/Actors/NoElementsInViewDetector"
|
||||
import FilteredLayer from "./FilteredLayer"
|
||||
import { PreferredRasterLayerSelector } from "../Logic/Actors/PreferredRasterLayerSelector"
|
||||
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"
|
||||
import { Imgur } from "../Logic/ImageProviders/Imgur"
|
||||
import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSource"
|
||||
import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource"
|
||||
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
|
||||
|
@ -64,7 +57,7 @@ import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl"
|
|||
import Zoomcontrol from "../UI/Zoomcontrol"
|
||||
import {
|
||||
SummaryTileSource,
|
||||
SummaryTileSourceRewriter
|
||||
SummaryTileSourceRewriter,
|
||||
} from "../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
|
||||
import summaryLayer from "../assets/generated/layers/summary.json"
|
||||
import last_click_layerconfig from "../assets/generated/layers/last_click.json"
|
||||
|
@ -73,6 +66,7 @@ import { LayerConfigJson } from "./ThemeConfig/Json/LayerConfigJson"
|
|||
import Hash from "../Logic/Web/Hash"
|
||||
import { GeoOperations } from "../Logic/GeoOperations"
|
||||
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
||||
import { PanoramaxUploader } from "../Logic/ImageProviders/Panoramax"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -272,14 +266,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
this.featureProperties = new FeaturePropertiesStore(layoutSource)
|
||||
|
||||
this.changes = new Changes(
|
||||
{
|
||||
dryRun: this.featureSwitches.featureSwitchIsTesting,
|
||||
allElements: layoutSource,
|
||||
featurePropertiesStore: this.featureProperties,
|
||||
osmConnection: this.osmConnection,
|
||||
historicalUserLocations: this.geolocation.historicalUserLocations,
|
||||
featureSwitches: this.featureSwitches
|
||||
},
|
||||
this,
|
||||
layout?.isLeftRightSensitive() ?? false,
|
||||
(e, extraMsg) => this.reportError(e, extraMsg)
|
||||
)
|
||||
|
@ -368,10 +355,12 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
this.hasDataInView = new NoElementsInViewDetector(this).hasFeatureInView
|
||||
this.imageUploadManager = new ImageUploadManager(
|
||||
layout,
|
||||
Imgur.singleton,
|
||||
new PanoramaxUploader(Constants.panoramax.url, Constants.panoramax.token),
|
||||
this.featureProperties,
|
||||
this.osmConnection,
|
||||
this.changes
|
||||
this.changes,
|
||||
this.geolocation.geolocationState.currentGPSLocation,
|
||||
this.indexedFeatures
|
||||
)
|
||||
this.favourites = new FavouritesFeatureSource(this)
|
||||
const longAgo = new Date()
|
||||
|
|
|
@ -90,7 +90,6 @@
|
|||
state.guistate.openUsersettings("picture-license")
|
||||
}}
|
||||
>
|
||||
<Tr t={t.currentLicense.Subs({ license: $licenseStore })} />
|
||||
</button>
|
||||
<br />
|
||||
<Tr cls="subtle italic" t={t.respectPrivacy} />
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||
import BaseUIElement from "./BaseUIElement"
|
||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
||||
import {
|
||||
FeatureSource,
|
||||
IndexedFeatureSource,
|
||||
WritableFeatureSource,
|
||||
} from "../Logic/FeatureSource/FeatureSource"
|
||||
import { FeatureSource, IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"
|
||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||
import { Changes } from "../Logic/Osm/Changes"
|
||||
import { ExportableMap, MapProperties } from "../Models/MapProperties"
|
||||
|
@ -18,9 +14,7 @@ import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
|||
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
||||
import { MenuState } from "../Models/MenuState"
|
||||
import OsmObjectDownloader from "../Logic/Osm/OsmObjectDownloader"
|
||||
import { RasterLayerPolygon } from "../Models/RasterLayers"
|
||||
import { ImageUploadManager } from "../Logic/ImageProviders/ImageUploadManager"
|
||||
import { OsmTags } from "../Models/OsmFeature"
|
||||
import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource"
|
||||
import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider"
|
||||
import GeoLocationHandler from "../Logic/Actors/GeoLocationHandler"
|
||||
|
@ -29,6 +23,7 @@ import LayoutSource from "../Logic/FeatureSource/Sources/LayoutSource"
|
|||
import { Map as MlMap } from "maplibre-gl"
|
||||
import ShowDataLayer from "./Map/ShowDataLayer"
|
||||
import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch"
|
||||
import FeaturePropertiesStore from "../Logic/FeatureSource/Actors/FeaturePropertiesStore"
|
||||
|
||||
/**
|
||||
* The state needed to render a special Visualisation.
|
||||
|
@ -40,10 +35,7 @@ export interface SpecialVisualizationState {
|
|||
|
||||
readonly layerState: LayerState
|
||||
readonly featureSummary: SummaryTileSourceRewriter
|
||||
readonly featureProperties: {
|
||||
getStore(id: string): UIEventSource<Record<string, string>>
|
||||
trackFeature?(feature: { properties: OsmTags })
|
||||
}
|
||||
readonly featureProperties: FeaturePropertiesStore
|
||||
|
||||
readonly indexedFeatures: IndexedFeatureSource & LayoutSource
|
||||
/**
|
||||
|
|
|
@ -714,15 +714,14 @@ export default class SpecialVisualizations {
|
|||
},
|
||||
],
|
||||
constr: (state, tags, args) => {
|
||||
return new FixedUiElement("Due to a technical limitation, image uploads are currently not possible").SetClass("subtle low-interaction p-4np")
|
||||
/*const targetKey = args[0] === "" ? undefined : args[0]
|
||||
const targetKey = args[0] === "" ? undefined : args[0]
|
||||
return new SvelteUIElement(UploadImage, {
|
||||
state,
|
||||
tags,
|
||||
targetKey,
|
||||
labelText: args[1],
|
||||
image: args[2],
|
||||
})*/
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue