From 5cf34201b4926b099e21335697fc133d920e6c13 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Tue, 13 May 2025 10:38:42 -0600 Subject: [PATCH] update trendline --- api/libs/database/src/types/metric_yml.rs | 23 ++++++++++++++++++- .../metric/charts/annotationInterfaces.ts | 4 ++-- .../ui/color-picker/ColorPicker.tsx | 16 ++++++++++--- .../MetricStylingApp/MetricStylingApp.tsx | 1 + .../EditTrendline/EditTrendline.tsx | 13 +++++++++-- .../EditTrendlineColorPicker.tsx | 15 +++++++++++- .../StylingAppStyling/StylingAppStyling.tsx | 8 +++++-- 7 files changed, 69 insertions(+), 11 deletions(-) diff --git a/api/libs/database/src/types/metric_yml.rs b/api/libs/database/src/types/metric_yml.rs index 67f5d6bdd..092b0afe8 100644 --- a/api/libs/database/src/types/metric_yml.rs +++ b/api/libs/database/src/types/metric_yml.rs @@ -548,6 +548,27 @@ pub struct Trendline { #[serde(skip_serializing_if = "Option::is_none")] #[serde(alias = "trend_line_color")] pub trend_line_color: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(alias = "trendline_label_position_offset")] + pub trendline_label_position_offset: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(alias = "projection")] + pub projection: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(alias = "line_style")] + pub line_style: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(alias = "offset")] + pub offset: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(alias = "polynomial_order")] + pub polynomial_order: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(alias = "aggregate_all_categories")] + pub aggregate_all_categories: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(alias = "id")] + pub id: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -705,7 +726,7 @@ pub enum MetricValueAggregate { Count, Max, Min, - First + First, } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/web/src/api/asset_interfaces/metric/charts/annotationInterfaces.ts b/web/src/api/asset_interfaces/metric/charts/annotationInterfaces.ts index dc5c2cd8d..2a7523125 100644 --- a/web/src/api/asset_interfaces/metric/charts/annotationInterfaces.ts +++ b/web/src/api/asset_interfaces/metric/charts/annotationInterfaces.ts @@ -22,10 +22,10 @@ export interface Trendline { | 'median'; //default is linear trend trendLineColor?: string | null | 'inherit'; //OPTIONAL: default is #000000, inherit will inherit the color from the line/bar columnId: string; - trendlineLabelPositionOffset?: number; //OPTIONAL: default is 0.85. Goes from 0 to 1. + trendlineLabelPositionOffset?: number; //OPTIONAL: default is 0.85. Goes from 0 to 1. This is where the label will be placed on the trendline. projection?: boolean; //OPTIONAL: default is false. if true, the trendline will be projected to the end of the chart. lineStyle?: 'solid' | 'dotted' | 'dashed' | 'dashdot'; - offset?: number; //OPTIONAL: default is -15. if true, the trendline will be projected to the end of the chart. + offset?: number; //OPTIONAL: default is 0. if true, the label will be offset vertically from the trendline. polynomialOrder?: number; aggregateAllCategories?: boolean; //OPTIONAL: default is true. if true, the trendline will be calculated for all categories. if false, the trendline will be calculated for the category specified in the columnId. id?: string; diff --git a/web/src/components/ui/color-picker/ColorPicker.tsx b/web/src/components/ui/color-picker/ColorPicker.tsx index fe568b4cd..c3c084519 100644 --- a/web/src/components/ui/color-picker/ColorPicker.tsx +++ b/web/src/components/ui/color-picker/ColorPicker.tsx @@ -20,6 +20,7 @@ interface ColorPickerProps { children?: React.ReactNode; showInput?: boolean; showPicker?: boolean; + pickerBackgroundImage?: string; } const colorPickerWrapperVariants = cva('border p-0.5 rounded cursor-pointer shadow', { @@ -47,6 +48,7 @@ const ColorPicker = ({ children, showInput = true, showPicker = true, + pickerBackgroundImage, ...props }: ColorPickerProps) => { const [open, setOpen] = useState(false); @@ -89,7 +91,12 @@ const ColorPicker = ({
- +
@@ -116,16 +123,19 @@ ColorPicker.displayName = 'ColorPicker'; const ColorPickerInputBox = ({ parsedValue, size, - disabled + disabled, + pickerBackgroundImage }: { parsedValue: string; size: 'default' | 'small' | 'tall'; disabled: boolean | undefined; + pickerBackgroundImage: string | undefined; }) => { const backgroundStyle = - parsedValue === 'inherit' + parsedValue === 'inherit' || pickerBackgroundImage ? { backgroundImage: + pickerBackgroundImage || 'linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet)' } : { backgroundColor: parsedValue }; diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/MetricStylingApp.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/MetricStylingApp.tsx index b3f98b469..1f87a21ec 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/MetricStylingApp.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/MetricStylingApp.tsx @@ -177,6 +177,7 @@ export const MetricStylingApp: React.FC<{ barShowTotalAtTop={barShowTotalAtTop} rowCount={rowCount} pieSortBy={pieSortBy} + colors={colors} /> )} diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendline.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendline.tsx index 7543d0bc3..321bb893e 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendline.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendline.tsx @@ -20,11 +20,11 @@ import { TypeToLabel } from './config'; import { JOIN_CHARACTER } from '@/components/ui/charts/commonHelpers'; import isEqual from 'lodash/isEqual'; import { TrendlineLabelPositionOffset } from './TrendlineLabelPositionOffset'; -import { TrendlineProjection } from './TrendlineProjection'; import { TrendlineLineStyle } from './TrendlineLineStyle'; import { TrendlineOffset } from './TrendlineOffset'; -import { TrendlinePolynomialOrder } from './TrendlinePolynomialOrder'; import { TrendlineAggregateAllCategories } from './TrendlineAggregateAllCategories'; +// import { TrendlineProjection } from './TrendlineProjection'; +// import { TrendlinePolynomialOrder } from './TrendlinePolynomialOrder'; export interface LoopTrendline extends Trendline { id: string; @@ -32,6 +32,7 @@ export interface LoopTrendline extends Trendline { export const EditTrendline: React.FC<{ trendlines: IBusterMetricChartConfig['trendlines']; + colors: string[]; onUpdateChartConfig: (chartConfig: Partial) => void; selectedAxis: ChartEncodes; columnMetadata: ColumnMetaData[]; @@ -40,6 +41,7 @@ export const EditTrendline: React.FC<{ }> = React.memo( ({ trendlines, + colors, onUpdateChartConfig, selectedAxis, columnMetadata, @@ -175,6 +177,7 @@ export const EditTrendline: React.FC<{ onDeleteTrendline={onDeleteTrendline} onUpdateExisitingTrendline={onUpdateExisitingTrendline} isNewTrend={newTrendIds.has(trend.id)} + colors={colors} /> ))} @@ -193,6 +196,7 @@ const EditTrendlineItem: React.FC<{ yAxisEncodes: string[]; xAxisEncodes: string[]; categoryEncodes: string[] | undefined; + colors: string[]; selectedChartType: IBusterMetricChartConfig['selectedChartType']; onUpdateExisitingTrendline: (trend: LoopTrendline) => void; onDeleteTrendline: (id: string) => void; @@ -205,6 +209,7 @@ const EditTrendlineItem: React.FC<{ yAxisEncodes, xAxisEncodes, categoryEncodes, + colors, selectedChartType, onUpdateExisitingTrendline, onDeleteTrendline @@ -234,6 +239,7 @@ const EditTrendlineItem: React.FC<{ columnLabelFormats={columnLabelFormats} yAxisEncodes={yAxisEncodes} xAxisEncodes={xAxisEncodes} + colors={colors} categoryEncodes={categoryEncodes} selectedChartType={selectedChartType} onUpdateExisitingTrendline={onUpdateExisitingTrendline} @@ -249,6 +255,7 @@ const TrendlineItemContent: React.FC<{ columnMetadata: ColumnMetaData[]; yAxisEncodes: string[]; xAxisEncodes: string[]; + colors: string[]; categoryEncodes: string[] | undefined; columnLabelFormats: IBusterMetricChartConfig['columnLabelFormats']; selectedChartType: IBusterMetricChartConfig['selectedChartType']; @@ -256,6 +263,7 @@ const TrendlineItemContent: React.FC<{ }> = React.memo( ({ trend, + colors, categoryEncodes, yAxisEncodes, xAxisEncodes, @@ -316,6 +324,7 @@ const TrendlineItemContent: React.FC<{ diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendlineColorPicker.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendlineColorPicker.tsx index 4e01aee3e..bf634ef1f 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendlineColorPicker.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/EditTrendline/EditTrendlineColorPicker.tsx @@ -1,5 +1,5 @@ import { ColorPicker } from '@/components/ui/color-picker'; -import React from 'react'; +import React, { useMemo } from 'react'; import { LabelAndInput } from '../../Common'; import { LoopTrendline } from './EditTrendline'; import { useMemoizedFn } from '@/hooks'; @@ -8,10 +8,12 @@ import { Switch } from '@/components/ui/switch'; export const TrendlineColorPicker = React.memo( ({ trend, + colors, onUpdateExisitingTrendline }: { trend: LoopTrendline; onUpdateExisitingTrendline: (trend: LoopTrendline) => void; + colors: string[]; }) => { const onChangeComplete = useMemoizedFn((color: string) => { const hexColor = color; @@ -24,6 +26,16 @@ export const TrendlineColorPicker = React.memo( const isInheritColor = trend.trendLineColor === 'inherit'; + const pickerBackgroundImage = useMemo(() => { + if (isInheritColor) { + const colorsToUse = colors.slice(0, 4); + return `repeating-linear-gradient(90deg, ${colorsToUse + .map((color, index) => `${color} ${index * 25}%, ${color} ${(index + 1) * 25}%`) + .join(', ')})`; + } + return undefined; + }, [colors, isInheritColor]); + return (
@@ -31,6 +43,7 @@ export const TrendlineColorPicker = React.memo( size="small" showInput={!isInheritColor} showPicker={!isInheritColor} + pickerBackgroundImage={pickerBackgroundImage} value={trend.trendLineColor || '#000000'} onChangeComplete={onChangeComplete}> diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/StylingAppStyling.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/StylingAppStyling.tsx index be7b178b1..182b314f4 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/StylingAppStyling.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppStyling/StylingAppStyling.tsx @@ -72,7 +72,8 @@ export const StylingAppStyling: React.FC< barShowTotalAtTop, yAxisShowAxisTitle, rowCount, - pieSortBy + pieSortBy, + colors }) => { const { onUpdateMetricChartConfig } = useUpdateMetricChart(); @@ -175,6 +176,7 @@ export const StylingAppStyling: React.FC< lineGroupType={lineGroupType} barGroupType={barGroupType} onUpdateChartConfig={onUpdateChartConfig} + colors={colors} />
); @@ -477,7 +479,8 @@ const EtcSettings: React.FC< columnMetadata, columnLabelFormats, lineGroupType, - barGroupType + barGroupType, + colors }) => { const isScatterChart = selectedChartType === 'scatter'; const isPieChart = selectedChartType === 'pie'; @@ -546,6 +549,7 @@ const EtcSettings: React.FC< columnMetadata={columnMetadata} selectedChartType={selectedChartType} onUpdateChartConfig={onUpdateChartConfig} + colors={colors} /> ) }