Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(declarative-chart): Create Scatter plot #33843

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Add padding to domain
  • Loading branch information
Anush2303 committed Feb 27, 2025
commit a721a2b6e853b4930ad496388014f7989f6755f7
2 changes: 1 addition & 1 deletion packages/charts/react-charting/etc/react-charting.api.md
Original file line number Diff line number Diff line change
@@ -1096,7 +1096,7 @@ export interface IModifiedCartesianChartProps extends ICartesianChartProps {
getDomainNRangeValues: (points: ILineChartPoints[] | IVerticalBarChartDataPoint[] | IVerticalStackedBarDataPoint[] | IHorizontalBarChartWithAxisDataPoint[] | IGroupedVerticalBarChartData[] | IHeatMapChartDataPoint[], margins: IMargins, width: number, chartType: ChartTypes, isRTL: boolean, xAxisType: XAxisTypes, barWidth: number, tickValues: Date[] | number[] | undefined, shiftX: number) => IDomainNRange;
getGraphData?: any;
getmargins?: (margins: IMargins) => void;
getMinMaxOfYAxis: (points: ILineChartPoints[] | IHorizontalBarChartWithAxisDataPoint[] | IVerticalBarChartDataPoint[] | IDataPoint[], yAxisType: YAxisType | undefined, containerHeight?: number, margins?: IMargins) => {
getMinMaxOfYAxis: (points: ILineChartPoints[] | IHorizontalBarChartWithAxisDataPoint[] | IVerticalBarChartDataPoint[] | IDataPoint[], yAxisType: YAxisType | undefined) => {
startValue: number;
endValue: number;
};
Original file line number Diff line number Diff line change
@@ -307,12 +307,7 @@ export class CartesianChartBase
yMaxValue: this.props.yMaxValue || 0,
tickPadding: 10,
maxOfYVal: this.props.maxOfYVal,
yMinMaxValues: this.props.getMinMaxOfYAxis(
points,
this.props.yAxisType,
this.state.containerHeight - this.state._removalValueForTextTuncate!,
this.margins,
),
yMinMaxValues: this.props.getMinMaxOfYAxis(points, this.props.yAxisType),
// please note these padding default values must be consistent in here
// and the parent chart(HBWA/Vertical etc..) for more details refer example
// http://using-d3js.com/04_07_ordinal_scales.html
Original file line number Diff line number Diff line change
@@ -659,8 +659,6 @@ export interface IModifiedCartesianChartProps extends ICartesianChartProps {
getMinMaxOfYAxis: (
points: ILineChartPoints[] | IHorizontalBarChartWithAxisDataPoint[] | IVerticalBarChartDataPoint[] | IDataPoint[],
yAxisType: YAxisType | undefined,
containerHeight?: number,
margins?: IMargins,
) => { startValue: number; endValue: number };

/**
Original file line number Diff line number Diff line change
@@ -50,7 +50,6 @@ import {
createStringYAxis,
formatDate,
areArraysEqual,
YAxisType,
} from '../../utilities/index';
import { IChart } from '../../types/index';

@@ -69,8 +68,11 @@ const DEFAULT_LINE_STROKE_SIZE = 4;
// The given shape of a icon must be 2.5 times bigger than line width (known as stroke width)
const PATH_MULTIPLY_SIZE = 2.5;

// markersize for scatter plot
let maxMarkerSize = 0;
// minimum of all x of line chart points
let xMin = 0;

//minimum of all y of line chart points
let yMin = 0;

/**
*
@@ -315,7 +317,7 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
legendBars={legendBars}
createYAxis={createNumericYAxis}
getmargins={this._getMargins}
getMinMaxOfYAxis={this._getNumericMinMaxOfYForLineChart}
getMinMaxOfYAxis={this._getNumericMinMaxOfY}
getGraphData={this._initializeLineChartData}
xAxisType={isXAxisDateType ? XAxisTypes.DateAxis : XAxisTypes.NumericAxis}
customizedCallout={this._getCustomizedCallout()}
@@ -456,41 +458,17 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
: null;
};

private _getNumericMinMaxOfYForLineChart = (
points: ILineChartPoints[],
yAxisType: YAxisType,
containerHeight: number,
margins: IMargins,
): { startValue: number; endValue: number } => {
private _getNumericMinMaxOfY = (points: ILineChartPoints[]): { startValue: number; endValue: number } => {
// eslint-disable-next-line @typescript-eslint/no-shadow
const { startValue, endValue } = findNumericMinMaxOfY(points);
let maxMarkerSizeForYAxis = 0;
if (this.props.lineMode === 'scatter') {
maxMarkerSize = d3Max(points, (point: ILineChartPoints) => {
return d3Max(point.data, (item: ILineChartDataPoint) => {
return item.markerSize as number;
});
})!;
maxMarkerSizeForYAxis = this._getExtendedDomainValue(
startValue,
endValue,
containerHeight - margins.bottom!,
margins.top!,
);
}
yMin = startValue;
const padding = this.props.lineMode === 'scatter' ? (endValue - startValue) * 0.1 : 0;
return {
startValue: startValue - maxMarkerSizeForYAxis,
endValue: endValue + maxMarkerSizeForYAxis,
startValue: startValue - padding,
endValue: endValue + padding,
};
};

private _getExtendedDomainValue = (x1: number, x2: number, y1: number, y2: number): number => {
return maxMarkerSize
? y2 > y1
? Math.abs((maxMarkerSize * (x2 - x1)) / (y2 - y1 - 2 * maxMarkerSize))
: Math.abs((-1 * maxMarkerSize * (x2 - x1)) / (y2 - y1 + 2 * maxMarkerSize))
: 0;
};

private _getMargins = (margins: IMargins) => {
this.margins = margins;
};
@@ -668,13 +646,24 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
}
}
};
private _getExtraPixelsToRender(containerHeight: number): number {
const extraXPixels = this._xAxisScale(xMin) - this.margins.left!;
const extraYPixels = containerHeight - this.margins.bottom! - this._yAxisScale(yMin);
return Math.min(extraXPixels, extraYPixels);
}
private _createLines(xElement: SVGElement, containerHeight: number): JSX.Element[] {
const lines: JSX.Element[] = [];
if (this.state.isSelectedLegend) {
this._points = this.state.selectedLegendPoints;
} else {
this._points = this._injectIndexPropertyInLineChartData(this.props.data.lineChartData);
}
const extraMaxPixels = this.props.lineMode === 'scatter' ? this._getExtraPixelsToRender(containerHeight) : 0;
const maxMarkerSize = d3Max(this._points, (point: ILineChartPoints) => {
return d3Max(point.data, (item: ILineChartDataPoint) => {
return item.markerSize as number;
});
})!;
for (let i = this._points.length - 1; i >= 0; i--) {
const linesForLine: JSX.Element[] = [];
const bordersForLine: JSX.Element[] = [];
@@ -690,11 +679,18 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
const circleId = `${this._circleId}_${i}`;
const isLegendSelected: boolean =
this._legendHighlighted(legendVal) || this._noLegendHighlighted() || this.state.isSelectedLegend;
const currentMarkerSize = this._points[i].data[0].markerSize!;
pointsForLine.push(
<circle
id={circleId}
key={circleId}
r={this._points[i].data[0].markerSize ?? 4}
r={
currentMarkerSize
? (currentMarkerSize! * extraMaxPixels) / maxMarkerSize
: activePoint === circleId
? 5.5
: 3.5
}
cx={this._xAxisScale(x1)}
cy={this._yAxisScale(y1)}
fill={activePoint === circleId ? theme!.semanticColors.bodyBackground : lineColor}
@@ -861,12 +857,13 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
this._legendHighlighted(legendVal) || this._noLegendHighlighted() || this.state.isSelectedLegend;

const currentPointHidden = this._points[i].hideNonActiveDots && activePoint !== circleId;
let currentMarkerSize = this._points[i].data[j - 1].markerSize!;
pointsForLine.push(
this.props.lineMode === 'scatter' ? (
<circle
id={circleId}
key={circleId}
r={this._points[i].data[j - 1].markerSize ?? 4}
r={currentMarkerSize ? (currentMarkerSize! * extraMaxPixels) / maxMarkerSize : 4}
cx={this._xAxisScale(x1)}
cy={this._yAxisScale(y1)}
data-is-focusable={isLegendSelected}
@@ -953,13 +950,14 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
xAxisCalloutData: lastCirlceXCallout,
xAxisCalloutAccessibilityData: lastCirlceXCalloutAccessibilityData,
} = this._points[i].data[j];
currentMarkerSize = this._points[i].data[j].markerSize!;
pointsForLine.push(
<React.Fragment key={`${lastCircleId}_container`}>
{this.props.lineMode === 'scatter' ? (
<circle
id={lastCircleId}
key={lastCircleId}
r={this._points[i].data[j].markerSize ?? 4}
r={currentMarkerSize ? (currentMarkerSize! * extraMaxPixels) / maxMarkerSize : 4}
cx={this._xAxisScale(x2)}
cy={this._yAxisScale(y2)}
data-is-focusable={isLegendSelected}
@@ -1651,7 +1649,7 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
width: number,
isRTL: boolean,
): IDomainNRange => {
const xMin = d3Min(points, (point: ILineChartPoints) => {
xMin = d3Min(points, (point: ILineChartPoints) => {
return d3Min(point.data, (item: ILineChartDataPoint) => item.x as number)!;
})!;

@@ -1661,20 +1659,20 @@ export class LineChartBase extends React.Component<ILineChartProps, ILineChartSt
});
})!;

const maxMarkerSizeForXAxis = this._getExtendedDomainValue(xMin, xMax, width - margins.right!, margins.left!);
const padding = this.props.lineMode === 'scatter' ? (xMax - xMin) * 0.1 : 0;
const rStartValue = margins.left!;
const rEndValue = width - margins.right!;

return isRTL
? {
dStartValue: xMax + maxMarkerSizeForXAxis,
dEndValue: xMin - maxMarkerSizeForXAxis,
dStartValue: xMax + padding,
dEndValue: xMin - padding,
rStartValue,
rEndValue,
}
: {
dStartValue: xMin - maxMarkerSizeForXAxis,
dEndValue: xMax + maxMarkerSizeForXAxis,
dStartValue: xMin - padding,
dEndValue: xMax + padding,
rStartValue,
rEndValue,
};