Skip to content

Commit

Permalink
feat(d3 plugin): basic line chart (#327)
Browse files Browse the repository at this point in the history
* feat(d3 plugin): basic line chart

* add dataLabels

* fix types

* fix review
  • Loading branch information
kuzmadom authored Oct 24, 2023
1 parent 651495d commit 8ad2f09
Show file tree
Hide file tree
Showing 28 changed files with 3,350 additions and 2,364 deletions.
22 changes: 22 additions & 0 deletions src/plugins/d3/__stories__/Showcase.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {StackedColumns} from '../examples/bar-x/StackedColumns';
import {Container, Row, Col, Text} from '@gravity-ui/uikit';
import {BasicPie} from '../examples/pie/Basic';
import {Basic as BasicScatter} from '../examples/scatter/Basic';
import {Basic as BasicLine} from '../examples/line/Basic';
import {Donut} from '../examples/pie/Donut';
import {LineAndBarXCombinedChart} from '../examples/combined/LineAndBarX';

const ShowcaseStory = () => {
const [loading, setLoading] = React.useState(true);
Expand All @@ -25,6 +27,15 @@ const ShowcaseStory = () => {
<Loader />
) : (
<Container spaceRow={5}>
<Row space={1}>
<Text variant="header-2">Line charts</Text>
</Row>
<Row space={3} style={{minHeight: 280}}>
<Col>
<Text variant="subheader-1">Basic line chart</Text>
<BasicLine />
</Col>
</Row>
<Row space={1}>
<Text variant="header-2">Bar-x charts</Text>
</Row>
Expand Down Expand Up @@ -64,6 +75,17 @@ const ShowcaseStory = () => {
<BasicScatter />
</Col>
</Row>
<Row space={1}>
<Text variant="header-2">Combined chart</Text>
</Row>
<Row space={3} style={{minHeight: 280}}>
<Col>
<Text variant="subheader-1">Line + Bar-X</Text>
<LineAndBarXCombinedChart />
</Col>
<Col></Col>
<Col></Col>
</Row>
</Container>
)}
</div>
Expand Down
40 changes: 40 additions & 0 deletions src/plugins/d3/__stories__/combined/LineAndBarX.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import {StoryObj} from '@storybook/react';
import {Button} from '@gravity-ui/uikit';
import {settings} from '../../../../libs';
import {D3Plugin} from '../..';
import {withKnobs} from '@storybook/addon-knobs';
import {LineAndBarXCombinedChart} from '../../examples/combined/LineAndBarX';

const ChartStory = ({Chart}: {Chart: React.FC}) => {
const [shown, setShown] = React.useState(false);

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

return (
<div
style={{
height: '80vh',
width: '100%',
}}
>
<Chart />
</div>
);
};

export const LineAndBarXCombinedChartStory: StoryObj<typeof ChartStory> = {
name: 'Line and Bar-x combined chart',
args: {
Chart: LineAndBarXCombinedChart,
},
};

export default {
title: 'Plugins/D3/Combined',
decorators: [withKnobs],
component: ChartStory,
};
114 changes: 114 additions & 0 deletions src/plugins/d3/__stories__/line/Playground.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React from 'react';
import {StoryObj} from '@storybook/react';
import {Button} from '@gravity-ui/uikit';
import {settings} from '../../../../libs';
import {D3Plugin} from '../..';
import {ChartKitWidgetData, LineSeriesData} from '../../../../types';
import {ChartKit} from '../../../../components/ChartKit';
import nintendoGames from '../../examples/nintendoGames';

function prepareData(): ChartKitWidgetData {
const games = nintendoGames.filter((d) => {
return d.date && d.user_score;
});

const byGenre = (genre: string) => {
return games
.filter((d) => d.genres.includes(genre))
.map((d) => {
return {
x: d.date,
y: d.user_score,
};
}) as LineSeriesData[];
};

return {
series: {
options: {
line: {
lineWidth: 2,
},
},
data: [
{
name: '3D',
type: 'line',
data: byGenre('3D'),
dataLabels: {
enabled: true,
},
},
{
name: '2D',
type: 'line',
data: byGenre('2D'),
},
{
name: 'Strategy',
type: 'line',
data: byGenre('Strategy'),
},
{
name: 'Shooter',
type: 'line',
data: byGenre('Shooter'),
},
],
},
xAxis: {
type: 'datetime',
title: {
text: 'Release date',
},
},
yAxis: [
{
title: {text: 'User score'},
labels: {
enabled: true,
},
ticks: {
pixelInterval: 120,
},
},
],
};
}

const ChartStory = ({data}: {data: ChartKitWidgetData}) => {
const [shown, setShown] = React.useState(false);

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

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

export const PlaygroundLineChartStory: StoryObj<typeof ChartStory> = {
name: 'Playground',
args: {
data: prepareData(),
},
argTypes: {
data: {
control: 'object',
},
},
};

export default {
title: 'Plugins/D3/Line',
component: ChartStory,
};
65 changes: 65 additions & 0 deletions src/plugins/d3/examples/combined/LineAndBarX.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import {ChartKitWidgetData} from '../../../../types';
import {ChartKit} from '../../../../components/ChartKit';
import nintendoGames from '../../examples/nintendoGames';
import {groups, max, min, median} from 'd3';

export const LineAndBarXCombinedChart = () => {
const gamesByPlatform = groups(nintendoGames, (item) => item.platform || 'unknown');

const widgetData: ChartKitWidgetData = {
series: {
options: {
line: {
lineWidth: 2,
},
},
data: [
{
type: 'bar-x',
data: gamesByPlatform.map(([value, games]) => ({
x: value,
y: median(games, (g) => g.user_score || 0),
})),
name: 'Median user score',
},
{
type: 'line',
data: gamesByPlatform.map(([value, games]) => ({
x: value,
y: max(games, (g) => g.user_score || 0),
})),
name: 'Max user score',
},
{
type: 'line',
data: gamesByPlatform.map(([value, games]) => ({
x: value,
y: min(games, (g) => g.user_score || 10),
})),
name: 'Min user score',
},
],
},
xAxis: {
categories: gamesByPlatform.map<string>(([key]) => key),
type: 'category',
title: {
text: 'Game Platforms',
},
},
yAxis: [
{
title: {text: 'User score'},
labels: {
enabled: true,
},
ticks: {
pixelInterval: 120,
},
},
],
};

return <ChartKit type="d3" data={widgetData} />;
};
75 changes: 75 additions & 0 deletions src/plugins/d3/examples/line/Basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import {ChartKit} from '../../../../components/ChartKit';
import type {ChartKitWidgetData, LineSeries, LineSeriesData} from '../../../../types';
import nintendoGames from '../nintendoGames';
import {dateTime} from '@gravity-ui/date-utils';

function prepareData() {
const dataset = nintendoGames.filter((d) => d.date && d.user_score);
const data = dataset.map((d) => ({
x: d.date || undefined,
y: d.user_score || undefined,
custom: d,
}));

return {
series: [
{
data,
name: 'Nintendo games',
},
],
};
}

export const Basic = () => {
const {series} = prepareData();

const widgetData: ChartKitWidgetData = {
series: {
data: series.map<LineSeries>((s) => ({
type: 'line',
data: s.data.filter((d) => d.x),
name: s.name,
})),
},
yAxis: [
{
title: {
text: 'User score',
},
},
],
xAxis: {
type: 'datetime',
title: {
text: 'Release dates',
},
},
tooltip: {
renderer: (d) => {
const point = d.hovered[0]?.data as LineSeriesData;

if (!point) {
return null;
}

const title = point.custom.title;
const score = point.custom.user_score;
const date = dateTime({input: point.custom.date}).format('DD MMM YYYY');

return (
<React.Fragment>
<b>{title}</b>
<br />
Release date: {date}
<br />
User score: {score}
</React.Fragment>
);
},
},
};

return <ChartKit type="d3" data={widgetData} />;
};
Loading

0 comments on commit 8ad2f09

Please sign in to comment.