【问题标题】:How to change the color of the DataPoint label based on the chart bar size?如何根据图表条大小更改 DataPoint 标签的颜色?
【发布时间】:2018-07-11 13:47:47
【问题描述】:

我用 ChartType Bar 添加了一个新的图表控件 (System.Windows.Forms.DataVisualiation.Charting)。 根据要求,标签文本必须为白色并进入条形值。因此,我将DataPoint 对象的CustomProperties 中的BarLabelStyle=RightLabelForeColor 设置为白色。 见下图。

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

但是,当栏太短时,标签文本位于栏外,使用白色无法看到文本。 有没有办法检查标签文本何时绘制在条形值之外,以便我可以更改颜色(例如黑色)?

谢谢。

【问题讨论】:

  • 如何添加数据点?在代码中?数据绑定?经常还是只有一次?动态的?
  • 我只有 2 个数据点,我在设计时设置了它们。然后我以编程方式设置 YValues 属性。

标签: c# charts


【解决方案1】:

不幸的是,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]);
}

【讨论】:

  • 不幸的是我不能使用第二种解决方案。作为要求,我必须将 'this.mychart.ChartAreas[0].AxisY.Maximum' 设置为两个栏的最大值。然后要定义阈值,我应该计算标签文本的像素大小、条形的像素大小并进行比较。我如何获得这两个值?
  • 它有效。非常感谢。 chart_PostPaint() 事件方法是强制性的。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-18
相关资源
最近更新 更多