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

📄 teeseriesregion.pas

📁 BCB第三方组件
💻 PAS
字号:
{**********************************************}
{   TSeriesRegionTool                          }
{   Copyright (c) 2006-2007 by Marjan Slatinek }
{**********************************************}
unit TeeSeriesRegion;
{$I TeeDefs.inc}

interface

uses
  {$IFNDEF LINUX}
  Windows,
  {$ENDIF}
  SysUtils, Classes,
  {$IFDEF CLX}
  QGraphics, QControls, QForms, QDialogs, QStdCtrls, QExtCtrls, QComCtrls,
  {$ELSE}
  Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls,
  {$ENDIF}
  TeeProcs, TeEngine, TeeToolSeriesEdit, TeCanvas, Chart, TeeEdiGrad, TeePenDlg;

type
  (*:Series region tool - it colors bounded area under the (series) curve.*)
  TSeriesRegionTool=class(TTeeCustomToolSeries)
  private
    FAutoBounds: Boolean;
    FDrawBehindSeries: Boolean;
    FGradient: TTeeGradient;
    FLowerBound: Double;
    FOrigin: Double;
    FTransparency: TTeeTransparency;
    FUpperBound: Double;
    FUseOrigin: Boolean;

    ISeriesDrawn : Boolean;

    function GetColor:TColor;
    function IntersectionPoint(const Value: double; out y: double): Integer;
    procedure SetAutoBounds(const Value: Boolean);
    procedure SetColor(const Value: TColor);
    procedure SetDrawBehindSeries(const Value: Boolean);
    procedure SetGradient(const Value: TTeeGradient);
    procedure SetLowerBound(const Value: double);
    procedure SetOrigin(const Value: double);
    procedure SetTransparency(const Value: TTeeTransparency);
    procedure SetUpperBound(const Value: double);
    procedure SetUseOrigin(const Value: boolean);
  protected
    procedure ChartEvent(AEvent: TChartToolEvent); override;
    procedure DrawRegion; virtual;
    class Function GetEditorClass:String; override;
    Procedure SeriesEvent(AEvent:TChartToolEvent); override;
    procedure SetSeries(const Value: TChartSeries); override;
  public
    Constructor Create(AOwner:TComponent); override;
    Destructor Destroy; override;

    procedure Assign(Source: TPersistent); override;
    class Function Description:String; override;
    class Function LongDescription:String; override;
  published
    property AutoBounds:Boolean read FAutoBounds write SetAutoBounds default True;

    (*:If true, draw region behind series. If false, draw region over series.*)
    property DrawBehindSeries:Boolean read FDrawBehindSeries write
                                              SetDrawBehindSeries default True;

    property Gradient:TTeeGradient read FGradient write SetGradient;

    (*:Region left (series not mandatory values lower) bound.*)
    property LowerBound: double read FLowerBound write SetLowerBound;

    (*:Region bottom or upper limit. Used only if UseOrigin is true*)
    property Origin: double read FOrigin write SetOrigin;

    (*:Region right (series not mandatory values upper) bound.*)
    property UpperBound: double read FUpperBound write SetUpperBound;

    (*:If true, region bottom or upper limit is defined by Origin*)
    property UseOrigin: boolean read FUseOrigin write SetUseOrigin default True;

    property Active;
    property Brush;
    property Color:TColor read GetColor write SetColor default clWhite;
    property Pen;
    property Series;
    property Transparency:TTeeTransparency read FTransparency
                                           write SetTransparency default 0;
  end;

  TSeriesRegionEditor = class(TSeriesToolEditor)
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    TabSheet2: TTabSheet;
    ButtonPen1: TButtonPen;
    TabGradient: TTabSheet;
    ButtonColor1: TButtonColor;
    Button1: TButton;
    GroupBox1: TGroupBox;
    Label3: TLabel;
    Label4: TLabel;
    ELower: TEdit;
    EUpper: TEdit;
    GroupBox2: TGroupBox;
    CBUseOrigin: TCheckBox;
    Label2: TLabel;
    EOrigin: TEdit;
    CBAutoBounds: TCheckBox;
    CBBehind: TCheckBox;
    Label5: TLabel;
    ETransp: TEdit;
    UDTransp: TUpDown;
    procedure FormShow(Sender: TObject);
    procedure CBBehindClick(Sender: TObject);
    procedure CBUseOriginClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ELowerChange(Sender: TObject);
    procedure EUpperChange(Sender: TObject);
    procedure EOriginChange(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure CBAutoBoundsClick(Sender: TObject);
    procedure ETranspChange(Sender: TObject);
  private
    { Private declarations }
  public
    { Pulic declarations }
    CreatingForm: Boolean;
  end;

implementation

{$IFNDEF CLX}
{$IFNDEF LCL}
{$R *.DFM}
{$ENDIF}
{$ELSE}
{$R *.xfm}
{$ENDIF}

uses
  Math, TeeBrushDlg, TeeProCo;

{ TSeriesRegionTool }

Constructor TSeriesRegionTool.Create(AOwner: TComponent);
begin
  inherited;
  FAutoBounds:=True;
  FDrawBehindSeries:=True;
  FUseOrigin:=True;
  Brush.BackColor:=clWhite;
  FGradient:=TTeeGradient.Create(CanvasChanged);
end;

Destructor TSeriesRegionTool.Destroy;
begin
  FGradient.Free;
  inherited;
end;

procedure TSeriesRegionTool.Assign(Source: TPersistent);
begin
  if Source is TSeriesRegionTool then
  with TSeriesRegionTool(Source) do
  begin
    Self.FAutoBounds:=FAutoBounds;
    Self.FDrawBehindSeries := DrawBehindSeries;
    Self.Gradient := Gradient;
    Self.FLowerBound := LowerBound;
    Self.FOrigin := Origin;
    Self.FUseOrigin := UseOrigin;
    Self.FTransparency := Transparency;
    Self.FUpperBound := UpperBound;
  end;

  inherited;
end;

procedure TSeriesRegionTool.ChartEvent(AEvent: TChartToolEvent);
begin
  inherited;

  if AEvent=cteBeforeDrawSeries then
     iSeriesDrawn := False;
end;

class function TSeriesRegionTool.Description: String;
begin
  Result := TeeMsg_SeriesRegion;
end;

class Function TSeriesRegionTool.LongDescription:String;
begin
  Result := TeeMsg_SeriesRegionDesc;
end;

procedure TSeriesRegionTool.DrawRegion;
var lb,ub    : double;
    yl,yu    : double;
    pts      : TPointArray;
    plen,
    i,
    first,
    last     : Integer;
    tmpR     : TRect;
    tmpBlend : TTeeBlend;
begin
  if Active and Visible and Assigned(ParentChart) and Assigned(Series) then
  begin
    lb:=Series.NotMandatoryValueList.MinValue;
    ub:=Series.NotMandatoryValueList.MaxValue;

    if not FAutoBounds then
    begin
      lb:=Max(lb,FLowerBound);
      ub:=Min(ub,FUpperBound);
    end;

    // plot only if it makes sense
    if (ub>Series.NotMandatoryValueList.MinValue) and
       (lb<Series.NotMandatoryValueList.MaxValue) then
    begin
      first:=IntersectionPoint(lb,yl);
      last:=IntersectionPoint(ub,yu);

      if last<first then
         SwapInteger(last,first);

      plen:= last - first + 1;

      SetLength(pts,plen+4); // 4 extra points
      try
        for i := 0 to plen-1 do
        begin
          pts[i].X := Series.CalcXPos(i+first);
          pts[i].Y := Series.CalcYPos(i+first);
        end;

        // upper bound intersect point
        pts[plen].X := Series.CalcXPosValue(ub);
        pts[plen].Y := Series.CalcYPosValue(yu);

        // upper bound origin point
        pts[plen+1].X := pts[plen].X;

        if FUseOrigin then
           pts[plen+1].Y := Series.CalcYPosValue(FOrigin)
        else
           pts[plen+1].Y := Series.GetVertAxis.IEndPos;

        // lower bound origin point
        pts[plen+2].X := Series.CalcXPosValue(lb);
        pts[plen+2].Y := pts[plen+1].Y;

        // lower bound intersect point
        pts[plen+3].X := pts[plen+2].X;
        pts[plen+3].Y := Series.CalcYPosValue(yl);

        With ParentChart,Canvas do
        begin
          AssignBrush(Self.Brush);
          AssignVisiblePen(Self.Pen);

          ClipRectangle(RectFromRectZ(ChartRect, Self.Series.StartZ));

          if Transparency<>0 then
          begin
            if View3D then
               tmpR:=RectFromRectZ(PolygonBounds(pts),Self.Series.StartZ)
            else
               tmpR:=PolygonBounds(pts);

            tmpBlend:=ParentChart.Canvas.BeginBlending(tmpR,Transparency);
          end
          else
            tmpBlend:=nil;

          if Self.Gradient.Visible and CanClip and View3DOptions.Orthogonal then
          begin
            Self.Gradient.Draw(Canvas,pts,Self.Series.StartZ,View3D);
            Brush.Style:=bsClear;
          end;

          if View3D then
             PolygonWithZ(pts,Self.Series.StartZ)
          else
             Polygon(pts);

          if Assigned(tmpBlend) then
             ParentChart.Canvas.EndBlending(tmpBlend);

          UnClipRectangle;
        end;
      finally
        pts := nil;
      end;
    end;
  end;
end;

class function TSeriesRegionTool.GetEditorClass: String;
begin
  result:='TSeriesRegionEditor';
end;

function TSeriesRegionTool.GetColor:TColor;
begin
  result:=Brush.BackColor;
end;

Function TSeriesRegionTool.IntersectionPoint(const Value: double; out y: double): Integer;
var i: Integer;
    k: double;
begin
  i := 0;
  y := Series.MandatoryValueList[i];

  while (Value>Series.NotMandatoryValueList[i]) and (i<Series.Count) do
        Inc(i);

  // We have two choices:
  // #1: value is exactly at point coordinate
  // #2: value is between two points - use linear interpolation to calculate y

  with Series do
  if Value=NotMandatoryValueList[i] then
     y := MandatoryValueList[i]
  else
  if (i>0) and (i<Series.Count) then
  begin
    k := (MandatoryValueList[i]-MandatoryValueList[i-1]) /
         (NotMandatoryValueList[i]-NotMandatoryValueList[i-1]);

    y := MandatoryValueList[i-1] + k*(Value-NotMandatoryValueList[i-1]);
  end;

  Result := i; // return point index
end;

procedure TSeriesRegionTool.SetColor(const Value: TColor);
begin
  Brush.BackColor:=Value;
end;

procedure TSeriesRegionTool.SetDrawBehindSeries(const Value: Boolean);
begin
  SetBooleanProperty(FDrawBehindSeries,Value);
end;

procedure TSeriesRegionTool.SetGradient(const Value: TTeeGradient);
begin
  FGradient.Assign(Value);
end;

procedure TSeriesRegionTool.SetLowerBound(const Value: double);
begin
  SetDoubleProperty(FLowerBound,Value);
end;

procedure TSeriesRegionTool.SetOrigin(const Value: double);
begin
  SetDoubleProperty(FOrigin,Value);
end;

procedure TSeriesRegionTool.SetSeries(const Value: TChartSeries);
begin
  inherited;
  Repaint;
end;

procedure TSeriesRegionTool.SetTransparency(const Value: TTeeTransparency);
begin
  if FTransparency<>Value then
  begin
    FTransparency:=Value;
    Repaint;
  end;
end;

procedure TSeriesRegionTool.SetUpperBound(const Value: double);
begin
  SetDoubleProperty(FUpperBound,Value);
end;

procedure TSeriesRegionTool.SetUseOrigin(const Value: boolean);
begin
  SetBooleanProperty(FUseOrigin,Value);
end;

procedure TSeriesRegionEditor.CBUseOriginClick(Sender: TObject);
begin
  if not CreatingForm then
     TSeriesRegionTool(Tool).UseOrigin := CBUseOrigin.Checked;
end;

procedure TSeriesRegionEditor.ELowerChange(Sender: TObject);
begin
  if not CreatingForm then
  with TSeriesRegionTool(Tool) do
       LowerBound:=StrToFloatDef(ELower.Text,LowerBound);
end;

procedure TSeriesRegionEditor.EUpperChange(Sender: TObject);
begin
  if not CreatingForm then
  with TSeriesRegionTool(Tool) do
       UpperBound:=StrToFloatDef(EUpper.Text,UpperBound);
end;

procedure TSeriesRegionEditor.FormCreate(Sender: TObject);
begin
  CreatingForm := True;
  inherited;
end;

procedure TSeriesRegionEditor.FormShow(Sender: TObject);
begin
  inherited;

  if Assigned(Tool) then
  with TSeriesRegionTool(Tool) do
  begin
    EOrigin.Text := FloatToStr(Origin);
    ButtonPen1.LinkPen(Pen);
    CBUseOrigin.Checked := UseOrigin;
    CBBehind.Checked := DrawBehindSeries;
    CBAutoBounds.Checked:=AutoBounds;
    UDTransp.Position:=Transparency;

    ELower.Text := FloatToStr(LowerBound);
    EUpper.Text := FloatToStr(UpperBound);
    
    ELower.Enabled:=not CBAutoBounds.Checked;
    EUpper.Enabled:=not CBAutoBounds.Checked;

    AddFormTo(TTeeGradientEditor.CreateCustom(Self,Gradient),TabGradient);
    ButtonColor1.LinkProperty(Tool,'Color');
  end;

  CreatingForm := False;
end;

procedure TSeriesRegionEditor.CBBehindClick(Sender: TObject);
begin
  TSeriesRegionTool(Tool).DrawBehindSeries := CBBehind.Checked;
end;

procedure TSeriesRegionEditor.EOriginChange(Sender: TObject);
begin
  if not CreatingForm then
  with TSeriesRegionTool(Tool) do
       Origin:=StrToFloatDef(EOrigin.Text,Origin);
end;

procedure TSeriesRegionEditor.Button1Click(Sender: TObject);
begin
  EditChartBrush(Self,Tool.Brush);
end;

procedure TSeriesRegionEditor.CBAutoBoundsClick(Sender: TObject);
begin
  if not CreatingForm then
  begin
    TSeriesRegionTool(Tool).AutoBounds:=CBAutoBounds.Checked;

    ELower.Enabled:=not CBAutoBounds.Checked;
    EUpper.Enabled:=not CBAutoBounds.Checked;
  end;
end;

procedure TSeriesRegionTool.SetAutoBounds(const Value: Boolean);
begin
  SetBooleanProperty(FAutoBounds,Value);
end;

procedure TSeriesRegionEditor.ETranspChange(Sender: TObject);
begin
  if not CreatingForm then
     TSeriesRegionTool(Tool).Transparency:=UDTransp.Position;
end;

procedure TSeriesRegionTool.SeriesEvent(AEvent: TChartToolEvent);
begin
  if Assigned(Series) then
     if ((AEvent=cteBeforeDrawSeries) and DrawBehindSeries) or
        ((AEvent=cteAfterDrawSeries) and (not DrawBehindSeries)) then
            DrawRegion;
end;

initialization
  RegisterTeeTools([TSeriesRegionTool]);
  RegisterClass(TSeriesRegionEditor);
finalization
  UnRegisterTeeTools([TSeriesRegionTool]);
end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -