⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 teecirculargauge.pas

📁 BCB第三方组件
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{**********************************************}
{   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 + -