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

📄 jvqchart.pas

📁 East make Tray Icon in delphi
💻 PAS
📖 第 1 页 / 共 5 页
字号:
//    procedure DataTests; // TESTING. WAP.
  published
    { Standard TControl Stuff}
    //property Color default clWindow;
    property Font;
    property Align;
    property Anchors;
    property Constraints;
    property OnDblClick; { TNotifyEvent from TControl } 
    property DragMode;
    property Enabled;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property Visible;
    { chart options}
    property Options: TJvChartOptions read FOptions write FOptions;
    { chart events}

    property OnChartClick: TJvChartClickEvent read FOnChartClick write FOnChartClick;

    property OnChartPaint: TJvChartPaintEvent read FOnChartPaint write FOnChartPaint;
      // After chart bitmap is painted onto control surface we can "decorate" it with owner-drawn extras.

    { Drag and Drop of Floating Marker Events - NEW Jan 2005 -WP}
    property OnBeginFloatingMarkerDrag: TJvChartFloatingMarkerDragEvent read FOnBeginFloatingMarkerDrag write
      FOnBeginFloatingMarkerDrag; // Drag/drop of floating markers beginning.
    property OnEndFloatingMarkerDrag: TJvChartFloatingMarkerDragEvent read FOnEndFloatingMarkerDrag write
      FOnEndFloatingMarkerDrag; // Drag/drop of floating markers ending.

      {
        Chart Margin Click Events  - you can click on the four
        'margin' areas (left,right,top,bottom) around the main chart
        area. The left and top margins have default behaviours
        which you can disable by turning off Options.MouseEdit.
        The other 2 margin areas are entirely up to the user to define.
        Clicking bottom or right margins does nothing by default.
      }
    property OnYAxisClick: TJvChartEvent read FOnYAxisClick write FOnYAxisClick;
      // When user clicks on Y axis, they can enter a new Y Scale value.
    property OnXAxisClick: TJvChartEvent read FOnXAxisClick write FOnXAxisClick;
      // Also allow user to define some optional action for clicking on the X axis.
    property OnAltYAxisClick: TJvChartEvent read FOnAltYAxisClick write FOnAltYAxisClick;
      // Right margin click (Secondary Y Axis labels)
    property OnTitleClick: TJvChartEvent read FOnTitleClick write FOnTitleClick; // Top margin area (Title area) click.
  end;

implementation

uses
  {$IFDEF UNITVERSIONING}
  JclUnitVersioning,
  {$ENDIF UNITVERSIONING}
  SysUtils, Math, QForms, QDialogs, QPrinters, QClipbrd, 
  JvQJVCLUtils, JvQConsts, JvQResources;

const
  CHART_SANITY_LIMIT = 60000;
        // Any attempt to have more than CHART_SANITY_LIMIT elements in this
        // graph will be treated as an internal failure on our part.  This prevents
        // ugly situations where we thrash because of excessive memory usage.
        // Better to set this than to have the system pig out when we
        // don't want it to. Set this very small when debugging,
        // large when releasing component, and don't remove it unless
        // you're absolutely sure. Increase it whenever necessary.
        // Remember, it's a debugging tool, here on purpose to help keep you
        // out of thrashing-virtual-memory-hell.   You probably have a screen
        // to view the chart that is a maximum of 1600x1200, so more than 1600
        // samples will mean the data should be reduced before charting.

  MAX_VALUES = 20000;
    // Any attempt to exceed this values count will cause array size and performance problems, thus we limit it.
  MAX_PEN = 100;
    // Any attempt to exceed this pen count will cause array size and performance problems, thus we hardcode the pen limit to 100 pens.
  DEFAULT_PEN_COUNT = 16; // By Default TJvChartData's internal data structures have room for up to 16 pens
  MAX_X_LEGENDS = 50;
  MAX_GRAPH_LEGEND_LEN = 9;
  REALPREC = 7;
  DEFAULT_MARKER_SIZE = 3;
  DEFAULT_VALUE_COUNT = 100;
    // By Default TJvChartData holds 100 values per pen. Grows autofragellisticexpialidociously. :-)

//=== {TJvChartFloatingMarker} ===============================================

constructor TJvChartFloatingMarker.Create(Owner: TJvChart);
begin
  FOwner := Owner;
  FVisible := False; // NOT visible by default.
  FIndex := -1; // not yet set.
  FLineToMarker := -1; // Don't draw a line to connect to another marker.
  //FYPositionToPen := -1; // Don't copy FYPosition from the pen values.
  FMarkerColor := clRed;
  FMarker := pmkDiamond; // default is diamond marker.
  FLineStyle := psDot;
  FLineColor := clBlue;
  //FCaptionBorderStyle := psClear;
  FXDragMin := -1; // no limit.
  FXDragMax := -1; // no limit.
  FRawXPosition := -1;
  FRawYPosition := -1;
  FLineWidth := 1;
  //FXPosition := 0;
  //FYPosition := 0.0;
end;

procedure TJvChartFloatingMarker.SetCaption(aCaption: string);
begin
  if aCaption <> FCaption then
  begin
    FCaption := aCaption;
    if Assigned(FOwner) and FVisible then
      if not FOwner.FUpdating then
        FOwner.Invalidate;
  end;
end;

procedure TJvChartFloatingMarker.SetXPosition(xPos: Integer); // should invalidate the chart (FOwner) if changed.
begin
  if xPos <> FXPosition then
  begin
    FXPosition := xPos;
    if Assigned(FOwner) and FVisible then
      if not FOwner.FUpdating then
        FOwner.Invalidate;
  end
end;

procedure TJvChartFloatingMarker.SetYPosition(yPos: Double); // should invalidate the chart (FOwner) if changed.
begin
  if yPos <> FYPosition then
  begin
    FYPosition := yPos;
    if Assigned(FOwner) and FVisible then
      if not FOwner.FUpdating then
        FOwner.Invalidate;
  end
end;

procedure TJvChartFloatingMarker.SetVisible(isVisible: Boolean);
begin
  if isVisible <> FVisible then
  begin
    FVisible := isVisible;
    if Assigned(FOwner) then
      if not FOwner.FUpdating then
        FOwner.Invalidate;
  end
end;

//=== { TJvChartData } =======================================================

constructor TJvChartData.Create;
var
  I: Integer;
begin
  inherited Create;
  for I := 0 to DEFAULT_PEN_COUNT do
    Grow(I, DEFAULT_VALUE_COUNT);
end;

destructor TJvChartData.Destroy;
var
  I: Integer;
begin
  for I := 0 to FDataAlloc - 1 do
    Finalize(FData[I]);
  Finalize(FData); // Free array.
  inherited Destroy;
end;

function TJvChartData.GetValue(Pen, ValueIndex: Integer): Double;
begin
  // Grow base array
  Assert(ValueIndex >= 0);
  Grow(Pen, ValueIndex);
  Result := FData[ValueIndex, Pen]; // This will raise EInvalidOP for NaN values.
end;

procedure TJvChartData.SetValue(Pen, ValueIndex: Integer; NewValue: Double);
begin
  // Grow base array
  Grow(Pen, ValueIndex);
  FData[ValueIndex, Pen] := NewValue;
  if ValueIndex >= FValueCount then
  begin
    Grow(Pen, ValueIndex + 1);
    FData[ValueIndex + 1, Pen] := NewValue; // Workaround for a graphical bug. Sorry.
    FValueCount := ValueIndex + 1;
  end;
end;

function TJvChartData.GetTimestamp(ValueIndex: Integer): TDateTime;
begin
  if (ValueIndex < 0) or (ValueIndex >= Length(FTimeStamp)) then
    Result := 0.0 // null datetime
  else
    Result := FTimeStamp[ValueIndex];
end;

procedure TJvChartData.SetTimestamp(ValueIndex: Integer; AValue: TDateTime);
begin
  if ValueIndex < 0 then
    Exit;
  if ValueIndex >= Length(FTimeStamp) then
    SetLength(FTimeStamp, ValueIndex + 1);
  FTimeStamp[ValueIndex] := AValue;
end;

procedure TJvChartData.Scroll;
var
  I, J: Integer;
begin
  if FValueCount < 2 then
  begin
    Clear;
    Exit;
  end;
  { ULTRA SLOW BUT NON-CRASHING Version }
  for I := 0 to FValueCount - 1 do
  begin
    for J := 0 to Length(FData[I]) - 1 do
      FData[I, J] := FData[I + 1, J];
    SetTimestamp(I, GetTimestamp(I + 1));
  end;
  FTimeStamp[FValueCount - 1] := 0;
  // Check we didn't break the heap:
end;

procedure TJvChartData.Grow(Pen, ValueIndex: Integer);
var
  I, J, oldLength: Integer;
begin
  if (Pen < 0) or (ValueIndex < 0) then
  begin
    raise ERangeError.CreateRes(@RsEDataIndexCannotBeNegative);
  end;
  if (Pen > CHART_SANITY_LIMIT) or (ValueIndex > CHART_SANITY_LIMIT) then
  begin
    raise ERangeError.CreateRes(@RsEDataIndexTooLargeProbablyAnInternal);
  end;

  if ValueIndex >= FDataAlloc then
  begin
      //--------------------------------------------------------
      // Performance tweak: Uses more memory but makes JvChart
      // much faster!
      // We Double our allocation unit size
      // until we start to get Really Huge, then grow in chunks!
      //--------------------------------------------------------
    if ValueIndex < 640000 then
      FDataAlloc := (ValueIndex * 2) // Double in size
    else
      FDataAlloc := ValueIndex + 64000;

    oldLength := Length(FData);
    SetLength(FData, FDataAlloc);

// new: If we set FClearToValue to NaN, special handling in growing arrays:
    if IsNaN(FClearToValue) then
      for I := oldLength to FDataAlloc - 1 do
        for J := 0 to Length(FData[I]) - 1 do
          FData[I][J] := FClearToValue; // XXX Debug me!

  end;
  if Pen >= Length(FData[ValueIndex]) then
  begin
    oldLength := Length(FData[ValueIndex]);
    SetLength(FData[ValueIndex], Pen + 1);
    if IsNaN(FClearToValue) then
    begin
      for I := oldLength to FDataAlloc - 1 do
      begin
        Assert(Length(FData) > ValueIndex);
        if (Length(FData[ValueIndex]) < FDataAlloc) then
          SetLength(FData[ValueIndex], FDataAlloc); // Safety code!
        FData[ValueIndex][I] := FClearToValue; // XXX Debug me!
      end;
    end;
  end;
end;

function TJvChartData.DebugStr(ValueIndex: Integer): string; // dump all pens for particular valueindex, as string.
var
  S: string;
  I, IMax: Integer;
begin
  if (ValueIndex < 0) or (ValueIndex >= FDataAlloc) then
    Exit;
  IMax := Length(FData[ValueIndex]) - 1;

  if Timestamp[ValueIndex] > 0.0 then
    S := FormatDateTime('hh:nn:ss ', Timestamp[ValueIndex]);
  for I := 0 to IMax do
  begin
    if IsNaN(FData[ValueIndex, I]) then
      S := S + '-'
    else
      S := S + Format('%5.2f', [FData[ValueIndex, I]]);

    if I < IMax then
      S := S + ', '
  end;
  Result := S;
end;

procedure TJvChartData.Clear; // Resets FValuesCount/FPenCount to zero. Zeroes everything too, just for good luck.
var
  I, J: Integer;
begin
  for I := 0 to FDataAlloc - 1 do
    for J := 0 to Length(FData[I]) - 1 do
      FData[I, J] := FClearToValue;
  FValueCount := 0;
end;

procedure TJvChartData.ClearPenValues; // Clears all pen values to NaN but does not reset pen definitions etc.
var
  I, J: Integer;
begin
  for I := 0 to FDataAlloc - 1 do
    for J := 0 to Length(FData[I]) - 1 do
      FData[I, J] := 0.0;
end;

//=== { TJvChartYAxisOptions } ===============================================

constructor TJvChartYAxisOptions.Create(Owner: TJvChartOptions);
begin
  inherited Create;
  FOwner := Owner;

  FMarkerValueDecimals := -1; // -1 = default (automatic decimals)

  FYLegends := TStringList.Create;
  FMaxYDivisions := 20;
  FMinYDivisions := 5;
  FYDivisions := 10;
  FDefaultYLegends := JvDefaultYLegends;
end;

destructor TJvChartYAxisOptions.Destroy;

⌨️ 快捷键说明

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