mirror of
https://github.com/dcarrillo/atalaya.git
synced 2026-04-18 02:24:05 +00:00
fix: edge tooltips were hidden inside the box (#5)
* fix: edge tooltips were hidden inside the box * Update README.md
This commit is contained in:
@@ -61,6 +61,8 @@ function getBarColor(uptimePercent: number | undefined): string {
|
|||||||
gap: 1px;
|
gap: 1px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar {
|
.bar {
|
||||||
@@ -93,13 +95,17 @@ function getBarColor(uptimePercent: number | undefined): string {
|
|||||||
background: var(--no-data);
|
background: var(--no-data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tooltip */
|
/* Tooltip - positioned below to avoid conflict with bar labels */
|
||||||
|
.bar {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.bar::before {
|
.bar::before {
|
||||||
content: attr(data-tooltip);
|
content: attr(data-tooltip);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 100%;
|
top: calc(100% + 8px);
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%) translateY(-8px);
|
transform: translateX(-50%);
|
||||||
background: var(--text);
|
background: var(--text);
|
||||||
color: var(--bg);
|
color: var(--bg);
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
@@ -112,16 +118,56 @@ function getBarColor(uptimePercent: number | undefined): string {
|
|||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
/* Prevent tooltip overflow */
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
/* Ensure tooltip stays within screen bounds */
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
/* Constrain to viewport */
|
||||||
|
max-width: min(200px, calc(100vw - 32px));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For left-edge bars, prevent left overflow */
|
||||||
|
.bar:nth-child(1)::before,
|
||||||
|
.bar:nth-child(2)::before,
|
||||||
|
.bar:nth-child(3)::before,
|
||||||
|
.bar:nth-child(4)::before,
|
||||||
|
.bar:nth-child(5)::before,
|
||||||
|
.bar:nth-child(6)::before,
|
||||||
|
.bar:nth-child(7)::before,
|
||||||
|
.bar:nth-child(8)::before,
|
||||||
|
.bar:nth-child(9)::before,
|
||||||
|
.bar:nth-child(10)::before {
|
||||||
|
left: 0;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For right-edge bars, prevent right overflow */
|
||||||
|
.bar:nth-last-child(1)::before,
|
||||||
|
.bar:nth-last-child(2)::before,
|
||||||
|
.bar:nth-last-child(3)::before,
|
||||||
|
.bar:nth-last-child(4)::before,
|
||||||
|
.bar:nth-last-child(5)::before,
|
||||||
|
.bar:nth-last-child(6)::before,
|
||||||
|
.bar:nth-last-child(7)::before,
|
||||||
|
.bar:nth-last-child(8)::before,
|
||||||
|
.bar:nth-last-child(9)::before,
|
||||||
|
.bar:nth-last-child(10)::before {
|
||||||
|
left: auto;
|
||||||
|
right: 0;
|
||||||
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar::after {
|
.bar::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 100%;
|
top: calc(100% + 2px);
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%) translateY(-2px);
|
transform: translateX(-50%);
|
||||||
border: 4px solid transparent;
|
border: 4px solid transparent;
|
||||||
border-top-color: var(--text);
|
border-bottom-color: var(--text);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
@@ -129,6 +175,21 @@ function getBarColor(uptimePercent: number | undefined): string {
|
|||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adjust arrow position for edge bars */
|
||||||
|
.bar:nth-child(1)::after,
|
||||||
|
.bar:nth-child(2)::after,
|
||||||
|
.bar:nth-child(3)::after,
|
||||||
|
.bar:nth-child(4)::after,
|
||||||
|
.bar:nth-child(5)::after,
|
||||||
|
.bar:nth-child(6)::after,
|
||||||
|
.bar:nth-child(7)::after,
|
||||||
|
.bar:nth-child(8)::after,
|
||||||
|
.bar:nth-child(9)::after,
|
||||||
|
.bar:nth-child(10)::after {
|
||||||
|
left: 8px;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
.bar:hover::before,
|
.bar:hover::before,
|
||||||
.bar:focus::before,
|
.bar:focus::before,
|
||||||
.bar:hover::after,
|
.bar:hover::after,
|
||||||
@@ -136,12 +197,4 @@ function getBarColor(uptimePercent: number | undefined): string {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar-labels {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 9px;
|
|
||||||
color: var(--text-dim);
|
|
||||||
margin-top: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -131,18 +131,54 @@ function tooltipPlugin(strokeColor: string): uPlot.Plugin {
|
|||||||
const msString = Math.round(yValue) + ' ms';
|
const msString = Math.round(yValue) + ' ms';
|
||||||
tooltipElement.textContent = `${timeString} ${msString}`;
|
tooltipElement.textContent = `${timeString} ${msString}`;
|
||||||
|
|
||||||
// Position tooltip, flipping side if near right edge
|
// Position tooltip, ensuring it stays within chart bounds
|
||||||
const tipWidth = tooltipElement.offsetWidth;
|
const tipWidth = tooltipElement.offsetWidth;
|
||||||
|
const tipHeight = tooltipElement.offsetHeight;
|
||||||
const plotWidth = over.clientWidth;
|
const plotWidth = over.clientWidth;
|
||||||
|
const plotHeight = over.clientHeight;
|
||||||
const shiftX = 12;
|
const shiftX = 12;
|
||||||
const shiftY = -10;
|
const shiftY = -10;
|
||||||
let posLeft = left + shiftX;
|
|
||||||
if (posLeft + tipWidth > plotWidth) {
|
// Calculate horizontal position - choose side with more space
|
||||||
|
let posLeft: number;
|
||||||
|
const spaceRight = plotWidth - (left + shiftX);
|
||||||
|
const spaceLeft = left - shiftX;
|
||||||
|
|
||||||
|
// Default to right side if there's enough space
|
||||||
|
if (spaceRight >= tipWidth) {
|
||||||
|
posLeft = left + shiftX;
|
||||||
|
}
|
||||||
|
// Try left side if there's more space there
|
||||||
|
else if (spaceLeft >= tipWidth) {
|
||||||
posLeft = left - tipWidth - shiftX;
|
posLeft = left - tipWidth - shiftX;
|
||||||
}
|
}
|
||||||
|
// Not enough space on either side, choose the better option
|
||||||
|
else {
|
||||||
|
// If right side has more space than left, use right side clamped
|
||||||
|
if (spaceRight > spaceLeft) {
|
||||||
|
posLeft = plotWidth - tipWidth;
|
||||||
|
} else {
|
||||||
|
// Use left side clamped
|
||||||
|
posLeft = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we don't go outside bounds
|
||||||
|
posLeft = Math.max(0, Math.min(posLeft, plotWidth - tipWidth));
|
||||||
|
|
||||||
|
// Calculate vertical position
|
||||||
|
let posTop = (top ?? 0) + shiftY;
|
||||||
|
// Check if tooltip would overflow top edge
|
||||||
|
if (posTop < 0) {
|
||||||
|
posTop = 0;
|
||||||
|
}
|
||||||
|
// Check if tooltip would overflow bottom edge
|
||||||
|
else if (posTop + tipHeight > plotHeight) {
|
||||||
|
posTop = plotHeight - tipHeight;
|
||||||
|
}
|
||||||
|
|
||||||
tooltipElement.style.left = posLeft + 'px';
|
tooltipElement.style.left = posLeft + 'px';
|
||||||
tooltipElement.style.top = (top ?? 0) + shiftY + 'px';
|
tooltipElement.style.top = posTop + 'px';
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user