forked from MapComplete/MapComplete
Compare commits
1 commit
develop
...
fix/photos
| Author | SHA1 | Date | |
|---|---|---|---|
| 611dabd5cb |
10 changed files with 156 additions and 134 deletions
|
|
@ -3,6 +3,7 @@ import BaseUIElement from "../../UI/BaseUIElement"
|
|||
import { LicenseInfo } from "./LicenseInfo"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Feature, Point } from "geojson"
|
||||
import { P4CPicture } from "../Web/NearbyImagesSearch"
|
||||
|
||||
export interface ProvidedImage {
|
||||
url: string
|
||||
|
|
@ -36,7 +37,8 @@ export interface PanoramaView {
|
|||
*/
|
||||
northOffset?: number
|
||||
pitchOffset?: number
|
||||
provider: ImageProvider | string
|
||||
provider: ImageProvider | string,
|
||||
p4c: P4CPicture
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -60,6 +62,7 @@ export interface HotspotProperties {
|
|||
pitch: number | "auto"
|
||||
|
||||
gotoPanorama: Feature<Point, PanoramaView>
|
||||
originalP4C: P4CPicture
|
||||
}
|
||||
|
||||
export default abstract class ImageProvider {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ class NearbyImageUtils {
|
|||
}
|
||||
|
||||
class P4CImageFetcher implements ImageFetcher {
|
||||
public static readonly services = ["flickr", "kartaview", "wikicommons"] as const
|
||||
public static readonly services = ["flickr", "kartaview", "wikicommons", "mapillary"] as const
|
||||
public static readonly apiUrls = ["https://api.flickr.com"]
|
||||
private _options: { maxDaysOld: number; searchRadius: number }
|
||||
public readonly name: P4CService
|
||||
|
|
@ -374,7 +374,7 @@ export class CombinedFetcher {
|
|||
start_captured_at: maxage,
|
||||
panoramas: "no",
|
||||
}),
|
||||
// new P4CImageFetcher("mapillary"),
|
||||
new P4CImageFetcher("mapillary"),
|
||||
new P4CImageFetcher("wikicommons"),
|
||||
].map((f) => new CachedFetcher(f))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,14 +146,14 @@
|
|||
<LinkableImage
|
||||
{tags}
|
||||
{state}
|
||||
image={{
|
||||
image={new UIEventSource({
|
||||
pictureUrl: image,
|
||||
provider: "Velopark",
|
||||
thumbUrl: image,
|
||||
details: undefined,
|
||||
coordinates: undefined,
|
||||
osmTags: { image },
|
||||
}}
|
||||
})}
|
||||
{feature}
|
||||
{layer}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@
|
|||
* Shows an image with attribution
|
||||
*/
|
||||
import ImageAttribution from "./ImageAttribution.svelte"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
|
||||
import type { HotspotProperties, ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
||||
import { Mapillary } from "../../Logic/ImageProviders/Mapillary"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { MagnifyingGlassPlusIcon } from "@babeard/svelte-heroicons/outline"
|
||||
import { CloseButton } from "flowbite-svelte"
|
||||
import ImageOperations from "./ImageOperations.svelte"
|
||||
|
|
@ -17,12 +16,11 @@
|
|||
import Loading from "../Base/Loading.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import DotMenu from "../Base/DotMenu.svelte"
|
||||
import LoadingPlaceholder from "../Base/LoadingPlaceholder.svelte"
|
||||
import { MenuState } from "../../Models/MenuState"
|
||||
import ThemeViewState from "../../Models/ThemeViewState"
|
||||
import Panorama360 from "../../assets/svg/Panorama360.svelte"
|
||||
import { ExternalLinkIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import AttributedImageDotMenu from "./AttributedImageDotMenu.svelte"
|
||||
|
||||
export let image: Partial<ProvidedImage> & { id: string; url: string }
|
||||
let fallbackImage: string = undefined
|
||||
|
|
@ -41,7 +39,6 @@
|
|||
| Store<Feature<Geometry, HotspotProperties>[]> = []
|
||||
|
||||
let loaded = false
|
||||
let visitUrl = image.provider?.visitUrl(image)
|
||||
let showBigPreview = new UIEventSource(false)
|
||||
onDestroy(
|
||||
showBigPreview.addCallbackAndRun((shown) => {
|
||||
|
|
@ -71,24 +68,37 @@
|
|||
type: "Feature",
|
||||
properties: {
|
||||
id: image.id,
|
||||
rotation: image.rotation,
|
||||
rotation: image.rotation
|
||||
},
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: [image.lon, image.lat],
|
||||
},
|
||||
coordinates: [image.lon, image.lat]
|
||||
}
|
||||
}
|
||||
state?.geocodedImages.set([f])
|
||||
}
|
||||
</script>
|
||||
|
||||
<Popup shown={showBigPreview} bodyPadding="p-0" dismissable={true}>
|
||||
<div style="height: 80vh">
|
||||
<ImageOperations {image} {nearbyFeatures}>
|
||||
<div style="height: 80vh" class="relative h-full w-full">
|
||||
<ImageOperations on:imagechange {image} {nearbyFeatures}>
|
||||
<slot name="preview-action" />
|
||||
<slot name="dot-menu-actions" slot="dot-menu-actions" />
|
||||
</ImageOperations>
|
||||
<div
|
||||
class="pointer-events-none absolute bottom-0 left-0 flex w-full flex-wrap items-end justify-between"
|
||||
>
|
||||
<div class="pointer-events-auto m-1 w-fit transition-colors duration-200">
|
||||
<ImageAttribution {image} attributionFormat="large" />
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
<AttributedImageDotMenu {image}>
|
||||
<slot name="dot-menu-actions" />
|
||||
</AttributedImageDotMenu>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="absolute right-4 top-4">
|
||||
<CloseButton
|
||||
class="normal-background"
|
||||
|
|
@ -112,17 +122,9 @@
|
|||
on:mouseenter={() => highlight()}
|
||||
on:mouseleave={() => highlight(false)}
|
||||
>
|
||||
{#if $$slots["dot-menu-actions"] || visitUrl !== undefined}
|
||||
<DotMenu dotsPosition="top-0 left-0 absolute" hideBackground>
|
||||
<AttributedImageDotMenu {image}>
|
||||
<slot name="dot-menu-actions" />
|
||||
{#if visitUrl !== undefined}
|
||||
<a href={visitUrl} target="_blank" rel="noopener">
|
||||
<ExternalLinkIcon class="w-6" />
|
||||
<Tr t={Translations.t.image.openOnWebsite.Subs(image.provider)} />
|
||||
</a>
|
||||
{/if}
|
||||
</DotMenu>
|
||||
{/if}
|
||||
</AttributedImageDotMenu>
|
||||
{#if !loaded}
|
||||
<LoadingPlaceholder />
|
||||
{/if}
|
||||
|
|
|
|||
33
src/UI/Image/AttributedImageDotMenu.svelte
Normal file
33
src/UI/Image/AttributedImageDotMenu.svelte
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<script lang="ts">
|
||||
|
||||
import Translations from "../i18n/Translations"
|
||||
import DotMenu from "../Base/DotMenu.svelte"
|
||||
import { DownloadIcon, ExternalLinkIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import ImageProvider from "../../Logic/ImageProviders/ImageProvider"
|
||||
import type { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
||||
|
||||
export let image: Partial<ProvidedImage> & { id: string; url: string }
|
||||
let visitUrl = image.provider?.visitUrl(image)
|
||||
|
||||
</script>
|
||||
|
||||
<DotMenu dotsPosition="top-0 left-0 absolute" hideBackground>
|
||||
{#if visitUrl !== undefined}
|
||||
<a href={visitUrl} target="_blank" rel="noopener">
|
||||
<ExternalLinkIcon class="w-6" />
|
||||
<Tr t={Translations.t.image.openOnWebsite.Subs(image.provider)} />
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="no-image-background pointer-events-auto flex items-center justify-start"
|
||||
on:click={() => ImageProvider.offerImageAsDownload(image)}
|
||||
>
|
||||
<DownloadIcon />
|
||||
<Tr t={Translations.t.general.download.downloadImage} />
|
||||
</button>
|
||||
|
||||
<slot />
|
||||
|
||||
</DotMenu>
|
||||
|
|
@ -3,66 +3,26 @@
|
|||
* The 'imageOperations' previews an image and offers some extra tools (e.g. download)
|
||||
*/
|
||||
|
||||
import ImageProvider from "../../Logic/ImageProviders/ImageProvider"
|
||||
import type { HotspotProperties } from "../../Logic/ImageProviders/ImageProvider"
|
||||
import type { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
||||
import ImageAttribution from "./ImageAttribution.svelte"
|
||||
import type { HotspotProperties, ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
||||
import ImagePreview from "./ImagePreview.svelte"
|
||||
import { DownloadIcon, ExternalLinkIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import DotMenu from "../Base/DotMenu.svelte"
|
||||
import type { Feature, Geometry } from "geojson"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
|
||||
export let image: Partial<ProvidedImage> & { id: string; url: string }
|
||||
export let clss: string = undefined
|
||||
export let nearbyFeatures:
|
||||
| Feature<Geometry, HotspotProperties>[]
|
||||
| Store<Feature<Geometry, HotspotProperties>[]> = []
|
||||
let visitUrl = image.provider?.visitUrl(image)
|
||||
let isLoaded = new UIEventSource(false)
|
||||
|
||||
</script>
|
||||
|
||||
<div class={twMerge("relative h-full w-full", clss)}>
|
||||
<div class="panzoom-container focusable absolute left-0 top-0 h-full w-full overflow-hidden">
|
||||
{#if !$isLoaded}
|
||||
<div class="flex h-full w-full items-center justify-center">
|
||||
<Loading />
|
||||
</div>
|
||||
{/if}
|
||||
<ImagePreview {image} {isLoaded} {nearbyFeatures} />
|
||||
<ImagePreview on:imagechange {image} {isLoaded} {nearbyFeatures} />
|
||||
</div>
|
||||
|
||||
{#if $$slots["dot-menu-actions"]}
|
||||
<DotMenu dotsPosition="top-0 left-0" dotsSize="w-8 h-8" hideBackground>
|
||||
<slot name="dot-menu-actions" />
|
||||
<button
|
||||
class="no-image-background pointer-events-auto flex items-center"
|
||||
on:click={() => ImageProvider.offerImageAsDownload(image)}
|
||||
>
|
||||
<DownloadIcon class="h-6 w-6 px-2 opacity-100" />
|
||||
<Tr t={Translations.t.general.download.downloadImage} />
|
||||
</button>
|
||||
|
||||
{#if visitUrl !== undefined}
|
||||
<a href={visitUrl} target="_blank" rel="noopener">
|
||||
<ExternalLinkIcon class="w-6" />
|
||||
<Tr t={Translations.t.image.openOnWebsite.Subs(image.provider)} />
|
||||
</a>
|
||||
{/if}
|
||||
</DotMenu>
|
||||
{/if}
|
||||
<div
|
||||
class="pointer-events-none absolute bottom-0 left-0 flex w-full flex-wrap items-end justify-between"
|
||||
>
|
||||
<div class="pointer-events-auto m-1 w-fit transition-colors duration-200">
|
||||
<ImageAttribution image={$image} attributionFormat="large" />
|
||||
</div>
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
*/
|
||||
import panzoom from "panzoom"
|
||||
import type { HotspotProperties, PanoramaView, ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
|
||||
import ImageProvider from "../../Logic/ImageProviders/ImageProvider"
|
||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import Zoomcontrol from "../Zoomcontrol"
|
||||
import { onDestroy } from "svelte"
|
||||
import { createEventDispatcher, onDestroy } from "svelte"
|
||||
import { PhotoSphereViewerWrapper } from "./photoSphereViewerWrapper"
|
||||
import type { Feature, Geometry, Point } from "geojson"
|
||||
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
|
||||
import type { P4CPicture } from "../../Logic/Web/NearbyImagesSearch"
|
||||
|
||||
export let nearbyFeatures:
|
||||
| Feature<Geometry, HotspotProperties>[]
|
||||
|
|
@ -21,6 +20,8 @@
|
|||
let viewerEl: HTMLElement
|
||||
export let isLoaded: UIEventSource<boolean> = undefined
|
||||
|
||||
let dispatch = createEventDispatcher<{ imagechange: P4CPicture }>()
|
||||
|
||||
onDestroy(Zoomcontrol.createLock())
|
||||
|
||||
let destroyed = false
|
||||
|
|
@ -29,20 +30,14 @@
|
|||
})
|
||||
async function initPhotosphere() {
|
||||
const imageInfo: Feature<Point, PanoramaView> = await image.provider.getPanoramaInfo(image)
|
||||
if (imageInfo === undefined) {
|
||||
console.error("Image info is apparently undefined for", image)
|
||||
if (imageInfo?.properties?.url === undefined) {
|
||||
console.error("Image info (or url) is apparently undefined for", image)
|
||||
return
|
||||
}
|
||||
const viewer = new PhotoSphereViewerWrapper(viewerEl, imageInfo)
|
||||
viewer.imageInfo.addCallbackAndRunD(panoramaInfo => {
|
||||
let provider: ImageProvider
|
||||
if (typeof panoramaInfo.properties.provider === "string") {
|
||||
provider = AllImageProviders.byName(panoramaInfo.properties.provider)
|
||||
} else {
|
||||
provider = panoramaInfo.properties.provider
|
||||
}
|
||||
console.log(">>> Got:", panoramaInfo, "by", provider.name)
|
||||
//actuallyDisplayed.set(image.properties.imageMeta)
|
||||
console.log("Sending imagechange with", panoramaInfo.properties.p4c, "from", imageInfo)
|
||||
dispatch("imagechange", panoramaInfo.properties.p4c)
|
||||
})
|
||||
if (Array.isArray(nearbyFeatures)) {
|
||||
viewer.setNearbyFeatures(nearbyFeatures)
|
||||
|
|
|
|||
|
|
@ -22,15 +22,23 @@
|
|||
|
||||
export let tags: UIEventSource<OsmTags>
|
||||
export let state: ThemeViewState
|
||||
export let image: P4CPicture
|
||||
export let image: UIEventSource<P4CPicture>
|
||||
export let feature: Feature
|
||||
export let layer: LayerConfig
|
||||
|
||||
export let highlighted: UIEventSource<string> = undefined
|
||||
export let nearbyFeatures: Feature<Point, HotspotProperties>[] | Store<Feature<Point, HotspotProperties>[]> = []
|
||||
export let linkable = true
|
||||
let targetValue = Object.values(image.osmTags)[0]
|
||||
let isLinked = new UIEventSource(Object.values(tags.data).some((v) => targetValue === v))
|
||||
let targetValue: Store<string> = image.mapD(image => {
|
||||
console.log("Calculating new targetValue", image.osmTags)
|
||||
return Object.values(image.osmTags)[0]
|
||||
})
|
||||
targetValue.addCallbackAndRunD(tv => console.log("New target value is", tv))
|
||||
let isLinked = new UIEventSource<boolean>(undefined)
|
||||
targetValue.mapD(targetValue => {
|
||||
Object.values(tags.data).some((v) => targetValue === v)
|
||||
}, [tags])
|
||||
|
||||
isLinked.addCallbackAndRun((linked) => {
|
||||
if (linked) {
|
||||
MenuState.previewedImage.set(undefined)
|
||||
|
|
@ -38,23 +46,22 @@
|
|||
})
|
||||
const t = Translations.t.image.nearby
|
||||
|
||||
|
||||
let providedImage: Store<ProvidedImage> = image.mapD(image => {
|
||||
let date: Date
|
||||
if (image.date) {
|
||||
try {
|
||||
date = new Date(image.date)
|
||||
} catch (e) {
|
||||
console.warn("Could not parse image date", image.date, "for", image.detailsUrl)
|
||||
}
|
||||
}
|
||||
|
||||
let license: LicenseInfo = {
|
||||
const license: LicenseInfo = <LicenseInfo>{
|
||||
artist: image.author,
|
||||
license: image.license,
|
||||
informationLocation: image.detailsUrl ?? image.pictureUrl ?? image.thumbUrl,
|
||||
date,
|
||||
date
|
||||
}
|
||||
|
||||
let providedImage: ProvidedImage = {
|
||||
return <ProvidedImage>{
|
||||
url: image.thumbUrl ?? image.pictureUrl,
|
||||
url_hd: image.pictureUrl,
|
||||
key: undefined,
|
||||
|
|
@ -62,60 +69,73 @@
|
|||
date,
|
||||
id: Object.values(image.osmTags)[0],
|
||||
isSpherical: image.details.isSpherical,
|
||||
license,
|
||||
license
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
async function applyLink(isLinked: boolean) {
|
||||
console.log("Applying linked image", isLinked, targetValue)
|
||||
const currentTags = tags.data
|
||||
const key = Object.keys(image.osmTags)[0]
|
||||
const url = targetValue
|
||||
const key = Object.keys(image.data.osmTags)[0]
|
||||
const url = image.data.osmTags[key]
|
||||
console.log("Applying linked image", isLinked, url)
|
||||
if (isLinked) {
|
||||
const action = new LinkImageAction(currentTags.id, key, url, tags, {
|
||||
theme: tags.data._orig_theme ?? state.theme.id,
|
||||
changeType: "link-image",
|
||||
changeType: "link-image"
|
||||
})
|
||||
await state.changes.applyAction(action)
|
||||
} else {
|
||||
for (const k in currentTags) {
|
||||
const v = currentTags[k]
|
||||
const v: string = currentTags[k]
|
||||
if (v === url) {
|
||||
const action = new ChangeTagAction(currentTags.id, new Tag(k, ""), currentTags, {
|
||||
theme: tags.data._orig_theme ?? state.theme.id,
|
||||
changeType: "remove-image",
|
||||
changeType: "remove-image"
|
||||
})
|
||||
state.changes.applyAction(action)
|
||||
await state.changes.applyAction(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onImageChanged(p4c: P4CPicture) {
|
||||
console.log("Viewer changed panorama, now got", p4c)
|
||||
if (p4c) {
|
||||
image.set(p4c)
|
||||
} else {
|
||||
console.trace("Got a null!")
|
||||
}
|
||||
}
|
||||
|
||||
isLinked.addCallback((isLinked) => applyLink(isLinked))
|
||||
|
||||
let element: HTMLDivElement
|
||||
if (highlighted) {
|
||||
onDestroy(
|
||||
highlighted.addCallbackD((highlightedUrl) => {
|
||||
if (highlightedUrl === image.pictureUrl) {
|
||||
if (highlightedUrl === image.data.pictureUrl) {
|
||||
Utils.scrollIntoView(element)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex w-fit shrink-0 flex-col overflow-hidden rounded-lg"
|
||||
class:border-interactive={$isLinked || $highlighted === image.pictureUrl}
|
||||
class:border-interactive={$isLinked || $highlighted === $image.pictureUrl}
|
||||
style="border-width: 2px"
|
||||
bind:this={element}
|
||||
>
|
||||
<AttributedImage
|
||||
{state}
|
||||
image={providedImage}
|
||||
image={$providedImage}
|
||||
{nearbyFeatures}
|
||||
imgClass="max-h-64 w-auto sm:h-32 md:h-64"
|
||||
attributionFormat="minimal"
|
||||
on:imagechange={(ev) => onImageChanged(ev.detail) }
|
||||
>
|
||||
<svelte:fragment slot="dot-menu-actions">
|
||||
<LoginToggle {state} silentFail={true} hiddenFail={true}>
|
||||
|
|
@ -123,6 +143,7 @@
|
|||
<label>
|
||||
<input bind:checked={$isLinked} type="checkbox" />
|
||||
<SpecialTranslation t={t.link} {tags} {state} {layer} {feature} />
|
||||
{$image.author} {$image.osmTags["panoramax"]}
|
||||
</label>
|
||||
{/if}
|
||||
</LoginToggle>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import type { P4CPicture } from "../../Logic/Web/NearbyImagesSearch"
|
||||
import LinkableImage from "./LinkableImage.svelte"
|
||||
import type { Feature, Geometry, Point } from "geojson"
|
||||
import type { Feature, Point } from "geojson"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
|
||||
|
|
@ -53,9 +53,9 @@
|
|||
)
|
||||
|
||||
// Panorama-views get a geojson feature to browse around
|
||||
let asFeatures = result.map((p4cs) =>
|
||||
let asFeatures = result.map((p4cs: P4CPicture[]) =>
|
||||
p4cs.map(
|
||||
(p4c) =>
|
||||
(p4c: P4CPicture) =>
|
||||
<Feature<Point, PanoramaView>>{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
|
|
@ -68,7 +68,8 @@
|
|||
northOffset: p4c.direction,
|
||||
rotation: p4c.direction,
|
||||
spherical: p4c.details.isSpherical ? "yes" : "no",
|
||||
provider: p4c.provider
|
||||
provider: p4c.provider,
|
||||
p4c
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
@ -150,7 +151,7 @@
|
|||
},
|
||||
})
|
||||
|
||||
let nearbyFeatures: Store<Feature<Geometry, HotspotProperties>[]> = asFeatures.map(
|
||||
let nearbyFeatures: Store<Feature<Point, HotspotProperties>[]> = asFeatures.map(
|
||||
(nearbyPoints) => {
|
||||
return [
|
||||
{
|
||||
|
|
@ -166,11 +167,12 @@
|
|||
.map((f) => ({
|
||||
...f,
|
||||
properties: <HotspotProperties>{
|
||||
name: "Nearby panorama",
|
||||
name: "Nearby panorama by " + f.properties.p4c.author,
|
||||
pitch: "auto",
|
||||
type: "scene",
|
||||
gotoPanorama: f,
|
||||
focus: false,
|
||||
originalP4C: f.properties.p4c
|
||||
},
|
||||
})),
|
||||
]
|
||||
|
|
@ -216,7 +218,7 @@
|
|||
>
|
||||
<LinkableImage
|
||||
{tags}
|
||||
{image}
|
||||
image={new UIEventSource(image)}
|
||||
{state}
|
||||
{feature}
|
||||
{layer}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ export class PhotoSphereViewerWrapper {
|
|||
imageInfo: Feature<Point, PanoramaView>,
|
||||
nearbyFeatures?: Feature<Geometry, HotspotProperties>[]
|
||||
) {
|
||||
this._imageInfo.set(imageInfo)
|
||||
console.log(">>>", imageInfo.properties.url)
|
||||
|
||||
this.viewer = pannellum.viewer(container, <any>{
|
||||
default: {
|
||||
firstScene: imageInfo.properties.url,
|
||||
|
|
@ -35,7 +36,7 @@ export class PhotoSphereViewerWrapper {
|
|||
panorama: imageInfo.properties.url,
|
||||
autoLoad: true,
|
||||
hotSpots: [],
|
||||
sceneFadeDuration: 250,
|
||||
// sceneFadeDuration: 250,
|
||||
compass: true,
|
||||
showControls: false,
|
||||
northOffset: imageInfo.properties.northOffset,
|
||||
|
|
@ -43,7 +44,7 @@ export class PhotoSphereViewerWrapper {
|
|||
},
|
||||
},
|
||||
})
|
||||
|
||||
this._imageInfo.set(imageInfo)
|
||||
this.setNearbyFeatures(nearbyFeatures)
|
||||
|
||||
}
|
||||
|
|
@ -80,17 +81,22 @@ export class PhotoSphereViewerWrapper {
|
|||
// Already the current scene
|
||||
return
|
||||
}
|
||||
if (!imageInfo?.properties?.url) {
|
||||
return // Not a panorama
|
||||
}
|
||||
console.log(">>><<<", imageInfo.properties.url)
|
||||
this.clearHotspots()
|
||||
this.viewer.addScene(imageInfo.properties.url, <any>{
|
||||
panorama: imageInfo.properties.url,
|
||||
northOffset: imageInfo.properties.northOffset,
|
||||
type: "equirectangular",
|
||||
showControls: false,
|
||||
compass: true
|
||||
})
|
||||
|
||||
this.viewer.loadScene(imageInfo.properties.url, 0, imageInfo.properties.northOffset)
|
||||
this.setNearbyFeatures(this.nearbyFeatures)
|
||||
this._imageInfo.set(imageInfo)
|
||||
this.setNearbyFeatures(this.nearbyFeatures) // Depends on 'imageInfo', must be set _after_
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue