@hpcc-js/api 3.4.15 → 3.4.16
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 +3 -3
- package/src/I1DChart.ts +13 -13
- package/src/I2DAggrChart.ts +25 -25
- package/src/I2DChart.ts +26 -26
- package/src/IGraph.ts +24 -24
- package/src/IHighlight.ts +7 -7
- package/src/IInput.ts +87 -87
- package/src/INDChart.ts +26 -26
- package/src/ITooltip.css +119 -119
- package/src/ITooltip.ts +225 -225
- package/src/ITree.ts +15 -15
- package/src/Tooltip.ts +384 -384
- package/src/__package__.ts +3 -3
- package/src/index.ts +10 -10
package/src/Tooltip.ts
CHANGED
|
@@ -1,384 +1,384 @@
|
|
|
1
|
-
// Based on https://github.com/GordonSmith/d3-tip forked from https://github.com/Caged/d3-tip
|
|
2
|
-
|
|
3
|
-
import { map } from "d3-collection";
|
|
4
|
-
import { select, selection } from "d3-selection";
|
|
5
|
-
|
|
6
|
-
export function tip() {
|
|
7
|
-
let direction = d3TipDirection;
|
|
8
|
-
let offset = d3TipOffset;
|
|
9
|
-
let html = d3TipHTML;
|
|
10
|
-
let rootElement = functor(document.body);
|
|
11
|
-
let node = initNode();
|
|
12
|
-
let svg = null;
|
|
13
|
-
let point = null;
|
|
14
|
-
let target = null;
|
|
15
|
-
|
|
16
|
-
const tip: any = function (vis) {
|
|
17
|
-
svg = getSVGNode(vis);
|
|
18
|
-
if (!svg) return;
|
|
19
|
-
point = svg.createSVGPoint();
|
|
20
|
-
const re = rootElement();
|
|
21
|
-
if (!re) return;
|
|
22
|
-
if (!node) return;
|
|
23
|
-
re.appendChild(node);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// Public - show the tooltip on the screen
|
|
27
|
-
//
|
|
28
|
-
// Returns a tip
|
|
29
|
-
tip.show = function (d, idx, arr) {
|
|
30
|
-
target = arr[idx];
|
|
31
|
-
const args = Array.prototype.slice.call(arguments) as [];
|
|
32
|
-
const content = html.apply(this, args);
|
|
33
|
-
if (content === null) {
|
|
34
|
-
return tip;
|
|
35
|
-
}
|
|
36
|
-
const poffset = offset.apply(this, args);
|
|
37
|
-
const nodel = getNodeEl();
|
|
38
|
-
let i = directions.length;
|
|
39
|
-
let coords;
|
|
40
|
-
const root_bbox = rootElement().getBoundingClientRect();
|
|
41
|
-
nodel.html(content)
|
|
42
|
-
.style("opacity", 1).style("pointer-events", "all");
|
|
43
|
-
|
|
44
|
-
while (i--) nodel.classed(directions[i], false);
|
|
45
|
-
let placement_success = false;
|
|
46
|
-
const placement_overflow = {};
|
|
47
|
-
let least_overflow_direction = directions[0];
|
|
48
|
-
for (let i = 0; i < directions.length; i++) {
|
|
49
|
-
placement_success = _placement_attempt(directions[i]);
|
|
50
|
-
if (placement_success) break;
|
|
51
|
-
}
|
|
52
|
-
if (!placement_success) {
|
|
53
|
-
nodel.classed("notick", true);
|
|
54
|
-
const top_offset = _vertical_adjustment(placement_overflow[least_overflow_direction]);
|
|
55
|
-
const left_offset = _horizontal_adjustment(placement_overflow[least_overflow_direction]);
|
|
56
|
-
_placement_attempt(least_overflow_direction, top_offset, left_offset);
|
|
57
|
-
} else {
|
|
58
|
-
nodel.classed("notick", false);
|
|
59
|
-
}
|
|
60
|
-
return tip;
|
|
61
|
-
|
|
62
|
-
function _horizontal_adjustment(overflow_obj) {
|
|
63
|
-
if (overflow_obj.left > overflow_obj.right) {
|
|
64
|
-
return overflow_obj.left > 0 ? -overflow_obj.left : 0;
|
|
65
|
-
} else {
|
|
66
|
-
return overflow_obj.right > 0 ? overflow_obj.right : 0;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function _vertical_adjustment(overflow_obj) {
|
|
70
|
-
if (overflow_obj.top > overflow_obj.bottom) {
|
|
71
|
-
return overflow_obj.top > 0 ? -overflow_obj.top : 0;
|
|
72
|
-
} else {
|
|
73
|
-
return overflow_obj.bottom;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function _placement_attempt(this: any, _dir, _top_offset?, _left_offset?) {
|
|
78
|
-
_top_offset = _top_offset ? _top_offset : 0;
|
|
79
|
-
_left_offset = _left_offset ? _left_offset : 0;
|
|
80
|
-
nodel.style("white-space", "nowrap");
|
|
81
|
-
coords = directionCallbacks.get(_dir).apply(this);
|
|
82
|
-
nodel.classed(_dir, true)
|
|
83
|
-
.style("top", (coords.top + poffset[0] - _top_offset) + "px")
|
|
84
|
-
.style("left", (coords.left + poffset[1] - _left_offset) + "px");
|
|
85
|
-
const nodel_bbox = nodel.node().getBoundingClientRect();
|
|
86
|
-
const ret = nodel_bbox.top > root_bbox.top
|
|
87
|
-
&& nodel_bbox.left > root_bbox.left
|
|
88
|
-
&& nodel_bbox.bottom < root_bbox.bottom
|
|
89
|
-
&& nodel_bbox.right < root_bbox.right
|
|
90
|
-
;
|
|
91
|
-
placement_overflow[_dir] = {
|
|
92
|
-
top: root_bbox.top - nodel_bbox.top,
|
|
93
|
-
right: nodel_bbox.right - root_bbox.right,
|
|
94
|
-
bottom: nodel_bbox.bottom - root_bbox.bottom,
|
|
95
|
-
left: root_bbox.left - nodel_bbox.left
|
|
96
|
-
};
|
|
97
|
-
nodel.style("white-space", "normal");
|
|
98
|
-
placement_overflow[_dir].total_overflow = Object.keys(placement_overflow[_dir])
|
|
99
|
-
.filter(side => placement_overflow[_dir][side] > 0)
|
|
100
|
-
.reduce((sum, side) => {
|
|
101
|
-
const side_overflow = placement_overflow[_dir][side];
|
|
102
|
-
return sum + side_overflow;
|
|
103
|
-
}, 0);
|
|
104
|
-
if (placement_overflow[least_overflow_direction].total_overflow > placement_overflow[_dir].total_overflow) {
|
|
105
|
-
least_overflow_direction = _dir;
|
|
106
|
-
}
|
|
107
|
-
if (!ret) {
|
|
108
|
-
nodel.classed(_dir, false);
|
|
109
|
-
}
|
|
110
|
-
return ret;
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
// Public - hide the tooltip
|
|
115
|
-
//
|
|
116
|
-
// Returns a tip
|
|
117
|
-
tip.hide = function () {
|
|
118
|
-
const nodel = getNodeEl();
|
|
119
|
-
nodel.style("opacity", 0).style("pointer-events", "none");
|
|
120
|
-
return tip;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
// Public: Proxy attr calls to the d3 tip container.
|
|
124
|
-
// Sets or gets attribute value.
|
|
125
|
-
//
|
|
126
|
-
// n - name of the attribute
|
|
127
|
-
// v - value of the attribute
|
|
128
|
-
//
|
|
129
|
-
// Returns tip or attribute value
|
|
130
|
-
tip.attr = function (n, v) {
|
|
131
|
-
if (arguments.length < 2 && typeof n === "string") {
|
|
132
|
-
return getNodeEl().attr(n);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const args = Array.prototype.slice.call(arguments);
|
|
136
|
-
selection.prototype.attr.apply(getNodeEl(), args);
|
|
137
|
-
return tip;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
// Public: Proxy style calls to the d3 tip container.
|
|
141
|
-
// Sets or gets a style value.
|
|
142
|
-
//
|
|
143
|
-
// n - name of the property
|
|
144
|
-
// v - value of the property
|
|
145
|
-
//
|
|
146
|
-
// Returns tip or style property value
|
|
147
|
-
tip.style = function (n, v) {
|
|
148
|
-
if (arguments.length < 2 && typeof n === "string") {
|
|
149
|
-
return getNodeEl().style(n);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const args = Array.prototype.slice.call(arguments);
|
|
153
|
-
selection.prototype.style.apply(getNodeEl(), args);
|
|
154
|
-
return tip;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// Public: Set or get the direction of the tooltip
|
|
158
|
-
//
|
|
159
|
-
// v - One of n(north), s(south), e(east), or w(west), nw(northwest),
|
|
160
|
-
// sw(southwest), ne(northeast) or se(southeast)
|
|
161
|
-
//
|
|
162
|
-
// Returns tip or direction
|
|
163
|
-
tip.direction = function (v) {
|
|
164
|
-
if (!arguments.length) return direction;
|
|
165
|
-
direction = v == null ? v : functor(v);
|
|
166
|
-
|
|
167
|
-
return tip;
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
// Public: Sets or gets the offset of the tip
|
|
171
|
-
//
|
|
172
|
-
// v - Array of [x, y] offset
|
|
173
|
-
//
|
|
174
|
-
// Returns offset or
|
|
175
|
-
tip.offset = function (v) {
|
|
176
|
-
if (!arguments.length) return offset;
|
|
177
|
-
offset = v == null ? v : functor(v);
|
|
178
|
-
|
|
179
|
-
return tip;
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// Public: sets or gets the html value of the tooltip
|
|
183
|
-
//
|
|
184
|
-
// v - String value of the tip
|
|
185
|
-
//
|
|
186
|
-
// Returns html value or tip
|
|
187
|
-
tip.html = function (v) {
|
|
188
|
-
if (!arguments.length) return html;
|
|
189
|
-
html = v == null ? v : functor(v);
|
|
190
|
-
|
|
191
|
-
return tip;
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// Public: sets or gets the root element anchor of the tooltip
|
|
195
|
-
//
|
|
196
|
-
// v - root element of the tooltip
|
|
197
|
-
//
|
|
198
|
-
// Returns root node of tip
|
|
199
|
-
tip.rootElement = function (v) {
|
|
200
|
-
if (!arguments.length) return rootElement;
|
|
201
|
-
rootElement = functor(v);
|
|
202
|
-
|
|
203
|
-
return tip;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// Public: destroys the tooltip and removes it from the DOM
|
|
207
|
-
//
|
|
208
|
-
// Returns a tip
|
|
209
|
-
tip.destroy = function () {
|
|
210
|
-
if (node) {
|
|
211
|
-
getNodeEl().remove();
|
|
212
|
-
node = null;
|
|
213
|
-
}
|
|
214
|
-
return tip;
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
function d3TipDirection() { return "n"; }
|
|
218
|
-
function d3TipOffset() { return [0, 0]; }
|
|
219
|
-
function d3TipHTML() { return " "; }
|
|
220
|
-
|
|
221
|
-
const directionCallbacks = map({
|
|
222
|
-
n: directionNorth,
|
|
223
|
-
s: directionSouth,
|
|
224
|
-
e: directionEast,
|
|
225
|
-
w: directionWest,
|
|
226
|
-
nw: directionNorthWest,
|
|
227
|
-
ne: directionNorthEast,
|
|
228
|
-
sw: directionSouthWest,
|
|
229
|
-
se: directionSouthEast
|
|
230
|
-
});
|
|
231
|
-
const directions = directionCallbacks.keys();
|
|
232
|
-
|
|
233
|
-
function directionNorth() {
|
|
234
|
-
const bbox = getScreenBBox(window);
|
|
235
|
-
return {
|
|
236
|
-
top: bbox.n.y - node.offsetHeight,
|
|
237
|
-
left: bbox.n.x - node.offsetWidth / 2
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
function directionSouth() {
|
|
242
|
-
const bbox = getScreenBBox(window);
|
|
243
|
-
return {
|
|
244
|
-
top: bbox.s.y + 8,
|
|
245
|
-
left: bbox.s.x - node.offsetWidth / 2
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function directionEast() {
|
|
250
|
-
const bbox = getScreenBBox(window);
|
|
251
|
-
return {
|
|
252
|
-
top: bbox.e.y - node.offsetHeight / 2,
|
|
253
|
-
left: bbox.e.x + 8
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
function directionWest() {
|
|
258
|
-
const bbox = getScreenBBox(window);
|
|
259
|
-
return {
|
|
260
|
-
top: bbox.w.y - node.offsetHeight / 2,
|
|
261
|
-
left: bbox.w.x - node.offsetWidth - 8
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function directionNorthWest() {
|
|
266
|
-
const bbox = getScreenBBox(window);
|
|
267
|
-
return {
|
|
268
|
-
top: bbox.nw.y - node.offsetHeight,
|
|
269
|
-
left: bbox.nw.x - node.offsetWidth
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
function directionNorthEast() {
|
|
274
|
-
const bbox = getScreenBBox(window);
|
|
275
|
-
return {
|
|
276
|
-
top: bbox.ne.y - node.offsetHeight,
|
|
277
|
-
left: bbox.ne.x
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function directionSouthWest() {
|
|
282
|
-
const bbox = getScreenBBox(window);
|
|
283
|
-
return {
|
|
284
|
-
top: bbox.sw.y,
|
|
285
|
-
left: bbox.sw.x - node.offsetWidth
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function directionSouthEast() {
|
|
290
|
-
const bbox = getScreenBBox(window);
|
|
291
|
-
return {
|
|
292
|
-
top: bbox.se.y,
|
|
293
|
-
left: bbox.se.x
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function initNode() {
|
|
298
|
-
const div = select(document.createElement("div"));
|
|
299
|
-
div
|
|
300
|
-
.attr("class", "d3-tip")
|
|
301
|
-
.style("position", "absolute")
|
|
302
|
-
.style("top", "0px")
|
|
303
|
-
.style("opacity", 0)
|
|
304
|
-
.style("pointer-events", "none")
|
|
305
|
-
.style("box-sizing", "border-box");
|
|
306
|
-
|
|
307
|
-
return div.node();
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function getSVGNode(element) {
|
|
311
|
-
const svgNode = element.node();
|
|
312
|
-
if (!svgNode) return null;
|
|
313
|
-
if (svgNode.tagName.toLowerCase() === "svg") return svgNode;
|
|
314
|
-
return svgNode.ownerSVGElement;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function getNodeEl() {
|
|
318
|
-
if (node == null) {
|
|
319
|
-
node = initNode();
|
|
320
|
-
// re-add node to DOM
|
|
321
|
-
rootElement().appendChild(node);
|
|
322
|
-
}
|
|
323
|
-
return select(node);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Private - gets the screen coordinates of a shape
|
|
327
|
-
//
|
|
328
|
-
// Given a shape on the screen, will return an SVGPoint for the directions
|
|
329
|
-
// n(north), s(south), e(east), w(west), ne(northeast), se(southeast),
|
|
330
|
-
// nw(northwest), sw(southwest).
|
|
331
|
-
//
|
|
332
|
-
// +-+-+
|
|
333
|
-
// | |
|
|
334
|
-
// + +
|
|
335
|
-
// | |
|
|
336
|
-
// +-+-+
|
|
337
|
-
//
|
|
338
|
-
// Returns an Object {n, s, e, w, nw, sw, ne, se}
|
|
339
|
-
function getScreenBBox(targetShape) {
|
|
340
|
-
let targetel = target || targetShape;
|
|
341
|
-
|
|
342
|
-
while (targetel.getCTM == null && targetel.parentNode != null) {
|
|
343
|
-
targetel = targetel.parentNode;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
const bbox: any = {};
|
|
347
|
-
const matrix = targetel.getCTM();
|
|
348
|
-
const tbbox = targetel.getBBox();
|
|
349
|
-
const width = tbbox.width;
|
|
350
|
-
const height = tbbox.height;
|
|
351
|
-
const x = tbbox.x;
|
|
352
|
-
const y = tbbox.y;
|
|
353
|
-
|
|
354
|
-
point.x = x;
|
|
355
|
-
point.y = y;
|
|
356
|
-
bbox.nw = point.matrixTransform(matrix);
|
|
357
|
-
point.x += width;
|
|
358
|
-
bbox.ne = point.matrixTransform(matrix);
|
|
359
|
-
point.y += height;
|
|
360
|
-
bbox.se = point.matrixTransform(matrix);
|
|
361
|
-
point.x -= width;
|
|
362
|
-
bbox.sw = point.matrixTransform(matrix);
|
|
363
|
-
point.y -= height / 2;
|
|
364
|
-
bbox.w = point.matrixTransform(matrix);
|
|
365
|
-
point.x += width;
|
|
366
|
-
bbox.e = point.matrixTransform(matrix);
|
|
367
|
-
point.x -= width / 2;
|
|
368
|
-
point.y -= height / 2;
|
|
369
|
-
bbox.n = point.matrixTransform(matrix);
|
|
370
|
-
point.y += height;
|
|
371
|
-
bbox.s = point.matrixTransform(matrix);
|
|
372
|
-
|
|
373
|
-
return bbox;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Private - replace D3JS 3.X d3.functor() function
|
|
377
|
-
function functor(v) {
|
|
378
|
-
return typeof v === "function" ? v : function () {
|
|
379
|
-
return v;
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return tip;
|
|
384
|
-
}
|
|
1
|
+
// Based on https://github.com/GordonSmith/d3-tip forked from https://github.com/Caged/d3-tip
|
|
2
|
+
|
|
3
|
+
import { map } from "d3-collection";
|
|
4
|
+
import { select, selection } from "d3-selection";
|
|
5
|
+
|
|
6
|
+
export function tip() {
|
|
7
|
+
let direction = d3TipDirection;
|
|
8
|
+
let offset = d3TipOffset;
|
|
9
|
+
let html = d3TipHTML;
|
|
10
|
+
let rootElement = functor(document.body);
|
|
11
|
+
let node = initNode();
|
|
12
|
+
let svg = null;
|
|
13
|
+
let point = null;
|
|
14
|
+
let target = null;
|
|
15
|
+
|
|
16
|
+
const tip: any = function (vis) {
|
|
17
|
+
svg = getSVGNode(vis);
|
|
18
|
+
if (!svg) return;
|
|
19
|
+
point = svg.createSVGPoint();
|
|
20
|
+
const re = rootElement();
|
|
21
|
+
if (!re) return;
|
|
22
|
+
if (!node) return;
|
|
23
|
+
re.appendChild(node);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Public - show the tooltip on the screen
|
|
27
|
+
//
|
|
28
|
+
// Returns a tip
|
|
29
|
+
tip.show = function (d, idx, arr) {
|
|
30
|
+
target = arr[idx];
|
|
31
|
+
const args = Array.prototype.slice.call(arguments) as [];
|
|
32
|
+
const content = html.apply(this, args);
|
|
33
|
+
if (content === null) {
|
|
34
|
+
return tip;
|
|
35
|
+
}
|
|
36
|
+
const poffset = offset.apply(this, args);
|
|
37
|
+
const nodel = getNodeEl();
|
|
38
|
+
let i = directions.length;
|
|
39
|
+
let coords;
|
|
40
|
+
const root_bbox = rootElement().getBoundingClientRect();
|
|
41
|
+
nodel.html(content)
|
|
42
|
+
.style("opacity", 1).style("pointer-events", "all");
|
|
43
|
+
|
|
44
|
+
while (i--) nodel.classed(directions[i], false);
|
|
45
|
+
let placement_success = false;
|
|
46
|
+
const placement_overflow = {};
|
|
47
|
+
let least_overflow_direction = directions[0];
|
|
48
|
+
for (let i = 0; i < directions.length; i++) {
|
|
49
|
+
placement_success = _placement_attempt(directions[i]);
|
|
50
|
+
if (placement_success) break;
|
|
51
|
+
}
|
|
52
|
+
if (!placement_success) {
|
|
53
|
+
nodel.classed("notick", true);
|
|
54
|
+
const top_offset = _vertical_adjustment(placement_overflow[least_overflow_direction]);
|
|
55
|
+
const left_offset = _horizontal_adjustment(placement_overflow[least_overflow_direction]);
|
|
56
|
+
_placement_attempt(least_overflow_direction, top_offset, left_offset);
|
|
57
|
+
} else {
|
|
58
|
+
nodel.classed("notick", false);
|
|
59
|
+
}
|
|
60
|
+
return tip;
|
|
61
|
+
|
|
62
|
+
function _horizontal_adjustment(overflow_obj) {
|
|
63
|
+
if (overflow_obj.left > overflow_obj.right) {
|
|
64
|
+
return overflow_obj.left > 0 ? -overflow_obj.left : 0;
|
|
65
|
+
} else {
|
|
66
|
+
return overflow_obj.right > 0 ? overflow_obj.right : 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function _vertical_adjustment(overflow_obj) {
|
|
70
|
+
if (overflow_obj.top > overflow_obj.bottom) {
|
|
71
|
+
return overflow_obj.top > 0 ? -overflow_obj.top : 0;
|
|
72
|
+
} else {
|
|
73
|
+
return overflow_obj.bottom;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function _placement_attempt(this: any, _dir, _top_offset?, _left_offset?) {
|
|
78
|
+
_top_offset = _top_offset ? _top_offset : 0;
|
|
79
|
+
_left_offset = _left_offset ? _left_offset : 0;
|
|
80
|
+
nodel.style("white-space", "nowrap");
|
|
81
|
+
coords = directionCallbacks.get(_dir).apply(this);
|
|
82
|
+
nodel.classed(_dir, true)
|
|
83
|
+
.style("top", (coords.top + poffset[0] - _top_offset) + "px")
|
|
84
|
+
.style("left", (coords.left + poffset[1] - _left_offset) + "px");
|
|
85
|
+
const nodel_bbox = nodel.node().getBoundingClientRect();
|
|
86
|
+
const ret = nodel_bbox.top > root_bbox.top
|
|
87
|
+
&& nodel_bbox.left > root_bbox.left
|
|
88
|
+
&& nodel_bbox.bottom < root_bbox.bottom
|
|
89
|
+
&& nodel_bbox.right < root_bbox.right
|
|
90
|
+
;
|
|
91
|
+
placement_overflow[_dir] = {
|
|
92
|
+
top: root_bbox.top - nodel_bbox.top,
|
|
93
|
+
right: nodel_bbox.right - root_bbox.right,
|
|
94
|
+
bottom: nodel_bbox.bottom - root_bbox.bottom,
|
|
95
|
+
left: root_bbox.left - nodel_bbox.left
|
|
96
|
+
};
|
|
97
|
+
nodel.style("white-space", "normal");
|
|
98
|
+
placement_overflow[_dir].total_overflow = Object.keys(placement_overflow[_dir])
|
|
99
|
+
.filter(side => placement_overflow[_dir][side] > 0)
|
|
100
|
+
.reduce((sum, side) => {
|
|
101
|
+
const side_overflow = placement_overflow[_dir][side];
|
|
102
|
+
return sum + side_overflow;
|
|
103
|
+
}, 0);
|
|
104
|
+
if (placement_overflow[least_overflow_direction].total_overflow > placement_overflow[_dir].total_overflow) {
|
|
105
|
+
least_overflow_direction = _dir;
|
|
106
|
+
}
|
|
107
|
+
if (!ret) {
|
|
108
|
+
nodel.classed(_dir, false);
|
|
109
|
+
}
|
|
110
|
+
return ret;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Public - hide the tooltip
|
|
115
|
+
//
|
|
116
|
+
// Returns a tip
|
|
117
|
+
tip.hide = function () {
|
|
118
|
+
const nodel = getNodeEl();
|
|
119
|
+
nodel.style("opacity", 0).style("pointer-events", "none");
|
|
120
|
+
return tip;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Public: Proxy attr calls to the d3 tip container.
|
|
124
|
+
// Sets or gets attribute value.
|
|
125
|
+
//
|
|
126
|
+
// n - name of the attribute
|
|
127
|
+
// v - value of the attribute
|
|
128
|
+
//
|
|
129
|
+
// Returns tip or attribute value
|
|
130
|
+
tip.attr = function (n, v) {
|
|
131
|
+
if (arguments.length < 2 && typeof n === "string") {
|
|
132
|
+
return getNodeEl().attr(n);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const args = Array.prototype.slice.call(arguments);
|
|
136
|
+
selection.prototype.attr.apply(getNodeEl(), args);
|
|
137
|
+
return tip;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Public: Proxy style calls to the d3 tip container.
|
|
141
|
+
// Sets or gets a style value.
|
|
142
|
+
//
|
|
143
|
+
// n - name of the property
|
|
144
|
+
// v - value of the property
|
|
145
|
+
//
|
|
146
|
+
// Returns tip or style property value
|
|
147
|
+
tip.style = function (n, v) {
|
|
148
|
+
if (arguments.length < 2 && typeof n === "string") {
|
|
149
|
+
return getNodeEl().style(n);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const args = Array.prototype.slice.call(arguments);
|
|
153
|
+
selection.prototype.style.apply(getNodeEl(), args);
|
|
154
|
+
return tip;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Public: Set or get the direction of the tooltip
|
|
158
|
+
//
|
|
159
|
+
// v - One of n(north), s(south), e(east), or w(west), nw(northwest),
|
|
160
|
+
// sw(southwest), ne(northeast) or se(southeast)
|
|
161
|
+
//
|
|
162
|
+
// Returns tip or direction
|
|
163
|
+
tip.direction = function (v) {
|
|
164
|
+
if (!arguments.length) return direction;
|
|
165
|
+
direction = v == null ? v : functor(v);
|
|
166
|
+
|
|
167
|
+
return tip;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Public: Sets or gets the offset of the tip
|
|
171
|
+
//
|
|
172
|
+
// v - Array of [x, y] offset
|
|
173
|
+
//
|
|
174
|
+
// Returns offset or
|
|
175
|
+
tip.offset = function (v) {
|
|
176
|
+
if (!arguments.length) return offset;
|
|
177
|
+
offset = v == null ? v : functor(v);
|
|
178
|
+
|
|
179
|
+
return tip;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Public: sets or gets the html value of the tooltip
|
|
183
|
+
//
|
|
184
|
+
// v - String value of the tip
|
|
185
|
+
//
|
|
186
|
+
// Returns html value or tip
|
|
187
|
+
tip.html = function (v) {
|
|
188
|
+
if (!arguments.length) return html;
|
|
189
|
+
html = v == null ? v : functor(v);
|
|
190
|
+
|
|
191
|
+
return tip;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Public: sets or gets the root element anchor of the tooltip
|
|
195
|
+
//
|
|
196
|
+
// v - root element of the tooltip
|
|
197
|
+
//
|
|
198
|
+
// Returns root node of tip
|
|
199
|
+
tip.rootElement = function (v) {
|
|
200
|
+
if (!arguments.length) return rootElement;
|
|
201
|
+
rootElement = functor(v);
|
|
202
|
+
|
|
203
|
+
return tip;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Public: destroys the tooltip and removes it from the DOM
|
|
207
|
+
//
|
|
208
|
+
// Returns a tip
|
|
209
|
+
tip.destroy = function () {
|
|
210
|
+
if (node) {
|
|
211
|
+
getNodeEl().remove();
|
|
212
|
+
node = null;
|
|
213
|
+
}
|
|
214
|
+
return tip;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
function d3TipDirection() { return "n"; }
|
|
218
|
+
function d3TipOffset() { return [0, 0]; }
|
|
219
|
+
function d3TipHTML() { return " "; }
|
|
220
|
+
|
|
221
|
+
const directionCallbacks = map({
|
|
222
|
+
n: directionNorth,
|
|
223
|
+
s: directionSouth,
|
|
224
|
+
e: directionEast,
|
|
225
|
+
w: directionWest,
|
|
226
|
+
nw: directionNorthWest,
|
|
227
|
+
ne: directionNorthEast,
|
|
228
|
+
sw: directionSouthWest,
|
|
229
|
+
se: directionSouthEast
|
|
230
|
+
});
|
|
231
|
+
const directions = directionCallbacks.keys();
|
|
232
|
+
|
|
233
|
+
function directionNorth() {
|
|
234
|
+
const bbox = getScreenBBox(window);
|
|
235
|
+
return {
|
|
236
|
+
top: bbox.n.y - node.offsetHeight,
|
|
237
|
+
left: bbox.n.x - node.offsetWidth / 2
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function directionSouth() {
|
|
242
|
+
const bbox = getScreenBBox(window);
|
|
243
|
+
return {
|
|
244
|
+
top: bbox.s.y + 8,
|
|
245
|
+
left: bbox.s.x - node.offsetWidth / 2
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function directionEast() {
|
|
250
|
+
const bbox = getScreenBBox(window);
|
|
251
|
+
return {
|
|
252
|
+
top: bbox.e.y - node.offsetHeight / 2,
|
|
253
|
+
left: bbox.e.x + 8
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function directionWest() {
|
|
258
|
+
const bbox = getScreenBBox(window);
|
|
259
|
+
return {
|
|
260
|
+
top: bbox.w.y - node.offsetHeight / 2,
|
|
261
|
+
left: bbox.w.x - node.offsetWidth - 8
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function directionNorthWest() {
|
|
266
|
+
const bbox = getScreenBBox(window);
|
|
267
|
+
return {
|
|
268
|
+
top: bbox.nw.y - node.offsetHeight,
|
|
269
|
+
left: bbox.nw.x - node.offsetWidth
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function directionNorthEast() {
|
|
274
|
+
const bbox = getScreenBBox(window);
|
|
275
|
+
return {
|
|
276
|
+
top: bbox.ne.y - node.offsetHeight,
|
|
277
|
+
left: bbox.ne.x
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function directionSouthWest() {
|
|
282
|
+
const bbox = getScreenBBox(window);
|
|
283
|
+
return {
|
|
284
|
+
top: bbox.sw.y,
|
|
285
|
+
left: bbox.sw.x - node.offsetWidth
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function directionSouthEast() {
|
|
290
|
+
const bbox = getScreenBBox(window);
|
|
291
|
+
return {
|
|
292
|
+
top: bbox.se.y,
|
|
293
|
+
left: bbox.se.x
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function initNode() {
|
|
298
|
+
const div = select(document.createElement("div"));
|
|
299
|
+
div
|
|
300
|
+
.attr("class", "d3-tip")
|
|
301
|
+
.style("position", "absolute")
|
|
302
|
+
.style("top", "0px")
|
|
303
|
+
.style("opacity", 0)
|
|
304
|
+
.style("pointer-events", "none")
|
|
305
|
+
.style("box-sizing", "border-box");
|
|
306
|
+
|
|
307
|
+
return div.node();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function getSVGNode(element) {
|
|
311
|
+
const svgNode = element.node();
|
|
312
|
+
if (!svgNode) return null;
|
|
313
|
+
if (svgNode.tagName.toLowerCase() === "svg") return svgNode;
|
|
314
|
+
return svgNode.ownerSVGElement;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function getNodeEl() {
|
|
318
|
+
if (node == null) {
|
|
319
|
+
node = initNode();
|
|
320
|
+
// re-add node to DOM
|
|
321
|
+
rootElement().appendChild(node);
|
|
322
|
+
}
|
|
323
|
+
return select(node);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Private - gets the screen coordinates of a shape
|
|
327
|
+
//
|
|
328
|
+
// Given a shape on the screen, will return an SVGPoint for the directions
|
|
329
|
+
// n(north), s(south), e(east), w(west), ne(northeast), se(southeast),
|
|
330
|
+
// nw(northwest), sw(southwest).
|
|
331
|
+
//
|
|
332
|
+
// +-+-+
|
|
333
|
+
// | |
|
|
334
|
+
// + +
|
|
335
|
+
// | |
|
|
336
|
+
// +-+-+
|
|
337
|
+
//
|
|
338
|
+
// Returns an Object {n, s, e, w, nw, sw, ne, se}
|
|
339
|
+
function getScreenBBox(targetShape) {
|
|
340
|
+
let targetel = target || targetShape;
|
|
341
|
+
|
|
342
|
+
while (targetel.getCTM == null && targetel.parentNode != null) {
|
|
343
|
+
targetel = targetel.parentNode;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const bbox: any = {};
|
|
347
|
+
const matrix = targetel.getCTM();
|
|
348
|
+
const tbbox = targetel.getBBox();
|
|
349
|
+
const width = tbbox.width;
|
|
350
|
+
const height = tbbox.height;
|
|
351
|
+
const x = tbbox.x;
|
|
352
|
+
const y = tbbox.y;
|
|
353
|
+
|
|
354
|
+
point.x = x;
|
|
355
|
+
point.y = y;
|
|
356
|
+
bbox.nw = point.matrixTransform(matrix);
|
|
357
|
+
point.x += width;
|
|
358
|
+
bbox.ne = point.matrixTransform(matrix);
|
|
359
|
+
point.y += height;
|
|
360
|
+
bbox.se = point.matrixTransform(matrix);
|
|
361
|
+
point.x -= width;
|
|
362
|
+
bbox.sw = point.matrixTransform(matrix);
|
|
363
|
+
point.y -= height / 2;
|
|
364
|
+
bbox.w = point.matrixTransform(matrix);
|
|
365
|
+
point.x += width;
|
|
366
|
+
bbox.e = point.matrixTransform(matrix);
|
|
367
|
+
point.x -= width / 2;
|
|
368
|
+
point.y -= height / 2;
|
|
369
|
+
bbox.n = point.matrixTransform(matrix);
|
|
370
|
+
point.y += height;
|
|
371
|
+
bbox.s = point.matrixTransform(matrix);
|
|
372
|
+
|
|
373
|
+
return bbox;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Private - replace D3JS 3.X d3.functor() function
|
|
377
|
+
function functor(v) {
|
|
378
|
+
return typeof v === "function" ? v : function () {
|
|
379
|
+
return v;
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return tip;
|
|
384
|
+
}
|