Improvements in loading images

This commit is contained in:
Pieter Vander Vennet 2021-10-01 02:57:41 +02:00
parent 634f4e316a
commit 8b870474d7
9 changed files with 61 additions and 31 deletions

View file

@ -46,7 +46,7 @@ export default class SelectedFeatureHandler {
// IF the selected element changes, set the hash correctly // IF the selected element changes, set the hash correctly
state.selectedElement.addCallback(feature => { state.selectedElement.addCallback(feature => {
if (feature === undefined) { if (feature === undefined) {
if (SelectedFeatureHandler._no_trigger_on.has(hash.data)) { if (!SelectedFeatureHandler._no_trigger_on.has(hash.data)) {
hash.setData("") hash.setData("")
} }
} }

View file

@ -16,7 +16,7 @@ export default class AllImageProviders {
Mapillary.singleton, Mapillary.singleton,
WikidataImageProvider.singleton, WikidataImageProvider.singleton,
WikimediaImageProvider.singleton, WikimediaImageProvider.singleton,
new GenericImageProvider([].concat(...Imgur.defaultValuePrefix, WikimediaImageProvider.commonsPrefix))] new GenericImageProvider([].concat(...Imgur.defaultValuePrefix, WikimediaImageProvider.commonsPrefix, ...Mapillary.valuePrefixes))]
private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>() private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<string, UIEventSource<ProvidedImage[]>>()
@ -37,8 +37,18 @@ export default class AllImageProviders {
this._cache.set(id, source) this._cache.set(id, source)
const allSources = [] const allSources = []
for (const imageProvider of AllImageProviders.ImageAttributionSource) { for (const imageProvider of AllImageProviders.ImageAttributionSource) {
let prefixes = imageProvider.defaultKeyPrefixes
if(imagePrefix !== undefined){
prefixes = [...prefixes]
if(prefixes.indexOf("image") >= 0){
prefixes.splice(prefixes.indexOf("image"), 1)
}
prefixes.push(imagePrefix)
}
const singleSource = imageProvider.GetRelevantUrls(tags, { const singleSource = imageProvider.GetRelevantUrls(tags, {
prefixes: imagePrefix !== undefined ? [imagePrefix] : undefined prefixes: prefixes
}) })
allSources.push(singleSource) allSources.push(singleSource)
singleSource.addCallbackAndRunD(_ => { singleSource.addCallbackAndRunD(_ => {

View file

@ -8,7 +8,7 @@ export interface ProvidedImage {
export default abstract class ImageProvider { export default abstract class ImageProvider {
protected abstract readonly defaultKeyPrefixes : string[] public abstract readonly defaultKeyPrefixes : string[] = ["mapillary", "image"]
private _cache = new Map<string, UIEventSource<LicenseInfo>>() private _cache = new Map<string, UIEventSource<LicenseInfo>>()
@ -33,6 +33,9 @@ export default abstract class ImageProvider {
prefixes?: string[] prefixes?: string[]
}):UIEventSource<ProvidedImage[]> { }):UIEventSource<ProvidedImage[]> {
const prefixes = options?.prefixes ?? this.defaultKeyPrefixes const prefixes = options?.prefixes ?? this.defaultKeyPrefixes
if(prefixes === undefined){
throw "The image provider"+this.constructor.name+" doesn't define `defaultKeyPrefixes`"
}
const relevantUrls = new UIEventSource<{ url: string; key: string; provider: ImageProvider }[]>([]) const relevantUrls = new UIEventSource<{ url: string; key: string; provider: ImageProvider }[]>([])
const seenValues = new Set<string>() const seenValues = new Set<string>()
allTags.addCallbackAndRunD(tags => { allTags.addCallbackAndRunD(tags => {
@ -45,10 +48,15 @@ export default abstract class ImageProvider {
continue continue
} }
seenValues.add(value) seenValues.add(value)
this.ExtractUrls(key, value).then(promises => { this.ExtractUrls(key, value).then(promises => {
for (const promise of promises) { for (const promise of promises ?? []) {
if(promise === undefined){
continue
}
promise.then(providedImage => { promise.then(providedImage => {
if(providedImage === undefined){
return
}
relevantUrls.data.push(providedImage) relevantUrls.data.push(providedImage)
relevantUrls.ping() relevantUrls.ping()
}) })

View file

@ -5,24 +5,25 @@ import Svg from "../../Svg";
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
import {LicenseInfo} from "./LicenseInfo"; import {LicenseInfo} from "./LicenseInfo";
import Constants from "../../Models/Constants"; import Constants from "../../Models/Constants";
import {fail} from "assert";
export class Mapillary extends ImageProvider { export class Mapillary extends ImageProvider {
defaultKeyPrefixes = ["mapillary"] defaultKeyPrefixes = ["mapillary","image"]
public static readonly singleton = new Mapillary(); public static readonly singleton = new Mapillary();
private static readonly valuePrefix = "https://a.mapillary.com"
private static readonly v4_cached_urls = new Map<string, UIEventSource<string>>(); public static readonly valuePrefixes = [Mapillary.valuePrefix, "http://mapillary.com","https://mapillary.com"]
private constructor() { private constructor() {
super(); super();
} }
private static ExtractKeyFromURL(value: string): { private static ExtractKeyFromURL(value: string, failIfNoMath = false): {
key: string, key: string,
isApiv4?: boolean isApiv4?: boolean
} { } {
if (value.startsWith("https://a.mapillary.com")) { if (value.startsWith(Mapillary.valuePrefix)) {
const key = value.substring(0, value.lastIndexOf("?")).substring(value.lastIndexOf("/") + 1) const key = value.substring(0, value.lastIndexOf("?")).substring(value.lastIndexOf("/") + 1)
return {key: key, isApiv4: !isNaN(Number(key))}; return {key: key, isApiv4: !isNaN(Number(key))};
} }
@ -48,6 +49,9 @@ export class Mapillary extends ImageProvider {
return {key: matchApi[1]}; return {key: matchApi[1]};
} }
if(failIfNoMath){
return undefined;
}
return {key: value, isApiv4: !isNaN(Number(value))}; return {key: value, isApiv4: !isNaN(Number(value))};
} }
@ -61,7 +65,12 @@ export class Mapillary extends ImageProvider {
} }
private async PrepareUrlAsync(key: string, value: string): Promise<ProvidedImage> { private async PrepareUrlAsync(key: string, value: string): Promise<ProvidedImage> {
const keyV = Mapillary.ExtractKeyFromURL(value) const failIfNoMatch = key.indexOf("mapillary") < 0
const keyV = Mapillary.ExtractKeyFromURL(value, failIfNoMatch)
if(keyV === undefined){
return undefined;
}
if (!keyV.isApiv4) { if (!keyV.isApiv4) {
const url = `https://images.mapillary.com/${keyV.key}/thumb-640.jpg?client_id=${Constants.mapillary_client_token_v3}` const url = `https://images.mapillary.com/${keyV.key}/thumb-640.jpg?client_id=${Constants.mapillary_client_token_v3}`
return { return {
@ -70,10 +79,8 @@ export class Mapillary extends ImageProvider {
key: key key: key
} }
} else { } else {
const key = keyV.key; const mapillaryId = keyV.key;
const metadataUrl = 'https://graph.mapillary.com/' + key + '?fields=thumb_1024_url&&access_token=' + Constants.mapillary_client_token_v4; const metadataUrl = 'https://graph.mapillary.com/' + mapillaryId + '?fields=thumb_1024_url&&access_token=' + Constants.mapillary_client_token_v4;
const source = new UIEventSource<string>(undefined)
Mapillary.v4_cached_urls.set(key, source)
const response = await Utils.downloadJson(metadataUrl) const response = await Utils.downloadJson(metadataUrl)
const url = <string> response["thumb_1024_url"]; const url = <string> response["thumb_1024_url"];
return { return {

View file

@ -26,6 +26,10 @@ export class WikidataImageProvider extends ImageProvider {
if (value.startsWith(wikidataUrl)) { if (value.startsWith(wikidataUrl)) {
value = value.substring(wikidataUrl.length) value = value.substring(wikidataUrl.length)
} }
if(value.startsWith("http")){
// Probably some random link in the image field - we skip it
return undefined
}
if (!value.startsWith("Q")) { if (!value.startsWith("Q")) {
value = "Q" + value value = "Q" + value
} }

View file

@ -44,7 +44,7 @@ export class WikimediaImageProvider extends ImageProvider {
if (continueParameter !== undefined) { if (continueParameter !== undefined) {
url = `${url}&cmcontinue=${continueParameter}`; url = `${url}&cmcontinue=${continueParameter}`;
} }
console.log("Loading a wikimedia category: ", url) console.debug("Loading a wikimedia category: ", url)
const response = await Utils.downloadJson(url) const response = await Utils.downloadJson(url)
const members = response.query?.categorymembers ?? []; const members = response.query?.categorymembers ?? [];
const imageOverview: string[] = members.map(member => member.title); const imageOverview: string[] = members.map(member => member.title);
@ -55,7 +55,7 @@ export class WikimediaImageProvider extends ImageProvider {
} }
if (maxLoad - imageOverview.length <= 0) { if (maxLoad - imageOverview.length <= 0) {
console.log(`Recursive wikimedia category load stopped for ${categoryName}`) console.debug(`Recursive wikimedia category load stopped for ${categoryName}`)
return imageOverview; return imageOverview;
} }

View file

@ -3,6 +3,7 @@ import Attribution from "./Attribution";
import Img from "../Base/Img"; import Img from "../Base/Img";
import {ProvidedImage} from "../../Logic/ImageProviders/ImageProvider"; import {ProvidedImage} from "../../Logic/ImageProviders/ImageProvider";
import BaseUIElement from "../BaseUIElement"; import BaseUIElement from "../BaseUIElement";
import {Mapillary} from "../../Logic/ImageProviders/Mapillary";
export class AttributedImage extends Combine { export class AttributedImage extends Combine {
@ -10,7 +11,9 @@ export class AttributedImage extends Combine {
constructor(imageInfo: ProvidedImage) { constructor(imageInfo: ProvidedImage) {
let img: BaseUIElement; let img: BaseUIElement;
let attr: BaseUIElement let attr: BaseUIElement
img = new Img(imageInfo.url); img = new Img(imageInfo.url, false, {
fallbackImage: imageInfo.provider === Mapillary.singleton ? "./assets/svg/blocked.svg" : undefined
});
attr = new Attribution(imageInfo.provider.GetAttributionFor(imageInfo.url), attr = new Attribution(imageInfo.provider.GetAttributionFor(imageInfo.url),
imageInfo.provider.SourceIcon(), imageInfo.provider.SourceIcon(),
) )

View file

@ -13,9 +13,7 @@ export class ImageCarousel extends Toggle {
const uiElements = images.map((imageURLS: { key: string, url: string, provider: ImageProvider }[]) => { const uiElements = images.map((imageURLS: { key: string, url: string, provider: ImageProvider }[]) => {
const uiElements: BaseUIElement[] = []; const uiElements: BaseUIElement[] = [];
for (const url of imageURLS) { for (const url of imageURLS) {
try { try {
let image = new AttributedImage(url) let image = new AttributedImage(url)
if (url.key !== undefined) { if (url.key !== undefined) {

View file

@ -912,14 +912,14 @@ video {
margin-right: 0px; margin-right: 0px;
} }
.mb-4 {
margin-bottom: 1rem;
}
.mb-1 { .mb-1 {
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
} }
.mb-4 {
margin-bottom: 1rem;
}
.box-border { .box-border {
box-sizing: border-box; box-sizing: border-box;
} }
@ -1156,14 +1156,14 @@ video {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
} }
.cursor-wait {
cursor: wait;
}
.cursor-pointer { .cursor-pointer {
cursor: pointer; cursor: pointer;
} }
.cursor-wait {
cursor: wait;
}
.resize { .resize {
resize: both; resize: both;
} }