Home > Delphi, OP4JS, Smart Mobile Studio > Smart Mobile Studio Superfast Scrolling

Smart Mobile Studio Superfast Scrolling

If you have been following my blog, you probably noticed that I published a wrapper unit and controller class for iScroll, the number one scroll library for JavaScript – allowing flicker-free, silky smooth touch & momentum scrolling for ordinary DIV tags.

But you are probably wondering – why is iScroll so fast and smooth while “ordinary” moving controls are so slow?

Sprite3d leveraged by SMS

Sprite3d leveraged by SMS

The answer is that iScroll is not really “scrolling” in the true sense of the word, but rather adjusting hardware accelerated CSS transforms very quickly, which uses the GPU to move html elements around the screen. And I must add that the the author behind iScroll is an expert in this field (he has also spent something like 6+ years updating and perfecting iScroll).

So, could we do something similar under “native” Smart Mobile Studio, without the help of third party libraries? I mean, it would be very handy to use CSS3 and hardware acceleration as much as possible in our apps right?

Well now you can! In fact, the code to CSS3 pimp your controls have been in the RTL for ages, but it has to date only been used for games and demos. If you have a peek at W3Sprite3d.pas and you will find a fully functioning “sprite” control, which uses CSS to move, rotate and live in 3d space. What we really need is to create a controller class – which allows us to attach this functionality to any HTML element (read: any TW3CustomControl based component).

By the way, Sprite3d is a native JS library which I completely implemented in Object Pascal. It is extremely fast and perfect for heavy-duty graphics operations outside the canvas.

In short, below is the CSS3 hardware accelerated controller class which makes it a snap to create super-fast scrolling elements. Simply create an instance of this inside your control, pass the handle (not the reference) of your html element to the constructor — and voila, you can now use the properties of TW3CSSTransformController to move the element around very, very quickly. Remember that you must call “update()” for each change, since the CSS is updated live by the code.

Who’s you daddy 😉

 

unit W3CssTransformController;

// Written by Jon Lennart Aasenden
// Copyright Jon Lennart Aasenden LTD, all rights reserved

interface

uses
  W3System, W3Graphics, W3Components;

type

  TW3CssTransformOptions = set of (toUsePos,toUseRotX,toUseRotY,toUseRotZ,toUseScale);

  TW3CSSTransformController = Class(TObject)
  private
    FHandle:  THandle;
    FX:       Float;
    FY:       Float;
    FZ:       Float;
    FRotX:    Float;
    FRotY:    Float;
    FRotZ:    Float;
    FRegX:    Float;
    FRegY:    Float;
    FRegZ:    Float;
    FScaleX:  Float;
    FScaleY:  Float;
    FScaleZ:  Float;
    FFlags:   TW3CssTransformOptions;
  public
    Property    Handle:THandle read FHandle;
    property    RotationX: Float read FRotX write FRotX;
    property    RotationY: Float read FRotY write FRotY;
    property    RotationZ: Float read FRotZ write FRotZ;
    property    ScaleX: Float read FScaleX write FScaleX;
    property    ScaleY: Float read FScaleY write FScaleY;
    property    ScaleZ: Float read FScaleZ write FScaleZ;
    property    RegX: Float read FRegX write FRegX;
    property    RegY: Float read FRegY write FRegY;
    property    RegZ: Float read FRegZ write FRegZ;
    property    X: Float read FX write FX;
    property    Y: Float read FY write FY;
    property    Z: Float read FZ write FZ;

    procedure   SetRegistrationPoint(const X, Y, Z: Float);
    procedure   SetTransformOrigin(const X, Y: Float);
    procedure   Scale(const X, Y, Z: Float); overload;
    procedure   Scale(const aValue: Float); overload;
    procedure   RotateX(const aValue: Float);
    procedure   RotateY(const aValue: Float);
    procedure   RotateZ(const aValue: Float);
    procedure   Rotate(const XFactor, YFactor, ZFactor: Float); overload;
    procedure   Rotate(const aValue: Float); overload;
    procedure   SetRotation(const X, Y, Z: Float);
    procedure   SetPosition(const X, Y, Z: Float);
    procedure   MoveX(const aValue: Float);
    procedure   MoveY(const aValue: Float);
    procedure   MoveZ(const aValue: Float);
    procedure   Move(X, Y, Z: Float);
    procedure   SetTransformFlags(const aValue:TW3CssTransformOptions);
    procedure   Update; virtual;
    Constructor Create(const aHandle:THandle);
  End;

implementation

{ **************************************************************************** }
{ TW3CSSTransformController                                                    }
{ **************************************************************************** }

Constructor TW3CSSTransformController.Create(const aHandle:THandle);
Begin
  inherited Create;

  FScaleX := 1.0;
  FScaleY := 1.0;
  FScaleZ := 1.0;

  FFlags:=[toUsePos,toUseRotX,toUseRotY,toUseRotZ,toUseScale];

  if (aHandle) then
  begin
    FHandle:=aHandle;

    FHandle.style[w3_CSSPrefix('transformStyle')] := 'preserve-3d';
    FHandle.style[w3_CSSPrefix('Perspective')] := 800;
    FHandle.style[w3_CSSPrefix('transformOrigin')] := '50% 50%';
    FHandle.style[w3_CSSPrefix('Transform')] := 'translateZ(0px)';

    Update;
  end else
  Raise EW3Exception.Create('Invalid control handle error');
end;


procedure TW3CSSTransformController.MoveX(const aValue: Float);
begin
  FX+=aValue;
end;

procedure TW3CSSTransformController.MoveY(const aValue: Float);
begin
  FY+=aValue;
end;

procedure TW3CSSTransformController.MoveZ(const aValue: Float);
begin
  FZ+=aValue;
end;

procedure TW3CSSTransformController.Move(x, y, z: Float);
begin
  FX+=X;
  FY+=Y;
  FZ+=Z;
end;

procedure TW3CSSTransformController.SetRegistrationPoint(const X,Y,Z: Float);
begin
  FRegX := X;
  FRegY := Y;
  FRegZ := Z;
end;

procedure TW3CSSTransformController.Scale(const X,Y,Z: Float);
begin
  FScaleX := X;
  FScaleY := Y;
  FScaleZ := Z;
end;

procedure TW3CSSTransformController.Scale(const aValue: Float);
begin
  FScaleX := aValue;
  FScaleY := aValue;
  FScaleZ := aValue;
end;

procedure TW3CSSTransformController.SetPosition(const X,Y,Z: Float);
begin
  FX := X;
  FY := Y;
  FZ := Z;
end;

procedure TW3CSSTransformController.SetRotation(const X,Y,Z: Float);
begin
  FRotX := X;
  FRotY := Y;
  FRotZ := Z;
end;

procedure TW3CSSTransformController.Rotate(const XFactor,YFactor,ZFactor: Float);
begin
  FRotX+=XFactor;
  FRotY+=YFactor;
  FRotZ+=ZFactor;
end;

procedure TW3CSSTransformController.Rotate(const aValue: Float);
begin
  FRotX+=aValue;
  FRotY+=aValue;
  FRotZ+=aValue;
end;

procedure TW3CSSTransformController.RotateX(const aValue: Float);
begin
  FRotX+=aValue;
end;

procedure TW3CSSTransformController.RotateY(const aValue: Float);
begin
  FRotY+=aValue;
end;

procedure TW3CSSTransformController.RotateZ(const aValue: Float);
begin
  FRotZ+=aValue;
end;

procedure TW3CSSTransformController.SetTransformOrigin(const X, Y: Float);
begin
  FHandle.style[w3_CSSPrefix('transformOrigin')]  :=
  FloatToStr(X) +'px ' + FloatToStr(Y) +'px';
end;

procedure TW3CSSTransformController.setTransformFlags(const aValue:TW3CssTransformOptions);
begin
  FFlags := aValue;
end;

procedure TW3CSSTransformController.Update;
var
  mTemp:  String;
begin
  if (FHandle) then
  begin
    if (toUsePos in FFlags) then
    mTemp := 'translate3d('
      + FloatToStr(FX - FRegX) + 'px,'
      + FloatToStr(FY - FRegY) + 'px,'
      + FloatToStr(FZ - FRegZ) + 'px) ';

    if (toUseRotX in FFlags) then
    mTemp := mTemp + 'rotateX(' + FloatToStr(FRotX) + 'deg) ';

    if (toUseRotY in FFlags) then
    mTemp := mTemp + 'rotateY(' + FloatToStr(FRotY) + 'deg) ';

    if (toUseRotZ in FFlags) then
    mTemp := mTemp + 'rotateZ(' + FloatToStr(FRotZ) + 'deg) ';

    if (toUseScale in FFlags) then
    mTemp := mTemp + 'scale3d(' + FloatToStr(FScaleX) + ','
      + FloatToStr(FScaleY) +','
      + FloatToStr(FScaleZ) + ') ';

    FHandle.style[w3_CSSPrefix('Transform')] := mTemp;
  end;
end;

end.
Advertisements
  1. Jon Lennart Aasenden
    August 7, 2014 at 6:23 pm

    If you just want to move stuff around X/Y style, then delete everything from line 206 + properties for rotx/y/z

  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: