Здесь может быть подходом, при котором вам не нужно вручную подписываться:
app.component. html
<div *ngIf="tooltip$ | async as tooltip"
class="diagram-tooltip"
[style.top.px]="tooltip.y"
[style.left.px]="tooltip.x">
<p>{{ tooltip.text }}</p>
</div>
app.component .ts
const diagramElementHover$ = merge(
fromEventPattern(handler => this.network.on('hoverNode', handler))
.pipe(
map<any, any>(params => ({ event: params.event, element: this.nodes.find(n => n.id === params.node) }))
),
fromEventPattern(handler => this.network.on('hoverEdge', handler))
.pipe(
map<any, any>(params => ({ event: params.event, element: this.edges.find(e => e.id === params.edge) }))
),
).pipe(
map(obj => ({
text: obj.element.label,
x: obj.event.offsetX + 10,
y: obj.event.offsetY + 10
})
)
);
const hideTooltipObs$ = merge(
fromEventPattern(handler => this.network.on('selectNode', handler)),
fromEventPattern(handler => this.network.on('blurEdge', handler)),
fromEventPattern(handler => this.network.on('blurNode', handler)),
).pipe(
mapTo(null),
tap(() => console.log('hide tooltip')),
publish(),
refCount(),
);
const showTooltip$ = diagramElementHover$.pipe(
switchMap(
obj =>
timer(1000).pipe(
takeUntil(hideTooltipObs$),
isEmpty(),
map(isEmpty => isEmpty ? null : obj)
),
)
);
const hideToolTip$ = hideTooltipObs$;
this.tooltip$ = merge(showTooltip$, hideToolTip$);
Давайте go через каждую соответствующую часть.
fromEventPattern
просто предоставляет способ преобразования API в Observable.
В случаях выше, он создает Observable, который будет генерировать каждый раз, когда вызывается функция-обработчик .
Подробнее об этом здесь .
const hideTooltipObs$ = merge(
/* ... */
).pipe(
mapTo(null),
tap(() => console.log('hide tooltip')),
publish(),
refCount(),
);
publish()
+ refCount()
будет выполнять многоадресную рассылку результатов, помещая экземпляр Subject
между источником данных (hideTooltipObs$
) и потребителями данных (например, hideTooltipObs$.pipe().subscribe()
). Это необходимо, так как hideTooltipObs$
подписан в нескольких местах.
const showTooltip$ = diagramElementHover$.pipe(
switchMap(
obj =>
timer(1000).pipe(
takeUntil(hideTooltipObs$),
isEmpty(),
map(isEmpty => isEmpty ? null : obj)
),
)
);
Каждый раз, когда выдает diagramElementHover$
, запускайте таймер (timer(1000)
), который завершится, когда пройдёт либо 1s
, либо hideTooltipObs$
излучает (из-за takeUntil
). isEmpty()
сгенерирует true
, если источник завершил без выдачи каких-либо значений и false
в противном случае.
Если isEmpty === true
, это означает, что hideTooltipObs$
сгенерирован до 1s
прошло.