From cd9ce49462a5041969361733fdef826cd0a6b512 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Sun, 25 Jun 2023 11:58:59 +0000 Subject: [PATCH] NiceChart: Add GridColor, Show[X|Y]AxisLine, TickLength, Series.LineWidth, ShowLegend[X|Y]Grid git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8851 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/nicechart/demo/Delphi/Project1.res | Bin 3320 -> 0 bytes components/nicechart/demo/common/Unit1.dfm | 43 +++- components/nicechart/demo/common/Unit1.lfm | 33 ++- components/nicechart/demo/common/Unit1.pas | 28 ++- components/nicechart/source/NiceChart.pas | 222 +++++++++++++----- 5 files changed, 261 insertions(+), 65 deletions(-) delete mode 100644 components/nicechart/demo/Delphi/Project1.res diff --git a/components/nicechart/demo/Delphi/Project1.res b/components/nicechart/demo/Delphi/Project1.res deleted file mode 100644 index 4f16aba1d085b75f9fc1c12fd637ec86b8cbedce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3320 zcmbtX-EZ4e6hCPz(XMQC64J)gj5Tct$%!31X;RX5)w)d)`_fj*8_2P*Gecqr+eua- zpwk|x)Q9~moBD!eA(bco4J3HrjlB(t3G=(xA4#`P6WeW%eb49b+;h*hV`X$(ugifV}xx#41z;v7L(wDeip*xth=@#7t-^TSS=6w7-_t(Ef+&_(x-`9nf zhzHCynTWoCpoDl41>}-PT|{%KM+}iYa>$3_im*}1AeEXR13B=FR%ijfx&0=5Lb61h z0phvv^#sgq$b9+=dJA$*$W)r2^4*3mfcL~lqcV_kBB~0kG?Gn25$PtG)Q2Y@$6*)( zeEF|9HC8{0>i>8`pAjl+JPoO7ADyucOUZOa^RjN>>9VuD>bPs z(Rr~eTLQ^L1$wZYuHC}iA9H^e{V`kg$I{ZIKRyD61iAz&iFla6=lHQpgn!!IO>ekj z3fiT^!$T-|lk!`V-f&I(HlaoBG#^XQim@2$7+S&4@9lFz!4v27)44g(-rimuKbi2t zK%=?M%}ll*A3UMCtD{jS0I$)tZr2%I5*B;=2inYq(Wu+C1-}UW%y``GjG}@ckH>-B zb%ewGUaSdzlm&=m{VdeEo^t*|YEJ+-J08npSr+~@4}eGG;Nmp@<1?tw3q0Zg0RsLr zm-0N|nTun&@;KvBk~8vnd_KN{D2{*H$9`b!XZ+)o#U63} zVxACZ_;^gar6kGea5hOeJ)M1+JUvCp(|75Ir}MP_Hz%TVoSsh+9!%#z>zvSDoX#Z= z9zIHTlV6j==d;P-_od{wwfCTU2Q&+M06GNy0{T5kl4tKD3l)?kr|1T4h-Y7$E{i82 z#A2vZ=YpSx5=qjWI2HU9m1q&sC0HiOSx_nUnR?c?*6;Uw(uf72>wBxRR#s(+d6sXx zUUyagZ0oAhkfks(J=^U09$S@nSSYWrojlPp!;tkmy&VYwyl_<>2Hr|&-D7<-RQj$J z_@VDaiskoL%&=b`X|mKeJ=bAjw0#6kxO1D4{@NhA3}i_HHmq07!Jy|_W`xYwAT8u$ z*R%a`c$Y;HRuQH;XzhW!F*XC1XM8V;1}l|HmUOvDx{RbNcW<;SRaLE3K0g{wUW!42PYBR|-#PLO!uY^jyB2FI+mm8qu7BdTVz0rPC^ z?oJjX7epJ`UKT6KH@6M*$c=VHd3lMWodKEvsCrc{gr3=l@J7Dr<*a1o%YMJ_d&*_s zivqtFP8^DUtCv;&H_;4+9qj3+Y-h{=nxP@+!C$$l^!X}4N+jIPUA79hn=*+YQLuL&FRIDgv zz`hxx>6v{ya7S*Bby?Ao=*dER_L)+D0SO~o(_P3f3TOR?)s+b|8Y z&h*CHAeXgQV{1-*xo$1jm4?bR#i;5{1xK`_G;~{a>b7c|%Ws3Nsjr4^Fx6Q$wW`u_ zIywr@8Vbr^Q;ddV*HlxhnN3mfg@py)eU%s5uT?qHro7GZs7&8tV8l Value then + begin + FLineWidth := Value; + Chart.Changed; + end; +end; + + { TNiceChart } constructor TNiceChart.Create(AOwner: TComponent); @@ -439,6 +465,7 @@ begin FShowTitle := True; FShowXGrid := True; FShowYGrid := True; + FGridColor := clGray; FMonochrome := False; FTitle := 'Chart Title'; FTitleFont := TFont.Create; @@ -453,6 +480,7 @@ begin FAxisYTitle := 'Y Axis'; FAxisXScale := 1; FAxisYScale := 1; + FTickLength := 2; XAxis := TList.Create; YAxis := TList.Create; FUpdating := False; @@ -498,6 +526,15 @@ begin InternalPaint(Canvas); end; +procedure TNiceChart.SetGridColor(const Value: TColor); +begin + if FGridColor <> value then + begin + FGridColor := Value; + DoPaint; + end; +end; + procedure TNiceChart.SetMonochrome(const Value: Boolean); begin if (FMonochrome <> Value) then @@ -638,6 +675,15 @@ begin end; end; +procedure TNiceChart.SetShowXAxisLine(const Value: Boolean); +begin + if (FShowXAxisLine <> Value) then + begin + FShowXAxisLine := Value; + DoPaint; + end; +end; + procedure TNiceChart.SetShowXGrid(const Value: Boolean); begin if (FShowXGrid <> Value) then @@ -647,6 +693,15 @@ begin end; end; +procedure TNiceChart.SetShowYAxisLine(const Value: Boolean); +begin + if (FShowYAxisLine <> Value) then + begin + FShowYAxisLine := Value; + DoPaint; + end; +end; + procedure TNiceChart.SetShowYGrid(const Value: Boolean); begin if (FShowYGrid <> Value) then @@ -656,6 +711,15 @@ begin end; end; +procedure TNiceChart.SetTickLength(const Value: Integer); +begin + if (FTickLength <> Value) and (Value >= 0) then + begin + FTickLength := Value; + DoPaint; + end; +end; + procedure TNiceChart.BeginUpdate; begin FUpdating := True; @@ -816,15 +880,13 @@ procedure TNiceChart.Calculate(AWidth, AHeight: Integer); var x, w, h, y, g: Integer; Titled: Boolean; - begin - ClearAxis; DestWidth := AWidth; DestHeight := AHeight; RcChart := Rect(0, 0, DestWidth, DestHeight); - MarkSize := Max(1, Round(DestWidth * 0.004)); + MarkSize := Max(1, Round(DestWidth * 0.006)); InflateRect(RcChart, -OUTER_MARGIN, -OUTER_MARGIN); @@ -843,13 +905,13 @@ begin Canvas.Font.Assign(FNormalFont); h := Canvas.TextHeight('Ag'); - RcChart.Bottom := RcChart.Bottom - (2 * h) - INNER_MARGIN - (2 * SMALL_MARGIN); + RcChart.Bottom := RcChart.Bottom - (2 * h) - INNER_MARGIN - FTickLength - SMALL_MARGIN; BuildYAxis; w := 0; for x := 0 to YAxis.Count-1 do w := Max(w, Canvas.TextWidth(PAxisInfo(YAxis[x])^.Caption)); - RcChart.Left := RcChart.Left + h + INNER_MARGIN + w + (2 * SMALL_MARGIN); + RcChart.Left := RcChart.Left + h + INNER_MARGIN + w + FTickLength + SMALL_MARGIN; RcTitle.Left := RcChart.Left; RcTitle.Right := RcChart.Right; AdjustYAxis; @@ -1113,32 +1175,69 @@ end; procedure TNiceChart.DrawXAxis(ACanvas: TCanvas); var - l, t, w, x: Integer; + l, t, w, i: Integer; P: PAxisInfo; Str: string; Last: Integer; + dummy, origin: Integer; begin with ACanvas do begin + if FShowXGrid then + begin + Pen.Style := psDot; + Pen.Width := 1; + if FMonochrome then + Pen.Color := clBlack + else + Pen.Color := FGridColor; + t := RcChart.Top; + for i := 0 to XAxis.Count-1 do + begin + P := PAxisInfo(XAxis[i]); + if (P^.Px <= RcChart.Left) or (P^.Px >= RcChart.Right) then + Continue; + MoveTo(P^.Px, P^.Py); + LineTo(P^.px, t); + end; + end; + + // Drawing the y axis here seems to be misplaced. But otherwise + // it could be overpainted by an x grid line. + if FShowYAxisLine then + begin + ChartToClient(0, 0, origin, dummy); + if (origin > RcChart.Left) and (origin < RcChart.Right) then + begin + Pen.Style := psSolid; + Pen.Color := clBlack; + Pen.Width := 1; + MoveTo(origin, RcChart.Top); + LineTo(origin, RcChart.Bottom); + end; + end; + Pen.Style := psSolid; Pen.Width := FAxisLineWidth; + Pen.Color := clBlack; MoveTo(RcChart.Left, RcChart.Bottom); LineTo(RcChart.Right, RcChart.Bottom); + Font.Assign(FNormalFont); Font.Style := [fsBold]; w := RcChart.Right - RcChart.Left; - t := RcChart.Bottom + INNER_MARGIN + (2 * SMALL_MARGIN) + TextHeight('Ag'); + t := RcChart.Bottom + INNER_MARGIN + FTickLength + SMALL_MARGIN + TextHeight('Ag'); l := RcChart.Left + ((w - TextWidth(FAxisXTitle)) div 2); TextOut(l, t, FAxisXTitle); Font.Assign(FNormalFont); Pen.Color := clBlack; Pen.Width := 1; Pen.Style := psSolid; - t := RcChart.Bottom + (2 * SMALL_MARGIN); + t := RcChart.Bottom + FTickLength + SMALL_MARGIN; Last := 0; - for x := 0 to XAxis.Count-1 do + for i := 0 to XAxis.Count-1 do begin - P := PAxisInfo(XAxis[x]); + P := PAxisInfo(XAxis[i]); Str := P^.Caption; w := TextWidth(Str); l := P^.Px - (w div 2); @@ -1148,20 +1247,7 @@ begin Last := l + w; end; MoveTo(P^.Px, P^.Py); - LineTo(P^.Px, P^.Py + SMALL_MARGIN + 1); - end; - if FShowXGrid then - begin - Pen.Style := psDot; - Pen.Color := clGray; - t := RcChart.Top; - for x := 1 to XAxis.Count-2 do - begin - P := PAxisInfo(XAxis[x]); - MoveTo(P^.Px, P^.Py); - LineTo(P^.px, t); - end; - Pen.Color := clBlack; + LineTo(P^.Px, P^.Py + FTickLength + 1); end; end; end; @@ -1169,16 +1255,52 @@ end; procedure TNiceChart.DrawYAxis(ACanvas: TCanvas); var l, t, h, w: Integer; - x: Integer; + i: Integer; Str: string; P: PAxisInfo; + origin, dummy: Integer; begin with ACanvas do begin + if FShowYGrid then + begin + Pen.Style := psDot; + Pen.Width := 1; + if FMonochrome then + Pen.Color := clBlack + else + Pen.Color := FGridColor; + for i := 0 to YAxis.Count-1 do + begin + P := PAxisInfo(YAxis[i]); + if (P^.Py <= RcChart.Top) or (P^.Py >= RcChart.Bottom) then + Continue; + MoveTo(P^.Px, P^.Py); + LineTo(RcChart.Right, P^.Py); + end; + Pen.Color := clBlack; + end; + + // Drawing the x axis here seems to be misplaced. But otherwise + // it could be overpainted by a y grid line. + if FShowXAxisLine then + begin + ChartToClient(0, 0, dummy, origin); + if (origin > RcChart.Top) and (origin < RcChart.Bottom) then + begin + Pen.Style := psSolid; + Pen.Color := clBlack; + Pen.Width := 1; + MoveTo(RcChart.Left, origin); + LineTo(RcChart.Right, origin); + end; + end; + Pen.Style := psSolid; Pen.Width := FAxisLineWidth; MoveTo(RcChart.Left, RcChart.Top); LineTo(RcChart.Left, RcChart.Bottom); + h := RcChart.Bottom - RcChart.Top; l := OUTER_MARGIN; Font.Assign(FNormalFont); @@ -1189,38 +1311,18 @@ begin Pen.Color := clBlack; Pen.Width := 1; Pen.Style := psSolid; - l := RcChart.Left - (2 * SMALL_MARGIN); - for x := 0 to YAxis.Count-1 do + l := RcChart.Left - FTickLength - SMALL_MARGIN; + for i := 0 to YAxis.Count-1 do begin - P := PAxisInfo(YAxis[x]); + P := PAxisInfo(YAxis[i]); Str := P^.Caption; w := TextWidth(Str); h := TextHeight(Str); t := P^.Py - (h div 2); TextOut(l - w, t, Str); - MoveTo(P^.Px - SMALL_MARGIN, P^.Py); + MoveTo(P^.Px - FTickLength, P^.Py); LineTo(P^.Px, P^.Py); end; - if FShowYGrid then - begin - l := RcChart.Right; - for x := 1 to YAxis.Count-2 do - begin - P := PAxisInfo(YAxis[x]); - if (P^.Value = 0) then - begin - Pen.Style := psSolid; - Pen.Color := clBlack; - end else - begin - Pen.Style := psDot; - Pen.Color := clGray; - end; - MoveTo(P^.Px, P^.Py); - LineTo(l, P^.Py); - end; - Pen.Color := clBlack; - end; end; end; @@ -1345,6 +1447,7 @@ begin begin if (sr.FKind = skBar) then begin + Pen.Width := 1; for x := 0 to Sr.Values.Count-1 do begin P := PXYInfo(Sr.Values[x]); @@ -1354,6 +1457,7 @@ begin begin if (sr.FKind = skLine) then begin + Pen.Width := sr.LineWidth; for x := 0 to Sr.Values.Count-1 do begin P := PXYInfo(Sr.Values[x]); @@ -1362,8 +1466,12 @@ begin else LineTo(P^.Px, P^.Py); end; end else - if (sr.FKind = skSmooth) - then sr.Spline.Draw(ACanvas); + if (sr.FKind = skSmooth) then + begin + Pen.Width := sr.LineWidth; + sr.Spline.Draw(ACanvas); + end; + Pen.Width := 1; for x := 0 to Sr.Values.Count-1 do begin P := PXYInfo(Sr.Values[x]); @@ -1381,9 +1489,11 @@ begin Rectangle(Rc); end else begin + Pen.Width := sr.LineWidth; t2 := t + (LEGEND_ITEM div 2); MoveTo(l, t2); LineTo(l + LEGEND_ITEM, t2); + Pen.Width := 1; Marker(ACanvas, l + (LEGEND_ITEM div 2), t2, MarkSize); end; end;