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