Skip to content

Commit

Permalink
Add missing data pill to LineChart
Browse files Browse the repository at this point in the history
  • Loading branch information
envex committed Apr 10, 2024
1 parent 70c8811 commit e63f213
Show file tree
Hide file tree
Showing 19 changed files with 437 additions and 23 deletions.
4 changes: 4 additions & 0 deletions packages/polaris-viz-core/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,10 @@ export const LIGHT_THEME: Theme = {
missingData: {
lineColor: variables.colorGray40,
},
badge: {
backgroundColor: variables.colorGray60,
textColor: variables.colorGray150,
},
};

export const PRINT_THEME = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {useEffect, useLayoutEffect, useState} from 'react';
import {useLayoutEffect, useState} from 'react';
import {createPortal} from 'react-dom';
import {changeColorOpacity, clamp, useTheme} from '@shopify/polaris-viz-core';

import {useHideTooltipWhenMounted} from '../../../../hooks/useHideTooltipWhenMounted';
import {TOOLTIP_BG_OPACITY} from '../../../../constants';
import {useBrowserCheck} from '../../../../hooks/useBrowserCheck';
import type {Annotation} from '../../../../types';
Expand Down Expand Up @@ -43,19 +44,7 @@ export function AnnotationContent({
setBounds(ref?.getBoundingClientRect());
}, [ref]);

useEffect(() => {
const tooltip = document.querySelector<HTMLElement>('[data-tooltip]');

if (tooltip) {
tooltip.style.display = 'none';
}

return () => {
if (tooltip) {
tooltip.style.display = 'block';
}
};
}, []);
useHideTooltipWhenMounted();

if (annotation.content == null) {
return null;
Expand Down
14 changes: 10 additions & 4 deletions packages/polaris-viz/src/components/Labels/SingleTextLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ interface SingleTextLineProps {
y: number;
ariaHidden?: boolean;
dominantBaseline?: 'middle' | 'hanging';
fontWeight?: number;
id?: string;
textAnchor?: 'left' | 'center' | 'right';
}

export function SingleTextLine({
ariaHidden = false,
color,
dominantBaseline = 'hanging',
fontWeight = 300,
id,
targetWidth,
text,
textAnchor = 'center',
Expand All @@ -39,14 +43,16 @@ export function SingleTextLine({
<Fragment>
<text
aria-hidden={ariaHidden}
textAnchor={textAnchor}
dominantBaseline={dominantBaseline}
height={LINE_HEIGHT}
width={targetWidth}
fill={color}
fontSize={FONT_SIZE}
y={y}
fontWeight={fontWeight}
height={LINE_HEIGHT}
id={id}
textAnchor={textAnchor}
width={targetWidth}
x={x}
y={y}
>
{truncated}
</text>
Expand Down
24 changes: 23 additions & 1 deletion packages/polaris-viz/src/components/LineChart/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@ import {useTheme} from '../../hooks';
import type {
Annotation,
LineChartSlotProps,
MissingData,
RenderLegendContent,
TooltipOptions,
} from '../../types';

import {Chart} from './Chart';
import {MissingDataArea} from './components';

export type LineChartProps = {
annotations?: Annotation[];
errorText?: string;
emptyStateText?: string;
missingData?: MissingData;
renderLegendContent?: RenderLegendContent;
renderHiddenLegendLabel?: (count: number) => string;
seriesNameFormatter?: LabelFormatter;
Expand All @@ -62,6 +65,7 @@ export function LineChart(props: LineChartProps) {
errorText,
id,
isAnimated,
missingData,
onError,
renderLegendContent,
renderHiddenLegendLabel,
Expand Down Expand Up @@ -127,7 +131,25 @@ export function LineChart(props: LineChartProps) {
theme={theme}
xAxisOptions={xAxisOptionsWithDefaults}
yAxisOptions={yAxisOptionsWithDefaults}
slots={props.slots}
slots={
props.slots == null
? {
chart: (props) => {
if (missingData == null) {
return null;
}

return (
<MissingDataArea
{...props}
data={data}
missingData={missingData}
/>
);
},
}
: props.slots
}
/>
)}
</ChartContainer>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {Fragment, memo, useRef} from 'react';
import type {LineChartSlotProps} from 'types';
import type {DataSeries} from '@shopify/polaris-viz-core';
import {uniqueId, useTheme} from '@shopify/polaris-viz-core';

import {useIndexForLabels} from '../../../../hooks/useIndexForLabels';

import {Pill} from './components/';

export interface Props extends LineChartSlotProps {
data: DataSeries[];
missingData: any;
}

function MissingDataAreaRaw({
data,
drawableHeight,
missingData,
xScale,
}: Props) {
const selectedTheme = useTheme();
const patternID = useRef(uniqueId('missingDataPattern'));
const indexForLabels = useIndexForLabels(data);

let fromIndex = -1;
let toIndex = -1;

data[indexForLabels].data.forEach(({key}, index) => {
if (key === missingData.to) {
toIndex = index;
}

if (key === missingData.from) {
fromIndex = index;
}
});

const width = xScale(toIndex - fromIndex);

const xPosition = xScale(fromIndex);

return (
<Fragment>
<defs>
<pattern
id={patternID.current}
patternUnits="userSpaceOnUse"
width="12"
height="12"
patternTransform="rotate(135)"
>
<line
x1="0"
y="0"
x2="0"
y2="12"
stroke={selectedTheme.missingData.lineColor}
strokeWidth="12"
opacity="0.2"
/>
</pattern>
</defs>

<line
x1={xPosition}
x2={xPosition}
y1="0"
y2={drawableHeight}
stroke={selectedTheme.missingData.lineColor}
strokeWidth="1"
strokeDasharray="4 4"
/>

<line
x1={xPosition + width}
x2={xPosition + width}
y1="0"
y2={drawableHeight}
stroke={selectedTheme.missingData.lineColor}
strokeWidth="1"
strokeDasharray="4 4"
/>

<rect
x={xPosition}
y={0}
height={drawableHeight}
width={width}
fill={`url(#${patternID.current})`}
/>

<Pill
containerWidth={width}
description={missingData.description}
label={missingData.label}
x={xPosition}
/>
</Fragment>
);
}

export const MissingDataArea = memo(MissingDataAreaRaw);
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.Wrapper {
pointerevents: 'none';
overflow: 'visible';
position: fixed;
top: 0;
left: 0;
}

.Container {
padding: 8px;
backdrop-filter: blur(5px);
border-radius: 5px;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2), 0 2px 10px rgba(0, 0, 0, 0.1);
max-width: 200px;
pointerevents: auto;
width: fit-content;
line-height: 16px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {createPortal} from 'react-dom';
import {FONT_SIZE, useChartContext} from '@shopify/polaris-viz-core';

import {useHideTooltipWhenMounted} from '../../../../../../hooks/useHideTooltipWhenMounted';
import {getChartId} from '../../../../../../utilities/getChartId';

import styles from './DescriptionPopover.scss';

export interface DescriptionPopoverProps {
description: string;
label: string;
onMouseLeave: () => void;
x: number;
y: number;
yOffset: number;
}

export function DescriptionPopover({
description,
label,
onMouseLeave,
x,
y,
yOffset,
}: DescriptionPopoverProps) {
const {id} = useChartContext();
const chartId = getChartId(id);

useHideTooltipWhenMounted();

return createPortal(
<div
className={styles.Wrapper}
style={{
top: y,
left: x,
paddingTop: yOffset,
}}
onMouseLeave={onMouseLeave}
data-block-tooltip-events
>
<div
aria-label={label}
className={styles.Container}
role="dialog"
style={{fontSize: FONT_SIZE}}
>
{description}
</div>
</div>,
document.getElementById(chartId) ?? document.body,
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {DescriptionPopover} from './DescriptionPopover';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import '../../../../../../styles/common';

.Group {
@include no-outline;
}
Loading

0 comments on commit e63f213

Please sign in to comment.