Add Mapillary image load support, close #136

This commit is contained in:
Pieter Vander Vennet 2020-10-17 00:37:45 +02:00
parent 5e869479c1
commit 6a2b3d82de
6 changed files with 166 additions and 63 deletions

View file

@ -4,6 +4,7 @@ import {UIElement} from "../UI/UIElement";
import {ImgurImage} from "../UI/Image/ImgurImage"; import {ImgurImage} from "../UI/Image/ImgurImage";
import {ImagesInCategory, Wikidata, Wikimedia} from "./Web/Wikimedia"; import {ImagesInCategory, Wikidata, Wikimedia} from "./Web/Wikimedia";
import {UIEventSource} from "./UIEventSource"; import {UIEventSource} from "./UIEventSource";
import {MapillaryImage} from "../UI/Image/MapillaryImage";
/** /**
* There are multiple way to fetch images for an object * There are multiple way to fetch images for an object
@ -33,50 +34,12 @@ export class ImageSearcher extends UIEventSource<{key: string, url: string}[]> {
this._tags = tags; this._tags = tags;
const self = this; const self = this;
this._wdItem.addCallback(() => {
// Load the wikidata item, then detect usage on 'commons' // By wrapping this in a UIEventSource, we prevent multiple queries of loadWikiData
let allWikidataId = self._wdItem.data.split(";"); this._wdItem.addCallback(() => self.loadWikidata());
for (let wikidataId of allWikidataId) { this._commons.addCallback(() => self.LoadCommons());
// @ts-ignore
if (wikidataId.startsWith("Q")) {
wikidataId = wikidataId.substr(1);
}
Wikimedia.GetWikiData(parseInt(wikidataId), (wd: Wikidata) => {
self.AddImage(undefined, wd.image);
Wikimedia.GetCategoryFiles(wd.commonsWiki, (images: ImagesInCategory) => {
for (const image of images.images) {
// @ts-ignore
if (image.startsWith("File:")) {
self.AddImage(undefined, image);
}
}
})
})
}
}
);
this._commons.addCallback(() => {
const allCommons: string[] = self._commons.data.split(";");
for (const commons of allCommons) {
// @ts-ignore
if (commons.startsWith("Category:")) {
Wikimedia.GetCategoryFiles(commons, (images: ImagesInCategory) => {
for (const image of images.images) {
// @ts-ignore
if (image.startsWith("File:")) {
self.AddImage(undefined, image);
}
}
})
} else { // @ts-ignore
if (commons.startsWith("File:")) {
self.AddImage(undefined, commons);
}
}
}
});
this._tags.addCallbackAndRun(() => self.LoadImages()); this._tags.addCallbackAndRun(() => self.LoadImages());
} }
@ -96,7 +59,50 @@ export class ImageSearcher extends UIEventSource<{key: string, url: string}[]> {
this.ping(); this.ping();
} }
private LoadImages(): void { private loadWikidata() {
// Load the wikidata item, then detect usage on 'commons'
let allWikidataId = this._wdItem.data.split(";");
for (let wikidataId of allWikidataId) {
// @ts-ignore
if (wikidataId.startsWith("Q")) {
wikidataId = wikidataId.substr(1);
}
Wikimedia.GetWikiData(parseInt(wikidataId), (wd: Wikidata) => {
this.AddImage(undefined, wd.image);
Wikimedia.GetCategoryFiles(wd.commonsWiki, (images: ImagesInCategory) => {
for (const image of images.images) {
// @ts-ignore
if (image.startsWith("File:")) {
this.AddImage(undefined, image);
}
}
})
})
}
}
private LoadCommons() {
const allCommons: string[] = this._commons.data.split(";");
for (const commons of allCommons) {
// @ts-ignore
if (commons.startsWith("Category:")) {
Wikimedia.GetCategoryFiles(commons, (images: ImagesInCategory) => {
for (const image of images.images) {
// @ts-ignore
if (image.startsWith("File:")) {
this.AddImage(undefined, image);
}
}
})
} else { // @ts-ignore
if (commons.startsWith("File:")) {
this.AddImage(undefined, commons);
}
}
}
}
private LoadImages(imagePrefix: string = "image", loadAdditional = true): void {
const imageTag = this._tags.data.image; const imageTag = this._tags.data.image;
if (imageTag !== undefined) { if (imageTag !== undefined) {
const bareImages = imageTag.split(";"); const bareImages = imageTag.split(";");
@ -112,6 +118,8 @@ export class ImageSearcher extends UIEventSource<{key: string, url: string}[]> {
} }
} }
if (loadAdditional) {
const wdItem = this._tags.data.wikidata; const wdItem = this._tags.data.wikidata;
if (wdItem !== undefined) { if (wdItem !== undefined) {
this._wdItem.setData(wdItem); this._wdItem.setData(wdItem);
@ -120,6 +128,12 @@ export class ImageSearcher extends UIEventSource<{key: string, url: string}[]> {
if (commons !== undefined) { if (commons !== undefined) {
this._commons.setData(commons); this._commons.setData(commons);
} }
if (this._tags.data.mapillary) {
this.AddImage("mapillary", "https://www.mapillary.com/map/im/" + this._tags.data.mapillary)
}
}
} }
@ -132,11 +146,13 @@ export class ImageSearcher extends UIEventSource<{key: string, url: string}[]> {
// @ts-ignore // @ts-ignore
if (url.startsWith("File:")) { if (url.startsWith("File:")) {
return new WikimediaImage(url); return new WikimediaImage(url);
}else if (url.startsWith("https://commons.wikimedia.org/wiki/")) { } else if (url.toLowerCase().startsWith("https://commons.wikimedia.org/wiki/")) {
const commons = url.substr("https://commons.wikimedia.org/wiki/".length); const commons = url.substr("https://commons.wikimedia.org/wiki/".length);
return new WikimediaImage(commons); return new WikimediaImage(commons);
}else if(url.startsWith("https://i.imgur.com/")){ } else if (url.toLowerCase().startsWith("https://i.imgur.com/")) {
return new ImgurImage(url); return new ImgurImage(url);
} else if (url.toLowerCase().startsWith("https://www.mapillary.com/map/im/")) {
return new MapillaryImage(url);
} else { } else {
return new SimpleImageElement(new UIEventSource<string>(url)); return new SimpleImageElement(new UIEventSource<string>(url));
} }

26
Logic/Web/Mapillary.ts Normal file
View file

@ -0,0 +1,26 @@
import $ from "jquery"
import {LicenseInfo} from "./Wikimedia";
export class Mapillary {
static getDescriptionOfImage(key: string,
handleDescription: ((license: LicenseInfo) => void)) {
const url = `https://a.mapillary.com/v3/images/${key}?client_id=TXhLaWthQ1d4RUg0czVxaTVoRjFJZzowNDczNjUzNmIyNTQyYzI2`
const settings = {
async: true,
type: 'GET',
url: url
};
$.getJSON(url, function(data) {
const license = new LicenseInfo();
license.artist = data.properties?.username;
license.licenseShortName = "CC BY-SA 4.0";
license.license = "Creative Commons Attribution-ShareAlike 4.0 International License";
license.attributionRequired = true;
handleDescription(license);
})
}
}

View file

@ -10,7 +10,7 @@ export class ImgurImage extends UIElement {
/*** /***
* Dictionary from url to alreayd known license info * Dictionary from url to alreayd known license info
*/ */
static allLicenseInfos: any = {}; private static allLicenseInfos: any = {};
private readonly _imageMeta: UIEventSource<LicenseInfo>; private readonly _imageMeta: UIEventSource<LicenseInfo>;
private readonly _imageLocation: string; private readonly _imageLocation: string;
@ -33,7 +33,7 @@ export class ImgurImage extends UIElement {
} }
InnerRender(): string { InnerRender(): string {
const image = "<img src='" + this._imageLocation + "' " + "alt='' >"; const image = `<img src='${this._imageLocation}' alt='' >`;
if(this._imageMeta.data === null){ if(this._imageMeta.data === null){
return image; return image;

View file

@ -0,0 +1,64 @@
import {UIElement} from "../UIElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import {LicenseInfo} from "../../Logic/Web/Wikimedia";
import {Imgur} from "../../Logic/Web/Imgur";
import {Mapillary} from "../../Logic/Web/Mapillary";
import {Img} from "../Img";
import {FixedUiElement} from "../Base/FixedUiElement";
export class MapillaryImage extends UIElement {
/***
* Dictionary from url to alreayd known license info
*/
private static allLicenseInfos: any = {};
private readonly _imageMeta: UIEventSource<LicenseInfo>;
private readonly _imageLocation: string;
constructor(source: string) {
super()
if(source.toLowerCase().startsWith("https://www.mapillary.com/map/im/")){
source = source.substring("https://www.mapillary.com/map/im/".length);
}
this._imageLocation = source;
if (MapillaryImage.allLicenseInfos[source] !== undefined) {
this._imageMeta = MapillaryImage.allLicenseInfos[source];
} else {
this._imageMeta = new UIEventSource<LicenseInfo>(null);
MapillaryImage.allLicenseInfos[source] = this._imageMeta;
const self = this;
Mapillary.getDescriptionOfImage(source, (license) => {
self._imageMeta.setData(license)
})
}
this.ListenTo(this._imageMeta);
}
InnerRender(): string {
const url = `https://images.mapillary.com/${this._imageLocation}/thumb-640.jpg?client_id=TXhLaWthQ1d4RUg0czVxaTVoRjFJZzowNDczNjUzNmIyNTQyYzI2`;
const image = `<img src='${url}'>`;
if (this._imageMeta === undefined || this._imageMeta.data === null) {
return image;
}
const attribution =
"<span class='attribution-author'><b>" + (this._imageMeta.data.artist ?? "") + "</b></span>" + " <span class='license'>" + (this._imageMeta.data.licenseShortName ?? "") + "</span>";
return "<div class='imgWithAttr'>" +
image +
"<div class='attribution'>" +
new FixedUiElement(Img.mapillaryLogo).SetStyle("height: 1.5em").Render() +
attribution +
"</div>" +
"</div>";
}
}

View file

@ -37,5 +37,7 @@ export class Img {
static openFilterButton: string = `<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> static openFilterButton: string = `<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 2L2 20M20 20L2 2" stroke="#003B8B" stroke-width="4"/> <path d="M20 2L2 20M20 20L2 2" stroke="#003B8B" stroke-width="4"/>
</svg> ` </svg> `
static mapillaryLogo = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" fill=\"none\" viewBox=\"0 0 32 32\"><path fill=\"#fff\" fill-rule=\"evenodd\" d=\"M32 16c0 8.837-7.163 16-16 16S0 24.837 0 16 7.163 0 16 0s16 7.163 16 16zm-24.44-.974c-.371-.201-.303-.725.166-.859.398-.113 3.627-1.196 4.605-1.524a.59.59 0 00.373-.369l1.57-4.603c.146-.43.678-.432.894-.015.024.046.325.593.731 1.331v.001c.896 1.629 2.302 4.185 2.372 4.34a.473.473 0 01-.194.617c-.133.083-.314.19-.469.28l-.269.16c-.237.148-.464.045-.573-.183-.065-.137-.39-.719-.713-1.299-.217-.389-.433-.776-.57-1.027-.17-.313-.682-.433-.854.072l-.566 1.66a.613.613 0 01-.376.373l-1.703.564c-.336.111-.5.626-.046.843.038.018.383.202.798.423h.001c.631.337 1.425.76 1.552.82.21.1.328.39.204.595-.168.28-.384.635-.462.75a.48.48 0 01-.626.149c-.223-.119-5.711-3.027-5.844-3.099zm7.378 3.9c.288.147 7.276 3.844 7.496 3.963.441.238.907-.222.668-.652-.041-.073-.507-.929-1.107-2.034l-.002-.004c-1.166-2.144-2.84-5.224-2.925-5.365-.128-.214-.442-.322-.678-.178-.232.14-.498.298-.648.374-.3.153-.338.383-.203.639.297.562 1.232 2.267 1.34 2.446.223.374-.276.801-.615.615-.054-.03-.408-.217-.834-.442-.697-.368-1.587-.839-1.684-.896-.157-.09-.435-.09-.626.218-.138.224-.308.502-.386.642-.155.274-.084.527.204.674z\" clip-rule=\"evenodd\" style=\"transition: all 0.2s ease 0s;\"></path></svg>"
} }

View file

@ -1,15 +1,10 @@
//* //*
import {UIEventSource} from "./Logic/UIEventSource"; import {MapillaryImage} from "./UI/Image/MapillaryImage";
import OpeningHoursVisualization from "./UI/OhVisualization";
const oh = "Tu-Fr 09:00-17:00 'as usual'; mo off 'yyy'; su off 'xxx'" new MapillaryImage("JVUQ9Lxtfef-Yj6-GYdGwQ").AttachTo("maindiv")
const tags = new UIEventSource<any>({opening_hours:oh});
new OpeningHoursVisualization(tags, 'opening_hours').AttachTo('maindiv')
window.setTimeout(() => {tags.data._country = "be"; }, 5000)
/*/ /*/