@internetstiftelsen/charts 0.13.2 → 0.13.3
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/dist/tooltip.d.ts +10 -1
- package/dist/tooltip.js +116 -59
- package/package.json +1 -1
package/dist/tooltip.d.ts
CHANGED
|
@@ -81,6 +81,10 @@ export declare class Tooltip implements ChartComponent<TooltipConfigBase> {
|
|
|
81
81
|
private countPlacedLayoutsOnEdge;
|
|
82
82
|
private doSplitTooltipLayoutsOverlap;
|
|
83
83
|
private resolveSplitTooltipPositions;
|
|
84
|
+
private resolveHorizontalChartSplitTooltipPositions;
|
|
85
|
+
private resolveVerticalChartSplitTooltipPositions;
|
|
86
|
+
private getSplitTooltipViewportBounds;
|
|
87
|
+
private groupSplitTooltipLayoutsByEdge;
|
|
84
88
|
private resolveSideSplitTooltipPositions;
|
|
85
89
|
private resolveHorizontalSideSplitTooltipPositions;
|
|
86
90
|
private resolveHorizontalSideSplitTooltipCollisions;
|
|
@@ -91,6 +95,11 @@ export declare class Tooltip implements ChartComponent<TooltipConfigBase> {
|
|
|
91
95
|
private assignLayoutToHorizontalTooltipLane;
|
|
92
96
|
private doHorizontalTooltipLanesOverlap;
|
|
93
97
|
private doSplitTooltipLayoutsOverlapHorizontally;
|
|
94
|
-
private
|
|
98
|
+
private resolveHorizontalChartAboveBelowSplitTooltipPositions;
|
|
99
|
+
private resolvePackedAboveBelowTooltipRow;
|
|
100
|
+
private resolveVerticalChartAboveBelowSplitTooltipPositions;
|
|
101
|
+
private resolveCollisionAwareAboveBelowTooltipPositions;
|
|
102
|
+
private resolveNonOverlappingAboveBelowTooltipLeft;
|
|
103
|
+
private doesSplitTooltipOverlapPlacedLayouts;
|
|
95
104
|
}
|
|
96
105
|
export {};
|
package/dist/tooltip.js
CHANGED
|
@@ -466,10 +466,6 @@ export class Tooltip {
|
|
|
466
466
|
if (layouts.length === 0) {
|
|
467
467
|
return;
|
|
468
468
|
}
|
|
469
|
-
if (!isHorizontal) {
|
|
470
|
-
this.resolveSplitTooltipCollisions(layouts, 'vertical', this.getOppositeVerticalArrowEdge);
|
|
471
|
-
this.resolveSplitTooltipCollisions(layouts, 'side', this.getOppositeSideArrowEdge);
|
|
472
|
-
}
|
|
473
469
|
this.resolveSplitTooltipPositions(layouts, isHorizontal);
|
|
474
470
|
layouts.forEach((layout) => {
|
|
475
471
|
this.renderTooltipWithConnector(layout.div, layout.arrowEdge, layout.left, layout.top, layout.width, layout.height, layout.targetX, layout.targetY, layout.anchor);
|
|
@@ -1303,19 +1299,42 @@ export class Tooltip {
|
|
|
1303
1299
|
a.top + a.height + SPLIT_TOOLTIP_GAP_PX > b.top);
|
|
1304
1300
|
}
|
|
1305
1301
|
resolveSplitTooltipPositions(layouts, isHorizontal) {
|
|
1306
|
-
if (isHorizontal
|
|
1307
|
-
this.
|
|
1302
|
+
if (isHorizontal) {
|
|
1303
|
+
this.resolveHorizontalChartSplitTooltipPositions(layouts);
|
|
1308
1304
|
return;
|
|
1309
1305
|
}
|
|
1306
|
+
this.resolveVerticalChartSplitTooltipPositions(layouts);
|
|
1307
|
+
}
|
|
1308
|
+
resolveHorizontalChartSplitTooltipPositions(layouts) {
|
|
1310
1309
|
if (this.position === 'vertical') {
|
|
1311
|
-
this.
|
|
1310
|
+
this.resolveSplitTooltipCollisions(layouts, 'vertical', this.getOppositeVerticalArrowEdge);
|
|
1311
|
+
this.resolveHorizontalChartAboveBelowSplitTooltipPositions(layouts);
|
|
1312
1312
|
return;
|
|
1313
1313
|
}
|
|
1314
|
+
this.resolveHorizontalSideSplitTooltipPositions(layouts);
|
|
1315
|
+
}
|
|
1316
|
+
resolveVerticalChartSplitTooltipPositions(layouts) {
|
|
1317
|
+
if (this.position === 'vertical') {
|
|
1318
|
+
this.resolveSplitTooltipCollisions(layouts, 'vertical', this.getOppositeVerticalArrowEdge);
|
|
1319
|
+
this.resolveVerticalChartAboveBelowSplitTooltipPositions(layouts);
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
this.resolveSplitTooltipCollisions(layouts, 'side', this.getOppositeSideArrowEdge);
|
|
1314
1323
|
this.resolveSideSplitTooltipPositions(layouts);
|
|
1315
1324
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1325
|
+
getSplitTooltipViewportBounds() {
|
|
1326
|
+
return {
|
|
1327
|
+
minLeft: window.scrollX + TOOLTIP_VIEWPORT_PADDING_PX,
|
|
1328
|
+
maxRight: window.scrollX +
|
|
1329
|
+
window.innerWidth -
|
|
1330
|
+
TOOLTIP_VIEWPORT_PADDING_PX,
|
|
1331
|
+
minTop: window.scrollY + TOOLTIP_VIEWPORT_PADDING_PX,
|
|
1332
|
+
maxBottom: window.scrollY +
|
|
1333
|
+
window.innerHeight -
|
|
1334
|
+
TOOLTIP_VIEWPORT_PADDING_PX,
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
groupSplitTooltipLayoutsByEdge(layouts) {
|
|
1319
1338
|
const tooltipsByEdge = {
|
|
1320
1339
|
left: [],
|
|
1321
1340
|
right: [],
|
|
@@ -1325,6 +1344,11 @@ export class Tooltip {
|
|
|
1325
1344
|
layouts.forEach((layout) => {
|
|
1326
1345
|
tooltipsByEdge[layout.arrowEdge].push(layout);
|
|
1327
1346
|
});
|
|
1347
|
+
return tooltipsByEdge;
|
|
1348
|
+
}
|
|
1349
|
+
resolveSideSplitTooltipPositions(layouts) {
|
|
1350
|
+
const { minTop, maxBottom } = this.getSplitTooltipViewportBounds();
|
|
1351
|
+
const tooltipsByEdge = this.groupSplitTooltipLayoutsByEdge(layouts);
|
|
1328
1352
|
Object.values(tooltipsByEdge).forEach((edgeLayouts) => {
|
|
1329
1353
|
if (edgeLayouts.length === 0) {
|
|
1330
1354
|
return;
|
|
@@ -1463,65 +1487,98 @@ export class Tooltip {
|
|
|
1463
1487
|
return (a.left < b.left + b.width + SPLIT_TOOLTIP_GAP_PX &&
|
|
1464
1488
|
a.left + a.width + SPLIT_TOOLTIP_GAP_PX > b.left);
|
|
1465
1489
|
}
|
|
1466
|
-
|
|
1467
|
-
const
|
|
1468
|
-
const
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
left
|
|
1473
|
-
right
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
layouts.
|
|
1478
|
-
|
|
1490
|
+
resolveHorizontalChartAboveBelowSplitTooltipPositions(layouts) {
|
|
1491
|
+
const bounds = this.getSplitTooltipViewportBounds();
|
|
1492
|
+
const tooltipsByEdge = this.groupSplitTooltipLayoutsByEdge(layouts);
|
|
1493
|
+
this.resolvePackedAboveBelowTooltipRow(tooltipsByEdge.top, bounds);
|
|
1494
|
+
this.resolvePackedAboveBelowTooltipRow(tooltipsByEdge.bottom, bounds);
|
|
1495
|
+
this.resolveSideSplitTooltipPositions([
|
|
1496
|
+
...tooltipsByEdge.left,
|
|
1497
|
+
...tooltipsByEdge.right,
|
|
1498
|
+
]);
|
|
1499
|
+
}
|
|
1500
|
+
resolvePackedAboveBelowTooltipRow(layouts, bounds) {
|
|
1501
|
+
if (layouts.length === 0) {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
const orderedLayouts = [...layouts].sort((a, b) => a.left - b.left || a.targetX - b.targetX);
|
|
1505
|
+
orderedLayouts.forEach((layout) => {
|
|
1506
|
+
const maxTop = Math.max(bounds.minTop, bounds.maxBottom - layout.height);
|
|
1507
|
+
layout.top = Math.max(bounds.minTop, Math.min(layout.top, maxTop));
|
|
1479
1508
|
});
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1509
|
+
const firstLayout = orderedLayouts[0];
|
|
1510
|
+
const firstMaxLeft = Math.max(bounds.minLeft, bounds.maxRight - firstLayout.width);
|
|
1511
|
+
firstLayout.left = Math.max(bounds.minLeft, Math.min(firstLayout.left, firstMaxLeft));
|
|
1512
|
+
for (let i = 1; i < orderedLayouts.length; i++) {
|
|
1513
|
+
const previousLayout = orderedLayouts[i - 1];
|
|
1514
|
+
const currentLayout = orderedLayouts[i];
|
|
1515
|
+
const minAllowedLeft = previousLayout.left +
|
|
1516
|
+
previousLayout.width +
|
|
1517
|
+
SPLIT_TOOLTIP_GAP_PX;
|
|
1518
|
+
currentLayout.left = Math.max(currentLayout.left, minAllowedLeft);
|
|
1519
|
+
}
|
|
1520
|
+
const lastLayout = orderedLayouts[orderedLayouts.length - 1];
|
|
1521
|
+
const overflow = lastLayout.left + lastLayout.width - bounds.maxRight;
|
|
1522
|
+
if (overflow > 0) {
|
|
1523
|
+
lastLayout.left -= overflow;
|
|
1524
|
+
for (let i = orderedLayouts.length - 2; i >= 0; i--) {
|
|
1525
|
+
const currentLayout = orderedLayouts[i];
|
|
1526
|
+
const nextLayout = orderedLayouts[i + 1];
|
|
1527
|
+
const maxAllowedLeft = nextLayout.left -
|
|
1528
|
+
currentLayout.width -
|
|
1491
1529
|
SPLIT_TOOLTIP_GAP_PX;
|
|
1492
|
-
currentLayout.left = Math.
|
|
1530
|
+
currentLayout.left = Math.min(currentLayout.left, maxAllowedLeft);
|
|
1493
1531
|
}
|
|
1494
|
-
const
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
const currentLayout = edgeLayouts[i];
|
|
1500
|
-
const nextLayout = edgeLayouts[i + 1];
|
|
1501
|
-
const maxAllowedLeft = nextLayout.left -
|
|
1502
|
-
currentLayout.width -
|
|
1503
|
-
SPLIT_TOOLTIP_GAP_PX;
|
|
1504
|
-
currentLayout.left = Math.min(currentLayout.left, maxAllowedLeft);
|
|
1505
|
-
}
|
|
1506
|
-
const underflow = minLeft - edgeLayouts[0].left;
|
|
1507
|
-
if (underflow > 0) {
|
|
1508
|
-
edgeLayouts.forEach((layout) => {
|
|
1509
|
-
layout.left += underflow;
|
|
1510
|
-
});
|
|
1511
|
-
}
|
|
1532
|
+
const underflow = bounds.minLeft - orderedLayouts[0].left;
|
|
1533
|
+
if (underflow > 0) {
|
|
1534
|
+
orderedLayouts.forEach((layout) => {
|
|
1535
|
+
layout.left += underflow;
|
|
1536
|
+
});
|
|
1512
1537
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
layout.top = Math.max(minTop, Math.min(layout.top, maxTop));
|
|
1518
|
-
});
|
|
1538
|
+
}
|
|
1539
|
+
orderedLayouts.forEach((layout) => {
|
|
1540
|
+
const maxLeft = Math.max(bounds.minLeft, bounds.maxRight - layout.width);
|
|
1541
|
+
layout.left = Math.max(bounds.minLeft, Math.min(layout.left, maxLeft));
|
|
1519
1542
|
});
|
|
1543
|
+
}
|
|
1544
|
+
resolveVerticalChartAboveBelowSplitTooltipPositions(layouts) {
|
|
1545
|
+
const bounds = this.getSplitTooltipViewportBounds();
|
|
1546
|
+
const tooltipsByEdge = this.groupSplitTooltipLayoutsByEdge(layouts);
|
|
1547
|
+
this.resolveCollisionAwareAboveBelowTooltipPositions(tooltipsByEdge.top, bounds);
|
|
1548
|
+
this.resolveCollisionAwareAboveBelowTooltipPositions(tooltipsByEdge.bottom, bounds);
|
|
1520
1549
|
this.resolveSideSplitTooltipPositions([
|
|
1521
1550
|
...tooltipsByEdge.left,
|
|
1522
1551
|
...tooltipsByEdge.right,
|
|
1523
1552
|
]);
|
|
1524
1553
|
}
|
|
1554
|
+
resolveCollisionAwareAboveBelowTooltipPositions(layouts, bounds) {
|
|
1555
|
+
const placedLayouts = [];
|
|
1556
|
+
const orderedLayouts = [...layouts].sort((a, b) => a.left - b.left || a.top - b.top);
|
|
1557
|
+
orderedLayouts.forEach((layout) => {
|
|
1558
|
+
const maxLeft = Math.max(bounds.minLeft, bounds.maxRight - layout.width);
|
|
1559
|
+
const maxTop = Math.max(bounds.minTop, bounds.maxBottom - layout.height);
|
|
1560
|
+
layout.top = Math.max(bounds.minTop, Math.min(layout.top, maxTop));
|
|
1561
|
+
layout.left = this.resolveNonOverlappingAboveBelowTooltipLeft(layout, placedLayouts, bounds.minLeft, maxLeft);
|
|
1562
|
+
placedLayouts.push(layout);
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
resolveNonOverlappingAboveBelowTooltipLeft(layout, placedLayouts, minLeft, maxLeft) {
|
|
1566
|
+
const preferredLeft = Math.max(minLeft, Math.min(layout.left, maxLeft));
|
|
1567
|
+
if (!this.doesSplitTooltipOverlapPlacedLayouts({ ...layout, left: preferredLeft }, placedLayouts)) {
|
|
1568
|
+
return preferredLeft;
|
|
1569
|
+
}
|
|
1570
|
+
const candidates = placedLayouts.flatMap((placedLayout) => [
|
|
1571
|
+
placedLayout.left + placedLayout.width + SPLIT_TOOLTIP_GAP_PX,
|
|
1572
|
+
placedLayout.left - layout.width - SPLIT_TOOLTIP_GAP_PX,
|
|
1573
|
+
]);
|
|
1574
|
+
return (Array.from(new Set(candidates.map((candidate) => Math.round(Math.max(minLeft, Math.min(candidate, maxLeft))))))
|
|
1575
|
+
.sort((a, b) => Math.abs(a - preferredLeft) -
|
|
1576
|
+
Math.abs(b - preferredLeft))
|
|
1577
|
+
.find((candidate) => !this.doesSplitTooltipOverlapPlacedLayouts({ ...layout, left: candidate }, placedLayouts)) ?? preferredLeft);
|
|
1578
|
+
}
|
|
1579
|
+
doesSplitTooltipOverlapPlacedLayouts(layout, placedLayouts) {
|
|
1580
|
+
return placedLayouts.some((placedLayout) => this.doSplitTooltipLayoutsOverlap(layout, placedLayout));
|
|
1581
|
+
}
|
|
1525
1582
|
}
|
|
1526
1583
|
Object.defineProperty(Tooltip, "nextTooltipId", {
|
|
1527
1584
|
enumerable: true,
|
package/package.json
CHANGED