Reputation: 149
I added a new chart control (System.Windows.Forms.DataVisualiation.Charting
) with ChartType Bar.
As requirement the label text must be white and into the bar value. Therefore I set the BarLabelStyle=Right
in the CustomProperties
of the DataPoint
objects and the LabelForeColor
to White.
See the below images.
The label in the 2nd gray bar is correctly shown.
The first bar instead is too small and the white text is shown out on the right side but is not visible.
However, when the bar is too short, the label text is positioned outside the bar and the text cannot be seen using white color. Is there a way to check when the label text is drawn outside the bar value so that I can change the color (e.g. black)?
Thanks.
Upvotes: 3
Views: 2389
Reputation: 54433
Unfortunately MCChart
has almost no capacities wrt to dynamic expressions.
To work around you can either..:
ForeColor
depending on the y-value your DataPoints
has. Either right when you add them or in a function that loops over all points, whenever you call it.. - Depending on the Font, the axis range and the label text this could be some threshold number you have to determine.Example:
int p = yourSeries.Points.AddXY(...);
yourSeries.Points[p].LabelForeColor = yourSeries.Points[p].YValues[0] < threshold ?
Color.Black : Color.White;
You can set the LabelBackColor
to have the same color as the Series
, i.e. the bar itself. Here is is how to do that:
To access the Series.Color
we have to call:
chart.ApplyPaletteColors();
Now we can set
yourSeries.LabelForeColor = Color.White;
yourSeries.LabelBackColor = yourSeries.Color;
Example:
Update:
Since you can't use the cheat you will have to set the colors.
The challenge is to know just how much space each label's text needs compared to how much space the bars have. The former can be measured (TextRenderer.MeasureString()
) and the latter can be extracted from the y-axis (Axis.ValueToPixelPosition()
).
Here is a function to do that; it is a little more complicated than I had hoped for, mostly because it tries to be generic..
void LabelColors(Chart chart, ChartArea ca, Series s)
{
if (chart.Series.Count <= 0 || chart.Series[0].Points.Count <= 0) return;
Axis ay = ca.AxisY;
// get the maximum & minimum values
double maxyv = ay.Maximum;
if (maxyv == double.NaN) maxyv = s.Points.Max(v => v.YValues[0]);
double minyv = s.Points.Min(v => v.YValues[0]);
// get the pixel positions of the minimum
int y0x = (int)ay.ValueToPixelPosition(0);
for (int i = 0; i < s.Points.Count; i++)
{
DataPoint dp = s.Points[i];
// pixel position of the bar right
int vx = (int)ay.ValueToPixelPosition(dp.YValues[0]);
// now we knowe the bar's width
int barWidth = vx - y0x;
// find out what the label text actauly is
string t = dp.LabelFormat != "" ?
String.Format(dp.LabelFormat, dp.YValues[0]) : dp.YValues[0].ToString();
string text = dp.Label != "" ? dp.Label : t;
// measure the (formatted) text
SizeF rect = TextRenderer.MeasureText(text, dp.Font);
Console.WriteLine(text);
dp.LabelForeColor = barWidth < rect.Width ? Color.Black : Color.White;
}
}
I may have overcomplicated the way to get at the text that should show; you certainly can decide if you can simplify for your case.
Note: You must call this function..
The former point is obvious, the latter isn't. It means that you can't call the function right after adding your points! Instead you must do it at some later place or else the axis function needed to get the bar size will not work.
MSDN says it can only happen in a PaintXXX
event; I found that all mouse events also work and then some..
To be save I'll put it in the PostPaint
event:
private void chart_PostPaint(object sender, ChartPaintEventArgs e)
{
LabelColors(chart, chart.ChartAreas[0], chart.Series[0]);
}
Upvotes: 4