Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

GeoChart: Add region and resolution props for state/province-level map views
24 changes: 19 additions & 5 deletions projects/js-packages/charts/src/charts/geo-chart/geo-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,31 @@ const DEFAULT_FEATURE_FILL_COLOR = '#ffffff';
const DEFAULT_BACKGROUND_COLOR = '#ffffff';

/**
* Renders a geographical chart using Google Charts GeoChart to visualize data by country.
* Renders a geographical chart using Google Charts GeoChart to visualize data.
*
* Supports the full Google Charts data format including custom tooltips, formatted values,
* and multiple data columns for maximum flexibility.
*
* Countries can be identified by full name (e.g., 'United States') or ISO 3166-1 alpha-2
* codes (e.g., 'US'). Full names are recommended for better readability in tooltips.
* Locations can be identified by full name (e.g., 'United States', 'California') or codes
* (e.g., 'US', 'US-CA'). Full names are recommended for better readability in tooltips.
*
* @param props - The props for the GeoChart component
* @param props.data - Data in Google Charts format (array of arrays with headers)
* @param props.width - Width of the chart in pixels
* @param props.height - Height of the chart in pixels
* @param props.region - Region to display ('world', 'US', or ISO 3166-1 alpha-2 code)
* @param props.resolution - Resolution level ('countries', 'provinces', or 'metros')
* @param props.className - Additional CSS class name for the chart container
* @param props.renderPlaceholder - Optional render function for the loading placeholder
* @return A React component displaying an interactive world map with data visualization
* @return A React component displaying an interactive map with data visualization
*/
const GeoChartInternal: FC< GeoChartProps > = ( {
className,
data,
width,
height,
region = 'world',
resolution = 'countries',
renderPlaceholder,
} ) => {
const {
Expand Down Expand Up @@ -91,6 +95,8 @@ const GeoChartInternal: FC< GeoChartProps > = ( {

const options: GoogleChartOptions = useMemo(
() => ( {
...( region !== 'world' && { region } ),
...( resolution !== 'countries' && { resolution } ),
colorAxis: { colors: [ lightColorHex, fullColorHex ] },
backgroundColor: backgroundColorHex,
datalessRegionColor: defaultFillColorHex,
Expand All @@ -99,7 +105,15 @@ const GeoChartInternal: FC< GeoChartProps > = ( {
legend: 'none',
keepAspectRatio: true,
} ),
[ lightColorHex, fullColorHex, backgroundColorHex, defaultFillColorHex, hasHtmlTooltips ]
[
region,
resolution,
lightColorHex,
fullColorHex,
backgroundColorHex,
defaultFillColorHex,
hasHtmlTooltips,
]
);

return (
Expand Down
2 changes: 1 addition & 1 deletion projects/js-packages/charts/src/charts/geo-chart/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { default as GeoChart, GeoChartUnresponsive } from './geo-chart';
export type { GeoChartProps } from './types';
export type { GeoChartProps, GeoRegion, GeoResolution } from './types';
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { viewsByEuropeanCountry, viewsByUSState } from '../../../stories/sample-data';
import GeoChart from '../geo-chart';
import { geoChartMetaArgs, geoChartStoryArgs } from './config';
import type { Meta, StoryObj } from '@storybook/react';
Expand Down Expand Up @@ -32,3 +33,21 @@ export const EmptyData: Story = {
data: [ [ 'Country', 'Views' ] ],
},
};

export const USStates: Story = {
args: {
...geoChartStoryArgs,
region: 'US',
resolution: 'provinces',
data: viewsByUSState,
},
};

export const EuropeanCountries: Story = {
args: {
...geoChartStoryArgs,
region: '150',
resolution: 'countries',
data: viewsByEuropeanCountry,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,62 @@ describe( 'GeoChart', () => {

expect( options.tooltip ).toEqual( { trigger: 'focus', isHtml: false } );
} );

test( 'does not include region in options when set to world (default)', () => {
renderWithTheme();

const chartOptions = screen.getByTestId( 'chart-options' );
const options = JSON.parse( chartOptions.textContent || '{}' );

expect( options.region ).toBeUndefined();
} );

test( 'does not include resolution in options when set to countries (default)', () => {
renderWithTheme();

const chartOptions = screen.getByTestId( 'chart-options' );
const options = JSON.parse( chartOptions.textContent || '{}' );

expect( options.resolution ).toBeUndefined();
} );

test( 'passes region to Google Charts when not world', () => {
renderWithTheme( { region: 'US' } );

const chartOptions = screen.getByTestId( 'chart-options' );
const options = JSON.parse( chartOptions.textContent || '{}' );

expect( options.region ).toBe( 'US' );
} );

test( 'passes resolution to Google Charts when not countries', () => {
renderWithTheme( { resolution: 'provinces' } );

const chartOptions = screen.getByTestId( 'chart-options' );
const options = JSON.parse( chartOptions.textContent || '{}' );

expect( options.resolution ).toBe( 'provinces' );
} );

test( 'passes both region and resolution for US states view', () => {
const stateData = [
[ 'State', 'Value' ],
[ 'California', 100 ],
[ 'Texas', 50 ],
] as [ string[], ...[ string, number ][] ];

renderWithTheme( {
region: 'US',
resolution: 'provinces',
data: stateData,
} );

const chartOptions = screen.getByTestId( 'chart-options' );
const options = JSON.parse( chartOptions.textContent || '{}' );

expect( options.region ).toBe( 'US' );
expect( options.resolution ).toBe( 'provinces' );
} );
} );

describe( 'Loading State', () => {
Expand Down
29 changes: 29 additions & 0 deletions projects/js-packages/charts/src/charts/geo-chart/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
import { BaseChartProps, GeoData } from '../../types';

/**
* Region to display on the map.
* Use 'world' for global view or any ISO 3166-1 alpha-2 country code
* (e.g., 'US' for United States, 'CA' for Canada).
*/
export type GeoRegion = 'world' | ( string & {} );

/**
* Resolution level for the map.
* - 'countries': Country-level (default for 'world')
* - 'provinces': State/province level (use with specific region like 'US')
* - 'metros': Metropolitan areas (US only)
*/
export type GeoResolution = 'countries' | 'provinces' | 'metros';

export interface GeoChartProps
extends Pick< BaseChartProps, 'className' | 'chartId' | 'width' | 'height' > {
/**
Expand All @@ -10,6 +25,20 @@ export interface GeoChartProps
* (e.g., 'United States' or 'US').
*/
data: GeoData;
/**
* Region to display. Use 'world' for global view, 'US' for United States,
* or any ISO 3166-1 alpha-2 country code.
* @default 'world'
*/
region?: GeoRegion;
/**
* Resolution level for the map.
* - 'countries': Country-level (default for 'world')
* - 'provinces': State/province level (use with specific region like 'US')
* - 'metros': Metropolitan areas (US only)
* @default 'countries'
*/
resolution?: GeoResolution;
/**
* Optional render function for the loading placeholder.
* Called while Google Charts is loading.
Expand Down
2 changes: 1 addition & 1 deletion projects/js-packages/charts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export {
export type * from './types';
export type * from './visx/types';
export type { PieChartProps } from './charts/pie-chart';
export type { GeoChartProps } from './charts/geo-chart';
export type { GeoChartProps, GeoRegion, GeoResolution } from './charts/geo-chart';
export type { LegendValueDisplay, BaseLegendItem } from './components/legend';
export type { TrendIndicatorProps, TrendDirection } from './components/trend-indicator';
export type { LineStyles, GridStyles, EventHandlerParams } from '@visx/xychart';
Expand Down
52 changes: 50 additions & 2 deletions projects/js-packages/charts/src/stories/sample-data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import type { FunnelStep } from '../../charts/conversion-funnel-chart';
import type { LeaderboardEntry } from '../../charts/leaderboard-chart';
import type { DataPointPercentage, SeriesData } from '../../types';
import type { DataPointPercentage, GeoData, SeriesData } from '../../types';

/**
* Olympic medals data for top countries (1896-2020)
Expand Down Expand Up @@ -938,7 +938,7 @@ export const customerRevenueLegendData = [
* - Data points: 25
* - Suitable for: GeoChart
*/
export const viewsByCountry: [ string[], ...[ string, number ][] ] = [
export const viewsByCountry: GeoData = [
[ 'Country', 'Views' ],
[ 'United States', 1000 ],
[ 'United Kingdom', 500 ],
Expand All @@ -965,3 +965,51 @@ export const viewsByCountry: [ string[], ...[ string, number ][] ] = [
[ 'Kenya', 0.0625 ],
[ 'South Korea', 0.03125 ],
];

/**
* US states views data
*
* Views by US state for geo chart visualization
* - Category: categorical
* - Data points: 15
* - Suitable for: GeoChart with region='US' and resolution='provinces'
*/
export const viewsByUSState: GeoData = [
[ 'State', 'Views' ],
[ 'California', 2500 ],
[ 'Texas', 1800 ],
[ 'Florida', 1500 ],
[ 'New York', 1400 ],
[ 'Illinois', 900 ],
[ 'Pennsylvania', 850 ],
[ 'Ohio', 750 ],
[ 'Georgia', 700 ],
[ 'North Carolina', 650 ],
[ 'Michigan', 600 ],
[ 'Washington', 550 ],
[ 'Arizona', 500 ],
[ 'Massachusetts', 480 ],
[ 'Colorado', 450 ],
[ 'Virginia', 420 ],
];

/**
* European countries views data
*
* Views by European country for geo chart visualization
* - Category: categorical
* - Data points: 9
* - Suitable for: GeoChart with region='150' (Europe)
*/
export const viewsByEuropeanCountry: GeoData = [
[ 'Country', 'Views' ],
[ 'United Kingdom', 1500 ],
[ 'France', 1000 ],
[ 'Germany', 800 ],
[ 'Italy', 600 ],
[ 'Spain', 500 ],
[ 'Portugal', 400 ],
[ 'Greece', 300 ],
[ 'Turkey', 200 ],
[ 'Russia', 100 ],
];
Loading