Skip to content

Commit

Permalink
Dark mode theme colors for declarative charts (#33439)
Browse files Browse the repository at this point in the history
  • Loading branch information
srmukher authored Dec 11, 2024
1 parent 608336d commit 221a380
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Dark mode theme colors for declarative charts",
"packageName": "@fluentui/react-charting",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ import { GaugeChart } from '../GaugeChart/index';
import { GroupedVerticalBarChart } from '../GroupedVerticalBarChart/index';
import { VerticalBarChart } from '../VerticalBarChart/index';

import { useTheme } from '@fluentui/react';

export const UseIsDarkTheme = (): boolean => {
const theme = useTheme();
return theme.isInverted;
};

export interface Schema {
/**
* Plotly schema represented as JSON object
Expand Down Expand Up @@ -76,42 +83,45 @@ export const DeclarativeChart: React.FunctionComponent<DeclarativeChartProps> =
const isXDate = isDateArray(xValues);
const isXNumber = isNumberArray(xValues);
const colorMap = useColorMapping();
const isDarkTheme = UseIsDarkTheme();

switch (plotlySchema.data[0].type) {
case 'pie':
return <DonutChart {...transformPlotlyJsonToDonutProps(plotlySchema, colorMap)} />;
return <DonutChart {...transformPlotlyJsonToDonutProps(plotlySchema, colorMap, isDarkTheme)} />;
case 'bar':
const orientation = plotlySchema.data[0].orientation;
if (orientation === 'h') {
return (
<HorizontalBarChartWithAxis {...transformPlotlyJsonToHorizontalBarWithAxisProps(plotlySchema, colorMap)} />
<HorizontalBarChartWithAxis
{...transformPlotlyJsonToHorizontalBarWithAxisProps(plotlySchema, colorMap, isDarkTheme)}
/>
);
} else {
if (['group', 'overlay'].includes(plotlySchema?.layout?.barmode)) {
return <GroupedVerticalBarChart {...transformPlotlyJsonToGVBCProps(plotlySchema, colorMap)} />;
return <GroupedVerticalBarChart {...transformPlotlyJsonToGVBCProps(plotlySchema, colorMap, isDarkTheme)} />;
}
return <VerticalStackedBarChart {...transformPlotlyJsonToVSBCProps(plotlySchema, colorMap)} />;
return <VerticalStackedBarChart {...transformPlotlyJsonToVSBCProps(plotlySchema, colorMap, isDarkTheme)} />;
}
case 'scatter':
const isAreaChart = plotlySchema.data.some((series: any) => series.fill === 'tonexty');
if (isXDate || isXNumber) {
if (isAreaChart) {
return <AreaChart {...transformPlotlyJsonToScatterChartProps(plotlySchema, true, colorMap)} />;
return <AreaChart {...transformPlotlyJsonToScatterChartProps(plotlySchema, true, colorMap, isDarkTheme)} />;
}
return <LineChart {...transformPlotlyJsonToScatterChartProps(plotlySchema, false, colorMap)} />;
return <LineChart {...transformPlotlyJsonToScatterChartProps(plotlySchema, false, colorMap, isDarkTheme)} />;
}
return <VerticalStackedBarChart {...transformPlotlyJsonToVSBCProps(plotlySchema, colorMap)} />;
return <VerticalStackedBarChart {...transformPlotlyJsonToVSBCProps(plotlySchema, colorMap, isDarkTheme)} />;
case 'heatmap':
return <HeatMapChart {...transformPlotlyJsonToHeatmapProps(plotlySchema)} />;
case 'sankey':
return <SankeyChart {...transformPlotlyJsonToSankeyProps(plotlySchema, colorMap)} />;
return <SankeyChart {...transformPlotlyJsonToSankeyProps(plotlySchema, colorMap, isDarkTheme)} />;
case 'indicator':
if (plotlySchema?.data?.[0]?.mode?.includes('gauge')) {
return <GaugeChart {...transformPlotlyJsonToGaugeProps(plotlySchema, colorMap)} />;
return <GaugeChart {...transformPlotlyJsonToGaugeProps(plotlySchema, colorMap, isDarkTheme)} />;
}
return <div>Unsupported Schema</div>;
case 'histogram':
return <VerticalBarChart {...transformPlotlyJsonToVBCProps(plotlySchema, colorMap)} />;
return <VerticalBarChart {...transformPlotlyJsonToVBCProps(plotlySchema, colorMap, isDarkTheme)} />;
default:
return <div>Unsupported Schema</div>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ const isNumber = (value: any): boolean => !isNaN(parseFloat(value)) && isFinite(
export const isDateArray = (array: any[]): boolean => isArrayOrTypedArray(array) && array.every(isDate);
export const isNumberArray = (array: any[]): boolean => isArrayOrTypedArray(array) && array.every(isNumber);

export const getColor = (legendLabel: string, colorMap: React.MutableRefObject<Map<string, string>>): string => {
export const getColor = (
legendLabel: string,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): string => {
if (!colorMap.current.has(legendLabel)) {
const nextColor = getNextColor(colorMap.current.size + 1);
const nextColor = getNextColor(colorMap.current.size + 1, 0, isDarkTheme);
colorMap.current.set(legendLabel, nextColor);
return nextColor;
}
Expand All @@ -48,12 +52,13 @@ export const getColor = (legendLabel: string, colorMap: React.MutableRefObject<M
export const transformPlotlyJsonToDonutProps = (
jsonObj: any,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): IDonutChartProps => {
const { data, layout } = jsonObj;
const firstData = data[0];

const donutData = firstData.labels?.map((label: string, index: number): IChartDataPoint => {
const color = getColor(label, colorMap);
const color = getColor(label, colorMap, isDarkTheme);
return {
legend: label,
data: firstData.values?.[index],
Expand Down Expand Up @@ -96,6 +101,7 @@ export const transformPlotlyJsonToDonutProps = (
export const transformPlotlyJsonToVSBCProps = (
jsonObj: any,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): IVerticalStackedBarChartProps => {
const { data, layout } = jsonObj;
const mapXToDataPoints: { [key: string]: IVerticalStackedChartProps } = {};
Expand All @@ -108,14 +114,14 @@ export const transformPlotlyJsonToVSBCProps = (
}
const legend: string = series.name || `Series ${index1 + 1}`;
if (series.type === 'bar') {
const color = getColor(legend, colorMap);
const color = getColor(legend, colorMap, isDarkTheme);
mapXToDataPoints[x].chartData.push({
legend,
data: series.y?.[index2],
color,
});
} else if (series.type === 'line') {
const color = getColor(legend, colorMap);
const color = getColor(legend, colorMap, isDarkTheme);
mapXToDataPoints[x].lineData!.push({
legend,
y: series.y?.[index2],
Expand All @@ -140,6 +146,7 @@ export const transformPlotlyJsonToVSBCProps = (
export const transformPlotlyJsonToGVBCProps = (
jsonObj: any,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): IGroupedVerticalBarChartProps => {
const { data, layout } = jsonObj;
const mapXToDataPoints: Record<string, IGroupedVerticalBarChartData> = {};
Expand All @@ -151,7 +158,7 @@ export const transformPlotlyJsonToGVBCProps = (
}
if (series.type === 'bar') {
const legend: string = series.name || `Series ${index1 + 1}`;
const color = getColor(legend, colorMap);
const color = getColor(legend, colorMap, isDarkTheme);

mapXToDataPoints[x].series.push({
key: legend,
Expand All @@ -175,6 +182,7 @@ export const transformPlotlyJsonToGVBCProps = (
export const transformPlotlyJsonToVBCProps = (
jsonObj: any,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): IVerticalBarChartProps => {
const { data, layout } = jsonObj;
const vbcData: IVerticalBarChartDataPoint[] = [];
Expand Down Expand Up @@ -216,7 +224,7 @@ export const transformPlotlyJsonToVBCProps = (

buckets.forEach(bucket => {
const legend = series.name || `Series ${index + 1}`;
const color = getColor(legend, colorMap);
const color = getColor(legend, colorMap, isDarkTheme);
let y = bucket.length;

if (series.histnorm === 'percent') {
Expand Down Expand Up @@ -262,6 +270,7 @@ export const transformPlotlyJsonToScatterChartProps = (
jsonObj: any,
isAreaChart: boolean,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): ILineChartProps | IAreaChartProps => {
const { data, layout } = jsonObj;

Expand All @@ -271,7 +280,7 @@ export const transformPlotlyJsonToScatterChartProps = (
const isXDate = isDateArray(xValues);
const isXNumber = isNumberArray(xValues);
const legend = series.name || `Series ${index + 1}`;
const lineColor = getColor(legend, colorMap);
const lineColor = getColor(legend, colorMap, isDarkTheme);

return {
legend,
Expand Down Expand Up @@ -304,13 +313,14 @@ export const transformPlotlyJsonToScatterChartProps = (
export const transformPlotlyJsonToHorizontalBarWithAxisProps = (
jsonObj: any,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): IHorizontalBarChartWithAxisProps => {
const { data, layout } = jsonObj;

const chartData: IHorizontalBarChartWithAxisDataPoint[] = data
.map((series: any, index: number) => {
return series.y.map((yValue: string, i: number) => {
const color = getColor(yValue, colorMap);
const color = getColor(yValue, colorMap, isDarkTheme);
return {
x: series.x[i],
y: yValue,
Expand Down Expand Up @@ -385,6 +395,7 @@ export const transformPlotlyJsonToHeatmapProps = (jsonObj: any): IHeatMapChartPr
export const transformPlotlyJsonToSankeyProps = (
jsonObj: any,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): ISankeyChartProps => {
const { data, layout } = jsonObj;
const { link, node } = data[0];
Expand All @@ -400,7 +411,7 @@ export const transformPlotlyJsonToSankeyProps = (

const sankeyChartData = {
nodes: node.label.map((label: string, index: number) => {
const color = getColor(label, colorMap);
const color = getColor(label, colorMap, isDarkTheme);

return {
nodeId: index,
Expand Down Expand Up @@ -439,13 +450,14 @@ export const transformPlotlyJsonToSankeyProps = (
export const transformPlotlyJsonToGaugeProps = (
jsonObj: any,
colorMap: React.MutableRefObject<Map<string, string>>,
isDarkTheme?: boolean,
): IGaugeChartProps => {
const { data, layout } = jsonObj;
const firstData = data[0];

const segments = firstData.gauge?.steps?.map((step: any, index: number): IGaugeChartSegment => {
const legend = step.name || `Segment ${index + 1}`;
const color = getColor(legend, colorMap);
const color = getColor(legend, colorMap, isDarkTheme);
return {
legend,
size: step.range?.[1] - step.range?.[0],
Expand All @@ -459,11 +471,11 @@ export const transformPlotlyJsonToGaugeProps = (
const diff = firstData.value - firstData.delta.reference;
if (diff >= 0) {
sublabel = `\u25B2 ${diff}`;
const color = getColor(firstData.delta.increasing?.color || '', colorMap);
const color = getColor(firstData.delta.increasing?.color || '', colorMap, isDarkTheme);
sublabelColor = color;
} else {
sublabel = `\u25BC ${Math.abs(diff)}`;
const color = getColor(firstData.delta.decreasing?.color || '', colorMap);
const color = getColor(firstData.delta.decreasing?.color || '', colorMap, isDarkTheme);
sublabelColor = color;
}
}
Expand Down

0 comments on commit 221a380

Please sign in to comment.