Skip to content

Commit

Permalink
Merge pull request #1568 from ag-grid/imoses/simplify-axis-gusser
Browse files Browse the repository at this point in the history
Simplify code for guessing invalid axes position
  • Loading branch information
alantreadway authored May 10, 2024
2 parents 375d831 + a5528a6 commit c12c616
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export abstract class CartesianAxis<S extends Scale<D, number, any> = Scale<any,
thickness: number = 0;

@Validate(POSITION)
position: AgCartesianAxisPosition = 'left';
position!: AgCartesianAxisPosition;

get direction() {
return ['top', 'bottom'].includes(this.position) ? ChartAxisDirection.X : ChartAxisDirection.Y;
Expand Down
10 changes: 6 additions & 4 deletions packages/ag-charts-community/src/chart/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { Keyboard } from './keyboard';
import { makeKeyboardPointerEvent } from './keyboardUtil';
import { Layers } from './layers';
import type { CategoryLegendDatum, ChartLegend, ChartLegendType, GradientLegendDatum } from './legendDatum';
import { AxisPositionGuesser } from './mapping/prepareAxis';
import { guessInvalidPositions } from './mapping/prepareAxis';
import { matchSeriesOptions } from './mapping/prepareSeries';
import { type SeriesOptionsTypes, isAgCartesianChartOptions } from './mapping/types';
import { ModulesManager } from './modulesManager';
Expand Down Expand Up @@ -1933,7 +1933,7 @@ export abstract class Chart extends Observable implements AgChartInstance {
}

private createAxis(options: AgBaseAxisOptions[], skip: string[]): ChartAxis[] {
const guesser: AxisPositionGuesser = new AxisPositionGuesser();
const newAxes: ChartAxis[] = [];
const moduleContext = this.getModuleContext();

for (let index = 0; index < options.length; index++) {
Expand All @@ -1942,10 +1942,12 @@ export abstract class Chart extends Observable implements AgChartInstance {
this.applyAxisModules(axis, axisOptions);
jsonApply(axis, axisOptions, { ...JSON_APPLY_PLUGINS, path: `axes[${index}]`, skip });

guesser.push(axis, axisOptions);
newAxes.push(axis);
}

return guesser.guessInvalidPositions();
guessInvalidPositions(newAxes);

return newAxes;
}

private applyAxisModules(axis: ChartAxis, options: AgBaseAxisOptions) {
Expand Down
78 changes: 20 additions & 58 deletions packages/ag-charts-community/src/chart/mapping/prepareAxis.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,34 @@
import type {
AgBaseAxisOptions,
AgBaseCartesianAxisOptions,
AgCartesianAxisPosition,
AgCartesianAxisType,
} from '../../options/agChartOptions';
import type { AgCartesianAxisPosition } from '../../options/agChartOptions';
import { CartesianAxis } from '../axis/cartesianAxis';
import type { ChartAxis } from '../chartAxis';

const CARTESIAN_AXIS_POSITIONS: AgCartesianAxisPosition[] = ['top', 'right', 'bottom', 'left'];
const CARTESIAN_AXIS_TYPES: AgCartesianAxisType[] = [
'category',
'grouped-category',
'ordinal-time',
'number',
'log',
'time',
];

function hasCartesianAxisPosition(axis: ChartAxis): axis is ChartAxis & { position: AgCartesianAxisPosition } {
const allowedTypes: string[] = CARTESIAN_AXIS_TYPES;
return allowedTypes.includes(axis.type);
}

function isCartesianAxisOptions(options: AgBaseAxisOptions): options is AgBaseCartesianAxisOptions {
const allowedTypes: string[] = CARTESIAN_AXIS_TYPES;
return allowedTypes.includes(options.type);
}
const CartesianAxisPositions: AgCartesianAxisPosition[] = ['top', 'right', 'bottom', 'left'];

function isAxisPosition(position: unknown): position is AgCartesianAxisPosition {
const allowedPositions: string[] = CARTESIAN_AXIS_POSITIONS;
return typeof position === 'string' && allowedPositions.includes(position);
return typeof position === 'string' && CartesianAxisPositions.includes(position as AgCartesianAxisPosition);
}

// If axis[].position, then we cannot always default to the same value. We need
// to default to an 'untaken' position (see AG-9963 for more info).
export class AxisPositionGuesser {
private readonly result: ChartAxis[] = [];
private readonly valid: ChartAxis[] = [];
private readonly invalid: ChartAxis[] = [];
export function guessInvalidPositions(axes: ChartAxis[]) {
const invalidAxes: ChartAxis[] = [];
const usedPositions: AgCartesianAxisPosition[] = [];
const guesses = [...CartesianAxisPositions];

push(axis: ChartAxis, options: AgBaseAxisOptions) {
const { result, valid, invalid } = this;
if (isCartesianAxisOptions(options)) {
if (isAxisPosition(options.position)) {
valid.push(axis);
for (const axis of axes) {
if (axis instanceof CartesianAxis) {
if (isAxisPosition(axis.position)) {
usedPositions.push(axis.position);
} else {
invalid.push(axis);
invalidAxes.push(axis);
}
}

result.push(axis);
}

guessInvalidPositions() {
const takenPosition: (AgCartesianAxisPosition | undefined)[] = this.valid
.filter((v) => hasCartesianAxisPosition(v))
.map((v) => v.position)
.filter((v) => v !== undefined);
const guesses: AgCartesianAxisPosition[] = ['top', 'right', 'bottom', 'left'];
for (const invalidAxis of this.invalid) {
let nextGuess = guesses.pop();
while (takenPosition.includes(nextGuess) && nextGuess !== undefined) {
nextGuess = guesses.pop();
}

if (nextGuess === undefined) break;
invalidAxis.position = nextGuess;
}

return this.result;
for (const axis of invalidAxes) {
let nextGuess: AgCartesianAxisPosition | undefined;
do {
nextGuess = guesses.pop();
} while (nextGuess && usedPositions.includes(nextGuess));
if (nextGuess == null) break;
axis.position = nextGuess;
}
}

0 comments on commit c12c616

Please sign in to comment.