Fix for ZoomIn and ZoomOut

The ZoomIn & ZoomOut do not work as described in the remarks and IMHO do not work in an intuitive manner. I would expect zooming in (or out) on a point to keep the same point under the cursor after the zoom but this is not the case, the zoom generally jumps back to the top left corner of the diagram.
I have a fix for this that I hope can be incorporated into the core atDiagram.pas:

procedure TatDiagram.ZoomIn(ARect: TSquare);
var
  hc, wc: number;
  r1, r2: double;
  Clicked: boolean;
  c: integer;
  RelPosn, ClickDot : TDot;
begin
  Clicked := AroundPoint(ARect.TopLeft, ARect.BottomRight, 10);

  wc := ClientWidth - FLeftRuler.VisibleSize;
  hc := ClientHeight - FTopRuler.VisibleSize;

  ClickDot.X := (ARect.Right + ARect.Left) / 2;
  ClickDot.Y := (ARect.Bottom + ARect.Top) / 2;
  ClickDot := ClientToCanvas(ClickDot);
  RelPosn.X := (ClickDot.x + HorzScrollBar.Position) / HorzScrollBar.range;
  RelPosn.Y := (ClickDot.y + VertScrollBar.Position) / VertScrollBar.range;

  if Clicked then
  begin
    c := 0;
    while (c < MaxZoomRatios - 1) and (FZoomRatio >= ZoomRatios[c]) do
      inc(c);
    FZoomRatio := ZoomRatios[c];
  end
  else
  begin
    r1 := wc / (ARect.Right - ARect.left);
    r2 := hc / (ARect.Bottom - ARect.top);
    if r1 < r2 then
      FZoomRatio := r1
    else
      FZoomRatio := r2;
  end;

  if FZoomRatio < 0.01 then
    FZoomRatio := 0.01;
  if FZoomRatio > 10 then
    FZoomRatio := 10;
  FTopRuler.Zoom := Trunc(ZoomRatio * 100);
  FLeftRuler.Zoom := FTopRuler.Zoom;
  CalcPanelSize;


  HorzScrollBar.Position := round((HorzScrollBar.Range * RelPosn.X) - ClickDot.x);
  VertScrollBar.Position := round((VertScrollBar.Range * RelPosn.Y) - ClickDot.y);
  UpdateScrollBars;

end;

procedure TatDiagram.ZoomOut(ARect: TSquare);
var
  hc, wc: number;
  r1, r2: double;
  Clicked: boolean;
  c: integer;
  RelPosn, ClickDot : TDot;
begin
  Clicked := AroundPoint(ARect.TopLeft, ARect.BottomRight, 10);

  wc := ClientWidth - FLeftRuler.VisibleSize;
  hc := ClientHeight - FTopRuler.VisibleSize;

  ClickDot.X := (ARect.Right + ARect.Left) / 2;
  ClickDot.Y := (ARect.Bottom + ARect.Top) / 2;
  ClickDot := ClientToCanvas(ClickDot);
  RelPosn.X := (ClickDot.x + HorzScrollBar.Position) / HorzScrollBar.range;
  RelPosn.Y := (ClickDot.y + VertScrollBar.Position) / VertScrollBar.range;

  if Clicked then
  begin
    c := MaxZoomRatios - 1;
    while (c > 0) and (FZoomRatio <= ZoomRatios[c]) do
      dec(c);
    FZoomRatio := ZoomRatios[c];
  end
  else
  begin
    r1 := (ARect.Right - ARect.left) * FZoomratio / ClientWidth;
    r2 := (ARect.Bottom - ARect.top) * FZoomRatio / ClientHeight;
    if r1 < r2 then
      r1 := r2;
    FZoomratio := r1;
  end;

  if FZoomRatio < 0.01 then
    FZoomRatio := 0.01;
  if FZoomRatio > 10 then
    FZoomRatio := 10;
  FTopRuler.Zoom := Trunc(ZoomRatio * 100);
  FLeftRuler.Zoom := FTopRuler.Zoom;
  CalcPanelSize;
  HorzScrollBar.Position := round((HorzScrollBar.Range * RelPosn.X) - ClickDot.x);
  VertScrollBar.Position := round((VertScrollBar.Range * RelPosn.Y) - ClickDot.y);
  UpdateScrollBars;
end;

I am sure there are lots of improvements that could be made, but the basic concept works correctly. Clicking on a point zooms in on that point, selecting an area zooms on the center of that area.

Hi @Wilbourn_David. Thank you for the contribution.
I agree with the click operation, the point should be kept under mouse cursor. However, I disagree about current behavior when using a square. It's working fine, and we kept that behavior.
Changes were incorporated into official source code, next release will include this fix.

Yes, my apologies, the ZoomIn to area did work - until I fixed the ZoomIn to point. :man_facepalming:

1 Like

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.