--- C:/projects/Components/JVCL/jvcl/run/JvChart.pas	Tue May  6 11:48:52 2014
+++ C:/projects/Components/JVCL/jvcl/run/JvChart - DM line fill 2.pas	Tue Aug 19 19:05:42 2014
@@ -19,6 +19,7 @@
 Contributor(s):
     Warren Postma (warrenpstma att hotmail dott com)
     Mårten Henrichson/AABSoft (no email known)
+    David Millington (vintagedave att gmail dott com)
 
     Contains some code which is
         (C) 1996-1998 AABsoft and Mårten Henrichson
@@ -83,6 +84,7 @@
                         - Calls only JclMath.IsNaN, not Math.IsNaN, which doesn't
                         exist on older Delphi/BCB versions.
                        - Added CopyFloatingMarkers (thought I did that yesterday but missed it)
+  2014-08-19 - DM - Added area graph option (ie, filling under the line of a line graph)
 
 You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
 located at http://jvcl.delphi-jedi.org
@@ -470,6 +472,7 @@
     FXAxisDivisionMarkers: Boolean; // Do you want grid-paper look?
     FXAxisHeader: string;
     FMarkerSize:Integer;
+    FFillUnderLine : Boolean; // New 2014
     FXLegends: TStringList; // Text labels.
     FXLegendMaxTextWidth: Integer; // runtime: display width (pixels) of widest string in FXLegends[1:X].
     FXAxisValuesPerDivision: Integer;
@@ -603,6 +606,7 @@
     { Y Range }
     { plotting markers }
     property MarkerSize: Integer read FMarkerSize write FMarkerSize default JvChartDefaultMarkerSize;
+    property FillUnderLine : Boolean read FFillUnderLine write FFillUnderLine default False;
     { !! New: Primary (left side) Y axis, and Secondary (right side) Y Axis !!}
     property PrimaryYAxis: TJvChartYAxisOptions read FPrimaryYAxis write SetPrimaryYAxis;
     property SecondaryYAxis: TJvChartYAxisOptions read FSecondaryYAxis write SetSecondaryYAxis;
@@ -1827,6 +1831,7 @@
   FPenColors[11] := clAqua;
 
   FChartKind := ckChartLine;
+  FFillUnderLine := false;
 
   FPenCount := 1;
 
@@ -2730,18 +2735,20 @@
   ACanvas.Brush.Style := bsClear;
 
   { NEW: Box around entire chart area. }
-  X1 := Round(XOrigin);
-  X2 := Round(Options.XStartOffset + Options.XPixelGap * VC);
-  Y1 := Options.YStartOffset - 1;
-  Y2 := Round(YOrigin) + 1; // was YTempOrigin
+  if Options.AxisLineWidth <> 0 then begin
+    X1 := Round(XOrigin);
+    X2 := Round(Options.XStartOffset + Options.XPixelGap * VC);
+    Y1 := Options.YStartOffset - 1;
+    Y2 := Round(YOrigin) + 1; // was YTempOrigin
 
-  if Y2 > Height then
-  begin
-    // I suspect that the value of YPixelGap is too large in some cases.
-    Options.PrimaryYAxis.Normalize;
-    //OutputDebugString( PChar('Y2 is bogus. PYVC='+IntToStr(PYVC)) );
+    if Y2 > Height then
+    begin
+      // I suspect that the value of YPixelGap is too large in some cases.
+      Options.PrimaryYAxis.Normalize;
+      //OutputDebugString( PChar('Y2 is bogus. PYVC='+IntToStr(PYVC)) );
+    end;
+    MyRectangle(ACanvas, X1, Y1, X2, Y2);
   end;
-  MyRectangle(ACanvas, X1, Y1, X2, Y2);
 
   ACanvas.Brush.Style := bsSolid;
 end;
@@ -2752,6 +2759,8 @@
 var
   ACanvas: TCanvas;
 begin
+  if Options.AxisLineWidth = 0 then Exit;
+
   ACanvas := GetChartCanvas(false);
   ACanvas.Pen.Style := psSolid;
   ACanvas.Pen.Color := Options.AxisLineColor;
@@ -2767,8 +2776,9 @@
 var
   LCanvas: TCanvas;
 begin
+  if Options.AxisLineWidth = 0 then Exit;
+
   LCanvas := GetChartCanvas(false);
-
   LCanvas.Pen.Style := psSolid;
   LCanvas.Pen.Color := Options.AxisLineColor;
   LCanvas.Pen.Width := Options.AxisLineWidth; // was missing. Added Feb 2005. -WPostma.
@@ -3310,7 +3320,6 @@
   end;
 
   // Keep Y in visible chart range:
-
   function GraphConstrainedLineY(Pen, Sample: Integer): Double;
   var
     V: Double;
@@ -3336,6 +3345,26 @@
       Result := Options.YStartOffset - 2; // Not quite good enough, but better than before.
   end;
 
+  function GetUnderLineFillColor(const A, B: TColor) : TColor;
+  const
+    Lerp = 0.85; // 0-1, where 0 is fully A and 1 is fully B. This value seems good
+  var
+    AR, AG, AB, BR, BG, BB: Byte;
+  begin
+    AR := GetRValue(A);
+    AG := GetGValue(A);
+    AB := GetBValue(A);
+    BR := GetRValue(B);
+    BG := GetGValue(B);
+    BB := GetBValue(B);
+
+    Result := RGB(
+      Round(AR + Lerp * (BR - AR)),
+      Round(AG + Lerp * (BG - AG)),
+      Round(AB + Lerp * (BB - AB))
+    );
+  end;
+
   procedure PlotGraphChartLine;
   var
     I, I2, J, Y1: Integer;
@@ -3359,6 +3388,7 @@
       // No line types?
       if Options.PenStyle[I] = psClear then
         Continue;
+
       SetLineColor(ACanvas, I);
       J := 0;
       V := GraphConstrainedLineY(I, J);
@@ -3406,8 +3436,9 @@
                 end;
               end;
             end;
+            //OldV := V; // keep track of last valid value, for handling gaps.
+
             MyPenLineTo(ACanvas, Round(XOrigin + J * LineXPixelGap), Y);
-            //OldV := V; // keep track of last valid value, for handling gaps.
           end;
         end;
       end;
@@ -3417,6 +3448,103 @@
     SetLineColor(ACanvas, jvChartAxisColorIndex);
   end;
 
+  procedure PlotGraphChartLineFill;
+  var
+    I, I2, J, Y1: Integer;
+    V, LineXPixelGap: Double;
+    NanFlag: Boolean;
+    VC: Integer;
+    FillPoints : array of TPoint;
+    FillPolyIndex : Integer;
+  begin
+    Assert(Assigned(ACanvas));
+    Assert(Assigned(ACanvas.Brush));
+
+    SetLength(FillPoints, 0); // Not set to 0 by compiler
+    try
+      VC := Options.XValueCount;
+      if VC < 2 then
+        VC := 2;
+      LineXPixelGap := ((Options.XEnd - 2) - Options.XStartOffset) / (VC - 1);
+
+      for I := 0 to Options.PenCount - 1 do
+      begin
+        // No line types?
+        if Options.PenStyle[I] = psClear then
+          Continue;
+
+        SetLength(FillPoints, FData.ValueCount + 2 {start and end points});
+        FillPolyIndex := 0;
+
+        J := 0;
+        V := GraphConstrainedLineY(I, J);
+        NanFlag := IsNaN(V);
+        if not NanFlag then
+        begin
+          Y := Round(V);
+          FillPoints[FillPolyIndex] := Point(Round(XOrigin)+1, Round(YOrigin)); // start at origin
+          Inc(FillPolyIndex);
+          FillPoints[FillPolyIndex] := Point(Round(XOrigin)+1, Y); // add first point
+          Inc(FillPolyIndex);
+        end;
+
+        for J := 1 to Options.XValueCount - 1 do
+        begin
+          V := GraphConstrainedLineY(I, J);
+          if IsNaN(V) then
+          begin
+            NanFlag := True; // skip.
+            FillPoints[FillPolyIndex] := Point(Round(XOrigin + J * LineXPixelGap), Round(YOrigin)); // !!! DEBUG
+            Inc(FillPolyIndex);
+          end
+          else
+          begin
+            if NanFlag then
+            begin // resume, valid value.
+              NanFlag := False;
+              Y := Round(V);
+              // pick up the pen and slide forward
+              FillPoints[FillPolyIndex] := Point(Round(XOrigin + J * LineXPixelGap), Y);
+              Inc(FillPolyIndex);
+            end
+            else
+            begin
+              Y := Round(V);
+              if I > 0 then
+              begin
+                for I2 := 0 to I - 1 do
+                begin
+                  V := GraphConstrainedLineY(I2, J);
+                  if IsNaN(V) then
+                    Continue;
+                end;
+              end;
+
+              FillPoints[FillPolyIndex] := Point(Round(XOrigin + J * LineXPixelGap), Y); // add next point
+              Inc(FillPolyIndex);
+            end;
+          end;
+        end;
+
+        // Add a final point which is the same as the last, but at the bottom
+        if FillPolyIndex > 0 then begin
+          FillPoints[FillPolyIndex] := Point(FillPoints[FillPolyIndex-1].X, Round(YOrigin));
+          Inc(FillPolyIndex);
+          SetLength(FillPoints, FillPolyIndex); // Trim to the actual usage
+
+          // First draw the fill
+          ACanvas.Pen.Style := psClear;
+          ACanvas.Brush.Color := GetUnderLineFillColor(Options.PenColor[I],
+            Options.PenColor[jvChartPaperColorIndex]);
+          ACanvas.Brush.Style := bsSolid;
+          ACanvas.Polygon(FillPoints);
+        end;
+      end;
+    finally
+      SetLength(FillPoints, 0);
+    end;
+  end;
+
   procedure PlotGraphStackedBarAverage;
   var
     I, J: Integer;
@@ -3621,8 +3749,11 @@
       PlotGraphBar;
     ckChartStackedBar:
       PlotGraphStackedBar;
-    ckChartLine: //, ckChartLineWithMarkers:
-      PlotGraphChartLine;
+    ckChartLine: begin//, ckChartLineWithMarkers:
+        if Options.FillUnderLine then
+          PlotGraphChartLineFill; // Do this before drawing lines, so lines are always visible
+        PlotGraphChartLine;
+      end;
     ckChartMarkers:
       PlotGraphChartMarkers;
     ckChartStackedBarAverage:
@@ -5223,6 +5354,8 @@
 
 procedure TJvChart.MyAxisLineTo(ACanvas: TCanvas; X, Y: Integer);
 begin
+  if Options.AxisLineWidth = 0 then Exit;
+
   ACanvas.Pen.Width := Options.AxisLineWidth;
   ACanvas.LineTo(X, Y);
   ACanvas.Pen.Width := 1;
