View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0006316 | JEDI VCL | 03 Donations | public | 2014-08-19 18:28 | 2015-09-21 17:47 |
Reporter | vintagedave | Assigned To | obones | ||
Priority | normal | Severity | feature | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Product Version | 3.47 | ||||
Target Version | Fixed in Version | 3.49 | |||
Summary | 0006316: Add area graphs to TJvChart | ||||
Description | An area graph is a line graph with the area under the line filled in (like this: http://www.qualia.hr/wp-content/uploads/2011/11/area.jpg ) I have written a small patch to add this to TJvChart, filling the area under the line with a color between the line color and page color. The main problem with this kind of chart is when lines overlap - does the background hide the underlying graph? In this implementation I draw the backgrounds first and lines second, so even if a line dips behind another line, it will still be visible. (More advanced would be to alpha-blend the filled areas, but...) Rather than adding another chart type (eg area chart) it is an option "FillUnderLine" property that's used when drawing line charts, and is off by default. I also (I know I should put this as another issue, sorry) made a tweak so when the axis width is 0, it won't draw (otherwise it draws a 1px line) and ditto for the rectangle around the whole graph. This is to give a more modern, minimal look without lines everywhere. | ||||
Additional Information | I have attached a patch against the latest downloadable version of the JVCL. | ||||
Tags | No tags attached. | ||||
2014-08-19 18:28
|
jvchart fill patch.patch (9,317 bytes)
--- 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; |
|
Please provide the zipped sources of a sample application showing this |
2014-09-08 15:46
|
JvChart filled demo.zip (27,332 bytes) |
2014-09-08 15:47
|
|
|
Done. I've attached a sample project and a screenshot of what it looks like. |
|
Any feedback on this? It's been in status "feedback" for two / three months. I added the demo app and screenshot as requested, but I haven't got permissions to change the status to indicate something was done. |
|
This is now in GIT |
Date Modified | Username | Field | Change |
---|---|---|---|
2014-08-19 18:28 | vintagedave | New Issue | |
2014-08-19 18:28 | vintagedave | File Added: jvchart fill patch.patch | |
2014-09-03 11:42 | obones | Note Added: 0021039 | |
2014-09-03 11:42 | obones | Status | new => feedback |
2014-09-08 15:46 | vintagedave | File Added: JvChart filled demo.zip | |
2014-09-08 15:47 | vintagedave | File Added: JvChart filled demo - screenshot.png | |
2014-09-08 15:47 | vintagedave | Note Added: 0021057 | |
2014-11-13 13:54 | vintagedave | Note Added: 0021071 | |
2014-12-04 15:04 | obones | Status | feedback => acknowledged |
2014-12-04 16:21 | obones | Note Added: 0021090 | |
2014-12-04 16:21 | obones | Status | acknowledged => resolved |
2014-12-04 16:21 | obones | Fixed in Version | => Daily / GIT |
2014-12-04 16:21 | obones | Resolution | open => fixed |
2014-12-04 16:21 | obones | Assigned To | => obones |
2015-09-21 17:47 | obones | Fixed in Version | Daily / GIT => 3.49 |