150 lines
5.3 KiB
TypeScript
150 lines
5.3 KiB
TypeScript
import Combine from "../Base/Combine";
|
|
import {UIEventSource} from "../../Logic/UIEventSource";
|
|
import {SlideShow} from "../Image/SlideShow";
|
|
import Toggle from "../Input/Toggle";
|
|
import Loading from "../Base/Loading";
|
|
import {AttributedImage} from "../Image/AttributedImage";
|
|
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders";
|
|
import Svg from "../../Svg";
|
|
import BaseUIElement from "../BaseUIElement";
|
|
import {InputElement} from "../Input/InputElement";
|
|
import {VariableUiElement} from "../Base/VariableUIElement";
|
|
import Translations from "../i18n/Translations";
|
|
import {Mapillary} from "../../Logic/ImageProviders/Mapillary";
|
|
import {SubtleButton} from "../Base/SubtleButton";
|
|
|
|
export interface P4CPicture {
|
|
pictureUrl: string,
|
|
date: number,
|
|
coordinates: { lat: number, lng: number },
|
|
provider: "Mapillary" | string,
|
|
author,
|
|
license,
|
|
detailsUrl: string,
|
|
direction,
|
|
osmTags: object /*To copy straight into OSM!*/
|
|
,
|
|
thumbUrl: string,
|
|
details: {
|
|
isSpherical: boolean,
|
|
}
|
|
}
|
|
|
|
|
|
export interface NearbyImageOptions {
|
|
lon: number,
|
|
lat: number,
|
|
radius: number,
|
|
maxDaysOld?: 1095 | number,
|
|
blacklist: UIEventSource<{url: string}[]>,
|
|
shownImagesCount?: UIEventSource<number>,
|
|
towardscenter?: boolean;
|
|
}
|
|
|
|
export default class NearbyImages extends VariableUiElement {
|
|
|
|
constructor(options: NearbyImageOptions) {
|
|
const t = Translations.t.image.nearbyPictures
|
|
const P4C = require("../../vendor/P4C.min")
|
|
const picManager = new P4C.PicturesManager({});
|
|
const shownImages = options.shownImagesCount ?? new UIEventSource(25);
|
|
const loadedPictures =
|
|
UIEventSource.FromPromise<P4CPicture[]>(
|
|
picManager.startPicsRetrievalAround(new P4C.LatLng(options.lat, options.lon), options.radius, {
|
|
mindate: new Date().getTime() - (options.maxDaysOld ?? (3*365)) * 24 * 60 * 60 * 1000,
|
|
towardscenter: options.towardscenter
|
|
})
|
|
).map(images => {
|
|
console.log("Images are" ,images, "blacklisted is", options.blacklist.data)
|
|
images?.sort((a, b) => b.date - a.date)
|
|
return images ?.filter(i => !(options.blacklist?.data?.some(blacklisted =>
|
|
Mapillary.sameUrl(i.pictureUrl, blacklisted.url)))
|
|
&& i.details.isSpherical === false);
|
|
}, [options.blacklist])
|
|
|
|
const loadMoreButton = new Combine([new SubtleButton(Svg.add_svg(), t.loadMore).onClick(() => {
|
|
shownImages.setData(shownImages.data + 25)
|
|
})]).SetClass("flex flex-col justify-center")
|
|
const imageElements = loadedPictures.map(imgs => {
|
|
const elements = (imgs ?? []).slice(0, shownImages.data).map(i => this.prepareElement(i));
|
|
if(imgs !== undefined && elements.length < imgs.length){
|
|
// We effectively sliced some items, so we can increase the count
|
|
elements.push(loadMoreButton)
|
|
}
|
|
return elements;
|
|
},[shownImages]);
|
|
|
|
super(loadedPictures.map(images => {
|
|
if(images === undefined){
|
|
return new Loading(t.loading);
|
|
}
|
|
if(images.length === 0){
|
|
return t.nothingFound.SetClass("alert block")
|
|
}
|
|
return new SlideShow(imageElements)
|
|
}));
|
|
|
|
}
|
|
|
|
protected prepareElement(info: P4CPicture): BaseUIElement {
|
|
const provider = AllImageProviders.byName(info.provider);
|
|
return new AttributedImage({url: info.pictureUrl, provider})
|
|
}
|
|
|
|
private asAttributedImage(info: P4CPicture): AttributedImage {
|
|
const provider = AllImageProviders.byName(info.provider);
|
|
return new AttributedImage({url: info.thumbUrl, provider, date: new Date(info.date)})
|
|
}
|
|
|
|
protected asToggle(info:P4CPicture): Toggle {
|
|
const imgNonSelected = this.asAttributedImage(info);
|
|
const imageSelected = this.asAttributedImage(info);
|
|
|
|
const nonSelected = new Combine([imgNonSelected]).SetClass("relative block")
|
|
const hoveringCheckmark =
|
|
new Combine([Svg.confirm_svg().SetClass("block w-24 h-24 -ml-12 -mt-12")]).SetClass("absolute left-1/2 top-1/2 w-0")
|
|
const selected = new Combine([
|
|
imageSelected,
|
|
hoveringCheckmark,
|
|
]).SetClass("relative block")
|
|
|
|
return new Toggle(selected, nonSelected).SetClass("").ToggleOnClick();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export class SelectOneNearbyImage extends NearbyImages implements InputElement<P4CPicture> {
|
|
private readonly value: UIEventSource<P4CPicture>;
|
|
|
|
constructor(options: NearbyImageOptions & {value?: UIEventSource<P4CPicture>}) {
|
|
super(options)
|
|
this.value = options.value ?? new UIEventSource<P4CPicture>(undefined);
|
|
}
|
|
|
|
GetValue(): UIEventSource<P4CPicture> {
|
|
return this.value;
|
|
}
|
|
|
|
IsValid(t: P4CPicture): boolean {
|
|
return false;
|
|
}
|
|
|
|
protected prepareElement(info: P4CPicture): BaseUIElement {
|
|
const toggle = super.asToggle(info)
|
|
toggle.isEnabled.addCallback(enabled => {
|
|
if (enabled) {
|
|
this.value.setData(info)
|
|
}
|
|
})
|
|
|
|
this.value.addCallback(inf => {
|
|
if(inf !== info){
|
|
toggle.isEnabled.setData(false)
|
|
}
|
|
})
|
|
|
|
return toggle
|
|
}
|
|
|
|
}
|