Skip to content

Commit

Permalink
fix(D3 plugin): fix tooltip position (#240)
Browse files Browse the repository at this point in the history
* change story container

* fix(D3 plugin): tooltip position

* fix position
  • Loading branch information
kuzmadom authored Aug 24, 2023
1 parent c0559cd commit d07764b
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/plugins/d3/__stories__/bar-x/category.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const Template: Story = () => {
const chartkitRef = React.useRef<ChartKitRef>();
const data: ChartKitWidgetData = {
legend: {enabled: true},
tooltip: {enabled: false},
tooltip: {enabled: true},
yAxis: [
{
type: 'linear',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ const Template: Story = () => {
}

return (
<div style={{height: '80vh', width: '100%'}}>
<div style={{height: '400px', width: '100%'}}>
<ChartKit ref={chartkitRef} type="d3" data={data} />
</div>
);
Expand Down
16 changes: 12 additions & 4 deletions src/plugins/d3/renderer/D3Widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import type {ChartKitProps, ChartKitWidgetRef} from '../../../types';
import {Chart} from './components';

type ChartDimensions = {
top: number;
left: number;
width: number;
height: number;
};
Expand All @@ -20,8 +22,8 @@ const D3Widget = React.forwardRef<ChartKitWidgetRef | undefined, ChartKitProps<'

const handleResize = React.useCallback(() => {
if (ref.current) {
const {width, height} = ref.current.getBoundingClientRect();
setDimensions({width, height});
const {top, left, width, height} = ref.current.getBoundingClientRect();
setDimensions({top, left, width, height});
}
}, []);

Expand Down Expand Up @@ -57,9 +59,15 @@ const D3Widget = React.forwardRef<ChartKitWidgetRef | undefined, ChartKitProps<'
}, [handleResize]);

return (
<div ref={ref} style={{width: '100%', height: '100%'}}>
<div ref={ref} style={{width: '100%', height: '100%', position: 'relative'}}>
{dimensions?.width && dimensions?.height && (
<Chart width={dimensions.width} height={dimensions.height} data={props.data} />
<Chart
top={dimensions?.top || 0}
left={dimensions.left || 0}
width={dimensions.width}
height={dimensions.height}
data={props.data}
/>
)}
</div>
);
Expand Down
8 changes: 7 additions & 1 deletion src/plugins/d3/renderer/components/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ import './styles.scss';
const b = block('d3');

type Props = {
top: number;
left: number;
width: number;
height: number;
data: ChartKitWidgetData;
};

export const Chart = ({width, height, data}: Props) => {
export const Chart = (props: Props) => {
const {top, left, width, height, data} = props;
// FIXME: add data validation
const {series} = data;
const svgRef = React.createRef<SVGSVGElement>();
const hasAxisRelatedSeries = series.data.some(isAxisRelatedSeries);
Expand Down Expand Up @@ -58,6 +62,8 @@ export const Chart = ({width, height, data}: Props) => {
tooltip,
});
const {shapes} = useShapes({
top,
left,
boundsWidth,
boundsHeight,
series: chartSeries,
Expand Down
21 changes: 20 additions & 1 deletion src/plugins/d3/renderer/components/Tooltip/DefaultContent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React from 'react';

import type {ScatterSeriesData, TooltipHoveredData} from '../../../../../types/widget-data';
import type {
ScatterSeriesData,
BarXSeriesData,
TooltipHoveredData,
} from '../../../../../types/widget-data';

import type {PreparedAxis} from '../../hooks';

Expand Down Expand Up @@ -31,6 +35,21 @@ export const DefaultContent = ({hovered, xAxis, yAxis}: Props) => {
</div>
);
}
case 'bar-x': {
const barXData = data as BarXSeriesData;
const xRow = xAxis.type === 'category' ? barXData.category : barXData.x;
const yRow = yAxis.type === 'category' ? barXData.category : barXData.y;
return (
<div>
<div>{xRow}</div>
<div>
<span>
<b>{series.name}</b>: {yRow}
</span>
</div>
</div>
);
}
default: {
return null;
}
Expand Down
22 changes: 19 additions & 3 deletions src/plugins/d3/renderer/hooks/useShapes/bar-x.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {ChartScale} from '../useAxisScales';
import {OnSeriesMouseLeave, OnSeriesMouseMove} from '../useTooltip/types';
import {BarXSeries, BarXSeriesData} from '../../../../../types/widget-data';
import {block} from '../../../../../utils/cn';
import {ScaleBand, ScaleLinear, ScaleTime} from 'd3';
import {pointer, ScaleBand, ScaleLinear, ScaleTime} from 'd3';

const DEFAULT_BAR_RECT_WIDTH = 50;
const DEFAULT_LINEAR_BAR_RECT_WIDTH = 20;
Expand All @@ -13,13 +13,16 @@ const MIN_RECT_GAP = 1;
const b = block('d3-bar');

type Args = {
top: number;
left: number;
series: BarXSeries[];
xAxis: ChartOptions['xAxis'];
xScale: ChartScale;
yAxis: ChartOptions['yAxis'];
yScale: ChartScale;
onSeriesMouseMove?: OnSeriesMouseMove;
onSeriesMouseLeave?: OnSeriesMouseLeave;
svgContainer: SVGSVGElement | null;
};

const getRectProperties = (args: {
Expand Down Expand Up @@ -79,7 +82,18 @@ function minDiff(arr: number[]) {
}

export function prepareBarXSeries(args: Args) {
const {series, xAxis, xScale, yAxis, yScale, onSeriesMouseMove, onSeriesMouseLeave} = args;
const {
top,
left,
series,
xAxis,
xScale,
yAxis,
yScale,
onSeriesMouseMove,
onSeriesMouseLeave,
svgContainer,
} = args;
const seriesData = series.map(({data}) => data).flat(2);
const minPointDistance = minDiff(seriesData.map((item) => Number(item.x)));

Expand All @@ -102,12 +116,14 @@ export function prepareBarXSeries(args: Args) {
className={b('rect')}
fill={item.color}
{...rectProps}
onMouseMove={function () {
onMouseMove={function (e) {
const [x, y] = pointer(e, svgContainer);
onSeriesMouseMove?.({
hovered: {
data: point,
series: item,
},
pointerPosition: [x - left, y - top],
});
}}
onMouseLeave={onSeriesMouseLeave}
Expand Down
10 changes: 10 additions & 0 deletions src/plugins/d3/renderer/hooks/useShapes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {PieSeriesComponent} from './pie';
import './styles.scss';

type Args = {
top: number;
left: number;
boundsWidth: number;
boundsHeight: number;
series: ChartSeries[];
Expand All @@ -29,6 +31,8 @@ type Args = {

export const useShapes = (args: Args) => {
const {
top,
left,
boundsWidth,
boundsHeight,
series,
Expand All @@ -40,6 +44,7 @@ export const useShapes = (args: Args) => {
onSeriesMouseMove,
onSeriesMouseLeave,
} = args;

const shapes = React.useMemo(() => {
const visibleSeries = getOnlyVisibleSeries(series);
const groupedSeries = group(visibleSeries, (item) => item.type);
Expand All @@ -51,13 +56,16 @@ export const useShapes = (args: Args) => {
if (xScale && yScale) {
acc.push(
...prepareBarXSeries({
top,
left,
series: chartSeries as BarXSeries[],
xAxis,
xScale,
yAxis,
yScale,
onSeriesMouseMove,
onSeriesMouseLeave,
svgContainer,
}),
);
}
Expand All @@ -67,6 +75,8 @@ export const useShapes = (args: Args) => {
if (xScale && yScale) {
acc.push(
...prepareScatterSeries({
top,
left,
series: chartSeries as ScatterSeries[],
xAxis,
xScale,
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/d3/renderer/hooks/useShapes/scatter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {ScatterSeries, ScatterSeriesData} from '../../../../../types/widget-data
import {block} from '../../../../../utils/cn';

type PrepareScatterSeriesArgs = {
top: number;
left: number;
series: ScatterSeries[];
xAxis: ChartOptions['xAxis'];
xScale: ChartScale;
Expand Down Expand Up @@ -62,6 +64,8 @@ const getPointProperties = (args: {

export function prepareScatterSeries(args: PrepareScatterSeriesArgs) {
const {
top,
left,
series,
xAxis,
xScale,
Expand Down Expand Up @@ -96,12 +100,13 @@ export function prepareScatterSeries(args: PrepareScatterSeriesArgs) {
fill={s.color}
{...pointProps}
onMouseMove={function (e) {
const [x, y] = pointer(e, svgContainer);
onSeriesMouseMove?.({
hovered: {
data: point,
series: s,
},
pointerPosition: pointer(e, svgContainer),
pointerPosition: [x - left, y - top],
});
}}
onMouseLeave={onSeriesMouseLeave}
Expand Down

0 comments on commit d07764b

Please sign in to comment.