Skip to content

Commit 3a9bb9b

Browse files
committed
MB-71194 - Fix location and size of query plan tool tips
There were two related problems: 1) The tooltip vertical size could be unbounded, especially in the case of "Project" nodes for queries with many explicitly specified fields. The tooltip size could easily exceed the vertical size of the window. 2) By default the tooltip's top left corner is the location where the user clicked, even if that meant that much of the tooltip would be off the bottom of the screen. This fix adds scrollbars to the tooltip, and ensures that tooltip's top is never so low as to cause the bottom of the tooltip to go off the screen. Change-Id: I25f9d63904c9de912c7b5455426571eab5b1295b Reviewed-on: https://review.couchbase.org/c/query-ui/+/242542 Well-Formed: Restriction Checker Reviewed-by: Eben Haber <eben@couchbase.com> Tested-by: Eben Haber <eben@couchbase.com>
1 parent 6f58f98 commit 3a9bb9b

3 files changed

Lines changed: 43 additions & 8 deletions

File tree

query-ui/angular-directives/qw.explain.viz.component.js

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { CommonModule } from '@angular/common';
2727
import _ from "lodash";
2828

2929
import {select as d3Select,
30-
event as d3Event} from "d3-selection";
30+
event as d3Event, mouse as d3Mouse} from "d3-selection";
3131
import {linkVertical as d3LinkVertical,
3232
linkHorizontal as d3LinkHorizontal} from "d3-shape";
3333

@@ -95,6 +95,7 @@ class QwExplainViz extends MnLifeCycleHooksToStream {
9595
//console.log("Directive ngAfterInit, input: " + this.qwJsonDataTable2);
9696
outerElement = this.element.nativeElement.querySelector('.wb-results-explain');
9797
wrapperElement = this.element.nativeElement.querySelector('.wb-explain-d3-wrapper');
98+
mainElement = window.document.querySelector('.main-content');
9899

99100
// when used in the workbench, we get an observable tied to the current
100101
// query result
@@ -155,6 +156,7 @@ var queryService;
155156
var outerElement;
156157
var wrapperElement;
157158
var simpleTree; // underlying data
159+
var mainElement;
158160

159161
function makeTree(element) {
160162
clearContent();
@@ -529,6 +531,11 @@ function makeTooltip(d) {
529531

530532
// the tooltip is relative to the query plan div, so we need to know its offset.
531533
var outerBox = outerElement.getBoundingClientRect();
534+
// tooltip is positioned absolutely, so compute location relative to top-level container
535+
var mainBox = mainElement?.getBoundingClientRect() || [0,0,0,0];
536+
var relativeTop = outerBox.top - mainBox.top;
537+
538+
var containerPadding = 8;
532539
// create the new tooltip
533540
var tooltip_div = d3Select(".wb-results-explain")
534541
.append("div")
@@ -538,14 +545,36 @@ function makeTooltip(d) {
538545
// return tooltip_div.style("display", "none");
539546
//})
540547
;
548+
var mouseCoords = d3Mouse(mainElement);
549+
550+
var pointerX = mouseCoords[0];
551+
var pointerY = mouseCoords[1];
541552

542553
if (d.data.tooltip && d.data.tooltip.length > 0) {
554+
var maxTooltipWidth = Math.max(200, outerBox.width - containerPadding * 2);
555+
var maxTooltipHeight = Math.max(120, outerBox.height - containerPadding * 2);
556+
543557
tooltip_div.transition().duration(300).style("display", "block");
544-
var header_div = tooltip_div.append("div");
545-
header_div.html('<a class="ui-dialog-titlebar-close modal-close" onclick="console.log(\"click\")"> X </a>');
546558
tooltip_div.html(d.data.tooltip)
547-
.style("left", (d3Event.x - outerBox.left) + "px")
548-
.style("top", (d3Event.y - outerElement.offsetTop/2) + "px");
559+
.style("max-width", maxTooltipWidth + "px")
560+
.style("max-height", maxTooltipHeight + "px")
561+
.style("overflow", "auto");
562+
563+
// Place near the click point, then clamp inside the visible explain area.
564+
var tooltipNode = tooltip_div.node();
565+
var tooltipBox = tooltipNode ? tooltipNode.getBoundingClientRect() : null;
566+
var tooltipWidth = tooltipBox ? tooltipBox.width : 0;
567+
var tooltipHeight = tooltipBox ? tooltipBox.height : 0;
568+
// don't allow bottom of tooltip to go off the panel
569+
const maxTop = relativeTop + (outerBox.height - tooltipHeight);
570+
571+
var left = Math.max(containerPadding,
572+
Math.min(pointerX, outerBox.width - tooltipWidth - containerPadding));
573+
var top = pointerY < maxTop ? pointerY : maxTop;
574+
575+
tooltip_div
576+
.style("left", left + "px")
577+
.style("top", top + "px");
549578
}
550579

551580
d3Event.stopPropagation();

query-ui/angular-directives/qw.explain.viz.template.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@
3838
<em *ngFor="let f of data.analysis.fields">{{ f }}&nbsp;&nbsp;</em>
3939
</div>
4040

41-
<div class="column row flex-grow-half flex-right">
41+
<div class="column row flex-grow-half flex-right margin-top-half">
4242
<span (click)="leftRight()" class="icon fa-caret-square-o-left wb-explain-plan-orient" [ngClass]="{'wb-explain-plan-selected-orient' : orientIs(1)}" title="change plan direction"></span>
4343
<span (click)="rightLeft()" class="icon fa-caret-square-o-right wb-explain-plan-orient" [ngClass]="{'wb-explain-plan-selected-orient' : orientIs(3)}" title="change plan direction"></span>
4444
<span (click)="bottomTop()" class="icon fa-caret-square-o-down wb-explain-plan-orient" [ngClass]="{'wb-explain-plan-selected-orient' : orientIs(4)}" title="change plan direction"></span>
4545
<span (click)="topDown()" class="icon fa-caret-square-o-up wb-explain-plan-orient" [ngClass]="{'wb-explain-plan-selected-orient' : orientIs(2)}" title="change plan direction"></span>
4646
</div>
4747

48-
<div class="column row flex-right">
48+
<div class="column row flex-right margin-top-half">
4949
<span (click)="zoomIn()" class="icon fa-search-minus wb-explain-plan-zoom" title="zoom out - or use scroll wheel"></span>
5050
<span (click)="zoomOut()" class="icon fa-search-plus wb-explain-plan-zoom" title="zoom in - or use scroll wheel"></span>
5151
</div>

query-ui/ui-current/query.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,12 @@ textarea.ng-invalid-number {
168168

169169
/* styles for D3-based query explain plan ---------------------------------- */
170170
.wb-explain-summary {
171+
display: flex;
172+
align-items: flex-start;
171173
font-size: .75rem;
172174
padding: .25rem 1rem;
175+
max-height: 3rem;
176+
overflow: clip;
173177
}
174178
.wb-explain-summary .column {
175179
flex-grow: 1;
@@ -186,7 +190,7 @@ textarea.ng-invalid-number {
186190
}
187191
.wb-explain-d3-wrapper, .wb-results-chart {
188192
width: 100%;
189-
height: 100%;
193+
height: calc(100% - 3.5rem);
190194
position: relative;
191195
font-family: OpenSans;
192196
}
@@ -288,6 +292,8 @@ marker {
288292
border-top: solid .25rem #4287d6;
289293
box-shadow: 0px 5px 14px 2px rgba(0,0,0,0.14);
290294
min-width: 200px;
295+
overscroll-behavior: contain;
296+
overflow-wrap: anywhere;
291297
z-index: 10;
292298
}
293299
.wb-explain-tooltip h5 {

0 commit comments

Comments
 (0)