如何根据图表条形大小更改DataPoint标签的颜色?

3
我添加了一个新的图表控件 (System.Windows.Forms.DataVisualiation.Charting),图表类型为柱形图。 要求标签文本必须是白色,并且在柱形值内。因此,我在 DataPoint 对象的 CustomProperties 中设置了 BarLabelStyle=Right,并将 LabelForeColor 设置为白色。 请参见下面的图片。

enter image description here

第二个灰色条中的标签正确显示。而第一个条太小了,白色文本会显示在右侧但不可见。

enter image description here

然而,当条形图太短时,标签文本会被放置在条形图外部,使用白色无法看到文本。 有没有一种方法可以检查标签文本是否绘制在条形图值的外部,以便我可以更改颜色(例如黑色)? 谢谢。

你如何在代码中添加数据点?使用数据绑定吗?经常还是只添加一次?动态地添加? - TaW
我只有2个数据点,我在设计时间设置它们。然后我通过编程设置YValues属性。 - Andrea86
1个回答

4

很不幸,MCChart 在动态表达式方面几乎没有任何功能。

为了解决这个问题,您可以选择以下两种方法:

  • 根据 DataPoints 所具有的 y 值编写代码来设置 ForeColor。可以在添加数据点时或循环遍历所有点时调用函数。- 根据字体、轴范围和标签文本等因素,您可能需要确定某个阈值。

示例:

int p = yourSeries.Points.AddXY(...);
yourSeries.Points[p].LabelForeColor = yourSeries.Points[p].YValues[0] < threshold ?
                                      Color.Black : Color.White;
  • 或者你可以小小作弊一下 ;-)

你可以将LabelBackColor设置为与Series即柱形本身相同的颜色。以下是如何实现:

要访问Series.Color,我们需要调用:

chart.ApplyPaletteColors();

我们现在可以设置

yourSeries.LabelForeColor = Color.White;
yourSeries.LabelBackColor =  yourSeries.Color;

示例:

输入图像描述


更新:

由于无法使用作弊,您需要设置颜色。

挑战在于知道每个标签文本所需的空间大小与条形图拥有的空间大小相比。前者可以测量 (TextRenderer.MeasureString()),后者可以从 y 轴中提取 (Axis.ValueToPixelPosition())。

以下是一个执行此操作的函数;它比我想象中要复杂一些,主要是因为它尝试具有通用性。

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

我可能过于复杂地解释了获取应该显示的文本的方法,你可以决定是否可以简化这个过程以适应你的情况。
注意:必须调用此函数...
每当数据可能已更改时 仅在图表轴完成其布局后(!)
前者很明显,后者则不然。这意味着您不能在添加点之后立即调用该函数!相反,您必须在稍后的某个位置执行它,否则需要获取条形大小的轴函数将无法工作。
MSDN表示它只能在PaintXXX事件中发生;我发现所有鼠标事件都可以工作,还有其他一些事件...
为了保险起见,我将把它放在PostPaint事件中:
private void chart_PostPaint(object sender, ChartPaintEventArgs e)
{
    LabelColors(chart, chart.ChartAreas[0], chart.Series[0]);
}

enter image description here


很遗憾,我不能使用第二种解决方案。 作为要求,我必须将'this.mychart.ChartAreas[0].AxisY.Maximum'设置为两个柱形图中最大的值。 然后,为了定义阈值,我应该计算标签文本的像素大小、柱形图的像素大小并进行比较。 我如何获得这两个值? - Andrea86
1
它运行正常。非常感谢。chart_PostPaint()事件方法是必需的。 :) - Andrea86

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接