2014-01-08 57 views
3

我在Windows窗體中使用圖表組件。如何在一條直線上和曲線下填充所有內容?

我使用

chart1.Series["Grenzwert"].Points.Add(new DataPoint(0, y)); 
chart1.Series["Grenzwert"].Points.Add(new DataPoint(maxwidth, y)); 

我也繪製了一系列由線連接的點,我們稱之爲curve創建straight line

如何顯示straight linecurve填滿的內容?

列填充整個區域,而不僅僅是straight line以上。

例子:

enter image description here

回答

2

我有一個想法,使用SeriesChartType.Range如下。

private void UpdateChart(float straight_line, List<DataPoint> curve) 
{ 
    float y = straight_line; // YValue of the straight line 
    var list = curve.ToList(); // Clone the curve 

    int count = list.Count - 2; 

    for (int i = 0; i < count; i++) // Calculate intersection point between the straight line and a line between (x0,y0) and (x1,y1) 
    { 
     double x0 = list[i + 0].XValue; 
     double y0 = list[i + 0].YValues[0]; 
     double x1 = list[i + 1].XValue; 
     double y1 = list[i + 1].YValues[0]; 

     if ((y0 > y && y1 < y) || (y0 < y && y1 > y)) 
     { 
      double x = (y - y0) * (x1 - x0)/(y1 - y0) + x0; 

      list.Add(new DataPoint(x, y)); 
     } 
    } 

    list.Sort((a, b) => Math.Sign(a.XValue - b.XValue)); 

    chart1.Series[0].Points.Clear(); 
    chart1.Series[0].ChartType = SeriesChartType.Range; 
    chart1.Series[0].Color = Color.Red; 
    chart1.Series[0].BorderColor = Color.Cyan; 
    chart1.ChartAreas[0].AxisX.Minimum = 0; 
    chart1.ChartAreas[0].AxisX.Interval = 1; 

    for (int i = 0; i < list.Count; i++) 
    { 
     double xx = list[i].XValue; 
     double yy = list[i].YValues[0]; 
     if (yy > y) 
     { 
      chart1.Series[0].Points.AddXY(xx, y, yy); 
     } 
     else 
     { 
      chart1.Series[0].Points.AddXY(xx, yy, yy); 
     } 
    } 

    chart1.ChartAreas[0].AxisY.StripLines.Add(new StripLine { IntervalOffset = y, Interval = 0, BorderColor = Color.Orange, BorderWidth = 2 }); 

} 

如以下繪圖來判斷該直線與(X0,Y0)和(X1,Y1)之間的線是否相交,殼體1是(y0 < y && y1 > y)和殼體2是(y0 > y && y1 < y)。在案例1和案例2中,它們相互交叉。在情況3和情況4中,它們不相互交叉。

the below drawing to judge whether the straight line and a line between (x0,y0) and (x1,y1) intersect

+0

它的工作原理,但我不明白你在做什麼。你能否詳細說明並創建一個像'private void UpdateChart(float straight_line,List curve)'這樣的函數http://pastebin.com/i6tf9iWA –

+0

@DeadGirl我編輯了我的答案。 – user3093781

+0

太好了。你能詳細說明它的工作原理嗎?特別是'if((y0> y && y1 y))'部分。 –

0

你可以做到這一點,如下所示。

  1. 像以前一樣設置列填充。一切都會變成紅色。
  2. 在同一個圖表上創建一個新的柱狀圖。
  3. 將其值設置爲與鋸齒線相同,但限制在已有直線的y值處。
  4. 將列的填充顏色設置爲白色。這將阻止不在線之間的任何區域的紅色填充。
+0

工程,但它阻止網格以及所有其他曲線。我只需要繪製有趣的區域,而不是使用視覺技巧...... –

+0

嗯。不確定沒有視覺技巧的方式。希望另一張海報有更好的解決方案。 – Baldrick

+0

看到我晚了,但另一種方法.. – TaW

3

這晚,並沒有真正短,但國際海事組織是圖表中的顏色區域的最佳途徑。

通過用正確的數據編碼Paint事件,可以非常精確地將LinesSpline charttypes着色。必要的像素值可以通過軸功能ValueToPixelPosition獲得。再例如here

下面的代碼是一個長一點,因爲我們需要在開始圖表每個彩色區域末尾添加某些點。除此之外,它非常直接:通過將像素座標與AddLines相加來創建GraphicsPaths,並在Paint事件中填入GraphicsPaths

爲了測試和樂趣,我添加了一個可移動的HorizontalLineAnnotation,所以我可以看到這些區域在上下拖動時會有所不同。:

enter image description here enter image description here enter image description here

Paint事件是相當簡單的;它指的是一個HorizontalLineAnnotation hl

private void chart1_Paint(object sender, PaintEventArgs e) 
{ 
    double limit = hl.Y; // get the limit value 
    hl.X = 0;    // reset the x value of the annotation 

    List<GraphicsPath> paths = getPaths(chart1.ChartAreas[0], chart1.Series[0], limit); 

    using (SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.Red))) 
     foreach (GraphicsPath gp in paths) 
      { e.Graphics.FillPath(brush, gp); gp.Dispose(); } 
} 

的代碼來獲取路徑顯然是太長了舒適..:

List<GraphicsPath> getPaths(ChartArea ca, Series ser, double limit) 
{ 
    List<GraphicsPath> paths = new List<GraphicsPath>(); 
    List<PointF> points = new List<PointF>(); 
    int first = 0; 
    float limitPix = (float)ca.AxisY.ValueToPixelPosition(limit); 

    for (int i = 0; i < ser.Points.Count; i++) 
    { 
     if ((ser.Points[i].YValues[0] > limit) && (i < ser.Points.Count - 1)) 
     { 
      if (points.Count == 0) first = i; // remember group start 
      // insert very first point: 
      if (i == 0) points.Insert(0, new PointF( 
       (float)ca.AxisX.ValueToPixelPosition(ser.Points[0].XValue), limitPix)); 

      points.Add(pointfFromDataPoint(ser.Points[i], ca)); // the regular points 
     } 
     else 
     { 
      if (points.Count > 0) 
      { 
       if (first > 0) points.Insert(0, median( 
            pointfFromDataPoint(ser.Points[first - 1], ca), 
            pointfFromDataPoint(ser.Points[first], ca), limitPix)); 
       if (i == ser.Points.Count - 1) 
       { 
        if ((ser.Points[i].YValues[0] > limit)) 
         points.Add(pointfFromDataPoint(ser.Points[i], ca)); 
        points.Add(new PointF( 
        (float)ca.AxisX.ValueToPixelPosition(ser.Points[i].XValue), limitPix)); 
       } 
       else 
        points.Add(median(pointfFromDataPoint(ser.Points[i - 1], ca), 
           pointfFromDataPoint(ser.Points[i], ca), limitPix)); 

       GraphicsPath gp = new GraphicsPath(); 
       gp.FillMode = FillMode.Winding; 
       gp.AddLines(points.ToArray()); 
       gp.CloseFigure(); 
       paths.Add(gp); 
       points.Clear(); 
      } 
     } 
    } 
    return paths; 
} 

它使用兩個輔助功能:

PointF pointfFromDataPoint(DataPoint dp, ChartArea ca) 
{ 
    return new PointF((float)ca.AxisX.ValueToPixelPosition(dp.XValue), 
         (float)ca.AxisY.ValueToPixelPosition(dp.YValues[0])); 
} 

PointF median(PointF p1, PointF p2, float y0) 
{ 
    float x0 = p2.X - (p2.X - p1.X) * (p2.Y - y0)/(p2.Y - p1.Y); 
    return new PointF(x0, y0); 
} 

HorizontalLineAnnotation設置如下:

hl = new HorizontalLineAnnotation(); 
hl.AllowMoving = true; 
hl.LineColor = Color.OrangeRed; 
hl.LineWidth = 1; 
hl.AnchorDataPoint = S1.Points[1]; 
hl.X = 0; 
hl.Y = 0;   // or some other starting value.. 
hl.Width = 100; // percent of chart.. 
hl.ClipToChartArea = chart1.ChartAreas[0].Name; // ..but clipped 
chart1.Annotations.Add(hl); 
+0

你能幫忙嗎? http://stackoverflow.com/questions/38175238/stackedbar-borders-between-different-series – user1477332

+0

會做,今天晚些時候.. – TaW

+0

這樣一個真棒功能!謝謝 –

相關問題