private buildDonutGraph()

in app/scripts/modules/netflix/availability/availability.donut.component.ts [74:159]


  private buildDonutGraph(): IDonutGraphData {
    const currentNines = Math.min(this.nines, maxNines);
    const angle = this.scaleTargets(currentNines, true);
    const arcs: IArcData[] = [
      // Availability arc
      {
        path: this.arc({
          startAngle: 0,
          endAngle: angle,
          innerRadius: this.outerRadius * this.donutWidthPercent,
          outerRadius: this.outerRadius,
          padAngle: 0
        }),
        score: this.score
      },
      // Empty arc
      {
        path: this.arc({
          startAngle: angle,
          endAngle: Math.PI * 2,
          innerRadius: this.outerRadius * this.donutWidthPercent,
          outerRadius: this.outerRadius,
          padAngle: 0
        }),
        score: 0
      }
    ];

    // Total donut (needed for a clean border)
    // Build a donut graph with one slice for the availability and one slice
    // for the empty space, then create a separate whole donut to fake a border.
    // If we add strokes to the paths, then there's a stroke on the connecting sides,
    // which we don't want. If I create a donut with the empty color that fills the
    // whole donut, then give _that_ a stroke, anti-aliasing ruins the border near
    // the availability score.
    const total = this.arc({
      startAngle: 0,
      endAngle: 2 * Math.PI,
      innerRadius: this.outerRadius * this.donutWidthPercent - 2,
      outerRadius: this.outerRadius + 2,
      padAngle: 0
    });

    // Figure out rotations needed for target inflection markers
    const radius = this.outerRadius + 5;
    const tHeight = 8;
    const tWidth = 7;

    const targetArrowPath = `M 0 -${radius} L -${tWidth / 2} -${radius + tHeight} L ${tWidth / 2} -${radius + tHeight} L 0 -${radius}`;
    const targetRotation = this.scaleTargets(this.targetNines);
    const targetUnderRotation = this.scaleTargets(this.targetNines * 0.95);
    const targetAngle = this.scaleTargets(this.targetNines, true) - (Math.PI / 2);
    const targetUnderAngle = this.scaleTargets(this.targetNines * 0.95, true) - (Math.PI / 2);

    const labelRadius = radius + tHeight + 3;
    const targets: ITargetData[] = [
      {
        availability: this.targetNines,
        rotation: targetRotation,
        path: targetArrowPath,
        labelPosition: [
          labelRadius * Math.cos(targetAngle),
          labelRadius * Math.sin(targetAngle)
        ],
        score: 1
      },
      {
        availability: (this.targetNines * 0.95),
        rotation: targetUnderRotation,
        path: targetArrowPath,
        labelPosition: [
          labelRadius * Math.cos(targetUnderAngle),
          labelRadius * Math.sin(targetUnderAngle)
        ],
        score: 2
      }
    ];

    return {
      arcs: arcs,
      total: total,
      targets: targets,
      width: this.outerRadius * 2.5,
      height: this.outerRadius * 2.5
    };
  }