UX: add link to Mapillary, fix #1637

This commit is contained in:
Pieter Vander Vennet 2023-12-02 03:12:34 +01:00
parent c7089c27a0
commit 804005e402
12 changed files with 82 additions and 37 deletions

View file

@ -31,11 +31,12 @@ export default class GenericImageProvider extends ImageProvider {
key: key,
url: value,
provider: this,
id: value
}),
]
}
SourceIcon(backlinkSource?: string) {
SourceIcon() {
return undefined
}

View file

@ -6,13 +6,14 @@ import { Utils } from "../../Utils"
export interface ProvidedImage {
url: string
key: string
provider: ImageProvider
provider: ImageProvider,
id: string
}
export default abstract class ImageProvider {
public abstract readonly defaultKeyPrefixes: string[]
public abstract SourceIcon(backlinkSource?: string): BaseUIElement
public abstract SourceIcon(id?: string, location?: {lon: number, lat: number}): BaseUIElement
/**
* Given a properies object, maps it onto _all_ the available pictures for this imageProvider
@ -28,7 +29,7 @@ export default abstract class ImageProvider {
throw "No `defaultKeyPrefixes` defined by this image provider"
}
const relevantUrls = new UIEventSource<
{ url: string; key: string; provider: ImageProvider }[]
{ id: string, url: string; key: string; provider: ImageProvider }[]
>([])
const seenValues = new Set<string>()
allTags.addCallbackAndRunD((tags) => {
@ -67,4 +68,10 @@ export default abstract class ImageProvider {
public abstract DownloadAttribution(url: string): Promise<LicenseInfo>
public abstract apiUrls(): string[]
public backlink(): string | undefined {
return undefined
}
}

View file

@ -66,6 +66,7 @@ export class Imgur extends ImageProvider implements ImageUploader {
url: value,
key: key,
provider: this,
id: value
}),
]
}

View file

@ -4,6 +4,7 @@ import Svg from "../../Svg"
import { Utils } from "../../Utils"
import { LicenseInfo } from "./LicenseInfo"
import Constants from "../../Models/Constants"
import Link from "../../UI/Base/Link"
export class Mapillary extends ImageProvider {
public static readonly singleton = new Mapillary()
@ -17,10 +18,6 @@ export class Mapillary extends ImageProvider {
]
defaultKeyPrefixes = ["mapillary", "image"]
apiUrls(): string[] {
return ["https://mapillary.com", "https://www.mapillary.com", "https://graph.mapillary.com"]
}
/**
* Indicates that this is the same URL
* Ignores 'stp' parameter
@ -57,6 +54,22 @@ export class Mapillary extends ImageProvider {
return false
}
static createLink(location: {
lon: number,
lat: number
} = undefined, zoom: number = 17, pKey?: string) {
const params = {
focus: pKey === undefined ? "map" : "photo",
lat: location.lat,
lng: location.lon,
z: location === undefined ? undefined : Math.max((zoom ?? 2) - 1, 1),
pKey,
}
const baselink = `https://www.mapillary.com/app/?`
const paramsStr = Utils.NoNull(Object.keys(params).map(k => params[k] === undefined ? undefined : k + "=" + params[k]))
return baselink + paramsStr.join("&")
}
/**
* Returns the correct key for API v4.0
*/
@ -80,8 +93,19 @@ export class Mapillary extends ImageProvider {
return undefined
}
SourceIcon(backlinkSource?: string): BaseUIElement {
return Svg.mapillary_svg()
apiUrls(): string[] {
return ["https://mapillary.com", "https://www.mapillary.com", "https://graph.mapillary.com"]
}
SourceIcon(id: string, location?: {
lon: number,
lat: number
}): BaseUIElement {
const icon = Svg.mapillary_svg()
if (!id) {
return icon
}
return new Link(icon, Mapillary.createLink(location, 16, "" + id), true)
}
async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
@ -111,6 +135,7 @@ export class Mapillary extends ImageProvider {
const response = await Utils.downloadJsonCached(metadataUrl, 60 * 60)
const url = <string>response["thumb_1024_url"]
return {
id: "" + mapillaryId,
url: url,
provider: this,
key: key,

View file

@ -15,7 +15,7 @@ export class WikidataImageProvider extends ImageProvider {
super()
}
public SourceIcon(_?: string): BaseUIElement {
public SourceIcon(): BaseUIElement {
return Svg.wikidata_svg()
}

View file

@ -1,7 +1,6 @@
import ImageProvider, { ProvidedImage } from "./ImageProvider"
import BaseUIElement from "../../UI/BaseUIElement"
import Svg from "../../Svg"
import Link from "../../UI/Base/Link"
import { Utils } from "../../Utils"
import { LicenseInfo } from "./LicenseInfo"
import Wikimedia from "../Web/Wikimedia"
@ -70,17 +69,8 @@ export class WikimediaImageProvider extends ImageProvider {
return WikimediaImageProvider.apiUrls
}
SourceIcon(backlink: string): BaseUIElement {
const img = Svg.wikimedia_commons_white_svg().SetStyle("width:2em;height: 2em")
if (backlink === undefined) {
return img
}
return new Link(
Svg.wikimedia_commons_white_svg(),
`https://commons.wikimedia.org/wiki/${backlink}`,
true
)
SourceIcon(): BaseUIElement {
return Svg.wikimedia_commons_white_svg().SetStyle("width:2em;height: 2em")
}
public PrepUrl(value: string): ProvidedImage {
@ -173,6 +163,6 @@ export class WikimediaImageProvider extends ImageProvider {
if (!image.startsWith("File:")) {
image = "File:" + image
}
return { url: WikimediaImageProvider.PrepareUrl(image), key: undefined, provider: this }
return { url: WikimediaImageProvider.PrepareUrl(image), key: undefined, provider: this , id: image}
}
}

View file

@ -5,6 +5,7 @@
import Tr from "../Base/Tr.svelte"
import ToSvelte from "../Base/ToSvelte.svelte"
import Mapillary_black from "../../assets/svg/Mapillary_black.svelte";
import { Mapillary } from "../../Logic/ImageProviders/Mapillary"
/*
A subtleButton which opens mapillary in a new tab at the current location
@ -16,9 +17,7 @@
}
let location = mapProperties.location
let zoom = mapProperties.zoom
let mapillaryLink = `https://www.mapillary.com/app/?focus=map&lat=${$location?.lat ?? 0}&lng=${
$location?.lon ?? 0
}&z=${Math.max(($zoom ?? 2) - 1, 1)}`
let mapillaryLink = Mapillary.createLink($location, $zoom)
</script>
<a class="button flex items-center" href={mapillaryLink} target="_blank">

View file

@ -5,21 +5,37 @@ import ImageProvider from "../../Logic/ImageProviders/ImageProvider"
import BaseUIElement from "../BaseUIElement"
import { Mapillary } from "../../Logic/ImageProviders/Mapillary"
import { UIEventSource } from "../../Logic/UIEventSource"
import { Feature } from "geojson"
import { GeoOperations } from "../../Logic/GeoOperations"
export class AttributedImage extends Combine {
constructor(imageInfo: { url: string; provider?: ImageProvider; date?: Date }) {
constructor(imageInfo: {
id: string,
url: string;
provider?: ImageProvider;
date?: Date
}, feature?: Feature) {
let img: BaseUIElement
img = new Img(imageInfo.url, false, {
fallbackImage:
imageInfo.provider === Mapillary.singleton ? "./assets/svg/blocked.svg" : undefined,
})
let location: {
lon: number,
lat: number
} = undefined
if (feature) {
const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
location = { lon, lat }
}
let attr: BaseUIElement = undefined
if (imageInfo.provider !== undefined) {
attr = new Attribution(
UIEventSource.FromPromise(imageInfo.provider?.DownloadAttribution(imageInfo.url)),
imageInfo.provider?.SourceIcon(),
imageInfo.date
imageInfo.provider?.SourceIcon(imageInfo.id, location),
imageInfo.date,
)
}

View file

@ -28,6 +28,7 @@ export default class Attribution extends VariableUiElement {
title = new Link(title, license.informationLocation.href, true)
}
}
return new Combine([
icon
?.SetClass("block left")

View file

@ -9,19 +9,21 @@ import ImageProvider from "../../Logic/ImageProviders/ImageProvider"
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import { Changes } from "../../Logic/Osm/Changes"
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"
import { Feature } from "geojson"
export class ImageCarousel extends Toggle {
constructor(
images: Store<{ key: string; url: string; provider: ImageProvider }[]>,
images: Store<{ id:string, key: string; url: string; provider: ImageProvider }[]>,
tags: Store<any>,
state: { osmConnection?: OsmConnection; changes?: Changes; layout: LayoutConfig }
state: { osmConnection?: OsmConnection; changes?: Changes; layout: LayoutConfig },
feature: Feature
) {
const uiElements = images.map(
(imageURLS: { key: string; url: string; provider: ImageProvider }[]) => {
(imageURLS: { key: string; url: string; provider: ImageProvider, id: string }[]) => {
const uiElements: BaseUIElement[] = []
for (const url of imageURLS) {
try {
let image = new AttributedImage(url)
let image = new AttributedImage(url, feature)
if (url.key !== undefined) {
image = new Combine([

View file

@ -28,11 +28,13 @@
const t = Translations.t.image.nearby
const c = [lon, lat]
console.log(">>>", image)
let attributedImage = new AttributedImage({
url: image.thumbUrl ?? image.pictureUrl,
provider: AllImageProviders.byName(image.provider),
date: new Date(image.date),
})
id: Object.values(image.osmTags)[0]
}, feature)
let distance = Math.round(
GeoOperations.distanceBetween([image.coordinates.lng, image.coordinates.lat], c)
)

View file

@ -654,7 +654,7 @@ export default class SpecialVisualizations {
},
],
needsUrls: AllImageProviders.apiUrls,
constr: (state, tags, args) => {
constr: (state, tags, args, feature) => {
let imagePrefixes: string[] = undefined
if (args.length > 0) {
imagePrefixes = [].concat(...args.map((a) => a.split(",")))
@ -662,7 +662,8 @@ export default class SpecialVisualizations {
return new ImageCarousel(
AllImageProviders.LoadImagesFor(tags, imagePrefixes),
tags,
state
state,
feature
)
},
},