diff --git a/projects/observability/src/shared/components/topology/d3/d3-topology.ts b/projects/observability/src/shared/components/topology/d3/d3-topology.ts index 9f64de3ea..2b5a18c0a 100644 --- a/projects/observability/src/shared/components/topology/d3/d3-topology.ts +++ b/projects/observability/src/shared/components/topology/d3/d3-topology.ts @@ -318,7 +318,7 @@ export class D3Topology implements Topology { this.neighborhoodFinder.neighborhoodForNode(hoverEvent.source.userNode), this.neighborhoodFinder.singleNodeNeighborhood(hoverEvent.source.userNode) ); - this.tooltip && this.tooltip.showWithNodeData(hoverEvent.source.userNode); + this.showNodeTooltip(hoverEvent.source, false); } } @@ -328,7 +328,7 @@ export class D3Topology implements Topology { this.tooltip && this.tooltip.hide(); } else { this.emphasizeTopologyNeighborhood(this.neighborhoodFinder.neighborhoodForEdge(hoverEvent.source.userEdge)); - this.tooltip && this.tooltip.showWithEdgeData(hoverEvent.source.userEdge); + this.showEdgeTooltip(hoverEvent.source, false); } } @@ -386,7 +386,7 @@ export class D3Topology implements Topology { ); if (this.tooltip) { // TODO - a modal tooltip disables the interactions like hover (which is good), but doesn't allow clicking another element without an extra click - this.tooltip.showWithNodeData(node.userNode, { modal: true }); + this.showNodeTooltip(node, true); this.tooltip.hidden$.pipe(take(1)).subscribe(() => this.resetVisibility()); } } @@ -395,7 +395,7 @@ export class D3Topology implements Topology { this.emphasizeTopologyNeighborhood(this.neighborhoodFinder.neighborhoodForEdge(edge.userEdge)); if (this.tooltip) { // TODO - a modal tooltip disables the interactions like hover (which is good), but doesn't allow clicking another element without an extra click - this.tooltip.showWithEdgeData(edge.userEdge, { modal: true }); + this.showEdgeTooltip(edge, true); this.tooltip.hidden$.pipe(take(1)).subscribe(() => this.resetVisibility()); } } @@ -422,5 +422,20 @@ export class D3Topology implements Topology { private select(selector: string | T): Selection { return this.d3Util.select(selector, this.domRenderer); } - // tslint:disable-next-line: max-file-line-count + + private showNodeTooltip(node: RenderableTopologyNode, modal: boolean): void { + const originEl = this.nodeRenderer.getElementForNode(node); + if (!originEl || !this.tooltip) { + return; + } + this.tooltip.showWithNodeData(node.userNode, new ElementRef(originEl), { modal: modal }); + } + + private showEdgeTooltip(edge: RenderableTopologyEdge, modal: boolean): void { + const originEl = this.edgeRenderer.getElementForEdge(edge); + if (!originEl || !this.tooltip) { + return; + } + this.tooltip.showWithEdgeData(edge.userEdge, new ElementRef(originEl), { modal: modal }); + } } diff --git a/projects/observability/src/shared/components/topology/renderers/tooltip/topology-tooltip-popover.ts b/projects/observability/src/shared/components/topology/renderers/tooltip/topology-tooltip-popover.ts index 1a3f35e45..a85bb769f 100644 --- a/projects/observability/src/shared/components/topology/renderers/tooltip/topology-tooltip-popover.ts +++ b/projects/observability/src/shared/components/topology/renderers/tooltip/topology-tooltip-popover.ts @@ -1,11 +1,5 @@ import { ElementRef, Injector } from '@angular/core'; -import { - PopoverBackdrop, - PopoverPositionType, - PopoverRef, - PopoverRelativePositionLocation, - PopoverService -} from '@hypertrace/components'; +import { PopoverBackdrop, PopoverPositionType, PopoverRef, PopoverService } from '@hypertrace/components'; import { BehaviorSubject, merge, Observable, ReplaySubject, Subject } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { TopologyEdge, TopologyNode, TopologyTooltip, TopologyTooltipOptions } from '../../topology'; @@ -26,12 +20,12 @@ export class TopologyTooltipPopover implements TopologyTooltip { private readonly injector: Injector, private readonly popoverService: PopoverService ) { - this.popoverSubject = new BehaviorSubject(this.buildPopover(false)); + this.popoverSubject = new BehaviorSubject(this.buildPopover(false, this.container)); this.hidden$ = this.popoverSubject.pipe(switchMap(popover => merge(popover.hidden$, popover.closed$))); } - public showWithNodeData(node: TopologyNode, options: TopologyTooltipOptions = {}): void { - this.rebuildPopoverIfNeeded(options); + public showWithNodeData(node: TopologyNode, origin: ElementRef, options: TopologyTooltipOptions = {}): void { + this.rebuildPopoverIfNeeded(origin, options); this.dataSubject.next({ type: 'node', node: node, @@ -40,8 +34,8 @@ export class TopologyTooltipPopover implements TopologyTooltip { this.popover.show(); } - public showWithEdgeData(edge: TopologyEdge, options: TopologyTooltipOptions = {}): void { - this.rebuildPopoverIfNeeded(options); + public showWithEdgeData(edge: TopologyEdge, origin: ElementRef, options: TopologyTooltipOptions = {}): void { + this.rebuildPopoverIfNeeded(origin, options); this.dataSubject.next({ type: 'edge', edge: edge, @@ -60,17 +54,17 @@ export class TopologyTooltipPopover implements TopologyTooltip { this.popoverSubject.complete(); } - private rebuildPopoverIfNeeded(options: TopologyTooltipOptions): void { + private rebuildPopoverIfNeeded(origin: ElementRef, options: TopologyTooltipOptions): void { const modal = !!options.modal; if (modal === this.popover.hasBackdrop()) { return; } this.popover.close(); // Close existing popover - this.popoverSubject.next(this.buildPopover(modal)); + this.popoverSubject.next(this.buildPopover(!!options.modal, origin)); } - private buildPopover(modal: boolean): PopoverRef { + private buildPopover(modal: boolean, origin: ElementRef): PopoverRef { const popover = this.popoverService.drawPopover({ componentOrTemplate: this.tooltipDefinition.class, position: { @@ -86,9 +80,10 @@ export class TopologyTooltipPopover implements TopologyTooltip { } popover.updatePositionStrategy({ - type: PopoverPositionType.Relative, - locationPreferences: [PopoverRelativePositionLocation.InsideTopLeft], - origin: this.container + type: PopoverPositionType.FollowMouse, + boundingElement: modal ? origin.nativeElement : this.container.nativeElement, + offsetX: 50, + offsetY: 30 }); return popover; diff --git a/projects/observability/src/shared/components/topology/topology.ts b/projects/observability/src/shared/components/topology/topology.ts index 66c423994..2c9558f1d 100644 --- a/projects/observability/src/shared/components/topology/topology.ts +++ b/projects/observability/src/shared/components/topology/topology.ts @@ -179,8 +179,8 @@ export interface TopologyTooltipRenderer { } export interface TopologyTooltip { - showWithNodeData(node: TopologyNode, options?: TopologyTooltipOptions): void; - showWithEdgeData(edge: TopologyEdge, options?: TopologyTooltipOptions): void; + showWithNodeData(node: TopologyNode, origin: ElementRef, options?: TopologyTooltipOptions): void; + showWithEdgeData(edge: TopologyEdge, origin: ElementRef, options?: TopologyTooltipOptions): void; hide(): void; destroy(): void; hidden$: Observable;