export function shapeViewModel()

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,
  };
}