Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
bfd1101
feat: mobile polar charts
hcopp Dec 8, 2025
35e05c3
Update mobile storybook
hcopp Dec 8, 2025
0cc9003
Bring polar charts to web
hcopp Dec 8, 2025
5fe4b65
Update mobile with web specific changes
hcopp Dec 8, 2025
37b6f14
Fix stroke of slices on dark mode
hcopp Dec 8, 2025
8711e29
Add new doc pages
hcopp Dec 8, 2025
441b794
feat: legend and tooltip on web
hcopp Dec 8, 2025
97c7c31
Support hideBeaconLabels and bar component
hcopp Dec 8, 2025
0a83723
Cleanup web tooltip examples
hcopp Dec 8, 2025
e541fd0
Switch from legend being a child to being a prop
hcopp Dec 8, 2025
6c85852
Bring legend to mobile
hcopp Dec 8, 2025
5d2fc99
Create docs
hcopp Dec 8, 2025
5e3db46
Support chart type in context
hcopp Dec 8, 2025
18a17f4
Fix spacing
hcopp Dec 8, 2025
c7b89ab
feat: wip chart highlight functionality
hcopp Dec 9, 2025
2cc4c1c
Continue migration
hcopp Dec 9, 2025
afb0bac
Fix defaults to be consistent across platforms
hcopp Dec 9, 2025
8df5ef0
Cleanup comments and early returns
hcopp Dec 9, 2025
d2a3bb0
Merge branch 'master' into hunter/polar-charts-2
hcopp Dec 9, 2025
c25cb3d
Merge branch 'hunter/polar-charts-2' into hunter/legend-tooltip-2
hcopp Dec 9, 2025
94072ab
Merge branch 'hunter/legend-tooltip-2' into hunter/chart-highlight
hcopp Dec 9, 2025
400accf
Drop unused default
hcopp Dec 9, 2025
fbc141a
Fix lint
hcopp Dec 9, 2025
fb8f8e8
Fix lint
hcopp Dec 9, 2025
f401909
Fix lint
hcopp Dec 9, 2025
4ab519b
Merge branch 'hunter/polar-charts-2' into hunter/legend-tooltip-2
hcopp Dec 9, 2025
1cae159
Fis routes
hcopp Dec 9, 2025
a176866
Merge branch 'hunter/legend-tooltip-2' into hunter/chart-highlight
hcopp Dec 9, 2025
312920b
Fix legend import
hcopp Dec 9, 2025
b3e490c
Merge branch 'hunter/legend-tooltip-2' into hunter/chart-highlight
hcopp Dec 9, 2025
d804527
Clean up chart tooltip
hcopp Dec 9, 2025
e0fb5b9
Add classNames and styles
hcopp Dec 10, 2025
67f0348
Merge branch 'hunter/legend-tooltip-2' into hunter/chart-highlight
hcopp Dec 10, 2025
687e4be
Support PolarChart with ChartTooltip
hcopp Dec 10, 2025
107e5b1
Set default chart insets
hcopp Dec 10, 2025
e66db38
Start improving docs
hcopp Dec 10, 2025
fe710f9
Add adaptive detail example
hcopp Dec 10, 2025
6c6f7df
Update examples
hcopp Dec 10, 2025
6d0b91c
Use charttooltip and legend on barchart examples
hcopp Dec 10, 2025
4897c1c
Update legend stories
hcopp Dec 10, 2025
ae2a690
Update chart tooltip examples
hcopp Dec 10, 2025
9b267d3
Fix chart tooltip showing stacked data count
hcopp Dec 10, 2025
6aad561
Update docs
hcopp Dec 10, 2025
0545f1f
Update example
hcopp Dec 10, 2025
f8850b7
Improve bar chart examples
hcopp Dec 10, 2025
6666b40
Set default inset to 8 for polar charts
hcopp Dec 10, 2025
d96c28f
Cleanup examples for pie and donut chart
hcopp Dec 10, 2025
89ae5b8
Update web and mobile examples
hcopp Dec 10, 2025
42bf815
Improve examples and fix mobile legend
hcopp Dec 11, 2025
3960305
Add new polar example
hcopp Dec 11, 2025
2a2f011
Fix math on polar chart
hcopp Dec 11, 2025
20ee7a2
Fix alignment in storybook
hcopp Dec 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/docs/docgen.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@ module.exports = {
'chart/area/AreaChart',
'chart/bar/BarChart',
'chart/CartesianChart',
'chart/ChartTooltip',
'chart/DonutChart',
'chart/legend/Legend',
'chart/line/LineChart',
'chart/pie/PieChart',
'chart/PolarChart',
'chart/line/ReferenceLine',
'chart/axis/XAxis',
'chart/axis/YAxis',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"import": "import { AreaChart } from '@coinbase/cds-mobile-visualization'",
"source": "https://github.com/coinbase/cds/blob/master/packages/mobile-visualization/src/chart/area/AreaChart.tsx",
"description": "A chart component that displays data as filled areas beneath lines. Ideal for showing cumulative values, stacked data, or emphasizing volume over time.",
"description": "A chart component built on CartesianChart that displays data as filled areas beneath lines. Ideal for showing cumulative values, stacked data, or emphasizing volume over time.",
"relatedComponents": [
{
"label": "CartesianChart",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"import": "import { AreaChart } from '@coinbase/cds-web-visualization'",
"source": "https://github.com/coinbase/cds/blob/master/packages/web-visualization/src/chart/area/AreaChart.tsx",
"description": "A chart component that displays data as filled areas beneath lines. Ideal for showing cumulative values, stacked data, or emphasizing volume over time.",
"description": "A chart component built on CartesianChart that displays data as filled areas beneath lines. Ideal for showing cumulative values, stacked data, or emphasizing volume over time.",
"relatedComponents": [
{
"label": "CartesianChart",
Expand Down
41 changes: 28 additions & 13 deletions apps/docs/docs/components/graphs/BarChart/_mobileExamples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ You can also round the baseline of the bars by setting the `roundBaseline` prop

```jsx
function PositiveAndNegativeCashFlow() {
const theme = useTheme();
const ThinSolidLine = memo((props: SolidLineProps) => <SolidLine {...props} strokeWidth={1} />);

const categories = Array.from({ length: 31 }, (_, i) => `3/${i + 1}`);
Expand All @@ -369,25 +370,39 @@ function PositiveAndNegativeCashFlow() {
0, 0, 0, -12, -10,
];
const series = [
{ id: 'gains', data: gains, color: 'var(--color-fgPositive)' },
{ id: 'losses', data: losses, color: 'var(--color-fgNegative)' },
{ id: 'gains', data: gains, color: theme.color.fgPositive, stackId: 'bars' },
{ id: 'losses', data: losses, color: theme.color.fgNegative, stackId: 'bars' },
];

// Custom bar component that dims non-highlighted bars
const DimmingBarComponent = memo(({ dataX, ...props }) => {
const highlightContext = useHighlightContext();

const fillOpacity = useDerivedValue(() => {
const highlightedIndex = highlightContext?.highlightedItem.value?.dataIndex;
return highlightedIndex === undefined || highlightedIndex === dataX ? 1 : 0.5;
}, [highlightContext, dataX]);

return <DefaultBar {...props} dataX={dataX} fillOpacity={fillOpacity.value} />;
});

return (
<BarChart
<CartesianChart
enableHighlighting
height={150}
inset={{ top: 8, bottom: 8, left: 0, right: 0 }}
series={series}
xAxis={{ data: categories }}
stacked
showXAxis
showYAxis
yAxis={{
showGrid: true,
GridLineComponent: ThinSolidLine,
tickLabelFormatter: (value) => `$${value}M`,
}}
/>
xAxis={{ data: categories, scaleType: 'band' }}
>
<XAxis />
<YAxis
showGrid
GridLineComponent={ThinSolidLine}
tickLabelFormatter={(value) => `$${value}M`}
/>
<BarPlot BarComponent={DimmingBarComponent} />
<ReferenceLine LineComponent={SolidLine} dataY={0} />
</CartesianChart>
);
}
```
Expand Down
117 changes: 93 additions & 24 deletions apps/docs/docs/components/graphs/BarChart/_webExamples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -369,25 +369,81 @@ function PositiveAndNegativeCashFlow() {
0, 0, 0, -12, -10,
];
const series = [
{ id: 'gains', data: gains, color: 'var(--color-fgPositive)' },
{ id: 'losses', data: losses, color: 'var(--color-fgNegative)' },
{ id: 'gains', data: gains, color: 'var(--color-fgPositive)', stackId: 'bars' },
{ id: 'losses', data: losses, color: 'var(--color-fgNegative)', stackId: 'bars' },
];

const DimmingBarComponent = memo(({ seriesId, dataX, ...props }) => {
const highlightContext = useHighlightContext();
const highlightedItem = highlightContext?.highlightedItem;
return (
<DefaultBar
{...props}
dataX={dataX}
fillOpacity={
highlightedItem?.dataIndex === undefined || highlightedItem.dataIndex === dataX ? 1 : 0.5
}
seriesId={seriesId}
/>
);
});

// Custom line component that renders a rect to highlight the entire bandwidth including gaps
const BandwidthHighlight = memo(({ stroke }) => {
const { getXScale, drawingArea } = useCartesianChartContext();
const highlightContext = useHighlightContext();
const scrubberPosition = highlightContext?.highlightedItem?.dataIndex;
const xScale = getXScale();

if (!xScale || scrubberPosition === undefined) return null;

const xPos = xScale(scrubberPosition);

if (xPos === undefined) return null;

const bandwidth = 'bandwidth' in xScale ? xScale.bandwidth() : 0;
const step = 'step' in xScale ? xScale.step() : bandwidth;
const gap = step - bandwidth;

// Expand the highlight to include half the gap on each side
const highlightWidth = bandwidth + gap;
const highlightX = xPos - gap / 2;

return (
<rect
fill={stroke}
height={drawingArea.height}
width={highlightWidth}
x={highlightX}
y={drawingArea.y}
/>
);
});

return (
<BarChart
<CartesianChart
enableHighlighting
height={{ base: 150, tablet: 200, desktop: 250 }}
inset={{ top: 8, bottom: 8, left: 0, right: 0 }}
series={series}
xAxis={{ data: categories }}
stacked
showXAxis
showYAxis
yAxis={{
showGrid: true,
GridLineComponent: ThinSolidLine,
tickLabelFormatter: (value) => `$${value}M`,
}}
/>
xAxis={{ data: categories, scaleType: 'band' }}
>
<XAxis />
<YAxis
showGrid
GridLineComponent={ThinSolidLine}
tickLabelFormatter={(value) => `$${value}M`}
/>
<BarPlot BarComponent={DimmingBarComponent} />
<ReferenceLine LineComponent={SolidLine} dataY={0} />
<Scrubber
hideOverlay
LineComponent={BandwidthHighlight}
lineStroke="var(--color-bgLine)"
seriesIds={[]}
/>
<ChartTooltip />
</CartesianChart>
);
}
```
Expand Down Expand Up @@ -691,25 +747,33 @@ function Candlesticks() {

const ThinSolidLine = memo((props: SolidLineProps) => <SolidLine {...props} strokeWidth={1} />);

// Custom line component that renders a rect to highlight the entire bandwidth
const BandwidthHighlight = memo(({ d, stroke }) => {
const { getXScale, drawingArea, getXAxis } = useCartesianChartContext();
const { scrubberPosition } = useScrubberContext();
// Custom line component that renders a rect to highlight the entire bandwidth including gaps
const BandwidthHighlight = memo(({ stroke }) => {
const { getXScale, drawingArea } = useCartesianChartContext();
const highlightContext = useHighlightContext();
const scrubberPosition = highlightContext?.highlightedItem?.dataIndex;
const xScale = getXScale();
const xAxis = getXAxis();

if (!xScale || scrubberPosition === undefined) return
if (!xScale || scrubberPosition === undefined) return null;

const xPos = xScale(scrubberPosition);

if (xPos === undefined) return
if (xPos === undefined) return null;

const bandwidth = 'bandwidth' in xScale ? xScale.bandwidth() : 0;
const step = 'step' in xScale ? xScale.step() : bandwidth;
const gap = step - bandwidth;

// Expand the highlight to include half the gap on each side
const highlightWidth = bandwidth + gap;
const highlightX = xPos - gap / 2;

return (
<rect
fill={stroke}
height={drawingArea.height}
width={xScale.bandwidth()}
x={xPos}
width={highlightWidth}
x={highlightX}
y={drawingArea.y}
/>
);
Expand All @@ -723,6 +787,8 @@ function Candlesticks() {
const CandlestickBarComponent = memo<BarComponentProps>(
({ x, y, width, height, originY, dataX, ...props }) => {
const { getYScale } = useCartesianChartContext();
const highlightContext = useHighlightContext();
const highlightedItem = highlightContext?.highlightedItem;
const yScale = getYScale();

const wickX = x + width / 2;
Expand All @@ -740,8 +806,11 @@ function Candlesticks() {
const bodyHeight = Math.abs(openY - closeY);
const bodyY = openY < closeY ? openY : closeY;

const fillOpacity =
highlightedItem?.dataIndex === undefined || highlightedItem.dataIndex === dataX ? 1 : 0.5;

return (
<g>
<g opacity={fillOpacity}>
<line stroke={color} strokeWidth={1} x1={wickX} x2={wickX} y1={y} y2={y + height} />
<rect fill={color} height={bodyHeight} width={width} x={x} y={bodyY} />
</g>
Expand Down Expand Up @@ -847,7 +916,7 @@ function Candlesticks() {
<Scrubber
hideOverlay
LineComponent={BandwidthHighlight}
lineStroke="var(--color-fgMuted)"
lineStroke="var(--color-bgLine)"
seriesIds={[]}
/>
</BarChart>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"import": "import { BarChart } from '@coinbase/cds-mobile-visualization'",
"source": "https://github.com/coinbase/cds/blob/master/packages/mobile-visualization/src/chart/bar/BarChart.tsx",
"description": "A bar chart component for comparing values across categories. Supports horizontal and vertical orientations, stacked bars, and grouped series.",
"description": "A bar chart component built on CartesianChart for comparing values across categories. Supports horizontal and vertical orientations, stacked bars, and grouped series.",
"relatedComponents": [
{
"label": "CartesianChart",
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/docs/components/graphs/BarChart/webMetadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"import": "import { BarChart } from '@coinbase/cds-web-visualization'",
"source": "https://github.com/coinbase/cds/blob/master/packages/web-visualization/src/chart/bar/BarChart.tsx",
"description": "A bar chart component for comparing values across categories. Supports horizontal and vertical orientations, stacked bars, and grouped series.",
"description": "A bar chart component built on CartesianChart for comparing values across categories. Supports horizontal and vertical orientations, stacked bars, and grouped series.",
"relatedComponents": [
{
"label": "CartesianChart",
Expand Down
Loading