Skip to content

Commit

Permalink
Charting: Vertical stacked bar chart minor changes including uncaught…
Browse files Browse the repository at this point in the history
… type error issue fix. (#15447)

* Vertical stacked bar chart minor edits

* Change files

* change files

* margins default description added and minor changes to cartesian margins

* lint warnings

* Non zero data, ref values updated

Co-authored-by: Jameela Kowsar Shaik (Zen3 Infosolutions America Inc) <v-jasha@microsoft.com>
  • Loading branch information
jameelakowsar and Jameela Kowsar Shaik (Zen3 Infosolutions America Inc) authored Oct 14, 2020
1 parent a6d0ce7 commit 8828fdc
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 89 deletions.
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": "v-jasha@microsoft.com",
"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": "v-jasha@microsoft.com",
"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

0 comments on commit 8828fdc

Please sign in to comment.