[Dashboards] Improve tooltip animations (#16357)
before - https://github.com/user-attachments/assets/069a8737-fcc9-4186-bdbf-e9ed0dfa41a8 after - https://github.com/user-attachments/assets/dbc8604c-dda0-46a9-a67b-f59cc91d7f53
This commit is contained in:
+45
-29
@@ -5,12 +5,13 @@ import {
|
||||
import { useGraphWidgetTooltipFloating } from '@/page-layout/widgets/graph/hooks/useGraphWidgetTooltipFloating';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { FloatingPortal, type VirtualElement } from '@floating-ui/react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { animated, useSpring } from '@react-spring/web';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type GraphWidgetFloatingTooltipProps = {
|
||||
reference: Element | VirtualElement;
|
||||
boundary: Element;
|
||||
reference: Element | VirtualElement | null;
|
||||
boundary: Element | null;
|
||||
tooltipOffsetFromAnchorInPx: number;
|
||||
items: GraphWidgetTooltipItem[];
|
||||
indexLabel?: string;
|
||||
highlightedKey?: string;
|
||||
@@ -23,6 +24,7 @@ type GraphWidgetFloatingTooltipProps = {
|
||||
export const GraphWidgetFloatingTooltip = ({
|
||||
reference,
|
||||
boundary,
|
||||
tooltipOffsetFromAnchorInPx,
|
||||
items,
|
||||
indexLabel,
|
||||
highlightedKey,
|
||||
@@ -33,51 +35,65 @@ export const GraphWidgetFloatingTooltip = ({
|
||||
}: GraphWidgetFloatingTooltipProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const { refs, floatingStyles } = useGraphWidgetTooltipFloating(
|
||||
const { refs, x, y, isPositioned } = useGraphWidgetTooltipFloating(
|
||||
reference,
|
||||
boundary,
|
||||
tooltipOffsetFromAnchorInPx,
|
||||
);
|
||||
|
||||
const xPos = x ?? 0;
|
||||
const yPos = y ?? 0;
|
||||
|
||||
const shouldShow = isDefined(reference) && items.length > 0;
|
||||
const isVisible = shouldShow && isPositioned;
|
||||
|
||||
const springStyles = useSpring({
|
||||
from: {
|
||||
transform: `translate(${xPos}px, ${yPos}px)`,
|
||||
opacity: 0,
|
||||
},
|
||||
to: {
|
||||
transform: `translate(${xPos}px, ${yPos}px)`,
|
||||
opacity: isVisible ? 1 : 0,
|
||||
},
|
||||
config: {
|
||||
tension: 300,
|
||||
friction: 30,
|
||||
},
|
||||
immediate: !isPositioned || !shouldShow,
|
||||
reset: !shouldShow,
|
||||
});
|
||||
|
||||
if (!isDefined(boundary) || !(boundary instanceof HTMLElement)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FloatingPortal root={boundary}>
|
||||
<div
|
||||
<animated.div
|
||||
ref={refs.setFloating}
|
||||
style={{
|
||||
...floatingStyles,
|
||||
...springStyles,
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
zIndex: theme.lastLayerZIndex,
|
||||
pointerEvents: disablePointerEvents ? 'none' : 'auto',
|
||||
pointerEvents: disablePointerEvents || !isVisible ? 'none' : 'auto',
|
||||
}}
|
||||
role="tooltip"
|
||||
aria-live="polite"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
initial={{
|
||||
opacity: 0,
|
||||
scale: 0.95,
|
||||
}}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.95 }}
|
||||
transition={{
|
||||
duration: theme.animation.duration.fast,
|
||||
ease: 'easeInOut',
|
||||
}}
|
||||
>
|
||||
<GraphWidgetTooltip
|
||||
items={items}
|
||||
indexLabel={indexLabel}
|
||||
highlightedKey={highlightedKey}
|
||||
onGraphWidgetTooltipClick={onGraphWidgetTooltipClick}
|
||||
/>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
{items.length > 0 && (
|
||||
<GraphWidgetTooltip
|
||||
items={items}
|
||||
indexLabel={indexLabel}
|
||||
highlightedKey={highlightedKey}
|
||||
onGraphWidgetTooltipClick={onGraphWidgetTooltipClick}
|
||||
/>
|
||||
)}
|
||||
</animated.div>
|
||||
</FloatingPortal>
|
||||
);
|
||||
};
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
export const GRAPH_TOOLTIP_OFFSET_PX = 2;
|
||||
+15
-31
@@ -1,15 +1,16 @@
|
||||
import { GraphWidgetFloatingTooltip } from '@/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip';
|
||||
import { BAR_CHART_TOOLTIP_OFFSET_PX } from '@/page-layout/widgets/graph/graphWidgetBarChart/constants/BarChartTooltipOffsetPx';
|
||||
import { graphWidgetBarTooltipComponentState } from '@/page-layout/widgets/graph/graphWidgetBarChart/states/graphWidgetBarTooltipComponentState';
|
||||
import { type BarChartEnrichedKey } from '@/page-layout/widgets/graph/graphWidgetBarChart/types/BarChartEnrichedKey';
|
||||
import { getBarChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetBarChart/utils/getBarChartTooltipData';
|
||||
import { getTooltipReferenceFromBarChartElementAnchor } from '@/page-layout/widgets/graph/utils/getTooltipReferenceFromBarChartElementAnchor';
|
||||
import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { type BarDatum, type ComputedDatum } from '@nivo/bar';
|
||||
import { type RefObject } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type GraphBarChartTooltipProps = {
|
||||
containerId: string;
|
||||
containerRef: RefObject<HTMLDivElement>;
|
||||
enrichedKeys: BarChartEnrichedKey[];
|
||||
formatOptions: GraphValueFormatOptions;
|
||||
enableGroupTooltip?: boolean;
|
||||
@@ -20,7 +21,7 @@ type GraphBarChartTooltipProps = {
|
||||
};
|
||||
|
||||
export const GraphBarChartTooltip = ({
|
||||
containerId,
|
||||
containerRef,
|
||||
enrichedKeys,
|
||||
formatOptions,
|
||||
enableGroupTooltip = true,
|
||||
@@ -33,6 +34,11 @@ export const GraphBarChartTooltip = ({
|
||||
graphWidgetBarTooltipComponentState,
|
||||
);
|
||||
|
||||
const containerElement = containerRef.current;
|
||||
if (!isDefined(containerElement)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleTooltipClick: (() => void) | undefined = isDefined(onBarClick)
|
||||
? () => {
|
||||
if (isDefined(tooltipState)) {
|
||||
@@ -51,38 +57,16 @@ export const GraphBarChartTooltip = ({
|
||||
layout,
|
||||
});
|
||||
|
||||
let reference = null;
|
||||
let boundary = null;
|
||||
|
||||
if (isDefined(tooltipState)) {
|
||||
try {
|
||||
const positioning = getTooltipReferenceFromBarChartElementAnchor(
|
||||
tooltipState.anchorElement,
|
||||
containerId,
|
||||
);
|
||||
reference = positioning.reference;
|
||||
boundary = positioning.boundary;
|
||||
} catch {
|
||||
reference = null;
|
||||
boundary = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!isDefined(tooltipData) ||
|
||||
!isDefined(reference) ||
|
||||
!isDefined(boundary)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const reference = isDefined(tooltipState) ? tooltipState.anchorElement : null;
|
||||
|
||||
return (
|
||||
<GraphWidgetFloatingTooltip
|
||||
reference={reference}
|
||||
boundary={boundary}
|
||||
items={tooltipData.tooltipItems}
|
||||
indexLabel={tooltipData.indexLabel}
|
||||
highlightedKey={tooltipData.hoveredKey}
|
||||
boundary={containerElement}
|
||||
tooltipOffsetFromAnchorInPx={BAR_CHART_TOOLTIP_OFFSET_PX}
|
||||
items={tooltipData?.tooltipItems ?? []}
|
||||
indexLabel={tooltipData?.indexLabel}
|
||||
highlightedKey={tooltipData?.hoveredKey}
|
||||
onGraphWidgetTooltipClick={handleTooltipClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
|
||||
+1
-1
@@ -284,7 +284,7 @@ export const GraphWidgetBarChart = ({
|
||||
</GraphWidgetChartContainer>
|
||||
|
||||
<GraphBarChartTooltip
|
||||
containerId={id}
|
||||
containerRef={containerRef}
|
||||
enrichedKeys={enrichedKeys}
|
||||
formatOptions={formatOptions}
|
||||
enableGroupTooltip={groupMode === 'stacked'}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const BAR_CHART_TOOLTIP_OFFSET_PX = 2;
|
||||
+18
-28
@@ -1,15 +1,17 @@
|
||||
import { GraphWidgetFloatingTooltip } from '@/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip';
|
||||
import { LINE_CHART_TOOLTIP_OFFSET_PX } from '@/page-layout/widgets/graph/graphWidgetLineChart/constants/LineChartTooltipOffsetPx';
|
||||
import { graphWidgetLineTooltipComponentState } from '@/page-layout/widgets/graph/graphWidgetLineChart/states/graphWidgetLineTooltipComponentState';
|
||||
import { type LineChartEnrichedSeries } from '@/page-layout/widgets/graph/graphWidgetLineChart/types/LineChartEnrichedSeries';
|
||||
import { getLineChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetLineChart/utils/getLineChartTooltipData';
|
||||
import { getTooltipReferenceFromLineChartPointAnchor } from '@/page-layout/widgets/graph/utils/getTooltipReferenceFromLineChartPointAnchor';
|
||||
import { createVirtualElementFromContainerOffset } from '@/page-layout/widgets/graph/utils/createVirtualElementFromContainerOffset';
|
||||
import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { type LineSeries, type Point } from '@nivo/line';
|
||||
import { type RefObject } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type GraphLineChartTooltipProps = {
|
||||
containerId: string;
|
||||
containerRef: RefObject<HTMLDivElement>;
|
||||
enrichedSeries: LineChartEnrichedSeries[];
|
||||
formatOptions: GraphValueFormatOptions;
|
||||
onSliceClick?: (point: Point<LineSeries>) => void;
|
||||
@@ -18,7 +20,7 @@ type GraphLineChartTooltipProps = {
|
||||
};
|
||||
|
||||
export const GraphLineChartTooltip = ({
|
||||
containerId,
|
||||
containerRef,
|
||||
enrichedSeries,
|
||||
formatOptions,
|
||||
onSliceClick,
|
||||
@@ -29,6 +31,11 @@ export const GraphLineChartTooltip = ({
|
||||
graphWidgetLineTooltipComponentState,
|
||||
);
|
||||
|
||||
const containerElement = containerRef.current;
|
||||
if (!isDefined(containerElement)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleTooltipClick: (() => void) | undefined = isDefined(onSliceClick)
|
||||
? () => {
|
||||
if (!isDefined(tooltipState)) return;
|
||||
@@ -52,38 +59,21 @@ export const GraphLineChartTooltip = ({
|
||||
formatOptions,
|
||||
});
|
||||
|
||||
let reference = null;
|
||||
let boundary = null;
|
||||
|
||||
if (isDefined(tooltipState)) {
|
||||
try {
|
||||
const positioning = getTooltipReferenceFromLineChartPointAnchor(
|
||||
containerId,
|
||||
const reference = !isDefined(tooltipState)
|
||||
? null
|
||||
: createVirtualElementFromContainerOffset(
|
||||
containerElement,
|
||||
tooltipState.offsetLeft,
|
||||
tooltipState.offsetTop,
|
||||
);
|
||||
reference = positioning.reference;
|
||||
boundary = positioning.boundary;
|
||||
} catch {
|
||||
reference = null;
|
||||
boundary = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!isDefined(tooltipData) ||
|
||||
!isDefined(reference) ||
|
||||
!isDefined(boundary)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<GraphWidgetFloatingTooltip
|
||||
reference={reference}
|
||||
boundary={boundary}
|
||||
items={tooltipData.items}
|
||||
indexLabel={tooltipData.indexLabel}
|
||||
boundary={containerElement}
|
||||
tooltipOffsetFromAnchorInPx={LINE_CHART_TOOLTIP_OFFSET_PX}
|
||||
items={tooltipData?.items ?? []}
|
||||
indexLabel={tooltipData?.indexLabel}
|
||||
highlightedKey={tooltipState?.highlightedSeriesId}
|
||||
onGraphWidgetTooltipClick={handleTooltipClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
|
||||
+1
-1
@@ -269,7 +269,7 @@ export const GraphWidgetLineChart = ({
|
||||
/>
|
||||
</GraphWidgetChartContainer>
|
||||
<GraphLineChartTooltip
|
||||
containerId={id}
|
||||
containerRef={containerRef}
|
||||
enrichedSeries={enrichedSeries}
|
||||
formatOptions={formatOptions}
|
||||
onSliceClick={onSliceClick}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const LINE_CHART_TOOLTIP_OFFSET_PX = 4;
|
||||
+27
-24
@@ -1,4 +1,5 @@
|
||||
import { GraphWidgetFloatingTooltip } from '@/page-layout/widgets/graph/components/GraphWidgetFloatingTooltip';
|
||||
import { PIE_CHART_TOOLTIP_OFFSET_PX } from '@/page-layout/widgets/graph/graphWidgetPieChart/constants/PieChartTooltipOffsetPx';
|
||||
import { graphWidgetPieTooltipComponentState } from '@/page-layout/widgets/graph/graphWidgetPieChart/states/graphWidgetPieTooltipComponentState';
|
||||
import { type PieChartDataItem } from '@/page-layout/widgets/graph/graphWidgetPieChart/types/PieChartDataItem';
|
||||
import { type PieChartEnrichedData } from '@/page-layout/widgets/graph/graphWidgetPieChart/types/PieChartEnrichedData';
|
||||
@@ -6,10 +7,11 @@ import { getPieChartTooltipData } from '@/page-layout/widgets/graph/graphWidgetP
|
||||
import { createVirtualElementFromContainerOffset } from '@/page-layout/widgets/graph/utils/createVirtualElementFromContainerOffset';
|
||||
import { type GraphValueFormatOptions } from '@/page-layout/widgets/graph/utils/graphFormatters';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { type RefObject } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type GraphPieChartTooltipProps = {
|
||||
containerId: string;
|
||||
containerRef: RefObject<HTMLDivElement>;
|
||||
enrichedData: PieChartEnrichedData[];
|
||||
formatOptions: GraphValueFormatOptions;
|
||||
displayType?: string;
|
||||
@@ -17,7 +19,7 @@ type GraphPieChartTooltipProps = {
|
||||
};
|
||||
|
||||
export const GraphPieChartTooltip = ({
|
||||
containerId,
|
||||
containerRef,
|
||||
enrichedData,
|
||||
formatOptions,
|
||||
displayType,
|
||||
@@ -27,41 +29,42 @@ export const GraphPieChartTooltip = ({
|
||||
graphWidgetPieTooltipComponentState,
|
||||
);
|
||||
|
||||
if (!isDefined(tooltipState)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const containerElement = document.getElementById(containerId);
|
||||
const containerElement = containerRef.current;
|
||||
if (!isDefined(containerElement)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tooltipData = getPieChartTooltipData({
|
||||
datum: tooltipState.datum,
|
||||
enrichedData,
|
||||
formatOptions,
|
||||
displayType,
|
||||
});
|
||||
const tooltipData = !isDefined(tooltipState)
|
||||
? null
|
||||
: getPieChartTooltipData({
|
||||
datum: tooltipState.datum,
|
||||
enrichedData,
|
||||
formatOptions,
|
||||
displayType,
|
||||
});
|
||||
|
||||
const handleTooltipClick: (() => void) | undefined = isDefined(onSliceClick)
|
||||
? () => onSliceClick(tooltipState.datum.data)
|
||||
? () => {
|
||||
if (isDefined(tooltipState)) {
|
||||
onSliceClick(tooltipState.datum.data);
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(tooltipData)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const reference = createVirtualElementFromContainerOffset(
|
||||
containerElement,
|
||||
tooltipState.offsetLeft,
|
||||
tooltipState.offsetTop,
|
||||
);
|
||||
const reference = !isDefined(tooltipState)
|
||||
? null
|
||||
: createVirtualElementFromContainerOffset(
|
||||
containerElement,
|
||||
tooltipState.offsetLeft,
|
||||
tooltipState.offsetTop,
|
||||
);
|
||||
|
||||
return (
|
||||
<GraphWidgetFloatingTooltip
|
||||
reference={reference}
|
||||
boundary={containerElement}
|
||||
items={[tooltipData.tooltipItem]}
|
||||
tooltipOffsetFromAnchorInPx={PIE_CHART_TOOLTIP_OFFSET_PX}
|
||||
items={tooltipData?.tooltipItem ? [tooltipData.tooltipItem] : []}
|
||||
disablePointerEvents
|
||||
onGraphWidgetTooltipClick={handleTooltipClick}
|
||||
/>
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ export const GraphWidgetPieChart = ({
|
||||
</StyledPieChartWrapper>
|
||||
</GraphWidgetChartContainer>
|
||||
<GraphPieChartTooltip
|
||||
containerId={id}
|
||||
containerRef={containerRef}
|
||||
enrichedData={enrichedData}
|
||||
formatOptions={formatOptions}
|
||||
displayType={displayType}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const PIE_CHART_TOOLTIP_OFFSET_PX = 14;
|
||||
+16
-14
@@ -1,5 +1,4 @@
|
||||
import { GRAPH_TOOLTIP_BOUNDARY_PADDING_PX } from '@/page-layout/widgets/graph/constants/GraphTooltipBoundaryPaddingPx';
|
||||
import { GRAPH_TOOLTIP_OFFSET_PX } from '@/page-layout/widgets/graph/constants/GraphTooltipOffsetPx';
|
||||
import { createVirtualElementFromSVGElement } from '@/page-layout/widgets/graph/utils/createVirtualElementFromSVGElement';
|
||||
import {
|
||||
autoUpdate,
|
||||
@@ -13,36 +12,39 @@ import { useMemo } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useGraphWidgetTooltipFloating = (
|
||||
element: Element | VirtualElement | null,
|
||||
boundaryElement?: Element | null,
|
||||
referenceElement: Element | VirtualElement | null,
|
||||
boundaryElement: Element | null,
|
||||
tooltipOffsetFromAnchorInPx: number,
|
||||
) => {
|
||||
const virtualElement = useMemo(() => {
|
||||
if (!isDefined(element)) return null;
|
||||
if (element instanceof Element) {
|
||||
return createVirtualElementFromSVGElement(element);
|
||||
if (!isDefined(referenceElement)) return null;
|
||||
if (referenceElement instanceof Element) {
|
||||
return createVirtualElementFromSVGElement(referenceElement);
|
||||
}
|
||||
return element;
|
||||
}, [element]);
|
||||
return referenceElement;
|
||||
}, [referenceElement]);
|
||||
|
||||
return useFloating({
|
||||
const rootBoundary = document.querySelector('#root') ?? undefined;
|
||||
|
||||
const { refs, x, y, isPositioned } = useFloating({
|
||||
elements: {
|
||||
reference: virtualElement,
|
||||
},
|
||||
placement: 'left',
|
||||
strategy: 'fixed',
|
||||
middleware: [
|
||||
offset(GRAPH_TOOLTIP_OFFSET_PX),
|
||||
offset(tooltipOffsetFromAnchorInPx),
|
||||
flip({
|
||||
fallbackPlacements: ['right', 'top', 'bottom'],
|
||||
boundary:
|
||||
boundaryElement ?? document.querySelector('#root') ?? undefined,
|
||||
boundary: boundaryElement ?? rootBoundary,
|
||||
}),
|
||||
shift({
|
||||
boundary:
|
||||
boundaryElement ?? document.querySelector('#root') ?? undefined,
|
||||
boundary: boundaryElement ?? rootBoundary,
|
||||
padding: GRAPH_TOOLTIP_BOUNDARY_PADDING_PX,
|
||||
}),
|
||||
],
|
||||
whileElementsMounted: autoUpdate,
|
||||
});
|
||||
|
||||
return { refs, x, y, isPositioned };
|
||||
};
|
||||
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
import { type VirtualElement } from '@floating-ui/react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getTooltipReferenceFromBarChartElementAnchor = (
|
||||
anchorElement: Element,
|
||||
containerId: string,
|
||||
): {
|
||||
reference: Element | VirtualElement;
|
||||
boundary: Element;
|
||||
} => {
|
||||
const containerElement = document.getElementById(containerId);
|
||||
|
||||
if (!isDefined(containerElement)) {
|
||||
throw new Error(`Bar chart container not found: ${containerId}`);
|
||||
}
|
||||
|
||||
return { reference: anchorElement, boundary: containerElement };
|
||||
};
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
import { createVirtualElementFromContainerOffset } from '@/page-layout/widgets/graph/utils/createVirtualElementFromContainerOffset';
|
||||
import { type VirtualElement } from '@floating-ui/react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getTooltipReferenceFromLineChartPointAnchor = (
|
||||
containerId: string,
|
||||
offsetLeft: number,
|
||||
offsetTop: number,
|
||||
): {
|
||||
reference: VirtualElement;
|
||||
boundary: Element;
|
||||
} => {
|
||||
const containerElement = document.getElementById(containerId);
|
||||
|
||||
if (!isDefined(containerElement)) {
|
||||
throw new Error(`Chart container not found: ${containerId}`);
|
||||
}
|
||||
|
||||
return {
|
||||
reference: createVirtualElementFromContainerOffset(
|
||||
containerElement,
|
||||
offsetLeft,
|
||||
offsetTop,
|
||||
),
|
||||
boundary: containerElement,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user