@tanstack/charts
Version:
A chart grammar for TypeScript and JavaScript. Marks consume your data directly, channels describe visual encodings, and the engine compiles them into a renderer-neutral keyed scene. TanStack's compact scales cover common numeric and categorical mappings.
74 lines (73 loc) • 2.54 kB
JavaScript
const defaultPlacements = [
"top",
"bottom",
"right",
"left"
];
function resolveChartTooltipPlacement(anchor, tooltip, boundary, placement, offset) {
const edge = 8;
const gap = offset !== void 0 && Number.isFinite(offset) ? Math.max(0, offset) : 10;
const minimumLeft = boundary.left + edge;
const minimumTop = boundary.top + edge;
const maxLeft = Math.max(minimumLeft, boundary.right - edge - tooltip.width);
const maxTop = Math.max(minimumTop, boundary.bottom - edge - tooltip.height);
const placements = placement === void 0 || placement === "auto" ? defaultPlacements : Array.isArray(placement) ? placement.length ? placement : defaultPlacements : [placement];
const candidates = placements.map(
(candidate) => tooltipPlacement(
candidate,
anchor.x,
anchor.y,
tooltip.width,
tooltip.height,
gap
)
);
let selected = candidates[0];
let selectedOverflow = overflow(
selected,
tooltip.width,
tooltip.height,
boundary,
edge
);
for (const candidate of candidates) {
const candidateOverflow = overflow(
candidate,
tooltip.width,
tooltip.height,
boundary,
edge
);
if (candidateOverflow === 0) {
selected = candidate;
break;
}
if (candidateOverflow < selectedOverflow) {
selected = candidate;
selectedOverflow = candidateOverflow;
}
}
return {
left: clamp(selected.left, minimumLeft, maxLeft),
top: clamp(selected.top, minimumTop, maxTop),
placement: selected.placement
};
}
function tooltipPlacement(placement, anchorX, anchorY, width, height, gap) {
const xDirection = placement.endsWith("right") || placement === "right" ? 1 : placement.endsWith("left") || placement === "left" ? -1 : 0;
const yDirection = placement.startsWith("bottom") || placement === "bottom" ? 1 : placement.startsWith("top") || placement === "top" ? -1 : 0;
return {
placement,
left: anchorX + (xDirection - 1) * width / 2 + xDirection * gap,
top: anchorY + (yDirection - 1) * height / 2 + yDirection * gap
};
}
function overflow(position, width, height, boundary, edge) {
return Math.max(0, boundary.left + edge - position.left) + Math.max(0, position.left + width + edge - boundary.right) + Math.max(0, boundary.top + edge - position.top) + Math.max(0, position.top + height + edge - boundary.bottom);
}
function clamp(value, minimum, maximum) {
return Math.max(minimum, Math.min(maximum, value));
}
export {
resolveChartTooltipPlacement
};