Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
18 changes: 3 additions & 15 deletions packages/x-charts/src/ChartsRadialGrid/ChartsRadialGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { GridRoot } from './styledComponents';
import { ChartsRotationGrid } from './ChartsRotationGrid';
import { ChartsRadiusGrid } from './ChartsRadiusGrid';
import { useRotationAxes, useRadiusAxes } from '../hooks/useAxis';
import { EPSILON } from '../utils/epsilon';

const useUtilityClasses = ({ classes }: ChartsRadialGridProps) => {
const slots = {
Expand Down Expand Up @@ -67,20 +66,8 @@ function ChartsRadialGrid(inProps: ChartsRadialGridProps) {
const outerRadius = radiusAxisConfig?.scale.range()[1] ?? 0;

const startAngle = rotationAxisConfig?.scale.range()[0] ?? 0;
let endAngle = rotationAxisConfig?.scale.range()[1] ?? 0;

if (rotationAxisConfig.scaleType === 'point') {
// The rotation gap we add between the first and last point.
const dataRotationGap = (2 * Math.PI) / rotationAxisConfig.data!.length;

// The missing angle between the last and first point.
const angleGap = 2 * Math.PI - Math.abs(endAngle - startAngle);
if (Math.abs(angleGap - dataRotationGap) < EPSILON) {
// If they are close enough we close the circle.
// Otherwise it means user deliberately modified the angles and so keep it as it is.
endAngle = startAngle + 2 * Math.PI;
}
}
const endAngle = rotationAxisConfig?.scale.range()[1] ?? 0;
const isFullCircle = rotationAxisConfig?.isFullCircle ?? false;

return (
<GridRoot {...other} className={clsx(classes.root, className)}>
Expand All @@ -98,6 +85,7 @@ function ChartsRadialGrid(inProps: ChartsRadialGridProps) {
axis={radiusAxisConfig}
startAngle={startAngle}
endAngle={endAngle}
isFullCircle={isFullCircle}
classes={classes}
/>
)}
Expand Down
6 changes: 2 additions & 4 deletions packages/x-charts/src/ChartsRadialGrid/ChartsRadiusGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
type UseChartPolarAxisSignature,
} from '../internals/plugins/featurePlugins/useChartPolarAxis';
import { type PolarAxisDefaultized } from '../models/axis';
import { EPSILON } from '../utils/epsilon';

interface ChartsRadiusGridProps {
axis: PolarAxisDefaultized<any, any, any>;
startAngle: number;
endAngle: number;
isFullCircle: boolean;
classes: Partial<ChartsRadialGridClasses>;
}

Expand All @@ -22,7 +22,7 @@ interface ChartsRadiusGridProps {
*/
export function ChartsRadiusGrid(props: ChartsRadiusGridProps) {
const { store } = useChartsContext<[UseChartPolarAxisSignature]>();
const { axis, startAngle, endAngle, classes } = props;
const { axis, startAngle, endAngle, isFullCircle, classes } = props;
const { cx, cy } = store.use(selectorChartPolarCenter);

const { scale, tickNumber, tickInterval, tickSpacing } = axis;
Expand All @@ -35,8 +35,6 @@ export function ChartsRadiusGrid(props: ChartsRadiusGridProps) {
direction: 'radius',
});

const isFullCircle = Math.abs(endAngle - startAngle) >= 2 * Math.PI - EPSILON;

if (isFullCircle) {
return (
<React.Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { deg2rad } from '../../../angleConversion';
import { getAxisTriggerTooltip } from './getAxisTriggerTooltip';
import { scaleBand, scalePoint } from '../../../scales';
import { type ComputedAxisConfig } from '../useChartCartesianAxis';
import { EPSILON } from '../../../../utils/epsilon';

export type DefaultizedAxisConfig<
AxisProps extends ChartsRotationAxisProps | ChartsRadiusAxisProps,
Expand All @@ -40,30 +41,28 @@ function getRange(
drawingArea: ChartDrawingArea,
axisDirection: 'rotation' | 'radius',
axis: PolarAxisConfig<ScaleName, any>,
) {
): { range: number[]; isFullCircle: boolean } {
if (axisDirection === 'rotation') {
if (axis.scaleType === 'point') {
const angles = [
deg2rad((axis as RotationConfig).startAngle, 0),
deg2rad((axis as RotationConfig).endAngle, 2 * Math.PI),
];
const diff = angles[1] - angles[0];
if (diff > Math.PI * 2 - 0.1) {
// If we cover a full circle, we remove a slice to avoid having data point at the same place.
angles[1] -= diff / axis.data!.length;
}
return angles;
}
return [
const angles = [
deg2rad((axis as RotationConfig).startAngle, 0),
deg2rad((axis as RotationConfig).endAngle, 2 * Math.PI),
];
const diff = angles[1] - angles[0];
const isFullCircle = diff >= Math.PI * 2 - EPSILON;
if (axis.scaleType === 'point' && diff > Math.PI * 2 - 0.1) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
if (axis.scaleType === 'point' && diff > Math.PI * 2 - 0.1) {
if (axis.scaleType === 'point' && isFullCircle) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Applied in 9f9196917. Thanks for catching it.

// For point scale, remove a slice to avoid overlapping first and last points.
angles[1] -= diff / axis.data!.length;
}
return { range: angles, isFullCircle };
}
const availableRadius = Math.min(drawingArea.height, drawingArea.width) / 2;
return [
(axis as RadiusConfig).minRadius ?? 0,
(axis as RadiusConfig).maxRadius ?? availableRadius,
];
return {
range: [
(axis as RadiusConfig).minRadius ?? 0,
(axis as RadiusConfig).maxRadius ?? availableRadius,
],
isFullCircle: false,
};
}

const DEFAULT_CATEGORY_GAP_RATIO = 0.2;
Expand Down Expand Up @@ -119,7 +118,7 @@ export function computeAxisValue<SeriesType extends ChartSeriesType>({
const completeAxis: DefaultizedAxisConfig<ChartsAxisProps> = {};
allAxis.forEach((eachAxis, axisIndex) => {
const axis = eachAxis as Readonly<AxisConfig<ScaleName, any, Readonly<ChartsAxisProps>>>;
const range = getRange(drawingArea, axisDirection, axis);
const { range, isFullCircle } = getRange(drawingArea, axisDirection, axis);

const [minData, maxData] = getAxisExtremum(
axis,
Expand Down Expand Up @@ -153,6 +152,7 @@ export function computeAxisValue<SeriesType extends ChartSeriesType>({
(axis.colorMap.type === 'ordinal'
? getOrdinalColorScale({ values: axis.data, ...axis.colorMap })
: getColorScale(axis.colorMap)),
isFullCircle,
};

if (isDateData(axis.data)) {
Expand All @@ -173,6 +173,7 @@ export function computeAxisValue<SeriesType extends ChartSeriesType>({
(axis.colorMap.type === 'ordinal'
? getOrdinalColorScale({ values: axis.data, ...axis.colorMap })
: getColorScale(axis.colorMap)),
isFullCircle,
};

if (isDateData(axis.data)) {
Expand Down Expand Up @@ -223,6 +224,7 @@ export function computeAxisValue<SeriesType extends ChartSeriesType>({
scale: finalScale.domain(domain) as any,
tickNumber,
colorScale: axis.colorMap && getColorScale(axis.colorMap),
isFullCircle,
};
});
return {
Expand Down
4 changes: 4 additions & 0 deletions packages/x-charts/src/models/axis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,8 @@ export type PolarAxisDefaultized<
* If true, the contents of the axis will be displayed by a tooltip with `trigger='axis'`.
*/
triggerTooltip?: boolean;
/** @ignore - internal. True when a rotation axis covers a full circle. */
isFullCircle?: boolean;
};
Comment on lines 611 to 612
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this one necessary?

The isFullCircle is only added in the computed axis

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried removing it and TypeScript breaks at the three write sites in computeAxisValue.ts (the completeAxis[axis.id] = { ..., isFullCircle } literals in the band, point, and continuous branches). completeAxis is typed DefaultizedAxisConfig<ChartsAxisProps> -> PolarAxisDefaultized, so the object literal hits the excess-property check if the field isn't declared there.

The reads go through ComputedAxis and the writes go through PolarAxisDefaultized, so both need it. Happy to remove it from PolarAxisDefaultized if you'd prefer to widen the write site with a cast though I'd lean toward keeping both since the @ignore - internal keeps it out of the public surface either way.


export type ComputedAxis<
Expand All @@ -626,6 +628,8 @@ export type ComputedAxis<
* Indicate if the axis should be consider by a tooltip with `trigger='axis'`.
*/
triggerTooltip?: boolean;
/** @ignore - internal. True when a rotation axis covers a full circle. */
isFullCircle?: boolean;
} & (AxisProps extends ChartsXAxisProps
? AxisSideConfig<AxisProps> & { height: number }
: AxisProps extends ChartsYAxisProps
Expand Down
Loading