📄 teecirculargauge.pas
字号:
{**********************************************}
{ TeeChart Circular Gauge style }
{ Copyright (c) 2007 by Steema Software }
{**********************************************}
unit TeeCircularGauge;
{$I TeeDefs.inc}
interface
uses
{$IFNDEF LINUX}
Windows, Messages,
{$ENDIF}
SysUtils, Classes, Math,
{$IFDEF CLX}
QGraphics, QControls, QForms, QDialogs, QStdCtrls, QExtCtrls, QComCtrls,
QButtons,
{$ELSE}
Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, Buttons,
{$ENDIF}
TeeLinearGauge, TeEngine, TeCanvas;
type
TCircularGauge=class;
TGaugeHand=class(TGaugeSeriesPointer)
private
FOffset: Integer;
FDistance: Integer;
procedure SetDistance(const Value: Integer);
procedure SetOffset(const Value: Integer);
public
Constructor Create(AOwner:TChartSeries);
procedure Draw(const Angle:Double; Center:TPoint; Off:Integer);
published
property Distance:Integer read FDistance write SetDistance default 80;
property Offset:Integer read FOffset write SetOffset default 30;
end;
TCircularGauge=class(TCustomGaugeMinMax)
private
FCenter : TGaugeSeriesPointer;
FEndPoint : TSeriesPointer;
FHand : TGaugeHand;
FLabelsInside : Boolean;
FRotateLabels : Boolean;
FTotalAngle : Double;
IAngleInc : Double;
ICenter : TPoint;
IStartAngle : Double;
FCircled : Boolean;
FRotAngle : Double;
FXRadius : Integer;
FYRadius : Integer;
function CalcAngleFromLength(const Point:TPoint; const Length:Double):Double;
function CalcDistance(Distance:Integer):Integer;
function CalcPoint(const Angle:Double; const Center:TPoint;
const RadiusX, RadiusY:Double):TPoint;
Procedure CalcRadius;
function CalcStartAngle:Double;
function CalcSweepAngle:Double;
function CalcValue(const AValue:Double):Double;
procedure DrawAxisMinorTick(const Inner, Outer:TPoint);
procedure DrawAxisTick(const Inner, InnerPlus, InnerMinus,
Outer, OuterPlus, OuterMinus:TPoint);
procedure DrawCenter;
procedure DrawColorLines;
procedure DrawEnd(Angle:Double);
procedure SetCenter(const Value: TGaugeSeriesPointer);
procedure SetCircled(const Value:Boolean);
procedure SetEndPoint(const Value: TSeriesPointer);
procedure SetHand(const Value: TGaugeHand);
procedure SetLabelsInside(const Value: Boolean);
procedure SetRotateLabels(const Value: Boolean);
procedure SetRotAngle(const Value: Double);
procedure SetTotalAngle(const Value: Double);
protected
function Axis:TChartAxis; override;
procedure CalcOrigRect; override;
Procedure DoBeforeDrawValues; override;
procedure DrawAxis; override;
procedure DrawFace; override;
procedure DrawHand; override;
class Function GetEditorClass:String; override;
procedure PrepareForGallery(IsEnabled:Boolean); override;
Procedure SetParentChart(const Value:TCustomAxisPanel); override;
procedure SetValues; override;
public
Constructor Create(AOwner:TComponent); override;
Destructor Destroy; override;
procedure Assign(Source:TPersistent); override;
function UseAxis:Boolean; override;
// From TCircledSeries
function CircleXCenter:Integer;
function CircleYCenter:Integer;
property XRadius:Integer read FXRadius;
property YRadius:Integer read FYRadius;
published
property Active;
property Cursor;
property ParentChart;
property DataSource; { after ParentChart }
property PercentFormat;
property ShowInLegend;
property Title;
property ValueFormat;
{ events }
property AfterDrawValues;
property BeforeDrawValues;
property OnAfterAdd;
property OnBeforeAdd;
property OnChange;
property OnClearValues;
property OnClick;
property OnDblClick;
property OnMouseEnter;
property OnMouseLeave;
property XValues;
property YValues;
property Center:TGaugeSeriesPointer read FCenter write SetCenter;
property Circled:Boolean read FCircled write SetCircled default True;
property EndPoint:TSeriesPointer read FEndPoint write SetEndPoint;
property Face;
property Frame;
property GreenLine;
property Hand:TGaugeHand read FHand write SetHand;
property LabelsInside:Boolean read FLabelsInside write SetLabelsInside
default True;
property Maximum;
property Minimum;
property MinorTickDistance default 3;
property MinorTicks;
property RedLine;
property RotateLabels:Boolean read FRotateLabels write SetRotateLabels
default True;
property RotationAngle:Double read FRotAngle write SetRotAngle;
property Ticks;
property TotalAngle:Double read FTotalAngle write SetTotalAngle; //default 300;
property Value;
end;
TCircularGaugeEditor = class(TLinearGaugeEditor)
BHand: TButton;
CBLabelsInside: TCheckBox;
CBRotateLabels: TCheckBox;
Label11: TLabel;
BCenter: TButton;
Button3: TButton;
ETotalAngle: TEdit;
UDTotalAngle: TUpDown;
Label12: TLabel;
Edit1: TEdit;
UDHandDist: TUpDown;
Label13: TLabel;
Edit3: TEdit;
UDHandOff: TUpDown;
Timer1: TTimer;
CBCircled: TCheckBox;
Label14: TLabel;
Edit4: TEdit;
UDRotAngle: TUpDown;
procedure FormShow(Sender: TObject);
procedure BHandClick(Sender: TObject);
procedure BCenterClick(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure CBLabelsInsideClick(Sender: TObject);
procedure CBRotateLabelsClick(Sender: TObject);
procedure Edit1Change(Sender: TObject);
procedure Edit3Change(Sender: TObject);
procedure ETotalAngleChange(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure CBCircledClick(Sender: TObject);
procedure Edit4Change(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{$IFNDEF CLX}
{$IFNDEF LCL}
{$R *.DFM}
{$ENDIF}
{$ELSE}
{$R *.xfm}
{$ENDIF}
uses
Chart, TeeProCo, TeeProcs, TeeNumericGauge, TeePoEdi, Series;
{ TCircularGauge }
type
TFramedAccess=class(TFramedBorder);
Constructor TCircularGauge.Create(AOwner: TComponent);
begin
inherited;
Face.ShapeStyle:=fosEllipse;
FHand:=TGaugeHand.Create(Self);
FTotalAngle:=300;
RedLine.StartValue:=80;
RedLine.EndValue:=100;
GreenLine.StartValue:=0;
GreenLine.EndValue:=70;
FLabelsInside:=True;
FRotateLabels:=True;
MinorTickDistance:=3;
FCircled:=True;
Frame.Circled:=True;
TFramedAccess(Frame).DefaultCircled:=True;
FCenter:=TGaugeSeriesPointer.Create(Self);
FCenter.GaugeStyle:=gpCenter;
FCenter.Size:=16;
FCenter.Gradient.Visible:=True;
FCenter.Pen.Hide;
FCenter.Style:=psCircle;
FCenter.Shadow.Visible:=True;
FCenter.Shadow.Size:=2;
FEndPoint:=TSeriesPointer.Create(Self);
FEndPoint.Style:=psCircle;
FEndPoint.Color:=clWhite;
end;
Destructor TCircularGauge.Destroy;
begin
FEndPoint.Free;
FCenter.Free;
FHand.Free;
inherited;
end;
procedure TCircularGauge.PrepareForGallery(IsEnabled:Boolean);
begin
inherited;
Axis.Visible:=False;
Center.VertSize:=3;
Center.HorizSize:=3;
Hand.HorizSize:=2;
Hand.Distance:=100;
RedLine.VertSize:=5;
Value:=70;
end;
procedure TCircularGauge.DrawFace;
begin
inherited;
DrawColorLines;
end;
procedure TCircularGauge.DrawColorLines;
procedure DrawLine(Line:TGaugePointerRange);
var tmpR : TRect;
minRadius : Double;
tmp : Integer;
begin
if Line.Visible then
begin
tmpR:=INewRect;
minRadius:=Min(XRadius,YRadius)*0.25;
tmp:= -Round(minRadius);
if Axis.Labels then
begin
ParentChart.Canvas.AssignFont(Axis.LabelsFont);
if RotateLabels then
Dec(tmp, ParentChart.Canvas.FontHeight)
else
Dec(tmp, ParentChart.Canvas.TextWidth(FormatFloat(Axis.AxisValuesFormat,Maximum)));
end;
InflateRect(tmpR,tmp,tmp);
Line.Draw(CalcValue(Line.StartValue),CalcValue(Line.EndValue),tmpR);
end;
end;
begin
DrawLine(RedLine);
DrawLine(GreenLine);
end;
function TCircularGauge.CircleXCenter:Integer;
begin
with ParentChart.ChartRect do
result:=(Left+Right) div 2;
end;
function TCircularGauge.CircleYCenter:Integer;
begin
with ParentChart.ChartRect do
result:=(Bottom+Top) div 2;
end;
procedure TCircularGauge.CalcOrigRect;
begin
inherited;
if Circled then
begin
INewRect:=IOrigRect;
CalcRadius;
TCircledSeries.AdjustScreenRatio(ParentChart.Canvas,
FXRadius,FYRadius,IOrigRect);
INewRect:=IOrigRect;
CalcRadius;
end;
end;
procedure TCircularGauge.SetValues;
begin
inherited;
IStartAngle := CalcStartAngle;
IAngleInc := TotalAngle / IRange;
CalcRadius;
end;
//returns the angle needed to draw the length on the circumference of the circle from a point
function TCircularGauge.CalcAngleFromLength(const Point:TPoint;
const Length:Double):Double;
var radius, tmp : Double;
begin
if Circled then
radius:=XRadius
else
radius:=TeeDistance(Abs(ICenter.X-Point.X),Abs(ICenter.Y-Point.Y));
// law of cosines
tmp:=Sqr(radius)*2;
if tmp=0 then
result:=0
else
result:=ArcCos((tmp - Sqr(Length)) / tmp);
end;
const
TeeZeroPoint:TPoint=(X:0; Y:0);
function TCircularGauge.CalcPoint(const Angle:Double; const Center:TPoint;
const RadiusX, RadiusY:Double):TPoint;
var tmpSin,
tmpCos : Extended;
begin
SinCos(Angle, tmpSin, tmpCos);
result.X := Center.X - Round(RadiusX * tmpCos);
result.Y := Center.Y - Round(RadiusY * tmpSin);
end;
procedure TCircularGauge.DrawAxisTick(const Inner, InnerPlus, InnerMinus,
Outer, OuterPlus, OuterMinus:TPoint);
begin
Ticks.Draw(Inner, InnerPlus, InnerMinus, Outer, OuterPlus, OuterMinus);
end;
procedure TCircularGauge.DrawAxisMinorTick(const Inner, Outer:TPoint);
begin
MinorTicks.Draw(Inner, TeeZeroPoint, TeeZeroPoint, Outer, TeeZeroPoint, TeeZeroPoint);
end;
procedure TCircularGauge.DrawAxis;
var tmp : Double;
tmpS : String;
tmpValue,
tmpStep,
tmpStep2,
tmpAngle,
tmpAngle2,
tmpXRad,
tmpYRad,
tmp2,
tmpWidth : Double;
x,y,
width,
height,
tmpFontH,
tmpXRadius,
tmpYRadius,
tmpW,
t : Integer;
P3Plus, P3Minus,
P4Plus, P4Minus,
P3, P4 : TPoint;
begin
if (Axis<>nil) and Axis.Visible then
begin
tmpXRadius:=XRadius;
tmpYRadius:=YRadius;
if Axis.Axis.Visible then
begin
ParentChart.Canvas.AssignVisiblePen(Axis.Axis);
ParentChart.Canvas.Arc(INewRect.Left, INewRect.Top, INewRect.Right,
INewRect.Bottom, IStartAngle - 90,
IStartAngle-90+CalcSweepAngle);
tmpW:=1+(Axis.Axis.Width div 2);
Dec(tmpXRadius,tmpW);
Dec(tmpYRadius,tmpW);
end;
tmpStep:=Axis.Increment;
if Axis.Title.Visible and (Axis.Title.Caption<>'') then
begin
ParentChart.Canvas.AssignFont(Axis.Title.Font);
width := ParentChart.Canvas.TextWidth(Axis.Title.Caption);
height := ParentChart.Canvas.FontHeight;
x := CircleXCenter - Round((tmpXRadius / 2.5) + (width * 0.5));
y := CircleYCenter - Round(height * 0.5);
ParentChart.Canvas.BackMode:=cbmTransparent;
ParentChart.Canvas.TextOut(x, y, Axis.Title.Caption);
end;
if Axis.Ticks.Visible or Axis.Labels then
begin
Axis.TickLength := Ticks.VertSize;
Axis.Ticks.Assign(Ticks.Pen);
ParentChart.Canvas.AssignFont(Axis.LabelsFont);
ParentChart.Canvas.AssignVisiblePen(Ticks.Pen);
tmpXRad := (tmpXRadius - Axis.TickLength);
tmpYRad := (tmpYRadius - Axis.TickLength);
tmpFontH := ParentChart.Canvas.FontHeight;
if (IRange<>0) and (tmpStep<>0) then
begin
tmpValue := Minimum;
repeat
tmpAngle :=(IStartAngle - 90) + (tmpValue * TotalAngle / IRange);
tmp:=TeePiStep * tmpAngle;
P3:= CalcPoint(tmp, ICenter, tmpXRad, tmpYRad);
P4:= CalcPoint(tmp, ICenter, tmpXRadius, tmpYRadius);
tmp2:= TeePiStep * (tmpAngle + (Ticks.HorizSize * 0.1));
P3Plus := CalcPoint(tmp2, ICenter, tmpXRad, tmpYRad);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -