Search code examples
imagedelphidelphi-2010pan

How to create a pan from composite image in Delphi


I'm kind of new to delphi graphics methods and I'm stucked at creating a ... viewport , thats how I call it while i was doing it for a project. I'm sorry I can't provide any code for it but I'm stuck at the logic part , searching google pointed me to some OnPaint , Draw methods. But those are not what I'm trying to accomplish, since I have , for example:

  1. A 1600x1000 background image anchored to the client's top/bottom/right and left.
  2. Multiple TImage elements placed at set x/y coords.
  3. A "hotspot" like a map element in HTML where I can set the clickable areas (for the images i'm placing at step 2)
  4. No zoom needed.
  5. And the most important thing, while the background is dragged, those TImages placed on top of the background need to be dragged too.

My logic (in HTML/jQuery) was to create a #viewportBinder (which was the div i was dragging, transparent bg), followed by another div inside it called #viewtown (1600x1000, the background) which contains the divs (those TImages) placed at set coordinates in CSS.

So when I am dragging the viewportBinder, jQuery sets the new x/y on the #viewport. Implicitly, the divs (TImages) inside the #viewport are moving because the parent was positioned relative.

Does anybody have any experience with this kind of project ? Any snippet of code ?

To be more specific i'll give you my html example of what i accomplised and what i want to port into Delphi code: http://www.youtube.com/watch?v=9iYqzvZFnGA

Sorry if i'm not clear enough, i have no starting point since I have no experience with this in delphi at all. (using RAD Studio 2010)


Solution

  • A very short example how it could be realized in an easy way.

    You would use a Paintbox for painting, 1 Backimage, an array of Records with info and transparent pngimages.

    Canvas can be manipulated in offset/zoom/rotation. Moving and hitdetection would happen in mousedown and mousemove.

    It's not complete, but might give you an idea how it could be done.

    [delphi]
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ExtCtrls,PNGImage, StdCtrls;
    
    type
      TBuilding=Record   // record for building informations
        Pos:TPoint;
        PNGImage:TPngImage;
        // what ever needed
      End;
    
      TBuildingArray=Array of TBuilding; // array of buildings
    
      TForm1 = class(TForm)
        PaintBox1: TPaintBox;
        Button1: TButton;
        procedure FormCreate(Sender: TObject);
        procedure PaintBox1Paint(Sender: TObject);
        procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
          Shift: TShiftState; X, Y: Integer);
        procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
          Y: Integer);
        procedure Button1Click(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        { Private-Deklarationen }
        FXoffs,FYOffs,FZoom:Double; // offset and zoom for painting
        FMouseDownPoint:TPoint;
        FBackGroundPNG:TPNGImage;
        FBuildingArray:TBuildingArray;
        procedure Check4Hit(X, Y: Integer);
      public
        { Public-Deklarationen }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    uses Math;
    {$R *.dfm}
    
    
    Procedure SetCanvasZoomAndRotation(ACanvas:TCanvas;Zoom:Double;Angle:Double;CenterpointX,CenterpointY:Double);
    var
        form : tagXFORM;
        Winkel:Double;
    begin
          Winkel := DegToRad(Angle);
          SetGraphicsMode(ACanvas.Handle, GM_ADVANCED);
          SetMapMode(ACanvas.Handle,MM_ANISOTROPIC);
          form.eM11 := Zoom * cos( Winkel);
          form.eM12 := Zoom *Sin( Winkel)  ;
          form.eM21 := Zoom * (-sin( Winkel));
          form.eM22 := Zoom * cos( Winkel) ;
          form.eDx := CenterpointX;
          form.eDy := CenterpointY;
          SetWorldTransform(ACanvas.Handle,form);
    end;
    
    Procedure ResetCanvas(ACanvas:TCanvas);
    begin
       SetCanvasZoomAndRotation(ACanvas , 1, 0, 0,0);
    end;
    
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
     Path:String;
     i:Integer;
    begin
       FZoom := 1;
       DoubleBuffered := true;
       Path := ExtractFilePath(Paramstr(0));
       FBackGroundPNG:=TPNGImage.Create;
       FBackGroundPNG.LoadFromFile(Path + 'infect.png');
       SetLength(FBuildingArray,3);
       for I := 0 to High(FBuildingArray)  do
          begin
             FBuildingArray[i].PNGImage := TPngImage.Create;
             FBuildingArray[i].PNGImage.LoadFromFile(Path + Format('B%d.png',[i]));
             FBuildingArray[i].Pos.X := I * 300;
             FBuildingArray[i].Pos.Y := Random(1000);
          end;
    
    end;
    procedure TForm1.FormDestroy(Sender: TObject);
    var
     i:Integer;
    begin
       for I := 0 to High(FBuildingArray)  do
          begin
             FBuildingArray[i].PNGImage.Free;
          end;
       FBackGroundPNG.Free;
    end;
    
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      if FZoom=0.5 then FZoom := 1 else FZoom := 0.5;
      PaintBox1.Invalidate;
    end;
    
    procedure TForm1.Check4Hit(X,Y:Integer);
    var
     i,Index:Integer;
     R:TRect;
     P:TPoint;
    begin
       index := -1;
       for I := 0 to High(FBuildingArray)  do
          begin
             R := Rect(FBuildingArray[i].Pos.X,FBuildingArray[i].Pos.Y
                        ,FBuildingArray[i].Pos.X + FBuildingArray[i].PNGImage.Width
                        ,FBuildingArray[i].Pos.Y + FBuildingArray[i].PNGImage.Height);
             P := Point(Round((x - FXOffs)/FZoom) ,Round((y - FYOffs)/FZoom));
             if PtInRect(R,P) then Index := i;
          end;
       if index > -1 then
          begin
            Caption := Format('Last hit %d',[index]);
          end
       else Caption := 'No Hit';
    end;
    
    procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    begin
       Check4Hit(X,Y);
       FMouseDownPoint.X := X;
       FMouseDownPoint.Y := Y;
    end;
    
    procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    begin
       if ssLeft in Shift then
          begin
             FXoffs := -( FMouseDownPoint.X - X) ;
             FYoffs := -( FMouseDownPoint.Y - Y) ;
             if FXoffs>0 then FXoffs := 0;
             if FYoffs>0 then FYoffs := 0;
             PaintBox1.Invalidate;
          end;
    end;
    
    procedure TForm1.PaintBox1Paint(Sender: TObject);
    var
     i:Integer;
    begin
       SetCanvasZoomAndRotation(PaintBox1.Canvas,FZoom,0,FXoffs,FYOffs);
       PaintBox1.Canvas.Draw(0,0,FBackGroundPNG);
       for I := 0 to High(FBuildingArray)  do
          begin
             PaintBox1.Canvas.Draw(FBuildingArray[i].Pos.X,FBuildingArray[i].Pos.Y,FBuildingArray[i].PNGImage);
          end;
    end;
    
    end.
    
    [/delphi]