Skip to content

Commit

Permalink
feat(D3 plugin): add basic bar chart (#225)
Browse files Browse the repository at this point in the history
* fix(D3 plugin): bar chart

* fix bar

* add min options to axis

* fix getPreparedLegend

* fix stories
  • Loading branch information
kuzmadom authored Aug 16, 2023
1 parent 4682fe2 commit 5806761
Show file tree
Hide file tree
Showing 18 changed files with 645 additions and 114 deletions.
89 changes: 89 additions & 0 deletions src/plugins/d3/__stories__/bar/category.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React from 'react';
import {Meta, Story} from '@storybook/react';
import {object, withKnobs} from '@storybook/addon-knobs';
import {Button} from '@gravity-ui/uikit';
import {settings} from '../../../../libs';
import {ChartKit} from '../../../../components/ChartKit';
import type {ChartKitRef} from '../../../../types';
import type {ChartKitWidgetData} from '../../../../types/widget-data';
import {D3Plugin} from '../..';

const Template: Story = () => {
const [shown, setShown] = React.useState(false);
const chartkitRef = React.useRef<ChartKitRef>();
const data: ChartKitWidgetData = {
legend: {enabled: true},
tooltip: {enabled: false},
yAxis: [
{
type: 'linear',
labels: {enabled: true},
min: 0,
},
],
series: {
data: [
{
type: 'bar',
visible: true,
data: [
{
category: 'A',
x: 10,
y: 100,
},
{
category: 'B',
x: 12,
y: 80,
},
],
name: 'AB',
},
{
type: 'bar',
visible: true,
data: [
{
category: 'C',
x: 95.5,
y: 120,
},
],
name: 'C',
},
],
},
title: {text: 'Category axis'},
xAxis: {
type: 'category',
categories: ['A', 'B', 'C'],
labels: {enabled: true},
},
};

if (!shown) {
settings.set({plugins: [D3Plugin]});
return <Button onClick={() => setShown(true)}>Show chart</Button>;
}

return (
<div
style={{
height: '80vh',
width: '100%',
}}
>
<ChartKit ref={chartkitRef} type="d3" data={object<ChartKitWidgetData>('data', data)} />
</div>
);
};

export const CategoryXAxis = Template.bind({});

const meta: Meta = {
title: 'Plugins/D3/Bar',
decorators: [withKnobs],
};

export default meta;
85 changes: 85 additions & 0 deletions src/plugins/d3/__stories__/bar/datetime.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import {Meta, Story} from '@storybook/react';
import {object, withKnobs} from '@storybook/addon-knobs';
import {Button} from '@gravity-ui/uikit';
import {settings} from '../../../../libs';
import {ChartKit} from '../../../../components/ChartKit';
import type {ChartKitRef} from '../../../../types';
import type {ChartKitWidgetData} from '../../../../types/widget-data';
import {D3Plugin} from '../..';

const Template: Story = () => {
const [shown, setShown] = React.useState(false);
const chartkitRef = React.useRef<ChartKitRef>();
const data: ChartKitWidgetData = {
title: {text: 'DateTime axis'},
xAxis: {
type: 'datetime',
labels: {enabled: true},
},
legend: {enabled: true},
tooltip: {enabled: false},
yAxis: [
{
type: 'linear',
labels: {enabled: true},
min: 0,
},
],
series: {
data: [
{
type: 'bar',
visible: true,
data: [
{
x: Number(new Date(2022, 10, 10)),
y: 100,
},
{
x: Number(new Date(2023, 2, 5)),
y: 80,
},
],
name: 'AB',
},
{
type: 'bar',
visible: true,
data: [
{
x: Number(new Date(2022, 11, 25)),
y: 120,
},
],
name: 'C',
},
],
},
};

if (!shown) {
settings.set({plugins: [D3Plugin]});
return <Button onClick={() => setShown(true)}>Show chart</Button>;
}

return (
<div
style={{
height: '80vh',
width: '100%',
}}
>
<ChartKit ref={chartkitRef} type="d3" data={object<ChartKitWidgetData>('data', data)} />
</div>
);
};

export const DatetimeXAxis = Template.bind({});

const meta: Meta = {
title: 'Plugins/D3/Bar',
decorators: [withKnobs],
};

export default meta;
88 changes: 88 additions & 0 deletions src/plugins/d3/__stories__/bar/linear.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react';
import {Meta, Story} from '@storybook/react';
import {withKnobs, object} from '@storybook/addon-knobs';
import {Button} from '@gravity-ui/uikit';
import {settings} from '../../../../libs';
import {ChartKit} from '../../../../components/ChartKit';
import type {ChartKitRef} from '../../../../types';
import type {ChartKitWidgetData} from '../../../../types/widget-data';
import {D3Plugin} from '../..';

const Template: Story = () => {
const [shown, setShown] = React.useState(false);
const chartkitRef = React.useRef<ChartKitRef>();
const data: ChartKitWidgetData = {
series: {
data: [
{
type: 'bar',
visible: true,
data: [
{
category: 'A',
x: 10,
y: 100,
},
{
category: 'B',
x: 12,
y: 80,
},
],
name: 'AB',
},
{
type: 'bar',
visible: true,
data: [
{
category: 'C',
x: 95.5,
y: 120,
},
],
name: 'C',
},
],
},
title: {text: 'Linear axis'},
xAxis: {
type: 'linear',
labels: {enabled: true},
},
yAxis: [
{
type: 'linear',
labels: {enabled: true},
min: 0,
},
],
legend: {enabled: true},
tooltip: {enabled: false},
};

if (!shown) {
settings.set({plugins: [D3Plugin]});
return <Button onClick={() => setShown(true)}>Show chart</Button>;
}

return (
<div
style={{
height: '80vh',
width: '100%',
}}
>
<ChartKit ref={chartkitRef} type="d3" data={object<ChartKitWidgetData>('data', data)} />
</div>
);
};

export const LinearXAxis = Template.bind({});

const meta: Meta = {
title: 'Plugins/D3/Bar',
decorators: [withKnobs],
};

export default meta;
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import random from 'lodash/random';
import {Meta, Story} from '@storybook/react';
import {withKnobs, select, radios, text} from '@storybook/addon-knobs';
import {Button} from '@gravity-ui/uikit';
import {settings} from '../../../libs';
import {ChartKit} from '../../../components/ChartKit';
import type {ChartKitRef} from '../../../types';
import {settings} from '../../../../libs';
import {ChartKit} from '../../../../components/ChartKit';
import type {ChartKitRef} from '../../../../types';
import type {
ChartKitWidgetAxis,
ChartKitWidgetData,
ScatterSeries,
ScatterSeriesData,
} from '../../../types/widget-data';
import {D3Plugin} from '..';
import penguins from './penguins.json';
} from '../../../../types/widget-data';
import {D3Plugin} from '../..';
import penguins from '../penguins.json';

const shapeScatterSeriesData = (args: {data: Record<string, any>[]; groupBy: string; map: any}) => {
const {data, groupBy, map} = args;
Expand Down Expand Up @@ -89,7 +89,9 @@ const shapeScatterChartData = (
}

return {
series,
series: {
data: series,
},
xAxis,
yAxis: [yAxis],
title: {
Expand Down Expand Up @@ -154,7 +156,7 @@ const Template: Story = () => {
export const LinearAndCategories = Template.bind({});

const meta: Meta = {
title: 'Plugins/D3',
title: 'Plugins/D3/Scatter',
decorators: [withKnobs],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import random from 'lodash/random';
import {Meta, Story} from '@storybook/react';
import {dateTime} from '@gravity-ui/date-utils';
import {Button} from '@gravity-ui/uikit';
import {settings} from '../../../libs';
import {ChartKit} from '../../../components/ChartKit';
import type {ChartKitRef} from '../../../types';
import {settings} from '../../../../libs';
import {ChartKit} from '../../../../components/ChartKit';
import type {ChartKitRef} from '../../../../types';
import type {
ChartKitWidgetData,
ScatterSeries,
ScatterSeriesData,
} from '../../../types/widget-data';
import {D3Plugin} from '..';
} from '../../../../types/widget-data';
import {D3Plugin} from '../..';

const rowData: ScatterSeriesData<string>[] = [
{
Expand Down Expand Up @@ -66,7 +66,9 @@ const shapeData = (data: Record<string, any>[]): ChartKitWidgetData<string> => {
};

return {
series: [scatterSeries],
series: {
data: [scatterSeries],
},
xAxis: {
type: 'datetime',
timestamps: data.map((d) => d.x),
Expand Down Expand Up @@ -103,7 +105,7 @@ const Template: Story = () => {
export const Timestamp = Template.bind({});

const meta: Meta = {
title: 'Plugins/D3',
title: 'Plugins/D3/Scatter',
};

export default meta;
6 changes: 3 additions & 3 deletions src/plugins/d3/renderer/components/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const Chart = ({width, height, data}: Props) => {
// FIXME: add data validation
const {series} = data;
const svgRef = React.createRef<SVGSVGElement>();
const hasAxisRelatedSeries = series.some(isAxisRelatedSeries);
const hasAxisRelatedSeries = series.data.some(isAxisRelatedSeries);
const {chartHovered, handleMouseEnter, handleMouseLeave} = useChartEvents();
const {chart, legend, title, tooltip, xAxis, yAxis} = useChartOptions(data);
const {boundsWidth, boundsHeight, legendHeight} = useChartDimensions({
Expand All @@ -46,8 +46,8 @@ export const Chart = ({width, height, data}: Props) => {
xAxis,
yAxis,
});
const {activeLegendItems, handleLegendItemClick} = useLegend({series});
const {chartSeries} = useSeries({activeLegendItems, series});
const {activeLegendItems, handleLegendItemClick} = useLegend({series: series.data});
const {chartSeries} = useSeries({activeLegendItems, series: series.data});
const {xScale, yScale} = useScales({
boundsWidth,
boundsHeight,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/d3/renderer/hooks/useChartOptions/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const getPreparedChart = (args: {
const marginLeft =
get(chart, 'margin.left', AXIS_WIDTH) +
preparedY1Axis.labels.padding +
getAxisLabelMaxWidth({axis: preparedY1Axis, series}) +
getAxisLabelMaxWidth({axis: preparedY1Axis, series: series.data}) +
(preparedY1Axis.title.height || 0);

return {
Expand Down
8 changes: 5 additions & 3 deletions src/plugins/d3/renderer/hooks/useChartOptions/legend.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import get from 'lodash/get';

import type {ChartKitWidgetData} from '../../../../../types/widget-data';

import type {PreparedLegend} from './types';
Expand All @@ -9,5 +7,9 @@ export const getPreparedLegend = (args: {
series: ChartKitWidgetData['series'];
}): PreparedLegend => {
const {legend, series} = args;
return {enabled: get(legend, 'enabled', true) && series.length > 1};
const enabled = legend?.enabled;

return {
enabled: typeof enabled === 'boolean' ? enabled : series.data.length > 1,
};
};
Loading

0 comments on commit 5806761

Please sign in to comment.