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

Charting: Vertical stacked bar chart minor changes including uncaught type error issue fix. #15447

Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "patch",
"comment": "Vertical stacked bar chart styled examples code updated.",
"packageName": "@fluentui/react-examples",
"email": "[email protected]",
"dependentChangeType": "patch",
"date": "2020-10-09T15:29:43.827Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "patch",
"comment": "Vertical stacked bar chart uncaught type error fixed. Minor edits to margins",
"packageName": "@uifabric/charting",
"email": "[email protected]",
"dependentChangeType": "patch",
"date": "2020-10-09T15:29:42.466Z"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
createDateXAxis,
createYAxis,
createStringYAxis,
additionalMarginRight,
IMargins,
getMinMaxOfYAxis,
XAxisTypes,
Expand Down Expand Up @@ -60,11 +59,17 @@ export class CartesianChartBase extends React.Component<IModifiedCartesianChartP
_height: this.props.height || 350,
};
this.idForGraph = getId('chart_');
/**
* In RTL mode, Only graph will be rendered left/right. We need to provide left and right margins manually.
* So that, in RTL, left margins becomes right margins and viceversa.
* As graph needs to be drawn perfecty, these values consider as default values.
* Same margins using for all other cartesian charts. Can be accessible through 'getMargins' call back method.
*/
this.margins = {
top: this.props.margins?.top || 20,
right: this.props.margins?.right || 20,
bottom: this.props.margins?.bottom || 35,
left: this.props.margins?.left || 40,
top: this.props.margins?.top ?? 20,
bottom: this.props.margins?.bottom ?? 35,
right: this._isRtl ? this.props.margins?.left ?? 40 : this.props.margins?.right ?? 20,
left: this._isRtl ? this.props.margins?.right ?? 20 : this.props.margins?.left ?? 40,
};
}

Expand Down Expand Up @@ -200,7 +205,7 @@ export class CartesianChartBase extends React.Component<IModifiedCartesianChartP
this.xAxisElement = e;
}}
id={`xAxisGElement${this.idForGraph}`}
transform={`translate(0, ${svgDimensions.height - 35})`}
transform={`translate(0, ${svgDimensions.height - this.margins.bottom!})`}
className={this._classNames.xAxis}
/>
<g
Expand All @@ -209,7 +214,7 @@ export class CartesianChartBase extends React.Component<IModifiedCartesianChartP
}}
id={`yAxisGElement${this.idForGraph}`}
transform={`translate(${
this._isRtl ? svgDimensions.width - this.margins.right! - additionalMarginRight : 40
this._isRtl ? svgDimensions.width - this.margins.right! : this.margins.left!
}, 0)`}
className={this._classNames.yAxis}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ export interface ICartesianChartProps {

/**
* Margins for the chart
* @default `{ top: 20, bottom: 35, left: 40, right: 20 }`
* To avoid edge cuttings to the chart, we recommend you use default values or greater then default values
*/
margins?: IMargins;

Expand Down
2 changes: 0 additions & 2 deletions packages/charting/src/components/Legends/Legends.base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ export class LegendsBase extends React.Component<ILegendsProps, ILegendState> {
>
<div
className={classNames.overflowIndicationTextStyle}
// eslint-disable-next-line react/jsx-no-bind
ref={(rootElem: HTMLDivElement) => (this._hoverCardRef = rootElem)}
{...(allowFocusOnLegends && {
'aria-expanded': this.state.isHoverCardVisible,
Expand Down Expand Up @@ -378,7 +377,6 @@ export class LegendsBase extends React.Component<ILegendsProps, ILegendState> {
{...(data.nativeButtonProps && { ...data.nativeButtonProps })}
key={index}
className={classNames.legend}
/* eslint-disable react/jsx-no-bind */
onClick={onClickHandler}
onMouseOver={onHoverHandler}
onMouseOut={onMouseOut}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,23 @@ import {
IChildProps,
IDataPoint,
IMargins,
IRefArrayData,
IVerticalStackedBarChartProps,
IVerticalStackedBarChartStyleProps,
IVerticalStackedBarChartStyles,
IVerticalStackedChartProps,
IVSChartDataPoint,
} from '../../index';
import { FocusZoneDirection } from '@fluentui/react-focus';
import { ChartTypes, XAxisTypes, additionalMarginRight } from '../../utilities/index';
import { ChartTypes, XAxisTypes } from '../../utilities/index';

const getClassNames = classNamesFunction<IVerticalStackedBarChartStyleProps, IVerticalStackedBarChartStyles>();
type NumericAxis = D3Axis<number | { valueOf(): number }>;
type NumericScale = D3ScaleLinear<number, number>;
type StringScale = D3ScaleLinear<string, string>;
const COMPONENT_NAME = 'VERTICAL STACKED BAR CHART';
interface IBarRef {
index: number | string;
refElement: SVGGElement;

interface IRefArrayData {
refElement?: SVGGElement | null;
}

export interface IVerticalStackedBarChartState extends IBasestate {
Expand All @@ -50,8 +49,6 @@ export class VerticalStackedBarChartBase extends React.Component<
private _barWidth: number;
private _calloutId: string;
private _classNames: IProcessedStyleSet<IVerticalStackedBarChartStyles>;
private _refArray: IRefArrayData[];
private _barRefArray: IBarRef[];
private _colors: string[];
private margins: IMargins;
private _isRtl: boolean = getRTL();
Expand All @@ -78,8 +75,6 @@ export class VerticalStackedBarChartBase extends React.Component<
this._onLegendLeave = this._onLegendLeave.bind(this);
this._handleMouseOut = this._handleMouseOut.bind(this);
this._calloutId = getId('callout');
this._refArray = [];
this._barRefArray = [];
this._adjustProps();
this._dataset = this._createDataSetLayer();
}
Expand Down Expand Up @@ -280,14 +275,6 @@ export class VerticalStackedBarChartBase extends React.Component<
);
}

private _refCallback(rectElement: SVGRectElement, legendTitle: string, index: number): void {
this._refArray[index] = { index: legendTitle, refElement: rectElement };
}

private _barRefCallback = (barElement: SVGGElement, index: number, xAxisPoint: number | string): void => {
this._barRefArray[index] = { index: xAxisPoint, refElement: barElement };
};

private _onRectHover(
xAxisPoint: string,
point: IVSChartDataPoint,
Expand Down Expand Up @@ -327,44 +314,36 @@ export class VerticalStackedBarChartBase extends React.Component<
});
};

private _onRectFocus(point: IVSChartDataPoint, xAxisPoint: string, color: string, refArrayIndexNumber: number): void {
private _onRectFocus(point: IVSChartDataPoint, xAxisPoint: string, color: string, ref: IRefArrayData): void {
if (
this.state.isLegendSelected === false ||
(this.state.isLegendSelected && this.state.selectedLegendTitle === point.legend)
) {
this._refArray.forEach((obj: IRefArrayData, index: number) => {
if (obj.index === point.legend && refArrayIndexNumber === index) {
this.setState({
refSelected: obj.refElement,
isCalloutVisible: true,
selectedLegendTitle: point.legend,
dataForHoverCard: point.data,
color: color,
xCalloutValue: point.xAxisCalloutData ? point.xAxisCalloutData : xAxisPoint,
yCalloutValue: point.yAxisCalloutData,
dataPointCalloutProps: point,
});
}
this.setState({
refSelected: ref.refElement,
isCalloutVisible: true,
selectedLegendTitle: point.legend,
dataForHoverCard: point.data,
color: color,
xCalloutValue: point.xAxisCalloutData ? point.xAxisCalloutData : xAxisPoint,
yCalloutValue: point.yAxisCalloutData,
dataPointCalloutProps: point,
});
}
}

private _onStackFocus = (xAxisPoint: string | number): void => {
private _onStackFocus = (xAxisPoint: string | number, groupRef: IRefArrayData): void => {
const found = find(
this._points,
(sinlgePoint: { xAxisPoint: string | number; chartData: IVSChartDataPoint[] }) =>
sinlgePoint.xAxisPoint === xAxisPoint,
);
this._barRefArray.forEach((obj: IBarRef) => {
if (obj.index === xAxisPoint) {
this.setState({
refSelected: obj.refElement,
isCalloutVisible: true,
YValueHover: found!.chartData,
hoverXValue: xAxisPoint,
stackCalloutProps: found!,
});
}
this.setState({
refSelected: groupRef.refElement,
isCalloutVisible: true,
YValueHover: found!.chartData,
hoverXValue: xAxisPoint,
stackCalloutProps: found!,
});
};

Expand All @@ -374,9 +353,9 @@ export class VerticalStackedBarChartBase extends React.Component<
});
};

private _redirectToUrl(): void {
private _redirectToUrl = (): void => {
this.props.href ? (window.location.href = this.props.href) : '';
}
};

private _getYMax(dataset: IDataPoint[]) {
return Math.max(d3Max(dataset, (point: IDataPoint) => point.y)!, this.props.yMaxValue || 0);
Expand All @@ -391,10 +370,18 @@ export class VerticalStackedBarChartBase extends React.Component<
let startingPointOfY = 0;
const isCalloutForStack = this.props.isCalloutForStack || false;

const singleBar = singleChartData.chartData.map((point: IVSChartDataPoint, index: number) => {
let xPoint: number | string;
if (this._isNumeric) {
xPoint = xBarScale(singleChartData.xAxisPoint as number);
} else {
xPoint = xBarScale(indexNumber);
}
// Removing datapoints with zero data
const nonZeroBars = singleChartData.chartData.filter(point => point.data > 0);
const singleBar = nonZeroBars.map((point: IVSChartDataPoint, index: number) => {
startingPointOfY = startingPointOfY + point.data;
const color = point.color ? point.color : this._colors[index];
const refArrayIndexNumber = indexNumber * singleChartData.chartData.length + index;
const ref: IRefArrayData = {};

let shouldHighlight = true;
if (this.state.isLegendHovered || this.state.isLegendSelected) {
Expand All @@ -405,20 +392,13 @@ export class VerticalStackedBarChartBase extends React.Component<
shouldHighlight: shouldHighlight,
href: this.props.href,
});
let xPoint;
if (this._isNumeric) {
xPoint = xBarScale(singleChartData.xAxisPoint as number);
} else {
xPoint = xBarScale(indexNumber);
}

const rectFocusProps = !isCalloutForStack && {
'data-is-focusable': true,
'aria-labelledby': this._calloutId,
onMouseOver: this._onRectHover.bind(this, singleChartData.xAxisPoint, point),
onMouseMove: this._onRectHover.bind(this, singleChartData.xAxisPoint, point),
onMouseLeave: this._handleMouseOut,
onFocus: this._onRectFocus.bind(this, point, singleChartData.xAxisPoint, color, refArrayIndexNumber),
onFocus: this._onRectFocus.bind(this, point, singleChartData.xAxisPoint, color, ref),
onBlur: this._handleMouseOut,
onClick: this._redirectToUrl,
};
Expand All @@ -431,19 +411,18 @@ export class VerticalStackedBarChartBase extends React.Component<
width={this._barWidth}
height={Math.max(yBarScale(point.data), 0)}
fill={color}
ref={(e: SVGRectElement) => {
this._refCallback(e, point.legend, refArrayIndexNumber);
}}
ref={e => (ref.refElement = e)}
{...rectFocusProps}
/>
);
});
const groupRef: IRefArrayData = {};
const stackFocusProps = isCalloutForStack && {
'data-is-focusable': true,
onMouseOver: this._onStackHover.bind(this, singleChartData.xAxisPoint),
onMouseMove: this._onStackHover.bind(this, singleChartData.xAxisPoint),
onMouseLeave: this._handleMouseOut,
onFocus: this._onStackFocus.bind(this, singleChartData.xAxisPoint),
onFocus: this._onStackFocus.bind(this, singleChartData.xAxisPoint, groupRef),
onBlur: this._handleMouseOut,
onClick: this._redirectToUrl,
};
Expand All @@ -452,9 +431,7 @@ export class VerticalStackedBarChartBase extends React.Component<
key={indexNumber}
id={`${indexNumber}-singleBar`}
data-is-focusable={this.props.isCalloutForStack}
ref={(gElement: SVGGElement) => {
this._barRefCallback(gElement, indexNumber, singleChartData.xAxisPoint);
}}
ref={e => (groupRef.refElement = e)}
{...stackFocusProps}
>
{singleBar}
Expand All @@ -471,10 +448,7 @@ export class VerticalStackedBarChartBase extends React.Component<
const xBarScale = d3ScaleLinear()
.domain(this._isRtl ? [xMax, 0] : [0, xMax])
.nice()
.range([
this.margins.left!,
containerWidth - this.margins.right! - this._barWidth - (this._isRtl ? additionalMarginRight : 0),
]);
.range([this.margins.left!, containerWidth - this.margins.right! - this._barWidth]);
const yBarScale = d3ScaleLinear()
.domain([0, yMax])
.range([0, containerHeight - this.margins.bottom! - this.margins.top!]);
Expand All @@ -485,16 +459,11 @@ export class VerticalStackedBarChartBase extends React.Component<
private _createStringBars = (containerHeight: number, containerWidth: number): JSX.Element[] => {
const yMax = this._getYMax(this._dataset);
const endpointDistance = 0.5 * ((containerWidth - this.margins.right!) / this._dataset.length);

const xBarScale = d3ScaleLinear()
.domain(this._isRtl ? [this._dataset.length - 1, 0] : [0, this._dataset.length - 1])
.range([
this.margins.left! + endpointDistance - 0.5 * this._barWidth,
containerWidth -
this.margins.right! -
endpointDistance -
0.5 * this._barWidth -
(this._isRtl ? additionalMarginRight : 0),
containerWidth - this.margins.right! - endpointDistance - 0.5 * this._barWidth,
]);
const yBarScale = d3ScaleLinear()
.domain([0, yMax])
Expand Down
Loading