@hpcc-js/html 3.3.6 → 3.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +43 -43
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +1 -1
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +6 -6
- package/src/BreakdownTable.ts +218 -218
- package/src/HTMLTooltip.ts +384 -384
- package/src/JSXWidget.ts +13 -13
- package/src/SimpleTable.ts +63 -63
- package/src/StatsTable.ts +103 -103
- package/src/StyledTable.ts +68 -68
- package/src/TitleBar.css +84 -84
- package/src/TitleBar.ts +136 -136
- package/src/VizComponent.tsx +39 -39
- package/src/VizInstance.tsx +39 -39
- package/src/__package__.ts +3 -3
- package/src/index.ts +11 -11
- package/src/reactD3.ts +127 -127
package/src/HTMLTooltip.ts
CHANGED
|
@@ -1,384 +1,384 @@
|
|
|
1
|
-
import { HTMLWidget, select as d3Select } from "@hpcc-js/common";
|
|
2
|
-
import { scopedLogger, ScopedLogging } from "@hpcc-js/util";
|
|
3
|
-
|
|
4
|
-
type Direction = "n" | "s" | "e" | "w" | "ne" | "nw" | "se" | "sw";
|
|
5
|
-
type Position = { x: number, y: number };
|
|
6
|
-
type DirectionalBBox = { [key in Direction]: Position; };
|
|
7
|
-
|
|
8
|
-
type Rectangle = { top: number, left: number, width: number, height: number };
|
|
9
|
-
export class HTMLTooltip extends HTMLWidget {
|
|
10
|
-
|
|
11
|
-
public _triggerElement;
|
|
12
|
-
public _contentNode;
|
|
13
|
-
protected _prevContentNode;
|
|
14
|
-
|
|
15
|
-
protected _tooltipElement;
|
|
16
|
-
protected _arrowElement;
|
|
17
|
-
protected _tooltipHTMLCallback = (data?) => "<b>_tooltipHTMLCallback is undefined</b>";
|
|
18
|
-
protected _logger: ScopedLogging = scopedLogger("html/HTMLTooltip");
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
this.visible(false);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
tooltipHTML(_: (data?) => string): this {
|
|
25
|
-
this._tooltipHTMLCallback = _;
|
|
26
|
-
return this;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
tooltipContent(_): this {
|
|
30
|
-
if (!arguments.length) return this._contentNode;
|
|
31
|
-
this._contentNode = _;
|
|
32
|
-
return this;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
triggerElement(_): this {
|
|
36
|
-
this._triggerElement = _;
|
|
37
|
-
return this;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
enter(domNode, element) {
|
|
41
|
-
super.enter(domNode, element);
|
|
42
|
-
const body = d3Select("body");
|
|
43
|
-
this._tooltipElement = body.append("div")
|
|
44
|
-
.attr("class", "tooltip-div")
|
|
45
|
-
.style("z-index", "2147483638")
|
|
46
|
-
.style("position", "fixed")
|
|
47
|
-
;
|
|
48
|
-
this._arrowElement = body.append("div")
|
|
49
|
-
.attr("class", "arrow-div")
|
|
50
|
-
.style("z-index", "2147483638")
|
|
51
|
-
.style("position", "fixed")
|
|
52
|
-
;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
update(domNode, element) {
|
|
56
|
-
super.update(domNode, element);
|
|
57
|
-
|
|
58
|
-
if (this._contentNode !== this._prevContentNode) {
|
|
59
|
-
const node = this._tooltipElement.node();
|
|
60
|
-
[...node.querySelectorAll("*")]
|
|
61
|
-
.map(n => n.__data__)
|
|
62
|
-
.filter(n => n)
|
|
63
|
-
.forEach(w => {
|
|
64
|
-
if (typeof w.target === "function") {
|
|
65
|
-
w.target(null);
|
|
66
|
-
}
|
|
67
|
-
if (typeof w.exit === "function") {
|
|
68
|
-
w.exit();
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
node.innerHTML = "";
|
|
72
|
-
node.appendChild(this._contentNode);
|
|
73
|
-
this._prevContentNode = this._contentNode;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (this._contentNode) {
|
|
77
|
-
this.onShowContent(this._contentNode);
|
|
78
|
-
} else {
|
|
79
|
-
this._tooltipElement
|
|
80
|
-
.html(() => {
|
|
81
|
-
return this._tooltipHTMLCallback(this.data());
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
if (this.fitContent()) {
|
|
85
|
-
this._tooltipElement
|
|
86
|
-
.style("width", "auto")
|
|
87
|
-
.style("height", "auto")
|
|
88
|
-
.style("padding", "0px")
|
|
89
|
-
.style("box-sizing", "content-box")
|
|
90
|
-
;
|
|
91
|
-
const rect = this._tooltipElement.node().getBoundingClientRect();
|
|
92
|
-
this.tooltipWidth_default(rect.width);
|
|
93
|
-
this.tooltipHeight_default(rect.height);
|
|
94
|
-
}
|
|
95
|
-
this._closing = false;
|
|
96
|
-
this._tooltipElement
|
|
97
|
-
.style("background-color", this.tooltipColor())
|
|
98
|
-
.style("color", this.fontColor())
|
|
99
|
-
.style("width", this.tooltipWidth() + "px")
|
|
100
|
-
.style("height", this.tooltipHeight() + "px")
|
|
101
|
-
.style("opacity", 1)
|
|
102
|
-
.style("padding", this.padding() + "px")
|
|
103
|
-
.style("pointer-events", this.enablePointerEvents() ? "all" : "none")
|
|
104
|
-
.style("box-sizing", "content-box")
|
|
105
|
-
;
|
|
106
|
-
this._arrowElement
|
|
107
|
-
.style("opacity", 1)
|
|
108
|
-
.style("pointer-events", "none")
|
|
109
|
-
;
|
|
110
|
-
this.updateTooltipPosition();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
onShowContent(node) {
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
protected updateTooltipPosition(): Position {
|
|
118
|
-
const bbox = this.calcReferenceBBox();
|
|
119
|
-
const direction = this.calcTooltipDirection(bbox);
|
|
120
|
-
const box = bbox[direction];
|
|
121
|
-
this._tooltipElement
|
|
122
|
-
.style("top", box.y + "px")
|
|
123
|
-
.style("left", box.x + "px")
|
|
124
|
-
;
|
|
125
|
-
this.setArrowPosition(box, direction);
|
|
126
|
-
return box;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
protected calcTooltipDirection(bbox: DirectionalBBox): Direction {
|
|
130
|
-
const directions: Direction[] = Object.keys(bbox) as Direction[];
|
|
131
|
-
|
|
132
|
-
const defaultDirection = this.direction();
|
|
133
|
-
directions.sort((a, b) => a === defaultDirection ? -1 : 1);
|
|
134
|
-
const windowRect = {
|
|
135
|
-
top: 0,
|
|
136
|
-
left: 0,
|
|
137
|
-
width: window.innerWidth,
|
|
138
|
-
height: window.innerHeight
|
|
139
|
-
};
|
|
140
|
-
for (let i = 0; i < directions.length; i++) {
|
|
141
|
-
const tooltipRect = {
|
|
142
|
-
top: bbox[directions[i]].y,
|
|
143
|
-
left: bbox[directions[i]].x,
|
|
144
|
-
width: this.tooltipWidth(),
|
|
145
|
-
height: this.tooltipHeight()
|
|
146
|
-
};
|
|
147
|
-
if (this.rectFits(tooltipRect, windowRect)) {
|
|
148
|
-
return directions[i];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
this._logger.warning(`Tooltip doesn't fit in the window for any of the directions. Defaulting to '${defaultDirection}'`);
|
|
152
|
-
this._logger.debug(windowRect);
|
|
153
|
-
this._logger.debug({
|
|
154
|
-
top: bbox[defaultDirection].y,
|
|
155
|
-
left: bbox[defaultDirection].x,
|
|
156
|
-
width: this.tooltipWidth(),
|
|
157
|
-
height: this.tooltipHeight()
|
|
158
|
-
});
|
|
159
|
-
return defaultDirection;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
protected rectFits(innerRect: Rectangle, outerRect: Rectangle): boolean {
|
|
163
|
-
return (
|
|
164
|
-
innerRect.top >= outerRect.top &&
|
|
165
|
-
innerRect.left >= outerRect.left &&
|
|
166
|
-
innerRect.width + innerRect.left <= outerRect.width + outerRect.left &&
|
|
167
|
-
innerRect.height + innerRect.top <= outerRect.height + outerRect.top
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
protected setArrowPosition(point: Position, direction: Direction) {
|
|
172
|
-
let top;
|
|
173
|
-
let left;
|
|
174
|
-
let visibleBorderStyle = "border-top-color";
|
|
175
|
-
this._arrowElement
|
|
176
|
-
.style("border", `${this.arrowHeight()}px solid ${this.tooltipColor()}`)
|
|
177
|
-
.style("border-top-color", "transparent")
|
|
178
|
-
.style("border-right-color", "transparent")
|
|
179
|
-
.style("border-bottom-color", "transparent")
|
|
180
|
-
.style("border-left-color", "transparent")
|
|
181
|
-
;
|
|
182
|
-
switch (direction) {
|
|
183
|
-
case "n":
|
|
184
|
-
top = point.y + this.tooltipHeight() + (this.padding() * 2);
|
|
185
|
-
left = point.x + (this.tooltipWidth() / 2) - (this.arrowWidth() / 2) + this.padding();
|
|
186
|
-
visibleBorderStyle = "border-top-color";
|
|
187
|
-
this._arrowElement
|
|
188
|
-
.style("border-top-width", `${this.arrowHeight()}px`)
|
|
189
|
-
.style("border-bottom-width", "0px")
|
|
190
|
-
.style("border-left-width", `${this.arrowWidth() / 2}px`)
|
|
191
|
-
.style("border-right-width", `${this.arrowWidth() / 2}px`)
|
|
192
|
-
;
|
|
193
|
-
break;
|
|
194
|
-
case "s":
|
|
195
|
-
top = point.y - this.arrowHeight();
|
|
196
|
-
left = point.x + this.padding() + (this.tooltipWidth() / 2) - (this.arrowWidth() / 2);
|
|
197
|
-
visibleBorderStyle = "border-bottom-color";
|
|
198
|
-
this._arrowElement
|
|
199
|
-
.style("border-top-width", "0px")
|
|
200
|
-
.style("border-bottom-width", `${this.arrowHeight()}px`)
|
|
201
|
-
.style("border-left-width", `${this.arrowWidth() / 2}px`)
|
|
202
|
-
.style("border-right-width", `${this.arrowWidth() / 2}px`)
|
|
203
|
-
;
|
|
204
|
-
break;
|
|
205
|
-
case "e":
|
|
206
|
-
top = point.y + (this.tooltipHeight() / 2) + this.padding() - (this.arrowWidth() / 2);
|
|
207
|
-
left = point.x - this.arrowHeight();
|
|
208
|
-
visibleBorderStyle = "border-right-color";
|
|
209
|
-
this._arrowElement
|
|
210
|
-
.style("border-top-width", `${this.arrowWidth() / 2}px`)
|
|
211
|
-
.style("border-bottom-width", `${this.arrowWidth() / 2}px`)
|
|
212
|
-
.style("border-left-width", "0px")
|
|
213
|
-
.style("border-right-width", `${this.arrowHeight()}px`)
|
|
214
|
-
;
|
|
215
|
-
break;
|
|
216
|
-
case "w":
|
|
217
|
-
top = point.y + (this.tooltipHeight() / 2) - (this.arrowWidth() / 2) + this.padding();
|
|
218
|
-
left = point.x + this.tooltipWidth() + (this.padding() * 2);
|
|
219
|
-
visibleBorderStyle = "border-left-color";
|
|
220
|
-
this._arrowElement
|
|
221
|
-
.style("border-top-width", `${this.arrowWidth() / 2}px`)
|
|
222
|
-
.style("border-bottom-width", `${this.arrowWidth() / 2}px`)
|
|
223
|
-
.style("border-left-width", `${this.arrowHeight()}px`)
|
|
224
|
-
.style("border-right-width", "0px")
|
|
225
|
-
;
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
if (typeof top !== "undefined" && typeof left !== "undefined") {
|
|
229
|
-
this._arrowElement
|
|
230
|
-
.style("top", top + "px")
|
|
231
|
-
.style("left", left + "px")
|
|
232
|
-
.style(visibleBorderStyle, this.tooltipColor())
|
|
233
|
-
.style("opacity", 1)
|
|
234
|
-
;
|
|
235
|
-
} else {
|
|
236
|
-
this._arrowElement
|
|
237
|
-
.style("opacity", 0)
|
|
238
|
-
;
|
|
239
|
-
}
|
|
240
|
-
return point;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
protected getReferenceNode() {
|
|
244
|
-
if (!this._triggerElement) {
|
|
245
|
-
return this.element().node().parentNode.parentNode;
|
|
246
|
-
}
|
|
247
|
-
return this._triggerElement.node();
|
|
248
|
-
}
|
|
249
|
-
public _cursorLoc;
|
|
250
|
-
protected calcReferenceBBox() {
|
|
251
|
-
const node = this.getReferenceNode();
|
|
252
|
-
let { top, left, width, height } = node.getBoundingClientRect();
|
|
253
|
-
const wholeW = this.tooltipWidth();
|
|
254
|
-
const wholeH = this.tooltipHeight();
|
|
255
|
-
const halfW = wholeW / 2;
|
|
256
|
-
const halfH = wholeH / 2;
|
|
257
|
-
const arrowH = this.arrowHeight();
|
|
258
|
-
const p = this.padding();
|
|
259
|
-
const p2 = p * 2;
|
|
260
|
-
|
|
261
|
-
if (this.followCursor() && this._cursorLoc) {
|
|
262
|
-
|
|
263
|
-
left = this._cursorLoc[0];
|
|
264
|
-
top = this._cursorLoc[1];
|
|
265
|
-
width = 1;
|
|
266
|
-
height = 1;
|
|
267
|
-
}
|
|
268
|
-
const bbox = {
|
|
269
|
-
n: {
|
|
270
|
-
x: left + (width / 2) - halfW - p,
|
|
271
|
-
y: top - wholeH - arrowH - p2
|
|
272
|
-
},
|
|
273
|
-
e: {
|
|
274
|
-
x: left + width + arrowH,
|
|
275
|
-
y: top + (height / 2) - halfH - p
|
|
276
|
-
},
|
|
277
|
-
s: {
|
|
278
|
-
x: left + (width / 2) - halfW - p,
|
|
279
|
-
y: top + height + arrowH
|
|
280
|
-
},
|
|
281
|
-
w: {
|
|
282
|
-
x: left - wholeW - arrowH - p2,
|
|
283
|
-
y: top + (height / 2) - halfH - p
|
|
284
|
-
},
|
|
285
|
-
nw: {
|
|
286
|
-
x: left - wholeW - p2,
|
|
287
|
-
y: top - wholeH - p2
|
|
288
|
-
},
|
|
289
|
-
ne: {
|
|
290
|
-
x: left + width,
|
|
291
|
-
y: top - wholeH - p2
|
|
292
|
-
},
|
|
293
|
-
se: {
|
|
294
|
-
x: left + width,
|
|
295
|
-
y: top + height
|
|
296
|
-
},
|
|
297
|
-
sw: {
|
|
298
|
-
x: left - wholeW - p2,
|
|
299
|
-
y: top + height
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
return bbox;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
private _closing = false;
|
|
306
|
-
mouseout() {
|
|
307
|
-
this._closing = true;
|
|
308
|
-
this._tooltipElement.on("mouseover", () => {
|
|
309
|
-
this._closing = false;
|
|
310
|
-
});
|
|
311
|
-
this._tooltipElement.on("mouseout", () => {
|
|
312
|
-
this.mouseout();
|
|
313
|
-
});
|
|
314
|
-
setTimeout(() => {
|
|
315
|
-
if (this._closing) {
|
|
316
|
-
this.visible(false);
|
|
317
|
-
}
|
|
318
|
-
}, this.closeDelay());
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
visible(): boolean;
|
|
322
|
-
visible(_: boolean): this;
|
|
323
|
-
visible(_?: boolean): boolean | this {
|
|
324
|
-
if (!arguments.length) return super.visible();
|
|
325
|
-
if (this._arrowElement) {
|
|
326
|
-
this._arrowElement.style("visibility", _ ? "visible" : "hidden");
|
|
327
|
-
this._tooltipElement.style("visibility", _ ? "visible" : "hidden");
|
|
328
|
-
}
|
|
329
|
-
super.visible(_);
|
|
330
|
-
return this;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
exit(domNode, element) {
|
|
334
|
-
if (this._arrowElement) {
|
|
335
|
-
this._arrowElement.remove();
|
|
336
|
-
this._tooltipElement.remove();
|
|
337
|
-
}
|
|
338
|
-
super.exit(domNode, element);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
HTMLTooltip.prototype._class += " html_HTMLTooltip";
|
|
342
|
-
|
|
343
|
-
export interface HTMLTooltip {
|
|
344
|
-
padding(): number;
|
|
345
|
-
padding(_: number): this;
|
|
346
|
-
direction(): Direction;
|
|
347
|
-
direction(_: Direction): this;
|
|
348
|
-
arrowHeight(): number;
|
|
349
|
-
arrowHeight(_: number): this;
|
|
350
|
-
arrowWidth(): number;
|
|
351
|
-
arrowWidth(_: number): this;
|
|
352
|
-
fontColor(): string;
|
|
353
|
-
fontColor(_: string): this;
|
|
354
|
-
tooltipColor(): string;
|
|
355
|
-
tooltipColor(_: string): this;
|
|
356
|
-
tooltipWidth(): number;
|
|
357
|
-
tooltipWidth(_: number): this;
|
|
358
|
-
tooltipWidth_default(_: number);
|
|
359
|
-
tooltipHeight(): number;
|
|
360
|
-
tooltipHeight(_: number): this;
|
|
361
|
-
tooltipHeight_default(_: number);
|
|
362
|
-
followCursor(): boolean;
|
|
363
|
-
followCursor(_: boolean): this;
|
|
364
|
-
enablePointerEvents(): boolean;
|
|
365
|
-
enablePointerEvents(_: boolean): this;
|
|
366
|
-
closeDelay(): number;
|
|
367
|
-
closeDelay(_: number): this;
|
|
368
|
-
fitContent(): boolean;
|
|
369
|
-
fitContent(_: boolean): this;
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
HTMLTooltip.prototype.publish("fitContent", false, "boolean", "If true, tooltip will grow to fit its html content");
|
|
374
|
-
HTMLTooltip.prototype.publish("followCursor", false, "boolean", "If true, tooltip will display relative to cursor location");
|
|
375
|
-
HTMLTooltip.prototype.publish("closeDelay", 400, "number", "Number of milliseconds to wait before closing tooltip (cancelled on tooltip mouseover event)");
|
|
376
|
-
HTMLTooltip.prototype.publish("direction", "n", "set", "Direction in which to display the tooltip", ["n", "s", "e", "w", "ne", "nw", "se", "sw"]);
|
|
377
|
-
HTMLTooltip.prototype.publish("padding", 8, "number", "Padding (pixels)");
|
|
378
|
-
HTMLTooltip.prototype.publish("arrowWidth", 16, "number", "Width (or height depending on direction) of the tooltip arrow (pixels)");
|
|
379
|
-
HTMLTooltip.prototype.publish("arrowHeight", 8, "number", "Height (or width depending on direction) of the tooltip arrow (pixels)");
|
|
380
|
-
HTMLTooltip.prototype.publish("fontColor", "#FFF", "html-color", "The default font color for text in the tooltip");
|
|
381
|
-
HTMLTooltip.prototype.publish("tooltipColor", "#000000EE", "html-color", "Background color of the tooltip");
|
|
382
|
-
HTMLTooltip.prototype.publish("tooltipWidth", 200, "number", "Width of the tooltip (not including arrow) (pixels)");
|
|
383
|
-
HTMLTooltip.prototype.publish("tooltipHeight", 200, "number", "Height of the tooltip (not including arrow) (pixels)");
|
|
384
|
-
HTMLTooltip.prototype.publish("enablePointerEvents", false, "boolean", "If true, the 'pointer-events: all' style will be used");
|
|
1
|
+
import { HTMLWidget, select as d3Select } from "@hpcc-js/common";
|
|
2
|
+
import { scopedLogger, ScopedLogging } from "@hpcc-js/util";
|
|
3
|
+
|
|
4
|
+
type Direction = "n" | "s" | "e" | "w" | "ne" | "nw" | "se" | "sw";
|
|
5
|
+
type Position = { x: number, y: number };
|
|
6
|
+
type DirectionalBBox = { [key in Direction]: Position; };
|
|
7
|
+
|
|
8
|
+
type Rectangle = { top: number, left: number, width: number, height: number };
|
|
9
|
+
export class HTMLTooltip extends HTMLWidget {
|
|
10
|
+
|
|
11
|
+
public _triggerElement;
|
|
12
|
+
public _contentNode;
|
|
13
|
+
protected _prevContentNode;
|
|
14
|
+
|
|
15
|
+
protected _tooltipElement;
|
|
16
|
+
protected _arrowElement;
|
|
17
|
+
protected _tooltipHTMLCallback = (data?) => "<b>_tooltipHTMLCallback is undefined</b>";
|
|
18
|
+
protected _logger: ScopedLogging = scopedLogger("html/HTMLTooltip");
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.visible(false);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
tooltipHTML(_: (data?) => string): this {
|
|
25
|
+
this._tooltipHTMLCallback = _;
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
tooltipContent(_): this {
|
|
30
|
+
if (!arguments.length) return this._contentNode;
|
|
31
|
+
this._contentNode = _;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
triggerElement(_): this {
|
|
36
|
+
this._triggerElement = _;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
enter(domNode, element) {
|
|
41
|
+
super.enter(domNode, element);
|
|
42
|
+
const body = d3Select("body");
|
|
43
|
+
this._tooltipElement = body.append("div")
|
|
44
|
+
.attr("class", "tooltip-div")
|
|
45
|
+
.style("z-index", "2147483638")
|
|
46
|
+
.style("position", "fixed")
|
|
47
|
+
;
|
|
48
|
+
this._arrowElement = body.append("div")
|
|
49
|
+
.attr("class", "arrow-div")
|
|
50
|
+
.style("z-index", "2147483638")
|
|
51
|
+
.style("position", "fixed")
|
|
52
|
+
;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
update(domNode, element) {
|
|
56
|
+
super.update(domNode, element);
|
|
57
|
+
|
|
58
|
+
if (this._contentNode !== this._prevContentNode) {
|
|
59
|
+
const node = this._tooltipElement.node();
|
|
60
|
+
[...node.querySelectorAll("*")]
|
|
61
|
+
.map(n => n.__data__)
|
|
62
|
+
.filter(n => n)
|
|
63
|
+
.forEach(w => {
|
|
64
|
+
if (typeof w.target === "function") {
|
|
65
|
+
w.target(null);
|
|
66
|
+
}
|
|
67
|
+
if (typeof w.exit === "function") {
|
|
68
|
+
w.exit();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
node.innerHTML = "";
|
|
72
|
+
node.appendChild(this._contentNode);
|
|
73
|
+
this._prevContentNode = this._contentNode;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (this._contentNode) {
|
|
77
|
+
this.onShowContent(this._contentNode);
|
|
78
|
+
} else {
|
|
79
|
+
this._tooltipElement
|
|
80
|
+
.html(() => {
|
|
81
|
+
return this._tooltipHTMLCallback(this.data());
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (this.fitContent()) {
|
|
85
|
+
this._tooltipElement
|
|
86
|
+
.style("width", "auto")
|
|
87
|
+
.style("height", "auto")
|
|
88
|
+
.style("padding", "0px")
|
|
89
|
+
.style("box-sizing", "content-box")
|
|
90
|
+
;
|
|
91
|
+
const rect = this._tooltipElement.node().getBoundingClientRect();
|
|
92
|
+
this.tooltipWidth_default(rect.width);
|
|
93
|
+
this.tooltipHeight_default(rect.height);
|
|
94
|
+
}
|
|
95
|
+
this._closing = false;
|
|
96
|
+
this._tooltipElement
|
|
97
|
+
.style("background-color", this.tooltipColor())
|
|
98
|
+
.style("color", this.fontColor())
|
|
99
|
+
.style("width", this.tooltipWidth() + "px")
|
|
100
|
+
.style("height", this.tooltipHeight() + "px")
|
|
101
|
+
.style("opacity", 1)
|
|
102
|
+
.style("padding", this.padding() + "px")
|
|
103
|
+
.style("pointer-events", this.enablePointerEvents() ? "all" : "none")
|
|
104
|
+
.style("box-sizing", "content-box")
|
|
105
|
+
;
|
|
106
|
+
this._arrowElement
|
|
107
|
+
.style("opacity", 1)
|
|
108
|
+
.style("pointer-events", "none")
|
|
109
|
+
;
|
|
110
|
+
this.updateTooltipPosition();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
onShowContent(node) {
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
protected updateTooltipPosition(): Position {
|
|
118
|
+
const bbox = this.calcReferenceBBox();
|
|
119
|
+
const direction = this.calcTooltipDirection(bbox);
|
|
120
|
+
const box = bbox[direction];
|
|
121
|
+
this._tooltipElement
|
|
122
|
+
.style("top", box.y + "px")
|
|
123
|
+
.style("left", box.x + "px")
|
|
124
|
+
;
|
|
125
|
+
this.setArrowPosition(box, direction);
|
|
126
|
+
return box;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
protected calcTooltipDirection(bbox: DirectionalBBox): Direction {
|
|
130
|
+
const directions: Direction[] = Object.keys(bbox) as Direction[];
|
|
131
|
+
|
|
132
|
+
const defaultDirection = this.direction();
|
|
133
|
+
directions.sort((a, b) => a === defaultDirection ? -1 : 1);
|
|
134
|
+
const windowRect = {
|
|
135
|
+
top: 0,
|
|
136
|
+
left: 0,
|
|
137
|
+
width: window.innerWidth,
|
|
138
|
+
height: window.innerHeight
|
|
139
|
+
};
|
|
140
|
+
for (let i = 0; i < directions.length; i++) {
|
|
141
|
+
const tooltipRect = {
|
|
142
|
+
top: bbox[directions[i]].y,
|
|
143
|
+
left: bbox[directions[i]].x,
|
|
144
|
+
width: this.tooltipWidth(),
|
|
145
|
+
height: this.tooltipHeight()
|
|
146
|
+
};
|
|
147
|
+
if (this.rectFits(tooltipRect, windowRect)) {
|
|
148
|
+
return directions[i];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
this._logger.warning(`Tooltip doesn't fit in the window for any of the directions. Defaulting to '${defaultDirection}'`);
|
|
152
|
+
this._logger.debug(windowRect);
|
|
153
|
+
this._logger.debug({
|
|
154
|
+
top: bbox[defaultDirection].y,
|
|
155
|
+
left: bbox[defaultDirection].x,
|
|
156
|
+
width: this.tooltipWidth(),
|
|
157
|
+
height: this.tooltipHeight()
|
|
158
|
+
});
|
|
159
|
+
return defaultDirection;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
protected rectFits(innerRect: Rectangle, outerRect: Rectangle): boolean {
|
|
163
|
+
return (
|
|
164
|
+
innerRect.top >= outerRect.top &&
|
|
165
|
+
innerRect.left >= outerRect.left &&
|
|
166
|
+
innerRect.width + innerRect.left <= outerRect.width + outerRect.left &&
|
|
167
|
+
innerRect.height + innerRect.top <= outerRect.height + outerRect.top
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
protected setArrowPosition(point: Position, direction: Direction) {
|
|
172
|
+
let top;
|
|
173
|
+
let left;
|
|
174
|
+
let visibleBorderStyle = "border-top-color";
|
|
175
|
+
this._arrowElement
|
|
176
|
+
.style("border", `${this.arrowHeight()}px solid ${this.tooltipColor()}`)
|
|
177
|
+
.style("border-top-color", "transparent")
|
|
178
|
+
.style("border-right-color", "transparent")
|
|
179
|
+
.style("border-bottom-color", "transparent")
|
|
180
|
+
.style("border-left-color", "transparent")
|
|
181
|
+
;
|
|
182
|
+
switch (direction) {
|
|
183
|
+
case "n":
|
|
184
|
+
top = point.y + this.tooltipHeight() + (this.padding() * 2);
|
|
185
|
+
left = point.x + (this.tooltipWidth() / 2) - (this.arrowWidth() / 2) + this.padding();
|
|
186
|
+
visibleBorderStyle = "border-top-color";
|
|
187
|
+
this._arrowElement
|
|
188
|
+
.style("border-top-width", `${this.arrowHeight()}px`)
|
|
189
|
+
.style("border-bottom-width", "0px")
|
|
190
|
+
.style("border-left-width", `${this.arrowWidth() / 2}px`)
|
|
191
|
+
.style("border-right-width", `${this.arrowWidth() / 2}px`)
|
|
192
|
+
;
|
|
193
|
+
break;
|
|
194
|
+
case "s":
|
|
195
|
+
top = point.y - this.arrowHeight();
|
|
196
|
+
left = point.x + this.padding() + (this.tooltipWidth() / 2) - (this.arrowWidth() / 2);
|
|
197
|
+
visibleBorderStyle = "border-bottom-color";
|
|
198
|
+
this._arrowElement
|
|
199
|
+
.style("border-top-width", "0px")
|
|
200
|
+
.style("border-bottom-width", `${this.arrowHeight()}px`)
|
|
201
|
+
.style("border-left-width", `${this.arrowWidth() / 2}px`)
|
|
202
|
+
.style("border-right-width", `${this.arrowWidth() / 2}px`)
|
|
203
|
+
;
|
|
204
|
+
break;
|
|
205
|
+
case "e":
|
|
206
|
+
top = point.y + (this.tooltipHeight() / 2) + this.padding() - (this.arrowWidth() / 2);
|
|
207
|
+
left = point.x - this.arrowHeight();
|
|
208
|
+
visibleBorderStyle = "border-right-color";
|
|
209
|
+
this._arrowElement
|
|
210
|
+
.style("border-top-width", `${this.arrowWidth() / 2}px`)
|
|
211
|
+
.style("border-bottom-width", `${this.arrowWidth() / 2}px`)
|
|
212
|
+
.style("border-left-width", "0px")
|
|
213
|
+
.style("border-right-width", `${this.arrowHeight()}px`)
|
|
214
|
+
;
|
|
215
|
+
break;
|
|
216
|
+
case "w":
|
|
217
|
+
top = point.y + (this.tooltipHeight() / 2) - (this.arrowWidth() / 2) + this.padding();
|
|
218
|
+
left = point.x + this.tooltipWidth() + (this.padding() * 2);
|
|
219
|
+
visibleBorderStyle = "border-left-color";
|
|
220
|
+
this._arrowElement
|
|
221
|
+
.style("border-top-width", `${this.arrowWidth() / 2}px`)
|
|
222
|
+
.style("border-bottom-width", `${this.arrowWidth() / 2}px`)
|
|
223
|
+
.style("border-left-width", `${this.arrowHeight()}px`)
|
|
224
|
+
.style("border-right-width", "0px")
|
|
225
|
+
;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
if (typeof top !== "undefined" && typeof left !== "undefined") {
|
|
229
|
+
this._arrowElement
|
|
230
|
+
.style("top", top + "px")
|
|
231
|
+
.style("left", left + "px")
|
|
232
|
+
.style(visibleBorderStyle, this.tooltipColor())
|
|
233
|
+
.style("opacity", 1)
|
|
234
|
+
;
|
|
235
|
+
} else {
|
|
236
|
+
this._arrowElement
|
|
237
|
+
.style("opacity", 0)
|
|
238
|
+
;
|
|
239
|
+
}
|
|
240
|
+
return point;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
protected getReferenceNode() {
|
|
244
|
+
if (!this._triggerElement) {
|
|
245
|
+
return this.element().node().parentNode.parentNode;
|
|
246
|
+
}
|
|
247
|
+
return this._triggerElement.node();
|
|
248
|
+
}
|
|
249
|
+
public _cursorLoc;
|
|
250
|
+
protected calcReferenceBBox() {
|
|
251
|
+
const node = this.getReferenceNode();
|
|
252
|
+
let { top, left, width, height } = node.getBoundingClientRect();
|
|
253
|
+
const wholeW = this.tooltipWidth();
|
|
254
|
+
const wholeH = this.tooltipHeight();
|
|
255
|
+
const halfW = wholeW / 2;
|
|
256
|
+
const halfH = wholeH / 2;
|
|
257
|
+
const arrowH = this.arrowHeight();
|
|
258
|
+
const p = this.padding();
|
|
259
|
+
const p2 = p * 2;
|
|
260
|
+
|
|
261
|
+
if (this.followCursor() && this._cursorLoc) {
|
|
262
|
+
|
|
263
|
+
left = this._cursorLoc[0];
|
|
264
|
+
top = this._cursorLoc[1];
|
|
265
|
+
width = 1;
|
|
266
|
+
height = 1;
|
|
267
|
+
}
|
|
268
|
+
const bbox = {
|
|
269
|
+
n: {
|
|
270
|
+
x: left + (width / 2) - halfW - p,
|
|
271
|
+
y: top - wholeH - arrowH - p2
|
|
272
|
+
},
|
|
273
|
+
e: {
|
|
274
|
+
x: left + width + arrowH,
|
|
275
|
+
y: top + (height / 2) - halfH - p
|
|
276
|
+
},
|
|
277
|
+
s: {
|
|
278
|
+
x: left + (width / 2) - halfW - p,
|
|
279
|
+
y: top + height + arrowH
|
|
280
|
+
},
|
|
281
|
+
w: {
|
|
282
|
+
x: left - wholeW - arrowH - p2,
|
|
283
|
+
y: top + (height / 2) - halfH - p
|
|
284
|
+
},
|
|
285
|
+
nw: {
|
|
286
|
+
x: left - wholeW - p2,
|
|
287
|
+
y: top - wholeH - p2
|
|
288
|
+
},
|
|
289
|
+
ne: {
|
|
290
|
+
x: left + width,
|
|
291
|
+
y: top - wholeH - p2
|
|
292
|
+
},
|
|
293
|
+
se: {
|
|
294
|
+
x: left + width,
|
|
295
|
+
y: top + height
|
|
296
|
+
},
|
|
297
|
+
sw: {
|
|
298
|
+
x: left - wholeW - p2,
|
|
299
|
+
y: top + height
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
return bbox;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private _closing = false;
|
|
306
|
+
mouseout() {
|
|
307
|
+
this._closing = true;
|
|
308
|
+
this._tooltipElement.on("mouseover", () => {
|
|
309
|
+
this._closing = false;
|
|
310
|
+
});
|
|
311
|
+
this._tooltipElement.on("mouseout", () => {
|
|
312
|
+
this.mouseout();
|
|
313
|
+
});
|
|
314
|
+
setTimeout(() => {
|
|
315
|
+
if (this._closing) {
|
|
316
|
+
this.visible(false);
|
|
317
|
+
}
|
|
318
|
+
}, this.closeDelay());
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
visible(): boolean;
|
|
322
|
+
visible(_: boolean): this;
|
|
323
|
+
visible(_?: boolean): boolean | this {
|
|
324
|
+
if (!arguments.length) return super.visible();
|
|
325
|
+
if (this._arrowElement) {
|
|
326
|
+
this._arrowElement.style("visibility", _ ? "visible" : "hidden");
|
|
327
|
+
this._tooltipElement.style("visibility", _ ? "visible" : "hidden");
|
|
328
|
+
}
|
|
329
|
+
super.visible(_);
|
|
330
|
+
return this;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
exit(domNode, element) {
|
|
334
|
+
if (this._arrowElement) {
|
|
335
|
+
this._arrowElement.remove();
|
|
336
|
+
this._tooltipElement.remove();
|
|
337
|
+
}
|
|
338
|
+
super.exit(domNode, element);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
HTMLTooltip.prototype._class += " html_HTMLTooltip";
|
|
342
|
+
|
|
343
|
+
export interface HTMLTooltip {
|
|
344
|
+
padding(): number;
|
|
345
|
+
padding(_: number): this;
|
|
346
|
+
direction(): Direction;
|
|
347
|
+
direction(_: Direction): this;
|
|
348
|
+
arrowHeight(): number;
|
|
349
|
+
arrowHeight(_: number): this;
|
|
350
|
+
arrowWidth(): number;
|
|
351
|
+
arrowWidth(_: number): this;
|
|
352
|
+
fontColor(): string;
|
|
353
|
+
fontColor(_: string): this;
|
|
354
|
+
tooltipColor(): string;
|
|
355
|
+
tooltipColor(_: string): this;
|
|
356
|
+
tooltipWidth(): number;
|
|
357
|
+
tooltipWidth(_: number): this;
|
|
358
|
+
tooltipWidth_default(_: number);
|
|
359
|
+
tooltipHeight(): number;
|
|
360
|
+
tooltipHeight(_: number): this;
|
|
361
|
+
tooltipHeight_default(_: number);
|
|
362
|
+
followCursor(): boolean;
|
|
363
|
+
followCursor(_: boolean): this;
|
|
364
|
+
enablePointerEvents(): boolean;
|
|
365
|
+
enablePointerEvents(_: boolean): this;
|
|
366
|
+
closeDelay(): number;
|
|
367
|
+
closeDelay(_: number): this;
|
|
368
|
+
fitContent(): boolean;
|
|
369
|
+
fitContent(_: boolean): this;
|
|
370
|
+
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
HTMLTooltip.prototype.publish("fitContent", false, "boolean", "If true, tooltip will grow to fit its html content");
|
|
374
|
+
HTMLTooltip.prototype.publish("followCursor", false, "boolean", "If true, tooltip will display relative to cursor location");
|
|
375
|
+
HTMLTooltip.prototype.publish("closeDelay", 400, "number", "Number of milliseconds to wait before closing tooltip (cancelled on tooltip mouseover event)");
|
|
376
|
+
HTMLTooltip.prototype.publish("direction", "n", "set", "Direction in which to display the tooltip", ["n", "s", "e", "w", "ne", "nw", "se", "sw"]);
|
|
377
|
+
HTMLTooltip.prototype.publish("padding", 8, "number", "Padding (pixels)");
|
|
378
|
+
HTMLTooltip.prototype.publish("arrowWidth", 16, "number", "Width (or height depending on direction) of the tooltip arrow (pixels)");
|
|
379
|
+
HTMLTooltip.prototype.publish("arrowHeight", 8, "number", "Height (or width depending on direction) of the tooltip arrow (pixels)");
|
|
380
|
+
HTMLTooltip.prototype.publish("fontColor", "#FFF", "html-color", "The default font color for text in the tooltip");
|
|
381
|
+
HTMLTooltip.prototype.publish("tooltipColor", "#000000EE", "html-color", "Background color of the tooltip");
|
|
382
|
+
HTMLTooltip.prototype.publish("tooltipWidth", 200, "number", "Width of the tooltip (not including arrow) (pixels)");
|
|
383
|
+
HTMLTooltip.prototype.publish("tooltipHeight", 200, "number", "Height of the tooltip (not including arrow) (pixels)");
|
|
384
|
+
HTMLTooltip.prototype.publish("enablePointerEvents", false, "boolean", "If true, the 'pointer-events: all' style will be used");
|