in packages/charts/src/chart_types/goal_chart/layout/viewmodel/viewmodel.ts [19:129]
export function shapeViewModel(spec: GoalSpec, theme: Theme, chartDimensions: Dimensions): ShapeViewModel {
const { width, height } = chartDimensions;
const { chartMargins: margin } = theme;
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const chartCenter = {
x: margin.left + innerWidth / 2,
y: margin.top + innerHeight / 2,
};
const {
subtype,
ticks,
bands,
domain,
bandFillColor,
tickValueFormatter,
labelMajor,
labelMinor,
centralMajor,
centralMinor,
bandLabels,
angleStart,
angleEnd,
} = spec;
const lowestValue = isFiniteNumber(domain.min) ? domain.min : 0;
const highestValue = isFiniteNumber(domain.max) ? domain.max : 1;
const base = clamp(spec.base, lowestValue, highestValue);
const target =
!isNil(spec.target) && spec.target <= highestValue && spec.target >= lowestValue ? spec.target : undefined;
const actual = clamp(spec.actual, lowestValue, highestValue);
const finalTicks = Array.isArray(ticks)
? ticks.filter(isBetween(lowestValue, highestValue))
: new ScaleContinuous(
{
type: 'linear',
domain: [lowestValue, highestValue],
range: [0, 1],
},
{
desiredTickCount: ticks ?? getDesiredTicks(subtype, angleStart, angleEnd),
},
).ticks();
const finalBands = Array.isArray(bands)
? bands.reduce(...clampAll(lowestValue, highestValue))
: new ScaleContinuous(
{
type: 'linear',
domain: [lowestValue, highestValue],
range: [0, 1],
},
{
desiredTickCount: bands ?? getDesiredTicks(subtype, angleStart, angleEnd),
},
).ticks();
const aboveBaseCount = finalBands.filter((b: number) => b > base).length;
const belowBaseCount = finalBands.filter((b: number) => b <= base).length;
const callbackArgs = {
base,
target,
actual,
highestValue,
lowestValue,
aboveBaseCount,
belowBaseCount,
};
const bulletViewModel: BulletViewModel = {
subtype,
base,
target,
actual,
bands: finalBands.map((value: number, index: number) => ({
value,
fillColor: bandFillColor({ value, index, ...callbackArgs }),
text: bandLabels,
})),
ticks: finalTicks.map((value: number, index: number) => ({
value,
text: tickValueFormatter({ value, index, ...callbackArgs }),
})),
labelMajor: typeof labelMajor === 'string' ? labelMajor : labelMajor({ value: NaN, index: 0, ...callbackArgs }),
labelMinor: typeof labelMinor === 'string' ? labelMinor : labelMinor({ value: NaN, index: 0, ...callbackArgs }),
centralMajor:
typeof centralMajor === 'string' ? centralMajor : centralMajor({ value: NaN, index: 0, ...callbackArgs }),
centralMinor:
typeof centralMinor === 'string' ? centralMinor : centralMinor({ value: NaN, index: 0, ...callbackArgs }),
highestValue,
lowestValue,
aboveBaseCount,
belowBaseCount,
angleStart,
angleEnd,
tooltipValueFormatter: () => '',
};
const pickQuads: PickFunction = (x, y) =>
-innerWidth / 2 <= x && x <= innerWidth / 2 && -innerHeight / 2 <= y && y <= innerHeight / 2
? [bulletViewModel]
: [];
return {
theme: theme.goal,
chartCenter,
bulletViewModel,
pickQuads,
};
}