Skip to content

Commit

Permalink
fix: viewer configuration as observables
Browse files Browse the repository at this point in the history
Avoid setting static properties which affects
all future Viewers created in the same app.
Use observables instead.
  • Loading branch information
oscarlorentzon committed Jun 10, 2021
1 parent b9ab9ba commit a1df915
Show file tree
Hide file tree
Showing 14 changed files with 327 additions and 198 deletions.
25 changes: 17 additions & 8 deletions src/component/attribution/AttributionComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { map } from "rxjs/operators";
import { Image } from "../../graph/Image";
import { ViewportSize } from "../../render/interfaces/ViewportSize";
import { VirtualNodeHash } from "../../render/interfaces/VirtualNodeHash";
import { ViewerConfiguration } from "../../viewer/ViewerConfiguration";

import { Component } from "../Component";
import { ComponentConfiguration } from "../interfaces/ComponentConfiguration";
Expand All @@ -18,13 +17,15 @@ export class AttributionComponent extends Component<ComponentConfiguration> {
protected _activate(): void {
this._subscriptions.push(
observableCombineLatest(
this._container.configurationService.exploreUrl$,
this._navigator.stateService.currentImage$,
this._container.renderService.size$).pipe(
map(
([image, size]: [Image, ViewportSize]): VirtualNodeHash => {
([exploreUrl, image, size]: [string, Image, ViewportSize]): VirtualNodeHash => {
const attribution =
this._makeAttribution(
image.creatorUsername,
exploreUrl,
image.id,
image.capturedAt,
size.width);
Expand All @@ -44,16 +45,21 @@ export class AttributionComponent extends Component<ComponentConfiguration> {
return {};
}

private makeImageUrl(exploreUrl: string, id: string): string {
return `${exploreUrl}/app/?pKey=${id}&focus=photo`;
}

private _makeAttribution(
creatorUsername: string,
exploreUrl: string,
imageId: string,
capturedAt: number,
viewportWidth: number)
: vd.VNode {
const compact = viewportWidth <= 640;

const date = this._makeDate(capturedAt, compact);
const by = this._makeBy(creatorUsername, imageId, compact);
const by = this._makeBy(creatorUsername, exploreUrl, imageId, compact);

const compactClass = compact ?
".mapillary-attribution-compact" : "";
Expand All @@ -66,25 +72,27 @@ export class AttributionComponent extends Component<ComponentConfiguration> {

private _makeBy(
creatorUsername: string,
exploreUrl: string,
imageId: string,
compact: boolean): vd.VNode[] {

const icon = vd.h(
"div.mapillary-attribution-logo",
[]);
return creatorUsername ?
this._makeCreatorBy(icon, creatorUsername, imageId, compact) :
this._makeGeneralBy(icon, imageId, compact);
this._makeCreatorBy(icon, creatorUsername, exploreUrl, imageId, compact) :
this._makeGeneralBy(icon, exploreUrl, imageId, compact);
}

private _makeCreatorBy(
icon: vd.VNode,
creatorUsername: string,
exploreUrl: string,
imageId: string,
compact: boolean): vd.VNode[] {
const mapillary = vd.h(
"a.mapillary-attribution-icon-container",
{ href: ViewerConfiguration.explore, rel: "noreferrer", target: "_blank" },
{ href: exploreUrl, rel: "noreferrer", target: "_blank" },
[icon]);

const content = compact ?
Expand All @@ -97,7 +105,7 @@ export class AttributionComponent extends Component<ComponentConfiguration> {
const image = vd.h(
"a.mapillary-attribution-image-container",
{
href: ViewerConfiguration.exploreImage(imageId),
href: this.makeImageUrl(exploreUrl, imageId),
rel: "noreferrer",
target: "_blank",
},
Expand All @@ -108,6 +116,7 @@ export class AttributionComponent extends Component<ComponentConfiguration> {

private _makeGeneralBy(
icon: vd.VNode,
exploreUrl: string,
imageId: string,
compact: boolean): vd.VNode[] {

Expand All @@ -134,7 +143,7 @@ export class AttributionComponent extends Component<ComponentConfiguration> {
const image = vd.h(
"a.mapillary-attribution-image-container",
{
href: ViewerConfiguration.exploreImage(imageId),
href: this.makeImageUrl(exploreUrl, imageId),
rel: "noreferrer",
target: "_blank",
},
Expand Down
17 changes: 12 additions & 5 deletions src/component/cover/CoverComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { MapillaryError } from "../../error/MapillaryError";
import { Image as MImage } from "../../graph/Image";
import { ViewportSize } from "../../render/interfaces/ViewportSize";
import { VirtualNodeHash } from "../../render/interfaces/VirtualNodeHash";
import { ViewerConfiguration } from "../../viewer/ViewerConfiguration";
import { Container } from "../../viewer/Container";
import { Navigator } from "../../viewer/Navigator";
import { ImagesContract } from "../../api/contracts/ImagesContract";
Expand Down Expand Up @@ -128,9 +127,11 @@ export class CoverComponent extends Component<CoverConfiguration> {

subs.push(observableCombineLatest(
this._configuration$,
this._container.configurationService.exploreUrl$,
this._container.renderService.size$).pipe(
map(
([configuration, size]: [CoverConfiguration, ViewportSize]): VirtualNodeHash => {
([configuration, exploreUrl, size]:
[CoverConfiguration, string, ViewportSize]): VirtualNodeHash => {
if (!configuration.src) {
return { name: this._name, vNode: vd.h("div", []) };
}
Expand All @@ -147,7 +148,7 @@ export class CoverComponent extends Component<CoverConfiguration> {

const container: vd.VNode = vd.h(
"div.mapillary-cover-container" + compactClass,
[this._getCoverButtonVNode(configuration)]);
[this._getCoverButtonVNode(configuration, exploreUrl)]);

return { name: this._name, vNode: container };
}))
Expand All @@ -162,13 +163,19 @@ export class CoverComponent extends Component<CoverConfiguration> {
return { state: CoverState.Visible };
}

private _getCoverButtonVNode(configuration: CoverConfiguration): vd.VNode {
private _getCoverButtonVNode(
configuration: CoverConfiguration,
exploreUrl: string): vd.VNode {

const cover: string = configuration.state === CoverState.Loading ? "div.mapillary-cover.mapillary-cover-loading" : "div.mapillary-cover";
const coverButton: vd.VNode = vd.h(
"div.mapillary-cover-button",
[vd.h("div.mapillary-cover-button-icon", [])]);

const coverLogo: vd.VNode = vd.h("a.mapillary-cover-logo", { href: ViewerConfiguration.explore, target: "_blank" }, []);
const coverLogo: vd.VNode = vd.h(
"a.mapillary-cover-logo",
{ href: exploreUrl, target: "_blank" },
[]);
const coverIndicator: vd.VNode = vd.h(
"div.mapillary-cover-indicator",
{ onclick: (): void => { this.configure({ state: CoverState.Loading }); } },
Expand Down
117 changes: 62 additions & 55 deletions src/component/image/ImageComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,8 @@ import { RegionOfInterestCalculator }
import { TextureProvider } from "../../tile/TextureProvider";
import { ComponentConfiguration } from "../interfaces/ComponentConfiguration";
import { Transform } from "../../geo/Transform";
import { ViewerConfiguration } from "../../viewer/ViewerConfiguration";
import { ComponentName } from "../ComponentName";
import { State } from "../../state/State";
import { Camera } from "three";

interface ImageGLRendererOperation {
(renderer: ImageGLRenderer): ImageGLRenderer;
Expand Down Expand Up @@ -170,9 +168,14 @@ export class ImageComponent extends Component<ComponentConfiguration> {
}))
.subscribe(this._rendererOperation$));

const textureProvider$ = this._navigator.stateService.currentState$
.pipe(
filter(() => ViewerConfiguration.imageTiling),
const textureProvider$ =
this._container.configurationService.imageTiling$.pipe(
switchMap(
(active): Observable<AnimationFrame> => {
return active ?
this._navigator.stateService.currentState$ :
new Subject();
}),
distinctUntilChanged(
undefined,
(frame: AnimationFrame): string => {
Expand Down Expand Up @@ -220,56 +223,60 @@ export class ImageComponent extends Component<ComponentConfiguration> {
previous.abort();
}));

const roiTrigger$ = ViewerConfiguration.imageTiling ?
observableCombineLatest(
this._navigator.stateService.state$,
this._navigator.stateService.inTranslation$)
.pipe(
switchMap(
([state, inTranslation]: [State, boolean]) => {
const streetState =
state === State.Traversing ||
state === State.Waiting ||
state === State.WaitingInteractively;
const active = streetState && !inTranslation;
return active ?
this._container.renderService.renderCameraFrame$ :
observableEmpty();
}),
map(
(camera: RenderCamera): PositionLookat => {
return {
camera,
height: camera.size.height.valueOf(),
lookat: camera.camera.lookat.clone(),
width: camera.size.width.valueOf(),
zoom: camera.zoom.valueOf(),
};
}),
pairwise(),
map(
([pl0, pl1]: [PositionLookat, PositionLookat])
: StalledCamera => {
const stalled =
pl0.width === pl1.width &&
pl0.height === pl1.height &&
pl0.zoom === pl1.zoom &&
pl0.lookat.equals(pl1.lookat);

return { camera: pl1.camera, stalled };
}),
distinctUntilChanged(
(x, y): boolean => {
return x.stalled === y.stalled;
}),
filter(
(camera: StalledCamera): boolean => {
return camera.stalled;
}),
withLatestFrom(
this._container.renderService.size$,
this._navigator.stateService.currentTransform$)) :
observableEmpty();
const roiTrigger$ =
this._container.configurationService.imageTiling$.pipe(
switchMap(
(active): Observable<[State, boolean]> => {
return active ?
observableCombineLatest(
this._navigator.stateService.state$,
this._navigator.stateService.inTranslation$) :
new Subject();
}),
switchMap(
([state, inTranslation]: [State, boolean]) => {
const streetState =
state === State.Traversing ||
state === State.Waiting ||
state === State.WaitingInteractively;
const active = streetState && !inTranslation;
return active ?
this._container.renderService.renderCameraFrame$ :
observableEmpty();
}),
map(
(camera: RenderCamera): PositionLookat => {
return {
camera,
height: camera.size.height.valueOf(),
lookat: camera.camera.lookat.clone(),
width: camera.size.width.valueOf(),
zoom: camera.zoom.valueOf(),
};
}),
pairwise(),
map(
([pl0, pl1]: [PositionLookat, PositionLookat])
: StalledCamera => {
const stalled =
pl0.width === pl1.width &&
pl0.height === pl1.height &&
pl0.zoom === pl1.zoom &&
pl0.lookat.equals(pl1.lookat);

return { camera: pl1.camera, stalled };
}),
distinctUntilChanged(
(x, y): boolean => {
return x.stalled === y.stalled;
}),
filter(
(camera: StalledCamera): boolean => {
return camera.stalled;
}),
withLatestFrom(
this._container.renderService.size$,
this._navigator.stateService.currentTransform$));

subs.push(textureProvider$.pipe(
switchMap(
Expand Down
Loading

0 comments on commit a1df915

Please sign in to comment.