Skip to content

Commit

Permalink
Merge pull request #11 from the-deep/feature/configurable-barchart
Browse files Browse the repository at this point in the history
Add more configuration options to the bar charts
  • Loading branch information
AdityaKhatri authored Mar 6, 2024
2 parents 286bb45 + 7d78d53 commit 34dcb52
Show file tree
Hide file tree
Showing 15 changed files with 311 additions and 170 deletions.
59 changes: 59 additions & 0 deletions lib/src/components/BarChartContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* eslint-disable react/require-default-props */
import React from 'react';
import { _cs, isDefined } from '@togglecorp/fujs';

import TextNode, { type Props as DefaultTextNodeProps } from '../TextNode';

import styles from './styles.module.css';

type TextNodeProps = Omit<DefaultTextNodeProps, 'as'>;

export interface Props {
className?: string;
title?: TextNodeProps;
subTitle?: TextNodeProps;
children: React.ReactNode;
chartHeight?: number;
svgClassName?: string;
containerRef?: React.RefObject<HTMLDivElement>;
}

function BarChartContainer(props: Props) {
const {
className,
title,
subTitle,
children,
chartHeight,
svgClassName,
containerRef,
} = props;

return (
<div className={_cs(styles.barChartContainer, className)}>
{isDefined(title) && (
<TextNode
as="h2"
// eslint-disable-next-line react/jsx-props-no-spreading
{...title}
/>
)}
{isDefined(subTitle) && (
<TextNode
// eslint-disable-next-line react/jsx-props-no-spreading
{...subTitle}
/>
)}
<div ref={containerRef}>
<svg
className={_cs(styles.svg, svgClassName)}
style={isDefined(chartHeight) ? { height: `${chartHeight}px}` } : undefined}
>
{children}
</svg>
</div>
</div>
);
}

export default BarChartContainer;
6 changes: 6 additions & 0 deletions lib/src/components/BarChartContainer/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.bar-chart-container {
.svg {
width: 100%;
height: 20rem;
}
}
41 changes: 20 additions & 21 deletions lib/src/components/CategoricalBarChart/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React, { useMemo, useRef } from 'react';
import { _cs, listToMap } from '@togglecorp/fujs';
import { listToMap } from '@togglecorp/fujs';

import useCategoricalChartData, { type Options } from '../../hooks/useCategoricalChartData';
import { extractProps, type CombinedProps } from '../../utils/chart';
import BarList from '../BarList';
import ChartAxes from '../ChartAxes';

import styles from './styles.module.css';
import BarChartContainer from '../BarChartContainer';

export type Props<DATUM, KEY extends string | number> = CombinedProps<DATUM, KEY, Omit<Options<DATUM, KEY>, 'containerRef'>>

function CategoricalBarChart<DATUM, KEY extends string | number>(props: Props<DATUM, KEY>) {
const {
containerProps,
commonProps: {
className,
data,
yValueKeys,
colorSelector,
Expand Down Expand Up @@ -47,25 +47,24 @@ function CategoricalBarChart<DATUM, KEY extends string | number>(props: Props<DA
const xTickWidth = chartData.dataAreaSize.width / chartData.numXAxisTicks;

return (
<div
className={_cs(styles.barChart, className)}
ref={chartContainerRef}
<BarChartContainer
containerRef={chartContainerRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...containerProps}
>
<svg className={styles.svg}>
<ChartAxes
chartData={chartData}
// eslint-disable-next-line react/jsx-props-no-spreading
{...chartAxesProps}
/>
<BarList
chartData={chartData}
xTickWidth={xTickWidth}
colorMap={colorMap}
// eslint-disable-next-line react/jsx-props-no-spreading
{...barGroupProps}
/>
</svg>
</div>
<ChartAxes
chartData={chartData}
// eslint-disable-next-line react/jsx-props-no-spreading
{...chartAxesProps}
/>
<BarList
chartData={chartData}
xTickWidth={xTickWidth}
colorMap={colorMap}
// eslint-disable-next-line react/jsx-props-no-spreading
{...barGroupProps}
/>
</BarChartContainer>
);
}

Expand Down
9 changes: 0 additions & 9 deletions lib/src/components/CategoricalBarChart/styles.module.css

This file was deleted.

105 changes: 72 additions & 33 deletions lib/src/components/ChartAxes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
/* eslint-disable react/require-default-props */
import React, {
Fragment,
useCallback,
useRef,
} from 'react';
import { isDefined } from '@togglecorp/fujs';
import { _cs, isDefined } from '@togglecorp/fujs';

import TextNode, { Props as DefaultTextNodeProps } from '../TextNode';

import {
type Rect,
Expand All @@ -12,6 +15,8 @@ import {

import styles from './styles.module.css';

type AxisLabelProps = Omit<DefaultTextNodeProps, 'as'>;

type Key = string | number;

interface TickX {
Expand All @@ -36,16 +41,17 @@ export interface Props {
xAxisHeight: number;
yAxisWidth: number;
}
// eslint-disable-next-line react/require-default-props
tooltipSelector?: (key: Key, i: number) => React.ReactNode;
// eslint-disable-next-line react/require-default-props
onHover?: (key: Key | undefined, i: number | undefined) => void;
// eslint-disable-next-line react/require-default-props
onClick?: (key: Key, i: number) => void;
// eslint-disable-next-line react/require-default-props
yAxisLabel?: React.ReactNode;
// eslint-disable-next-line react/require-default-props
xAxisLabel?: React.ReactNode;
yAxisLabel?: AxisLabelProps & { width?: number };
xAxisLabel?: AxisLabelProps & { height?: number };

xAxisGridLineStyle?: React.CSSProperties;
yAxisGridLineStyle?: React.CSSProperties;

xAxisLineStyle?: React.CSSProperties;
yAxisLineStyle?: React.CSSProperties;
}

function ChartAxes(props: Props) {
Expand All @@ -65,6 +71,10 @@ function ChartAxes(props: Props) {
onClick,
yAxisLabel,
xAxisLabel,
xAxisGridLineStyle,
yAxisGridLineStyle,
xAxisLineStyle,
yAxisLineStyle,
} = props;

const hoverOutTimeoutRef = useRef<number | undefined>();
Expand Down Expand Up @@ -120,9 +130,8 @@ function ChartAxes(props: Props) {

const xAxisDiff = dataAreaSize.width / xAxisTicks.length;

// TODO: make it dynamic maybe?
const yAxisLabelWidth = 20;
const xAxisLabelHeight = 20;
const yAxisLabelWidth = yAxisLabel?.width ?? 20;
const xAxisLabelHeight = xAxisLabel?.height ?? 20;

const yAxisAreaX1 = chartMargin.left;
const yAxisAreaX2 = chartMargin.left + yAxisWidth;
Expand All @@ -146,21 +155,36 @@ function ChartAxes(props: Props) {
className={styles.yAxisLabelContainer}
style={{ transformOrigin: `0 ${chartSize.height - yAxisLabelWidth}px` }}
>
<div className={styles.yAxisLabel}>
{yAxisLabel}
</div>
<TextNode
// eslint-disable-next-line react/jsx-props-no-spreading
{...yAxisLabel}
className={_cs(styles.yAxisLabel, yAxisLabel.className)}
/>
</foreignObject>
)}
<g>
{yAxisTicks.map((pointData) => (
{yAxisTicks.map((pointData, i) => (
<Fragment key={pointData.y}>
<line
className={styles.xAxisGridLine}
x1={yAxisAreaX2}
y1={pointData.y}
x2={chartAreaX2}
y2={pointData.y}
/>
{i === 0 && xAxisLineStyle && (
<line
className={styles.xAxisGridLine}
style={xAxisLineStyle}
x1={yAxisAreaX2}
y1={pointData.y}
x2={chartAreaX2}
y2={pointData.y}
/>
)}
{i !== 0 && xAxisGridLineStyle && (
<line
className={styles.xAxisGridLine}
style={xAxisGridLineStyle}
x1={yAxisAreaX2}
y1={pointData.y}
x2={chartAreaX2}
y2={pointData.y}
/>
)}
<foreignObject
x={yAxisAreaX1}
y={pointData.y - yAxisTickHeight / 2}
Expand Down Expand Up @@ -195,13 +219,26 @@ function ChartAxes(props: Props) {

return (
<Fragment key={tick.x}>
<line
className={styles.yAxisGridLine}
x1={x}
y1={chartAreaY1}
x2={x}
y2={xAxisAreaY1}
/>
{i === 0 && yAxisLineStyle && (
<line
className={styles.yAxisGridLine}
style={yAxisLineStyle}
x1={x}
y1={chartAreaY1}
x2={x}
y2={xAxisAreaY1}
/>
)}
{i !== 0 && yAxisGridLineStyle && (
<line
className={styles.yAxisGridLine}
style={yAxisGridLineStyle}
x1={x}
y1={chartAreaY1}
x2={x}
y2={xAxisAreaY1}
/>
)}
<foreignObject
className={styles.xAxisTick}
x={xTickLabelX1}
Expand Down Expand Up @@ -244,14 +281,16 @@ function ChartAxes(props: Props) {
{isDefined(xAxisLabel) && (
<foreignObject
x={dataAreaOffset.left}
y={chartSize.height - yAxisLabelWidth}
y={chartSize.height - xAxisLabelHeight - dataAreaOffset.top}
width={dataAreaSize.width}
height={xAxisLabelHeight}
className={styles.xAxisLabelContainer}
>
<div className={styles.xAxisLabel}>
{xAxisLabel}
</div>
<TextNode
// eslint-disable-next-line react/jsx-props-no-spreading
{...xAxisLabel}
className={_cs(styles.xAxisLabel, xAxisLabel.className)}
/>
</foreignObject>
)}
</g>
Expand Down
3 changes: 3 additions & 0 deletions lib/src/components/ChartAxes/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@

.x-axis-grid-line,
.y-axis-grid-line {
stroke-width: 1pt;
/*
stroke: var(--drm-color-gray);
stroke-dasharray: 4 4;
stroke-opacity: 0.5;
*/

&.hovered {
stroke-opacity: 1;
Expand Down
42 changes: 20 additions & 22 deletions lib/src/components/NumericBarChart/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import React, { useMemo, useRef } from 'react';
import { _cs, listToMap } from '@togglecorp/fujs';
import { listToMap } from '@togglecorp/fujs';

import useNumericChartData, { type Options } from '../../hooks/useNumericChartData';
import { extractProps, type CombinedProps } from '../../utils/chart';
import BarChartContainer from '../BarChartContainer';
import BarList from '../BarList';
import ChartAxes from '../ChartAxes';

import styles from './styles.module.css';

export type Props<DATUM, KEY extends string | number> = CombinedProps<DATUM, KEY, Omit<Options<DATUM, KEY>, 'containerRef'>>

function NumericBarChart<DATUM, KEY extends string | number>(props: Props<DATUM, KEY>) {
const {
containerProps,
commonProps: {
className,
data,
yValueKeys,
colorSelector,
Expand Down Expand Up @@ -47,25 +46,24 @@ function NumericBarChart<DATUM, KEY extends string | number>(props: Props<DATUM,
const xTickWidth = chartData.dataAreaSize.width / chartData.numXAxisTicks;

return (
<div
className={_cs(styles.barChart, className)}
ref={chartContainerRef}
<BarChartContainer
containerRef={chartContainerRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...containerProps}
>
<svg className={styles.svg}>
<ChartAxes
chartData={chartData}
// eslint-disable-next-line react/jsx-props-no-spreading
{...chartAxesProps}
/>
<BarList
chartData={chartData}
xTickWidth={xTickWidth}
colorMap={colorMap}
// eslint-disable-next-line react/jsx-props-no-spreading
{...barGroupProps}
/>
</svg>
</div>
<ChartAxes
chartData={chartData}
// eslint-disable-next-line react/jsx-props-no-spreading
{...chartAxesProps}
/>
<BarList
chartData={chartData}
xTickWidth={xTickWidth}
colorMap={colorMap}
// eslint-disable-next-line react/jsx-props-no-spreading
{...barGroupProps}
/>
</BarChartContainer>
);
}

Expand Down
Loading

0 comments on commit 34dcb52

Please sign in to comment.