Skip to content

Commit 261fa27

Browse files
authored
fix(react-charting): Fixing markers appearing as lines (microsoft#35170)
1 parent 6a2064f commit 261fa27

File tree

5 files changed

+74
-8
lines changed

5 files changed

+74
-8
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "fix(react-charting): Fixing markers appearing as lines",
4+
"packageName": "@fluentui/react-charting",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

packages/charts/react-charting/etc/react-charting.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ export interface IAreaChartStyles extends ICartesianChartStyles {
246246
export interface IBaseDataPoint {
247247
callOutAccessibilityData?: IAccessibilityProps;
248248
hideCallout?: boolean;
249+
markerColor?: string;
249250
markerSize?: number;
250251
onDataPointClick?: () => void;
251252
text?: string;

packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,11 @@ const transformPlotlyJsonToScatterTraceProps = (
10841084
const markerSizes = isArrayOrTypedArray(series.marker?.size)
10851085
? (series.marker!.size as number[]).slice(rangeStart, rangeEnd)
10861086
: [];
1087+
const markerColors = isArrayOrTypedArray(series.marker?.color)
1088+
? (series.marker!.color as string[]).slice(rangeStart, rangeEnd)
1089+
: Array.isArray(series.marker?.color)
1090+
? (series.marker!.color as string[]).slice(rangeStart, rangeEnd)
1091+
: undefined;
10871092
const textValues = Array.isArray(series.text) ? series.text.slice(rangeStart, rangeEnd) : undefined;
10881093

10891094
return {
@@ -1097,6 +1102,7 @@ const transformPlotlyJsonToScatterTraceProps = (
10971102
: typeof series.marker?.size === 'number'
10981103
? { markerSize: series.marker.size }
10991104
: {}),
1105+
...(markerColors ? { markerColor: markerColors[i] } : {}),
11001106
...(textValues ? { text: textValues[i] } : {}),
11011107
yAxisCalloutData: getFormattedCalloutYData(rangeYValues[i] as number, yAxisTickFormat),
11021108
})),

packages/charts/react-charting/src/components/LineChart/LineChart.base.tsx

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,10 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
880880
]);
881881
}
882882

883-
if (isLegendSelected) {
883+
// Check if lines should be drawn based on mode
884+
const lineMode = this._points[i].lineOptions?.mode;
885+
const shouldDrawLines = lineMode !== 'markers';
886+
if (shouldDrawLines && isLegendSelected) {
884887
const lineBorderWidth = this._points[i].lineOptions?.lineBorderWidth
885888
? Number.parseFloat(this._points[i].lineOptions!.lineBorderWidth!.toString())
886889
: 0;
@@ -917,7 +920,7 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
917920
opacity={1}
918921
/>,
919922
);
920-
} else {
923+
} else if (shouldDrawLines) {
921924
linesForLine.push(
922925
<path
923926
id={lineId}
@@ -935,6 +938,8 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
935938
}
936939

937940
const isPointHighlighted = this.state.activeLine !== null && this.state.activeLine === i;
941+
942+
// Always add the highlight circle for large dataset hover
938943
pointsForLine.push(
939944
<circle
940945
id={`${this._staticHighlightCircle}_${i}`}
@@ -951,6 +956,46 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
951956
onMouseOut={this._handleMouseOut}
952957
/>,
953958
);
959+
960+
// Add individual markers if mode includes 'markers'
961+
const showMarkers = lineMode?.includes('markers') || !lineMode; // Show markers by default if no mode specified
962+
if (showMarkers) {
963+
for (let k = 0; k < this._points[i].data.length; k++) {
964+
const { x, y } = this._points[i].data[k];
965+
const xPoint = this._xAxisScale(x instanceof Date ? x.getTime() : x);
966+
const yPoint = yScale(y);
967+
968+
if (isPlottable(xPoint, yPoint)) {
969+
const markerSize = this._points[i].data[k].markerSize;
970+
const perPointColor = this._points[i].data[k]?.markerColor;
971+
pointsForLine.push(
972+
<circle
973+
key={`${this._circleId}_${i}_${k}_marker`}
974+
r={
975+
markerSize
976+
? (markerSize! * extraMaxPixels * 0.3) / maxMarkerSize
977+
: activePoint === this._circleId
978+
? 5.5
979+
: 3.5
980+
}
981+
cx={xPoint}
982+
cy={yPoint}
983+
fill={
984+
activePoint === this._circleId
985+
? theme!.semanticColors.bodyBackground
986+
: perPointColor || this._points[i]?.color || lineColor
987+
}
988+
stroke={perPointColor || lineColor}
989+
strokeWidth={1}
990+
opacity={isLegendSelected ? 1 : 0.1}
991+
onMouseMove={this._onMouseOverLargeDataset.bind(this, i, verticaLineHeight, yScale)}
992+
onMouseOver={this._onMouseOverLargeDataset.bind(this, i, verticaLineHeight, yScale)}
993+
onMouseOut={this._handleMouseOut}
994+
/>,
995+
);
996+
}
997+
}
998+
}
954999
} else if (!this.props.optimizeLargeData) {
9551000
for (let j = 1; j < this._points[i].data.length; j++) {
9561001
const gapResult = this._checkInGap(j, gaps, gapIndex);
@@ -1019,8 +1064,8 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
10191064
onBlur={this._handleMouseOut}
10201065
{...this._getClickHandler(this._points[i].data[j - 1].onDataPointClick)}
10211066
opacity={isLegendSelected && !currentPointHidden ? 1 : 0.01}
1022-
fill={this._getPointFill(lineColor, circleId, j, false)}
1023-
stroke={lineColor}
1067+
fill={this._points[i].data[j - 1]?.markerColor || this._getPointFill(lineColor, circleId, j, false)}
1068+
stroke={this._points[i].data[j - 1]?.markerColor || lineColor}
10241069
strokeWidth={strokeWidth}
10251070
role="img"
10261071
aria-label={this._points[i].data[j - 1].text ?? this._getAriaLabel(i, j - 1)}
@@ -1078,8 +1123,8 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
10781123
onBlur={this._handleMouseOut}
10791124
{...this._getClickHandler(this._points[i].data[j - 1].onDataPointClick)}
10801125
opacity={isLegendSelected && !currentPointHidden ? 1 : 0.01}
1081-
fill={this._getPointFill(lineColor, circleId, j, false)}
1082-
stroke={lineColor}
1126+
fill={this._points[i].data[j - 1]?.markerColor || this._getPointFill(lineColor, circleId, j, false)}
1127+
stroke={this._points[i].data[j - 1]?.markerColor || lineColor}
10831128
strokeWidth={strokeWidth}
10841129
role="img"
10851130
aria-label={this._getAriaLabel(i, j - 1)}
@@ -1214,8 +1259,10 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
12141259
onBlur={this._handleMouseOut}
12151260
{...this._getClickHandler(this._points[i].data[j].onDataPointClick)}
12161261
opacity={isLegendSelected && !lastPointHidden ? 1 : 0.01}
1217-
fill={this._getPointFill(lineColor, lastCircleId, j, true)}
1218-
stroke={lineColor}
1262+
fill={
1263+
this._points[i].data[j]?.markerColor || this._getPointFill(lineColor, lastCircleId, j, true)
1264+
}
1265+
stroke={this._points[i].data[j]?.markerColor || lineColor}
12191266
strokeWidth={strokeWidth}
12201267
role="img"
12211268
aria-label={this._getAriaLabel(i, j)}

packages/charts/react-charting/src/types/IDataPoint.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ export interface IBaseDataPoint {
340340
* text labels of marker points
341341
*/
342342
text?: string;
343+
344+
/**
345+
* Per-point marker color (overrides series color when present)
346+
*/
347+
markerColor?: string;
343348
}
344349

345350
/**

0 commit comments

Comments
 (0)