diff --git a/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx index 3e0a28021b649555ac5c86a83dbf41ce94660655..8c8d5e168e963b817b61e2e367ab511a30ad2240 100644 --- a/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx +++ b/frontend/src/metabase/static-viz/components/CategoricalAreaChart/CategoricalAreaChart.jsx @@ -32,6 +32,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -65,6 +66,7 @@ const CategoricalAreaChart = ({ accessors = POSITIONAL_ACCESSORS, settings, labels, + getColor, }) => { const colors = settings?.colors; const isVertical = data.length > 10; @@ -138,9 +140,9 @@ const CategoricalAreaChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <LinePath data={data} @@ -156,9 +158,9 @@ const CategoricalAreaChart = ({ numTicks={data.length} stroke={palette.textLight} tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickComponent={props => <Text {...getXTickProps(props)} />} - tickLabelProps={() => getXTickLabelProps(layout, isVertical)} + tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx index edb38de3b6cae61ae029bc001429f2e84028af00..b5231519c866d2d88f376d75ae99fe96a9320927 100644 --- a/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx +++ b/frontend/src/metabase/static-viz/components/CategoricalBarChart/CategoricalBarChart.jsx @@ -32,6 +32,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -64,6 +65,7 @@ const CategoricalBarChart = ({ accessors = POSITIONAL_ACCESSORS, settings, labels, + getColor, }) => { const colors = settings?.colors; const isVertical = data.length > 10; @@ -142,9 +144,9 @@ const CategoricalBarChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <AxisBottom scale={xScale} @@ -153,9 +155,9 @@ const CategoricalBarChart = ({ numTicks={data.length} stroke={palette.textLight} tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickComponent={props => <Text {...getXTickProps(props)} />} - tickLabelProps={() => getXTickLabelProps(layout, isVertical)} + tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx index ddc832c5afa548443ce1ff0464232812e30eb054..a6e46aa3027db66d79a4e407fe000d9dc634a162 100644 --- a/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx +++ b/frontend/src/metabase/static-viz/components/CategoricalLineChart/CategoricalLineChart.jsx @@ -32,6 +32,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -64,6 +65,7 @@ const CategoricalLineChart = ({ accessors = POSITIONAL_ACCESSORS, settings, labels, + getColor, }) => { const colors = settings?.colors; const isVertical = data.length > 10; @@ -136,9 +138,9 @@ const CategoricalLineChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <AxisBottom scale={xScale} @@ -147,9 +149,9 @@ const CategoricalLineChart = ({ numTicks={data.length} stroke={palette.textLight} tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickComponent={props => <Text {...getXTickProps(props)} />} - tickLabelProps={() => getXTickLabelProps(layout, isVertical)} + tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx b/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx index f4bc76fce4cdb42381dc19c702f4199b739ec46d..527be39e3f13055ea97d3fda03c3fa3f6ec4ccae 100644 --- a/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx +++ b/frontend/src/metabase/static-viz/components/CategoricalWaterfallChart/CategoricalWaterfallChart.jsx @@ -22,6 +22,7 @@ import { getWaterfallEntryColor, } from "metabase/static-viz/lib/waterfall"; import { POSITIONAL_ACCESSORS } from "../../constants/accessors"; +import { getWaterfallColors } from "../../lib/colors"; const propTypes = { data: PropTypes.array.isRequired, @@ -39,6 +40,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -54,14 +56,6 @@ const layout = { size: 11, family: "Lato, sans-serif", }, - colors: { - brand: "#509ee3", - textLight: "#b8bbc3", - textMedium: "#949aab", - waterfallTotal: "#4C5773", - waterfallPositive: "#88BF4D", - waterfallNegative: "#EF8C8C", - }, barPadding: 0.2, labelFontWeight: 700, labelPadding: 12, @@ -74,13 +68,13 @@ const CategoricalWaterfallChart = ({ accessors = POSITIONAL_ACCESSORS, settings, labels, + getColor, }) => { const entries = calculateWaterfallEntries( data, accessors, settings?.showTotal, ); - const colors = settings?.colors; const isVertical = entries.length > 10; const xTickWidth = getXTickWidth( data, @@ -100,7 +94,6 @@ const CategoricalWaterfallChart = ({ const textBaseline = Math.floor(layout.font.size / 2); const leftLabel = labels?.left; const bottomLabel = !isVertical ? labels?.bottom : undefined; - const palette = { ...layout.colors, ...colors }; const xScale = scaleBand({ domain: entries.map(entry => entry.x), @@ -119,7 +112,11 @@ const CategoricalWaterfallChart = ({ const height = Math.abs(yScale(entry.start) - yScale(entry.end)); const x = xScale(entry.x); const y = yScale(Math.max(entry.start, entry.end)); - const fill = getWaterfallEntryColor(entry, palette); + + const fill = getWaterfallEntryColor( + entry, + getWaterfallColors(settings?.colors, getColor), + ); return { x, y, width, height, fill }; }; @@ -158,9 +155,9 @@ const CategoricalWaterfallChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <AxisBottom @@ -169,11 +166,11 @@ const CategoricalWaterfallChart = ({ top={yMax + layout.margin.top} label={bottomLabel} numTicks={entries.length} - stroke={palette.textLight} - tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + stroke={getColor("text-light")} + tickStroke={getColor("text-light")} + labelProps={getLabelProps(layout, getColor)} tickComponent={props => <Text {...getXTickProps(props)} />} - tickLabelProps={() => getXTickLabelProps(layout, isVertical)} + tickLabelProps={() => getXTickLabelProps(layout, isVertical, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx index 947236dbfc57992903faca3f7874dfa06561fa3c..e3b6db5562332412fe3094afb9c1d51256491e11 100644 --- a/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx +++ b/frontend/src/metabase/static-viz/components/TimeSeriesAreaChart/TimeSeriesAreaChart.jsx @@ -30,6 +30,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -64,6 +65,7 @@ const TimeSeriesAreaChart = ({ accessors = DATE_ACCESSORS, settings, labels, + getColor, }) => { data = sortTimeSeries(data); const colors = settings?.colors; @@ -119,9 +121,9 @@ const TimeSeriesAreaChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <AxisBottom scale={xScale} @@ -130,9 +132,9 @@ const TimeSeriesAreaChart = ({ numTicks={layout.numTicks} stroke={palette.textLight} tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatDate(value, settings?.x)} - tickLabelProps={() => getXTickLabelProps(layout)} + tickLabelProps={() => getXTickLabelProps(layout, false, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx index 3c10908778ad2edd970bddb7c6f237a50b029507..158c65b93fe809eb540dd39c608387a591ce753e 100644 --- a/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx +++ b/frontend/src/metabase/static-viz/components/TimeSeriesBarChart/TimeSeriesBarChart.jsx @@ -30,6 +30,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -62,6 +63,7 @@ const TimeSeriesBarChart = ({ accessors = DATE_ACCESSORS, settings, labels, + getColor, }) => { data = sortTimeSeries(data); const colors = settings?.colors; @@ -116,9 +118,9 @@ const TimeSeriesBarChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <AxisBottom scale={xScale} @@ -127,9 +129,9 @@ const TimeSeriesBarChart = ({ numTicks={layout.numTicks} stroke={palette.textLight} tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatDate(value, settings?.x)} - tickLabelProps={() => getXTickLabelProps(layout)} + tickLabelProps={() => getXTickLabelProps(layout, false, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx index 32695e569d8d3239ae81ae8b79e8e0de59fe858c..7d720b3f8c86c9338ba967ec6788f8b407125693 100644 --- a/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx +++ b/frontend/src/metabase/static-viz/components/TimeSeriesLineChart/TimeSeriesLineChart.jsx @@ -30,6 +30,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -62,6 +63,7 @@ const TimeSeriesLineChart = ({ accessors = DATE_ACCESSORS, settings, labels, + getColor, }) => { data = sortTimeSeries(data); const colors = settings?.colors; @@ -109,9 +111,9 @@ const TimeSeriesLineChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <AxisBottom scale={xScale} @@ -120,9 +122,9 @@ const TimeSeriesLineChart = ({ numTicks={layout.numTicks} stroke={palette.textLight} tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatDate(value, settings?.x)} - tickLabelProps={() => getXTickLabelProps(layout)} + tickLabelProps={() => getXTickLabelProps(layout, false, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx b/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx index 1b5356e46c9aff9c130abebaa5d9d4d3d09007c3..1b9573821505b456b5bbc81bdc593980c8eaa534 100644 --- a/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx +++ b/frontend/src/metabase/static-viz/components/TimeSeriesWaterfallChart/TimeSeriesWaterfallChart.jsx @@ -20,6 +20,7 @@ import { } from "metabase/static-viz/lib/waterfall"; import { sortTimeSeries } from "../../lib/sort"; import { DATE_ACCESSORS } from "../../constants/accessors"; +import { getWaterfallColors } from "../../lib/colors"; const propTypes = { data: PropTypes.array.isRequired, @@ -37,6 +38,7 @@ const propTypes = { left: PropTypes.string, bottom: PropTypes.string, }), + getColor: PropTypes.func, }; const layout = { @@ -52,14 +54,6 @@ const layout = { size: 11, family: "Lato, sans-serif", }, - colors: { - brand: "#509ee3", - textLight: "#b8bbc3", - textMedium: "#949aab", - waterfallTotal: "#4C5773", - waterfallPositive: "#88BF4D", - waterfallNegative: "#EF8C8C", - }, numTicks: 4, barPadding: 0.2, labelFontWeight: 700, @@ -72,9 +66,9 @@ const TimeSeriesWaterfallChart = ({ accessors = DATE_ACCESSORS, settings, labels, + getColor, }) => { data = sortTimeSeries(data); - const colors = settings?.colors; const yTickWidth = getYTickWidth(data, accessors, settings, layout.font.size); const yLabelOffset = yTickWidth + layout.labelPadding; const xMin = yLabelOffset + layout.font.size * 1.5; @@ -83,7 +77,6 @@ const TimeSeriesWaterfallChart = ({ const innerWidth = xMax - xMin; const leftLabel = labels?.left; const bottomLabel = labels?.bottom; - const palette = { ...layout.colors, ...colors }; const entries = calculateWaterfallEntries( data, @@ -108,7 +101,10 @@ const TimeSeriesWaterfallChart = ({ const height = Math.abs(yScale(entry.start) - yScale(entry.end)); const x = xScale(entry.x); const y = yScale(Math.max(entry.start, entry.end)); - const fill = getWaterfallEntryColor(entry, palette); + const fill = getWaterfallEntryColor( + entry, + getWaterfallColors(settings?.colors, getColor), + ); return { x, y, width, height, fill }; }; @@ -133,9 +129,9 @@ const TimeSeriesWaterfallChart = ({ labelOffset={yLabelOffset} hideTicks hideAxisLine - labelProps={getLabelProps(layout)} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatNumber(value, settings?.y)} - tickLabelProps={() => getYTickLabelProps(layout)} + tickLabelProps={() => getYTickLabelProps(layout, getColor)} /> <AxisBottom scale={xScale} @@ -143,11 +139,11 @@ const TimeSeriesWaterfallChart = ({ top={yMax + layout.margin.top} label={bottomLabel} numTicks={layout.numTicks} - stroke={palette.textLight} - tickStroke={palette.textLight} - labelProps={getLabelProps(layout)} + stroke={getColor("text-light")} + tickStroke={getColor("text-light")} + labelProps={getLabelProps(layout, getColor)} tickFormat={value => formatTimescaleWaterfallTick(value, settings)} - tickLabelProps={() => getXTickLabelProps(layout)} + tickLabelProps={() => getXTickLabelProps(layout, false, getColor)} /> </svg> ); diff --git a/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx b/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx index 4bd5e7603c9695875a6c27835c283e781d1c6515..318377e6a166fd760b7cb5503d634095730e0dc6 100644 --- a/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx +++ b/frontend/src/metabase/static-viz/containers/StaticChart/StaticChart.tsx @@ -23,34 +23,38 @@ import LineAreaBarChart from "../../components/LineAreaBarChart"; import { LINE_AREA_BAR_CHART_TYPE } from "../../components/LineAreaBarChart/constants"; import Funnel from "../../components/FunnelChart"; import { FUNNEL_CHART_TYPE } from "../../components/FunnelChart/constants"; +import { createColorGetter } from "metabase/static-viz/lib/colors"; import { StaticChartProps } from "./types"; const StaticChart = ({ type, options }: StaticChartProps) => { + const getColor = createColorGetter(options.colors); + const chartProps = { ...options, getColor }; + switch (type) { case CATEGORICAL_AREA_CHART_TYPE: - return <CategoricalAreaChart {...options} />; + return <CategoricalAreaChart {...chartProps} />; case CATEGORICAL_BAR_CHART_TYPE: - return <CategoricalBarChart {...options} />; + return <CategoricalBarChart {...chartProps} />; case CATEGORICAL_DONUT_CHART_TYPE: - return <CategoricalDonutChart {...options} />; + return <CategoricalDonutChart {...chartProps} />; case CATEGORICAL_LINE_CHART_TYPE: - return <CategoricalLineChart {...options} />; + return <CategoricalLineChart {...chartProps} />; case CATEGORICAL_WATERFALL_CHART_TYPE: - return <CategoricalWaterfallChart {...options} />; + return <CategoricalWaterfallChart {...chartProps} />; case TIME_SERIES_AREA_CHART_TYPE: - return <TimeSeriesAreaChart {...options} />; + return <TimeSeriesAreaChart {...chartProps} />; case TIME_SERIES_BAR_CHART_TYPE: - return <TimeSeriesBarChart {...options} />; + return <TimeSeriesBarChart {...chartProps} />; case TIME_SERIES_LINE_CHART_TYPE: - return <TimeSeriesLineChart {...options} />; + return <TimeSeriesLineChart {...chartProps} />; case TIME_SERIES_WATERFALL_CHART_TYPE: - return <TimeSeriesWaterfallChart {...options} />; + return <TimeSeriesWaterfallChart {...chartProps} />; case PROGRESS_BAR_TYPE: - return <ProgressBar {...options} />; + return <ProgressBar {...chartProps} />; case LINE_AREA_BAR_CHART_TYPE: - return <LineAreaBarChart {...options} />; + return <LineAreaBarChart {...chartProps} />; case FUNNEL_CHART_TYPE: - return <Funnel {...options} />; + return <Funnel {...chartProps} />; } }; diff --git a/frontend/src/metabase/static-viz/containers/StaticChart/types.ts b/frontend/src/metabase/static-viz/containers/StaticChart/types.ts index 5104371c633645afb9a5140b67467cc279eded76..bf78b5a76bf649ad73d7227314194a6f0af8fbf9 100644 --- a/frontend/src/metabase/static-viz/containers/StaticChart/types.ts +++ b/frontend/src/metabase/static-viz/containers/StaticChart/types.ts @@ -1,3 +1,4 @@ +import { ColorPalette } from "metabase/lib/colors/types"; import { STATIC_CHART_TYPES } from "./constants"; type StaticChartType = typeof STATIC_CHART_TYPES[number]; @@ -5,4 +6,5 @@ type StaticChartType = typeof STATIC_CHART_TYPES[number]; export interface StaticChartProps { type: StaticChartType; options: any; + colors?: ColorPalette; } diff --git a/frontend/src/metabase/static-viz/lib/axes.js b/frontend/src/metabase/static-viz/lib/axes.js index 747c5ef11dfb8d65c1b7f5b721e2a7faf692cabd..a6cf5f96ab600d6a6fde69a4883a2bf9cbb05a29 100644 --- a/frontend/src/metabase/static-viz/lib/axes.js +++ b/frontend/src/metabase/static-viz/lib/axes.js @@ -26,24 +26,24 @@ export const getYTickWidth = (data, accessors, settings, fontSize) => { .reduce((a, b) => Math.max(a, b), 0); }; -export const getXTickLabelProps = (layout, isVertical) => ({ +export const getXTickLabelProps = (layout, isVertical, getColor) => ({ fontSize: layout.font.size, fontFamily: layout.font.family, - fill: layout.colors.textMedium, + fill: getColor("text-medium"), textAnchor: isVertical ? "start" : "middle", }); -export const getYTickLabelProps = layout => ({ +export const getYTickLabelProps = (layout, getColor) => ({ fontSize: layout.font.size, fontFamily: layout.font.family, - fill: layout.colors.textMedium, + fill: getColor("text-medium"), textAnchor: "end", }); -export const getLabelProps = layout => ({ +export const getLabelProps = (layout, getColor) => ({ fontWeight: layout.labelFontWeight, fontSize: layout.font.size, fontFamily: layout.font.family, - fill: layout.colors.textMedium, + fill: getColor("text-medium"), textAnchor: "middle", }); diff --git a/frontend/src/metabase/static-viz/lib/colors.ts b/frontend/src/metabase/static-viz/lib/colors.ts new file mode 100644 index 0000000000000000000000000000000000000000..4566ef8bf5578dc4b5c5a4ae77d5fe3d534ff614 --- /dev/null +++ b/frontend/src/metabase/static-viz/lib/colors.ts @@ -0,0 +1,29 @@ +import { colors, color } from "metabase/lib/colors/palette"; +import { ColorPalette } from "metabase/lib/colors/types"; + +export type ColorGetter = (colorName: string) => string; + +export const createColorGetter = ( + instanceColors: ColorPalette = {}, +): ColorGetter => { + const palette = { ...colors, ...instanceColors }; + + return (colorName: string) => color(colorName, palette); +}; + +export type WaterfallColors = { + waterfallTotal: string; + waterfallPositive: string; + waterfallNegative: string; +}; + +export const getWaterfallColors = ( + colorSettings: Partial<WaterfallColors> = {}, + getColor: ColorGetter, +): WaterfallColors => { + return { + waterfallTotal: colorSettings.waterfallTotal ?? getColor("text-dark"), + waterfallPositive: colorSettings.waterfallPositive ?? getColor("accent1"), + waterfallNegative: colorSettings.waterfallNegative ?? getColor("accent3"), + }; +}; diff --git a/resources/frontend_shared/static_viz_interface.js b/resources/frontend_shared/static_viz_interface.js index a664ba6aa76d76c5cbb6142b560ef410e0545367..97dc555c2aff50ee73e84c19628a37265d78bbb1 100644 --- a/resources/frontend_shared/static_viz_interface.js +++ b/resources/frontend_shared/static_viz_interface.js @@ -47,11 +47,12 @@ function combo_chart(series, settings, colors) { }); } -function timeseries_waterfall(data, labels, settings) { +function timeseries_waterfall(data, labels, settings, instanceColors) { return StaticViz.RenderChart("timeseries/waterfall", { data: toJSArray(data), labels: toJSMap(labels), settings: JSON.parse(settings), + colors: JSON.parse(instanceColors), }); } @@ -93,11 +94,12 @@ function categorical_donut(rows, colors) { }); } -function categorical_waterfall(data, labels, settings) { +function categorical_waterfall(data, labels, settings, instanceColors) { return StaticViz.RenderChart("categorical/waterfall", { data: toJSArray(data), labels: toJSMap(labels), settings: JSON.parse(settings), + colors: JSON.parse(instanceColors), }); } diff --git a/src/metabase/pulse/render/body.clj b/src/metabase/pulse/render/body.clj index a03f555a09cb8c2a6988f4c75e1f14dd8487096c..240f6834c745ae0b91b5df36b65277ab4ee2bdbc 100644 --- a/src/metabase/pulse/render/body.clj +++ b/src/metabase/pulse/render/body.clj @@ -776,9 +776,9 @@ (:waterfall.show_total viz-settings)) settings (-> (->js-viz x-col y-col viz-settings) (update :colors assoc - :waterfallTotal (or (:waterfall.total_color viz-settings) (nth colors 0)) - :waterfallPositive (or (:waterfall.increase_color viz-settings) (nth colors 1)) - :waterfallNegative (or (:waterfall.decrease_color viz-settings) (nth colors 2))) + :waterfallTotal (:waterfall.total_color viz-settings) + :waterfallPositive (:waterfall.increase_color viz-settings) + :waterfallNegative (:waterfall.decrease_color viz-settings)) (assoc :showTotal show-total)) image-bundle (image-bundle/make-image-bundle render-type diff --git a/src/metabase/pulse/render/js_svg.clj b/src/metabase/pulse/render/js_svg.clj index 6014ce9b21b77d8c45b6286aeaa2262735324946..e74d3b3c7c873a5fc966a54bf4cda3a1698bb9cf 100644 --- a/src/metabase/pulse/render/js_svg.clj +++ b/src/metabase/pulse/render/js_svg.clj @@ -5,6 +5,7 @@ `toJSMap` functions to turn Clojure's normal datastructures into js native structures." (:require [cheshire.core :as json] [clojure.string :as str] + [metabase.public-settings :as public-settings] [metabase.pulse.render.js-engine :as js]) (:import [java.io ByteArrayInputStream ByteArrayOutputStream] java.nio.charset.StandardCharsets @@ -115,7 +116,8 @@ [rows labels settings] (let [svg-string (.asString (js/execute-fn-name @context "timeseries_waterfall" rows (map (fn [[k v]] [(name k) v]) labels) - (json/generate-string settings)))] + (json/generate-string settings) + (json/generate-string (public-settings/application-colors))))] (svg-string->bytes svg-string))) (defn funnel @@ -174,7 +176,8 @@ [rows labels settings] (let [svg-string (.asString (js/execute-fn-name @context "categorical_waterfall" rows (map (fn [[k v]] [(name k) v]) labels) - (json/generate-string settings)))] + (json/generate-string settings) + (json/generate-string (public-settings/application-colors))))] (svg-string->bytes svg-string))) (defn categorical-bar diff --git a/test/metabase/pulse/render/js_svg_test.clj b/test/metabase/pulse/render/js_svg_test.clj index eaea55d5d71e5bbf00ef0c0a10829ffa3bfe4298..6d4f7b493f8c0e1f4145ca7a4bb45842c925a872 100644 --- a/test/metabase/pulse/render/js_svg_test.clj +++ b/test/metabase/pulse/render/js_svg_test.clj @@ -9,6 +9,7 @@ [clojure.set :as set] [clojure.spec.alpha :as s] [clojure.test :refer :all] + [metabase.public-settings :as public-settings] [metabase.pulse.render.js-engine :as js] [metabase.pulse.render.js-svg :as js-svg]) (:import org.apache.batik.anim.dom.SVGOMDocument @@ -175,7 +176,7 @@ (testing "It returns bytes" (let [svg-bytes (js-svg/timelineseries-waterfall rows labels settings)] (is (bytes? svg-bytes)))) - (let [svg-string (.asString (js/execute-fn-name @context "timeseries_waterfall" rows labels settings))] + (let [svg-string (.asString (js/execute-fn-name @context "timeseries_waterfall" rows labels settings (json/generate-string (public-settings/application-colors))))] (testing "it returns a valid svg string (no html in it)" (validate-svg-string :timelineseries-waterfall svg-string))))) @@ -245,5 +246,5 @@ (testing "It returns bytes" (let [svg-bytes (js-svg/categorical-waterfall rows labels {})] (is (bytes? svg-bytes)))) - (let [svg-string (.asString ^Value (js/execute-fn-name @context "categorical_waterfall" rows labels settings))] + (let [svg-string (.asString ^Value (js/execute-fn-name @context "categorical_waterfall" rows labels settings (json/generate-string (public-settings/application-colors))))] (validate-svg-string :categorical/waterfall svg-string))))