/// <summary> /// Calculate the values needed to properly display this <see cref="PieItem"/>. /// </summary> /// <param name="pane"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="maxDisplacement">maximum slice displacement</param> private static void CalculatePieChartParams(GraphPane pane, ref double maxDisplacement) { string lblStr = " "; //loop thru slices and get total value and maxDisplacement double pieTotalValue = 0; foreach (PieItem curve in pane.CurveList) { if (curve.IsPie) { pieTotalValue += curve._pieValue; if (curve.Displacement > maxDisplacement) { maxDisplacement = curve.Displacement; } } } double nextStartAngle = 0; //now loop thru and calculate the various angle values foreach (PieItem curve in pane.CurveList) { lblStr = curve._labelStr; curve.StartAngle = (float)nextStartAngle; curve.SweepAngle = (float)(360 * curve.Value / pieTotalValue); curve.MidAngle = curve.StartAngle + curve.SweepAngle / 2; nextStartAngle = curve._startAngle + curve._sweepAngle; PieItem.BuildLabelString(curve); } }
/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The <see cref="PieItem"/> object from which to copy</param> public PieItem(PieItem rhs) : base(rhs) { _pieValue = rhs._pieValue; _fill = rhs._fill.Clone(); this.Border = rhs._border.Clone(); _displacement = rhs._displacement; _labelDetail = rhs._labelDetail.Clone(); _labelType = rhs._labelType; _valueDecimalDigits = rhs._valueDecimalDigits; _percentDecimalDigits = rhs._percentDecimalDigits; }
/// <summary> /// Build the string that will be displayed as the slice label as determined by /// <see cref="LabelType"/>. /// </summary> /// <param name="curve">reference to the <see cref="PieItem"/></param> private static void BuildLabelString(PieItem curve) { //set up label string formatting NumberFormatInfo labelFormat = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone(); labelFormat.NumberDecimalDigits = curve._valueDecimalDigits; labelFormat.PercentPositivePattern = 1; //no space between number and % sign labelFormat.PercentDecimalDigits = curve._percentDecimalDigits; switch (curve._labelType) { case PieLabelType.Value: curve._labelStr = curve._pieValue.ToString("F", labelFormat); break; case PieLabelType.Percent: curve._labelStr = (curve._sweepAngle / 360).ToString("P", labelFormat); break; case PieLabelType.Name_Value: curve._labelStr = curve._label._text + ": " + curve._pieValue.ToString("F", labelFormat); break; case PieLabelType.Name_Percent: curve._labelStr = curve._label._text + ": " + (curve._sweepAngle / 360).ToString("P", labelFormat); break; case PieLabelType.Name_Value_Percent: curve._labelStr = curve._label._text + ": " + curve._pieValue.ToString("F", labelFormat) + " (" + (curve._sweepAngle / 360).ToString("P", labelFormat) + ")"; break; case PieLabelType.Name: curve._labelStr = curve._label._text; break; case PieLabelType.None: default: break; } }
/// <summary> ///Creates all the <see cref="PieItem"/>s for a single Pie Chart. /// </summary> /// <param name="values">double array containing all <see cref="PieItem.Value"/>s /// for a single PieChart. /// </param> /// <param name="labels"> string array containing all <see cref="CurveItem.Label"/>s /// for a single PieChart. /// </param> /// <returns>an array containing references to all <see cref="PieItem"/>s comprising /// the Pie Chart.</returns> public PieItem[] AddPieSlices( double[] values, string[] labels ) { PieItem[] slices = new PieItem[values.Length]; for ( int x = 0; x < values.Length; x++ ) { slices[x] = new PieItem( values[x], labels[x] ); this.CurveList.Add( slices[x] ); } return slices; }
/// <summary> /// Add a <see cref="PieItem"/> to the display, providing a gradient fill for the pie color. /// </summary> /// <param name="value">The value associated with this <see cref="PieItem"/> instance.</param> /// <param name="color1">The starting display color for the gradient <see cref="Fill"/> for this /// <see cref="PieItem"/> instance.</param> /// <param name="color2">The ending display color for the gradient <see cref="Fill"/> for this /// <see cref="PieItem"/> instance.</param> /// <param name="fillAngle">The angle for the gradient <see cref="Fill"/>.</param> /// <param name="displacement">The amount this <see cref="PieItem"/> instance will be /// displaced from the center point.</param> /// <param name="label">Text label for this <see cref="PieItem"/> instance.</param> public PieItem AddPieSlice( double value, Color color1, Color color2, float fillAngle, double displacement, string label ) { PieItem slice = new PieItem( value, color1, color2, fillAngle, displacement, label ); this.CurveList.Add( slice ); return slice; }
/// <summary> /// Build the string that will be displayed as the slice label as determined by /// <see cref="LabelType"/>. /// </summary> /// <param name="curve">reference to the <see cref="PieItem"/></param> private static void BuildLabelString( PieItem curve ) { //set up label string formatting NumberFormatInfo labelFormat = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone(); labelFormat.NumberDecimalDigits = curve._valueDecimalDigits; labelFormat.PercentPositivePattern = 1; //no space between number and % sign labelFormat.PercentDecimalDigits = curve._percentDecimalDigits; switch ( curve._labelType ) { case PieLabelType.Value: curve._labelStr = curve._pieValue.ToString( "F", labelFormat ); break; case PieLabelType.Percent: curve._labelStr = ( curve._sweepAngle / 360 ).ToString( "P", labelFormat ); break; case PieLabelType.Name_Value: curve._labelStr = curve._label._text + ": " + curve._pieValue.ToString( "F", labelFormat ); break; case PieLabelType.Name_Percent: curve._labelStr = curve._label._text + ": " + ( curve._sweepAngle / 360 ).ToString( "P", labelFormat ); break; case PieLabelType.Name_Value_Percent: curve._labelStr = curve._label._text + ": " + curve._pieValue.ToString( "F", labelFormat ) + " (" + ( curve._sweepAngle / 360 ).ToString( "P", labelFormat ) + ")"; break; case PieLabelType.Name: curve._labelStr = curve._label._text; break; case PieLabelType.None: default: break; } }
/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The <see cref="PieItem"/> object from which to copy</param> public PieItem( PieItem rhs ) : base(rhs) { _pieValue = rhs._pieValue; _fill = rhs._fill.Clone(); this.Border = rhs._border.Clone(); _displacement = rhs._displacement; _labelDetail = rhs._labelDetail.Clone(); _labelType = rhs._labelType; _valueDecimalDigits = rhs._valueDecimalDigits; _percentDecimalDigits = rhs._percentDecimalDigits; }
/// <summary> /// Calculate the <see cref="RectangleF"/> that will be used to define the bounding rectangle of /// the Pie. /// </summary> /// <remarks>This rectangle always lies inside of the <see cref="Chart.Rect"/>, and it is /// normally a square so that the pie itself is not oval-shaped.</remarks> /// <param name="g"> /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// </param> /// <param name="pane"> /// A reference to the <see cref="GraphPane"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> /// <param name="chartRect">The <see cref="RectangleF"/> (normally the <see cref="Chart.Rect"/>) /// that bounds this pie.</param> /// <returns></returns> public static RectangleF CalcPieRect(Graphics g, GraphPane pane, float scaleFactor, RectangleF chartRect) { //want to draw the largest pie possible within ChartRect //but want to leave 5% slack around the pie so labels will not overrun clip area //largest pie is limited by the smaller of ChartRect.height or ChartRect.width... //this rect (nonExplRect)has to be re-positioned so that it's in the center of ChartRect. //Where ChartRect is almost a square - low Aspect Ratio -, need to contract pieRect so that there's some //room for labels, if they're visible. double maxDisplacement = 0; RectangleF tempRect; //= new RectangleF(0,0,0,0); RectangleF nonExplRect = chartRect; if (pane.CurveList.IsPieOnly) { if (nonExplRect.Width < nonExplRect.Height) { //create slack rect nonExplRect.Inflate(-(float)0.05F * nonExplRect.Height, -(float)0.05F * nonExplRect.Width); //get the difference between dimensions float delta = (nonExplRect.Height - nonExplRect.Width) / 2; //make a square so we end up with circular pie nonExplRect.Height = nonExplRect.Width; //keep the center point the same nonExplRect.Y += delta; } else { nonExplRect.Inflate(-(float)0.05F * nonExplRect.Height, -(float)0.05F * nonExplRect.Width); float delta = (nonExplRect.Width - nonExplRect.Height) / 2; nonExplRect.Width = nonExplRect.Height; nonExplRect.X += delta; } //check aspect ratio double aspectRatio = chartRect.Width / chartRect.Height; //make an adjustment in rect size,as aspect ratio varies if (aspectRatio < 1.5) { nonExplRect.Inflate(-(float)(.1 * (1.5 / aspectRatio) * nonExplRect.Width), -(float)(.1 * (1.5 / aspectRatio) * nonExplRect.Width)); } //modify the rect to determine if any of the labels need to be wrapped.... //first see if there's any exploded slices and if so, what's the max displacement... //also, might as well get all the display params we can PieItem.CalculatePieChartParams(pane, ref maxDisplacement); if (maxDisplacement != 0) //need new rectangle if any slice exploded { CalcNewBaseRect(maxDisplacement, ref nonExplRect); } foreach (PieItem slice in pane.CurveList) { slice._boundingRectangle = nonExplRect; //if exploded, need to re-calculate rectangle for slice if (slice.Displacement != 0) { tempRect = nonExplRect; slice.CalcExplodedRect(ref tempRect); slice._boundingRectangle = tempRect; } //now get all the other slice specific drawing details, including need for wrapping label slice.DesignLabel(g, pane, slice._boundingRectangle, scaleFactor); } } return(nonExplRect); }