Improvements in loading images
This commit is contained in:
parent
634f4e316a
commit
8b870474d7
9 changed files with 61 additions and 31 deletions
|
@ -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("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(_ => {
|
||||||
|
|
|
@ -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()
|
||||||
})
|
})
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue