Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
72 changes: 72 additions & 0 deletions src/components/GraphPanel/GraphPanel.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const GraphPanel = ({
aggregationType,
maxDataPoints,
calculatedValues,
secondaryYAxisType,
} = graphConfig;

// Limit data points for performance
Expand All @@ -154,6 +155,77 @@ const GraphPanel = ({
result = processBarLineData(limitedData, xColumn, valueColumn, groupByColumn, aggregationType, calculatedValues);
break;
}

// Apply secondary Y-axis chart type to datasets on secondary axis
if (result && result.datasets && secondaryYAxisType && (chartType === 'bar' || chartType === 'line')) {
result.datasets = result.datasets.map(dataset => {
if (dataset.yAxisID === 'y1') {
return {
...dataset,
type: secondaryYAxisType,
};
}
return dataset;
});
}

// Apply line styles to datasets (convert lineStyle to Chart.js borderDash)
// Apply when chart type is line, or when dataset is on secondary axis with line type
if (result && result.datasets && (chartType === 'line' || secondaryYAxisType === 'line')) {
const lineStyleToBorderDash = {
solid: [],
dashed: [8, 4],
dotted: [2, 2],
};

result.datasets = result.datasets.map(dataset => {
// Apply line style if:
// 1. Chart type is line (all datasets are lines), or
// 2. Dataset is on secondary axis and secondary axis type is line
const isLineDataset = chartType === 'line' || (dataset.yAxisID === 'y1' && secondaryYAxisType === 'line');
if (isLineDataset && dataset.lineStyle && lineStyleToBorderDash[dataset.lineStyle]) {
return {
...dataset,
borderDash: lineStyleToBorderDash[dataset.lineStyle],
};
}
return dataset;
});
}

// Apply bar styles to datasets
// Apply when chart type is bar, or when dataset is on secondary axis with bar type
if (result && result.datasets && (chartType === 'bar' || secondaryYAxisType === 'bar')) {
result.datasets = result.datasets.map(dataset => {
// Apply bar style if:
// 1. Chart type is bar (all datasets are bars), or
// 2. Dataset is on secondary axis and secondary axis type is bar
const isBarDataset = chartType === 'bar' || (dataset.yAxisID === 'y1' && secondaryYAxisType === 'bar');
if (isBarDataset && dataset.barStyle) {
switch (dataset.barStyle) {
case 'outlined':
// Outlined: transparent fill with thick border
return {
...dataset,
backgroundColor: 'transparent',
borderWidth: 2,
};
case 'striped':
// Striped: lighter fill with dashed border to indicate pattern
return {
...dataset,
backgroundColor: dataset.backgroundColor.replace('0.8', '0.3'),
borderWidth: 2,
borderDash: [4, 4],
};
default:
return dataset;
}
}
return dataset;
});
}

return { processedData: result, validationError: null };
} catch (err) {
console.error('Error processing graph data:', err);
Expand Down
70 changes: 70 additions & 0 deletions src/dashboard/Data/Browser/GraphDialog.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ const CALCULATED_VALUE_OPERATORS = [
{ value: 'formula', label: 'Formula' },
];

const LINE_STYLES = [
{ value: 'solid', label: 'Solid' },
{ value: 'dashed', label: 'Dashed' },
{ value: 'dotted', label: 'Dotted' },
];

const BAR_STYLES = [
{ value: 'solid', label: 'Solid' },
{ value: 'outlined', label: 'Outlined' },
{ value: 'striped', label: 'Striped' },
];

export default class GraphDialog extends React.Component {
constructor(props) {
super(props);
Expand Down Expand Up @@ -77,6 +89,7 @@ export default class GraphDialog extends React.Component {
title: initialConfig.title || '',
yAxisTitlePrimary: initialConfig.yAxisTitlePrimary || '',
yAxisTitleSecondary: initialConfig.yAxisTitleSecondary || '',
secondaryYAxisType: initialConfig.secondaryYAxisType || null,
showLegend: initialConfig.showLegend !== undefined ? initialConfig.showLegend : true,
showGrid: initialConfig.showGrid !== undefined ? initialConfig.showGrid : true,
showAxisLabels: initialConfig.showAxisLabels !== undefined ? initialConfig.showAxisLabels : true,
Expand Down Expand Up @@ -547,6 +560,44 @@ export default class GraphDialog extends React.Component {
</div>
</div>
)}
{(this.state.chartType === 'line' || (calc.useSecondaryYAxis && this.state.secondaryYAxisType === 'line')) && (
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', borderTop: '1px solid #e3e3e3' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Label text="Line Style" />
</div>
<div>
<Dropdown
value={calc.lineStyle || 'solid'}
onChange={lineStyle => this.updateCalculatedValue(index, 'lineStyle', lineStyle)}
>
{LINE_STYLES.map(style => (
<Option key={style.value} value={style.value}>
{style.label}
</Option>
))}
</Dropdown>
</div>
</div>
)}
{(this.state.chartType === 'bar' || (calc.useSecondaryYAxis && this.state.secondaryYAxisType === 'bar')) && (
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', borderTop: '1px solid #e3e3e3' }}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Label text="Bar Style" />
</div>
<div>
<Dropdown
value={calc.barStyle || 'solid'}
onChange={barStyle => this.updateCalculatedValue(index, 'barStyle', barStyle)}
>
{BAR_STYLES.map(style => (
<Option key={style.value} value={style.value}>
{style.label}
</Option>
))}
</Dropdown>
</div>
</div>
)}
{hasCircular && (
<div style={{ borderTop: '1px solid #e3e3e3', padding: '12px', background: '#fff3cd', color: '#856404' }}>
<strong>⚠ Circular Reference Detected</strong>
Expand Down Expand Up @@ -686,6 +737,25 @@ export default class GraphDialog extends React.Component {
} />
)}

{(this.state.chartType === 'bar' || this.state.chartType === 'line') && (
<Field label={
<Label
text="Secondary Y-Axis Chart Type"
description="Chart type for secondary axis series"
/>
} input={
<Dropdown
value={this.state.secondaryYAxisType || ''}
onChange={secondaryYAxisType => this.setState({ secondaryYAxisType: secondaryYAxisType || null })}
placeHolder="Same as chart type"
>
<Option value="">Same as chart type</Option>
<Option value="bar">Bar</Option>
<Option value="line">Line</Option>
</Dropdown>
} />
)}

<Field label={
<Label
text="Max Data Points"
Expand Down
26 changes: 24 additions & 2 deletions src/lib/GraphDataUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -720,10 +720,12 @@ export function processBarLineData(data, xColumn, valueColumn, groupByColumn, ag
const sortedXLabels = sortedXKeys.map(key => xValues.get(key));
const groupKeys = Object.keys(groups);

// Create maps for calculated value properties (operator, secondary Y axis)
// Create maps for calculated value properties (operator, secondary Y axis, line style, bar style)
// This handles both simple calc names and grouped calc names like "CalcName (GroupValue)"
const calcValueOperatorMap = new Map();
const calcValueSecondaryYAxisMap = new Map();
const calcValueLineStyleMap = new Map();
const calcValueBarStyleMap = new Map();
if (calculatedValues && Array.isArray(calculatedValues)) {
calculatedValues.forEach(calc => {
if (calc.name && calc.operator) {
Expand All @@ -736,6 +738,12 @@ export function processBarLineData(data, xColumn, valueColumn, groupByColumn, ag
if (calc.useSecondaryYAxis) {
calcValueSecondaryYAxisMap.set(groupKey, true);
}
if (calc.lineStyle) {
calcValueLineStyleMap.set(groupKey, calc.lineStyle);
}
if (calc.barStyle) {
calcValueBarStyleMap.set(groupKey, calc.barStyle);
}
}
});
}
Expand Down Expand Up @@ -770,14 +778,28 @@ export function processBarLineData(data, xColumn, valueColumn, groupByColumn, ag
}
});

return {
const dataset = {
label: groupKey,
data: values,
backgroundColor: colors[index],
borderColor: colors[index].replace('0.8', '1'),
borderWidth: 1,
yAxisID: calcValueSecondaryYAxisMap.get(groupKey) ? 'y1' : 'y',
};

// Add line style if specified
const lineStyle = calcValueLineStyleMap.get(groupKey);
if (lineStyle) {
dataset.lineStyle = lineStyle;
}

// Add bar style if specified
const barStyle = calcValueBarStyleMap.get(groupKey);
if (barStyle) {
dataset.barStyle = barStyle;
}

return dataset;
});

return {
Expand Down
Loading