Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

added prop rotateAngle to avoid the overlapping x-axis tick values #322

Merged
merged 10 commits into from
Nov 24, 2023
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
3 changes: 3 additions & 0 deletions packages/carbon-graphs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added prop `tickLabelsRotation` to allow rotation of x-axis tick labels to prevent overlap.

## 2.23.3 - (September 25, 2023)

* Fixed
Expand Down
5 changes: 5 additions & 0 deletions packages/carbon-graphs/src/js/controls/Graph/Graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ const beforeInit = (control) => {
console.warn('allowCalibration for x-axis is a new feature that is currently a work in progress and may have stability issues. Use it at your own risk.');
getAxesDataRange({}, constants.X_AXIS, control.config);
}
const isInvalidTickLabelRotations = !utils.isDefined(control.config.axis.x.ticks.tickLabelsRotation) || !utils.validTickLabelRotations.has(control.config.axis.x.ticks.tickLabelsRotation);
if (isInvalidTickLabelRotations) {
control.config.axis.x.ticks.tickLabelsRotation = 0;
console.warn(`${control.config.axis.x.ticks.tickLabelsRotation} is an invalid value for tickLabelsRotation. Valid values are: 0, -45. Resorting to the default value of 0`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add a condition where if config.axis.x.ticks.tickLabelsRotation is undefined, then it should be set to 0 as the default value.


updateAxesDomain(control.config);
updateXAxisDomain(control.config);
Expand Down
39 changes: 35 additions & 4 deletions packages/carbon-graphs/src/js/helpers/axis.js
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,25 @@ const createAxes = (axis, scale, config, canvasSVG) => {
)})`,
)
.call(axis.x)
.call(resetD3FontSize);
.call(resetD3FontSize)
.attr('id', 'x')
.selectAll('text')
.style('text-anchor', () => {
if (!utils.isDefined(config.axis.x.ticks.tickLabelsRotation)) {
config.axis.x.ticks.tickLabelsRotation = 0;
return 'middle';
}
const rotation = config.axis.x.ticks.tickLabelsRotation;
if (rotation === 0) {
return 'middle';
} if (rotation !== 0) {
return 'end';
} if (!utils.validTickLabelRotations.has(rotation)) {
return 'middle';
}
return 'middle';
sdadn marked this conversation as resolved.
Show resolved Hide resolved
})
.attr('transform', () => `rotate(${config.axis.x.ticks.tickLabelsRotation})`);
canvasSVG
.append('g')
.classed(styles.axis, true)
Expand Down Expand Up @@ -922,7 +940,6 @@ const createAxes = (axis, scale, config, canvasSVG) => {
.call(resetD3FontSize);
}
};

/**
* X Axis's position vertically relative to the canvas
*
Expand Down Expand Up @@ -1122,6 +1139,13 @@ const getXAxisHeight = (config) => {
const dummy = d3.select('body').append('div');
const svg = dummy.append('svg');
const group = svg.append('g').call(axis);
if (config.axis.x.ticks && config.axis.x.ticks.tickLabelsRotation !== 0) {
// Add extra padding for rotated tick labels
group.selectAll('.tick text').attr('transform', `rotate(${config.axis.x.ticks.tickLabelsRotation})`);
const rotatedTickLabelsHeight = group.node().getBoundingClientRect().height;
dummy.remove();
return rotatedTickLabelsHeight;
}
const { height } = group.node().getBoundingClientRect();
dummy.remove();
return height;
Expand Down Expand Up @@ -1205,10 +1229,16 @@ const getAxisLabelWidth = (label, axis, config) => {
* @param {string} label - Label text
* @returns {number} label height
*/
const getAxisLabelHeight = (label) => {
const getAxisLabelHeight = (label, tickLabelsRotation) => {
const dummy = d3.select('body').append('div');
const svg = dummy.append('svg');
const grouper = svg.append('g');

if (tickLabelsRotation) {
// Adding extra padding for rotated labels
grouper.attr('transform', `rotate(${tickLabelsRotation * constants.DEFAULT_OVERLAPPING_PADDING})`);
}

buildAxisLabel(grouper, label);
const { height } = grouper.node().getBoundingClientRect();
dummy.remove();
Expand Down Expand Up @@ -1293,7 +1323,8 @@ const calculateAxesLabelSize = (config) => {
config.axisLabelWidths.y2 = 0;
if (config.showLabel) {
if (config.axis.x.label) {
config.axisLabelHeights.x = getAxisLabelHeight(config.axis.x.label);
const tickLabelsRotation = config.axis.x.ticks && config.axis.x.ticks.tickLabelsRotation;
config.axisLabelHeights.x = getAxisLabelHeight(config.axis.x.label, tickLabelsRotation);
}
if (config.axis.y.label) {
config.axisLabelWidths.y = constants.DEFAULT_CHARACTER_SVG_ELEMENT_WIDTH;
Expand Down
1 change: 1 addition & 0 deletions packages/carbon-graphs/src/js/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,5 @@ export default {
DEFAULT_LEGEND_LINE_WIDTH: 28,
DEFAULT_LEGEND_LINE_WIDTH_WITH_SYMBOL: 18,
LEGEND_LINE_POSITION: 1.5,
DEFAULT_OVERLAPPING_PADDING: 0.55,
};
7 changes: 7 additions & 0 deletions packages/carbon-graphs/src/js/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ const getEpocFromDateString = (dateISO) => parseInt(new Date(dateISO).getTime(),
* @returns {object typeof Date} - Date object based on epoc
*/
const getDateFromEpoc = (epocDate) => new Date(epocDate);
/**
* Enum for tick label rotations.
* @readonly
* @enum {number}
*/
const validTickLabelRotations = new Set([0, -45]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


/**
* @enum {Function}
Expand All @@ -242,4 +248,5 @@ export default {
notEmpty,
parseDateTime,
sanitize,
validTickLabelRotations,
};
10 changes: 4 additions & 6 deletions packages/carbon-graphs/tests/unit/controls/Graph/Graph-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,15 +361,13 @@ describe('Graph', () => {
expect(graph.config.showVGrid).toEqual(true);
expect(graph.config.dimension).toEqual({});
expect(graph.config.axis.x.type).toEqual(AXIS_TYPE.DEFAULT);
expect(graph.config.axis.x.ticks).toEqual({});
expect(graph.config.axis.x.ticks).toEqual({ tickLabelsRotation: 0 });
expect(graph.config.axis.x.rangeRounding).toEqual(true);
expect(graph.config.axis.y.ticks).toEqual({});
expect(graph.config.axis.y.rangeRounding).toEqual(true);
expect(graph.config.axis.x.show).toEqual(true);
expect(graph.config.axis.y.show).toEqual(true);
expect(graph.config.axis.x.orientation).toEqual(
AXES_ORIENTATION.X.BOTTOM,
);
expect(graph.config.axis.x.orientation).toEqual(AXES_ORIENTATION.X.BOTTOM);
expect(graph.config.axisPadding.y).toEqual(true);
expect(graph.config.axisInfoRowLabelHeight).toEqual(0);
});
Expand Down Expand Up @@ -454,7 +452,7 @@ describe('Graph', () => {
expect(graph.config.dimension).toEqual({});
expect(graph.config.axis.x.type).toEqual(AXIS_TYPE.TIME_SERIES);
expect(graph.config.axis.x.rangeRounding).toEqual(true);
expect(graph.config.axis.x.ticks).toEqual({});
expect(graph.config.axis.x.ticks).toEqual({ tickLabelsRotation: 0 });
expect(graph.config.axis.y.ticks).toEqual({});
expect(graph.config.axis.y.rangeRounding).toEqual(true);
expect(graph.config.axis.x.show).toEqual(true);
Expand Down Expand Up @@ -857,7 +855,7 @@ describe('Graph', () => {
expect(graph.config.showVGrid).toEqual(true);
expect(graph.config.dimension).toEqual({});
expect(graph.config.axis.x.type).toEqual(AXIS_TYPE.DEFAULT);
expect(graph.config.axis.x.ticks).toEqual({});
expect(graph.config.axis.x.ticks).toEqual({ tickLabelsRotation: 0 });
expect(graph.config.axis.y.ticks).toEqual({});
expect(graph.config.axis.x.show).toEqual(true);
expect(graph.config.axis.y.show).toEqual(true);
Expand Down
48 changes: 48 additions & 0 deletions packages/carbon-graphs/tests/unit/controls/Graph/GraphAxes-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2931,6 +2931,54 @@ describe('Graph - Axes', () => {
});
});
});
describe('Tick Labels Rotation', () => {
it('tickLabelsRotation values will be 0', () => {
const localeAxisObj = utils.deepClone(axisTimeSeries);
localeAxisObj.x = {
type: 'timeseries',
label: 'Some X Label',
lowerLimit: new Date(2017, 0).toISOString(),
upperLimit: new Date(2017, 6).toISOString(),
};
localeAxisObj.x.ticks = {
tickLabelsRotation: 0,
};
graph = new Graph(getAxes(localeAxisObj));
expect(graph.config.axis.x.ticks.tickLabelsRotation).toBe(0);
});
it('tickLabelsRotation values will be -45', () => {
const localeAxisObj = utils.deepClone(axisTimeSeries);
localeAxisObj.x = {
type: 'timeseries',
label: 'Some X Label',
lowerLimit: new Date(2017, 0).toISOString(),
upperLimit: new Date(2017, 6).toISOString(),
};
localeAxisObj.x.ticks = {
tickLabelsRotation: -45,
};
graph = new Graph(getAxes(localeAxisObj));
expect(graph.config.axis.x.ticks.tickLabelsRotation).toBe(-45);
});
it('uses the default value of zero of tickLabelsRotation it is invalid', () => {
const localeAxisObj = utils.deepClone(axisTimeSeries);
localeAxisObj.x.ticks = {
tickLabelsRotation: 23,
};
graph = new Graph(getAxes(localeAxisObj));

expect(graph.config.axis.x.ticks.tickLabelsRotation).toBe(0);
});
it('uses the default value of zero if tickLabelsRotation is undefind', () => {
const localeAxisObj = utils.deepClone(axisTimeSeries);
localeAxisObj.x.ticks = {
// tickLabelsRotation is undefind
};
graph = new Graph(getAxes(localeAxisObj));

expect(graph.config.axis.x.ticks.tickLabelsRotation).toBe(0);
});
});
describe('when graph is destroyed', () => {
it('should remove div element for the popup tooltip', () => {
if (graph !== null) {
Expand Down
3 changes: 3 additions & 0 deletions packages/terra-graphs-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added examples for the Xaxis Overlapping tick values.

## 1.6.0 - (September 25, 2023)

* Changed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Carbon from '@cerner/carbon-graphs/lib/js/carbon';

const getLineTimeseriesConfig = (id) => ({
bindTo: id,
axis: {
x: {
type: Carbon.helpers.AXIS_TYPE.TIME_SERIES,
label: 'Datetime',
lowerLimit: new Date(2016, 0, 1).toISOString(),
upperLimit: new Date(2016, 0, 12).toISOString(),
ticks: {
values: [
new Date(2016, 0, 1).toISOString(),
new Date(2016, 0, 2).toISOString(),
new Date(2016, 0, 3).toISOString(),
new Date(2016, 0, 4).toISOString(),
new Date(2016, 0, 5).toISOString(),
new Date(2016, 0, 6).toISOString(),
new Date(2016, 0, 7).toISOString(),
new Date(2016, 0, 8).toISOString(),
new Date(2016, 0, 9).toISOString(),
new Date(2016, 0, 10).toISOString(),
new Date(2016, 0, 11).toISOString(),
],
tickLabelsRotation: -45,
format: '%Y, %X',
},
},
y: {
label: 'Line Set A',
lowerLimit: 10,
upperLimit: 30,
},
y2: {
show: false,
label: 'Line Set B',
lowerLimit: 0,
upperLimit: 250,
},
},
showLabel: true,
showLegend: true,
showShapes: true,
showVGrid: true,
showHGrid: true,
locale: Carbon.helpers.LOCALE.en_US,
});

export default getLineTimeseriesConfig;
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ axis: {
suppressingTrailingZeros: <bool>,
ticks: <Ticks object>,
type: <string>
rotateAngle: <integer>,
},
y: {
lowerLimit: <number> or <Date>,
Expand Down Expand Up @@ -80,7 +81,8 @@ axis: {
| show | boolean | `true` | no | Toggle for showing the axis. |
| suppressTrailingZeros | boolean | `false` | no | Toggle to suppress tick values's trailing zeros when default d3 tick formatting is used. For X axis, this property works only when X axis type is set to AXIS_TYPE.DEFAULT. Specifying `~` in the tick format takes precedence over `suppressTrailingZeros` property. |
| ticks | object | `null` | no | See [Ticks](./Ticks). |
| type | string | `AXIS_TYPE.DEFAULT` | no | See [type](#type). Normal number value or time-based. Only for x-axis. |
| type | string | `AXIS_TYPE.DEFAULT` | no | See [type](#type). Normal number value or time-based. Only for x-axis. |
| tickLabelsRotation | integer | - | no | Sets the rotation of the x-axis tick labels to `0º` or `-45º`. Accepted values: 0 or -45. Only for x-axis. |

- ### `allowCalibration`
Set calibration for the axis.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import LineGraph from '../../../example/Graphs-Carbon/General/Axes/XAxisTickLabelOrientation?dev-site-example';
import GraphConfig from '@cerner/terra-graphs-docs/lib/example-datasets/graphConfigObjects/General/generalDefaultXAxisOverlapping.js?dev-site-codeblock';
require('details-polyfill');

# X-Axis Tick Label orientation

This is a simple timeseries line graph with x-axis ticks label orientation `tickLabelsRotation = -45`. Tick label rotation is used to prevent labels from overlapping in a narrow viewport or due to long tick labels.

## Getting Started

- Install with [npmjs](https://www.npmjs.com):
- `npm i @cerner/carbon-graphs --save-dev`

## Usage
```js
import Carbon from '@cerner/carbon-graphs/dist/js/carbon-graphs.js';
import '@cerner/carbon-graphs/dist/css/carbon-graphs.css';
```

## Example
<LineGraph />

<details>
<summary style={{fontSize: 24 }}>
<b>Data</b>
</summary>

### Graph Config object
<GraphConfig />

</details>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import Carbon from '@cerner/carbon-graphs/lib/js/carbon';
import utils from '@cerner/carbon-graphs/lib/js/helpers/utils';
import '@cerner/terra-graphs-docs/lib/terra-graphs-src/components/Graph.module.scss';
import ExampleGraphContainer from '@cerner/terra-graphs-docs/lib/terra-dev-site/ExampleGraphContainer/ExampleGraphContainer';
import getGraphConfig from '@cerner/terra-graphs-docs/lib/example-datasets/graphConfigObjects/General/generalDefaultXAxisOverlapping';

/*
Please refer to the documentation below to see the graphConfig and data objects
*/

const graphConfig = utils.deepClone(getGraphConfig('#XAxisTickLabelOrientation'));

const XAxisTickLabelOrientationGeneralExample = () => {
React.useEffect(() => {
Carbon.api.graph(graphConfig);
}, []);
return (
<ExampleGraphContainer id="XAxisTickLabelOrientation" />
);
};

export default XAxisTickLabelOrientationGeneralExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import utils from '@cerner/carbon-graphs/lib/js/helpers/utils';
import LineGraph from '@cerner/terra-graphs-docs/lib/terra-graphs-src/components/Line/LineGraph';
import '@cerner/terra-graphs-docs/lib/terra-dev-site/ExampleGraphContainer/ExampleGraphContainer.module.scss';
import getGraphConfig from '@cerner/terra-graphs-docs/lib/example-datasets/graphConfigObjects/General/generalDefaultXAxisOverlapping';
import exampleData from '@cerner/terra-graphs-docs/lib/example-datasets/dataObjects/General/datasetTimeseries1';

const graphConfig = utils.deepClone(getGraphConfig('#xAxisTicksVlauesOverlapping'));
const dataset = [utils.deepClone(exampleData)];

const timeoutArray = [0, 750, 750 * 2, 750 * 3, 750 * 4, 750 * 5, 750 * 6];

export default () => (
<>
<div id="tooltip" className="initial-tooltip" />
<LineGraph graphID="xAxisTicksVlauesOverlapping" graphConfig={graphConfig} dataset={dataset} timeout={timeoutArray} />
;
</>
);
Loading