in src/component/sequence/SequenceComponent.ts [209:516]
protected _activate(): void {
this._sequenceDOMRenderer.activate();
const edgeStatus$ = this._navigator.stateService.currentImage$.pipe(
switchMap(
(image: Image): Observable<NavigationEdgeStatus> => {
return image.sequenceEdges$;
}),
publishReplay(1),
refCount());
const sequence$ = this._navigator.stateService.currentImage$.pipe(
distinctUntilChanged(
undefined,
(image: Image): string => {
return image.sequenceId;
}),
switchMap(
(image: Image): Observable<Sequence> => {
return observableConcat(
observableOf(null),
this._navigator.graphService.cacheSequence$(image.sequenceId).pipe(
retry(3),
catchError(
(e: Error): Observable<Sequence> => {
console.error("Failed to cache sequence", e);
return observableOf(null);
})));
}),
startWith(null),
publishReplay(1),
refCount());
const subs = this._subscriptions;
subs.push(sequence$.subscribe());
const rendererId$ = this._sequenceDOMRenderer.index$.pipe(
withLatestFrom(sequence$),
map(
([index, sequence]: [number, Sequence]): string => {
return sequence != null ? sequence.imageIds[index] : null;
}),
filter(
(id: string): boolean => {
return !!id;
}),
distinctUntilChanged(),
publish(),
refCount());
subs.push(observableMerge(
rendererId$.pipe(debounceTime(100, this._scheduler)),
rendererId$.pipe(auditTime(400, this._scheduler))).pipe(
distinctUntilChanged(),
switchMap(
(id: string): Observable<Image> => {
return this._navigator.moveTo$(id).pipe(
catchError(
(): Observable<Image> => {
return observableEmpty();
}));
}))
.subscribe());
subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(
filter(
(changing: boolean): boolean => {
return changing;
}))
.subscribe(
(): void => {
this._navigator.graphService.setGraphMode(GraphMode.Sequence);
}));
subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(
filter(
(changing: boolean): boolean => {
return !changing;
}))
.subscribe(
(): void => {
this._navigator.graphService.setGraphMode(GraphMode.Spatial);
}));
this._navigator.graphService.graphMode$.pipe(
switchMap(
(mode: GraphMode): Observable<Image> => {
return mode === GraphMode.Spatial ?
this._navigator.stateService.currentImage$.pipe(
take(2)) :
observableEmpty();
}),
filter(
(image: Image): boolean => {
return !image.spatialEdges.cached;
}),
switchMap(
(image: Image): Observable<Image> => {
return this._navigator.graphService.cacheImage$(image.id).pipe(
catchError(
(): Observable<Image> => {
return observableEmpty();
}));
}))
.subscribe();
subs.push(this._sequenceDOMRenderer.changingPositionChanged$.pipe(
filter(
(changing: boolean): boolean => {
return changing;
}))
.subscribe(
(): void => {
this._navigator.playService.stop();
}));
subs.push(observableCombineLatest(
this._navigator.graphService.graphMode$,
this._sequenceDOMRenderer.changingPositionChanged$.pipe(
startWith(false),
distinctUntilChanged())).pipe(
withLatestFrom(this._navigator.stateService.currentImage$),
switchMap(
([[mode, changing], image]: [[GraphMode, boolean], Image]): Observable<Sequence> => {
return changing && mode === GraphMode.Sequence ?
this._navigator.graphService.cacheSequenceImages$(image.sequenceId, image.id).pipe(
retry(3),
catchError(
(error: Error): Observable<Sequence> => {
console.error("Failed to cache sequence images.", error);
return observableEmpty();
})) :
observableEmpty();
}))
.subscribe());
const position$: Observable<{ index: number, max: number }> = sequence$.pipe(
switchMap(
(sequence: Sequence): Observable<{ index: number, max: number }> => {
if (!sequence) {
return observableOf({ index: null, max: null });
}
let firstCurrentId: boolean = true;
return this._sequenceDOMRenderer.changingPositionChanged$.pipe(
startWith(false),
distinctUntilChanged(),
switchMap(
(changingPosition: boolean): Observable<string> => {
const skipCount: number =
!changingPosition &&
firstCurrentId ?
0 : 1;
firstCurrentId = false;
return changingPosition ?
rendererId$ :
this._navigator.stateService.currentImage$.pipe(
map(
(image: Image): string => {
return image.id;
}),
distinctUntilChanged(),
skip(skipCount));
}),
map(
(imageId: string): { index: number, max: number } => {
const index: number = sequence.imageIds.indexOf(imageId);
if (index === -1) {
return { index: null, max: null };
}
return { index: index, max: sequence.imageIds.length - 1 };
}));
}));
const earth$ = this._navigator.stateService.state$.pipe(
map(
(state: State): boolean => {
return state === State.Earth;
}),
distinctUntilChanged());
subs.push(observableCombineLatest(
edgeStatus$,
this._configuration$,
this._containerWidth$,
this._sequenceDOMRenderer.changed$.pipe(startWith(this._sequenceDOMRenderer)),
this._navigator.playService.speed$,
position$,
earth$).pipe(
map(
(
[edgeStatus, configuration, containerWidth, , speed, position, earth]:
[
NavigationEdgeStatus,
SequenceConfiguration,
number,
SequenceDOMRenderer,
number,
{ index: number, max: number },
boolean,
]): VirtualNodeHash => {
const vNode: vd.VNode = this._sequenceDOMRenderer
.render(
edgeStatus,
configuration,
containerWidth,
speed,
position.index,
position.max,
!earth,
this,
this._navigator);
return { name: this._name, vNode: vNode };
}))
.subscribe(this._container.domRenderer.render$));
subs.push(this._sequenceDOMRenderer.speed$
.subscribe(
(speed: number): void => {
this._navigator.playService.setSpeed(speed);
}));
subs.push(this._configuration$.pipe(
map(
(configuration: SequenceConfiguration): NavigationDirection => {
return configuration.direction;
}),
distinctUntilChanged())
.subscribe(
(direction: NavigationDirection): void => {
this._navigator.playService.setDirection(direction);
}));
subs.push(observableCombineLatest(
this._container.renderService.size$,
this._configuration$.pipe(
distinctUntilChanged(
(value1: [number, number], value2: [number, number]): boolean => {
return value1[0] === value2[0] && value1[1] === value2[1];
},
(configuration: SequenceConfiguration) => {
return [configuration.minWidth, configuration.maxWidth];
}))).pipe(
map(
([size, configuration]: [ViewportSize, SequenceConfiguration]): number => {
return this._sequenceDOMRenderer.getContainerWidth(
size,
configuration);
}))
.subscribe(this._containerWidth$));
subs.push(this._configuration$.pipe(
map(
(configuration: SequenceConfiguration): boolean => {
return configuration.playing;
}),
distinctUntilChanged())
.subscribe(
(playing: boolean) => {
if (playing) {
this._navigator.playService.play();
} else {
this._navigator.playService.stop();
}
}));
subs.push(this._sequenceDOMRenderer.mouseEnterDirection$.pipe(
switchMap(
(direction: NavigationDirection): Observable<string> => {
const edgeTo$: Observable<string> = edgeStatus$.pipe(
map(
(edgeStatus: NavigationEdgeStatus): string => {
for (let edge of edgeStatus.edges) {
if (edge.data.direction === direction) {
return edge.target;
}
}
return null;
}),
takeUntil(this._sequenceDOMRenderer.mouseLeaveDirection$));
return observableConcat(edgeTo$, observableOf<string>(null));
}),
distinctUntilChanged())
.subscribe(this._hoveredIdSubject$));
subs.push(this._hoveredId$
.subscribe(
(id: string): void => {
const type: ComponentEventType = "hover";
const event: ComponentHoverEvent = {
id,
target: this,
type,
}
this.fire(type, event);
}));
}