Archive
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
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.
Recent
The vatican vault
- January 2022
- October 2021
- March 2021
- November 2020
- September 2020
- July 2020
- June 2020
- April 2020
- March 2020
- February 2020
- January 2020
- November 2019
- October 2019
- September 2019
- August 2019
- July 2019
- June 2019
- May 2019
- April 2019
- March 2019
- February 2019
- January 2019
- December 2018
- November 2018
- October 2018
- September 2018
- August 2018
- July 2018
- June 2018
- May 2018
- April 2018
- March 2018
- February 2018
- January 2018
- December 2017
- November 2017
- October 2017
- August 2017
- July 2017
- June 2017
- May 2017
- April 2017
- March 2017
- February 2017
- January 2017
- December 2016
- November 2016
- October 2016
- September 2016
- August 2016
- July 2016
- June 2016
- May 2016
- April 2016
- March 2016
- January 2016
- December 2015
- November 2015
- October 2015
- September 2015
- August 2015
- June 2015
- May 2015
- April 2015
- March 2015
- February 2015
- January 2015
- December 2014
- November 2014
- October 2014
- September 2014
- August 2014
- July 2014
- June 2014
- May 2014
- April 2014
- March 2014
- February 2014
- January 2014
- December 2013
- November 2013
- October 2013
- September 2013
- August 2013
- July 2013
- June 2013
- May 2013
- February 2013
- August 2012
- June 2012
- May 2012
- April 2012
You must be logged in to post a comment.