Archive

Archive for August 15, 2014

CSS powered scrolltext for Smart Mobile Studio

August 15, 2014 2 comments

Ok so I know scroll-texts (marquee as some call it) is so 90’s, but while it takes me back to the age of Amiga demo’s and hacker parties – it does represent a challenge under HTML5. As you probably know, JavaScript and HTML is initially poorly equipped to move things around. I write initially because with the advent of HTML5 the browser makes use of hardware accelleration – using the GPU to push pixels around.

Yet to date I have not found a single update to the classic, horizontal scrolltext. There are plenty of jQuery plugins that emulates or builds on the marquee principles, but they still tax the CPU and (in many cases) flicker just as much as the old Microsoft marquee implementation.

GPU Scroller in action

GPU Scroller in action

A challenge for the evening

So, with the release of QTX – could I put together a non-flickering, component based, GPU powered scrolltext? Well here is what I came up with, and it works like a charm. Tested in Chromium, Chrome and iOS (iPhone 5 and iPad 3). I had some issues with the Font’s not being assigned properly – but other than that it works as expected.

How does it work?

Very differently from “traditional” scrolltext’s. On the Amiga (and pc using “native” code) scrolling is typically achieved by brute force. You have to draw the characters one-by-one, and at the same time copy the scanline data pixel by pixel to the left. So it’s very CPU intensive. The good news is that effects like running the scanlines through a sinus table costs very little in terms of CPU, but in general a scroller is costly business.

Under HTML5 however there is no such thing as “scroll” in terms of pixels. In order to emulate scrolling what I do is:

  • Measure the total with of the text to be scrolled
  • Size a child container control to this size
  • place the text into the container
  • Move the container to the absolute right (clientwidth)
  • use the new fxMove method to transition-move the container towards -TotalWidth.
  • If Scroller still active, loop and repeat step #4

The only thing missing right now, which I am playing around with under QTX, is the fxAbort() method and fxBusy() function. These allows us to stop and check if a CSS animation is active on a handle. Also, fxPause() is missing, although that might defeat the “call and forget” nature of the effects library.

When this is done i’m going to aim for a sinus-scrolltext. This means dividing the text into characters – and then applying a rather massive, path generated CSS transformation to each character in realtime. I dont think I have seen anything like that in the world of JS before – so it will be fun to try 🙂

Note: You will find this unit on my Google Code repository. Just update your SVN to get the code. Also, you require the latest QTX commit for this to work properly (just update and you have it). Remember to check-out the repo into your SMS/Library folder so the Smart IDE can find the files.

unit qtxscrolltext;

interface

uses
  W3System, w3Components, w3graphics,
  qtxutils,
  qtxeffects;

  Type

  TQTXScrollText = Class(TW3CustomControl)
  private
    FActive:  Boolean;
    FText:    String;
    FSpeed:   Integer;
    FContent: TW3CustomControl;
    function  getSpeed:Integer;
    Procedure setSpeed(const aValue:Integer);
    procedure setText(aValue:String);
    Procedure setActive(const aValue:Boolean);

    Procedure UpdateScroll;

  protected
    Procedure Resize;override;
  protected
    procedure InitializeObject;Override;
    Procedure FinalizeObject;Override;
  published
    Property  Active:Boolean read FActive write setActive;
    Property  Text:String read FText write setText;
    Property  Speed:Integer read getSpeed write setSpeed;
  End;

implementation

procedure TQTXScrollText.InitializeObject;
begin
  inherited;
  FContent:=TW3CustomControl.Create(self);

  FContent.handle.style.background:='transparent';

  QTX_ExecuteOnElementReady(Handle, procedure ()
    Begin
      Font.Name:='verdana';
      Font.Size:=16;
    end);
end;

Procedure TQTXScrollText.FinalizeObject;
Begin
  FContent.free;
  inherited;
end;

function  TQTXScrollText.getSpeed:Integer;
Begin
  result:=FSpeed;
end;

Procedure TQTXScrollText.setSpeed(const aValue:Integer);
Begin
  FSpeed:=TInteger.ensureRange(aValue,1,10);
end;

procedure TQTXScrollText.setText(aValue:String);
Begin
  aValue:=trim(aValue);
  if aValue<>FText then
  Begin
    FText:=aValue;
    FContent.InnerHtml:=FText;

    if FActive then
    begin
      FContent.left:=clientWidth;
      FContent.top:=(Height div 2) - (FContent.height div 2);
    end;
  end;
end;

Procedure TQTXScrollText.UpdateScroll;
begin
  FContent.fxMoveTo(-FContent.width,
  (Height div 2) - (FContent.height div 2),
  StrToFloat(IntToStr(22-FSpeed) +'.0'),
    procedure ()
      Begin
        if FActive then
        w3_callback( Procedure ()
          Begin
            FContent.left:=clientWidth;
            FContent.top:=(Height div 2) - (FContent.height div 2);
            UpdateScroll;
          end,
          120);
      end);
end;

Procedure TQTXScrollText.setActive(const aValue:Boolean);
var
  mMetrics: TQTXTextMetric;
Begin
  if aValue<>FActive then
  Begin
    FActive:=aValue;
    if FActive then
    Begin
      FContent.handle.style['color']:='#FFFFFF';
      FContent.handle.style['font']:='22px Verdana';
      FContent.handle.style.background:='transparent';

      mMetrics:=TQTXControlTools.calcTextMetrics(FText,'Verdana',22);
      FContent.Width:=mMetrics.tmWidth;
      FContent.Height:=mMetrics.tmHeight;

      FContent.Left:=clientwidth;
      FContent.top:=(Height div 2) - (FContent.height div 2);
      UpdateScroll;
    end;
  end;
end;

Procedure TQTXScrollText.Resize;
Begin
  inherited;

  if assigned(FContent)
  and qtxutils.QTX_ElementInDOM(FContent.handle)
  and qtxutils.qtx_elementInDOM(Handle) then
  begin
    if not FActive then
    Begin
      if assigned(FContent) then
      FContent.left:=clientWidth+1;
      exit;
    end;

    if assigned(FContent) then
    FContent.top:=(Height div 2) - (FContent.height div 2);
  end;
end;

end.

QTXLibrary on google code

August 15, 2014 3 comments
Quartex is 4ever

Quartex is 4ever

To make things easier in the future I decided to push all my Smart Pascal examples into one basket and upload them to Google Code. That way people don’t have to copy & paste from this website, but rather just update their SVN repo folder.

Point your SVN client at: https://code.google.com/p/qtxlibrary/

Only human

I must however stress that these units should be considered “examples”. This blog is more about experimentation, research and education than it is anything else. I do not provide any form of support. I work full-time as a professional software developer, so there is quite frankly not enough time for large-scale hobby projects.

For new features and ideas around Smart Pascal, send an email to the Smart Mobile Studio team. It will be registered in the system and receive a proper ticket.

Ayways, do a checkout of the google repository – remember to check out to the Smart Mobile Studio Libraries folder – and have a peek 🙂

What can it do?

All sorts of cool stuff! You have the in-memory dataset class, which is very handy. And the latest additions are the effect helpers. Smart Mobile Studio RTL contains a lot of cool stuff – but for beginners it may be hard to get to grips with all the new terminology. If you are serious about y0ur HTML5 coding, you should get a book and learn some JS. It makes all the difference.

So how are the effect helpers useful? Well, for instance, to make buttons that “grow” when you move your mouse hovers over them, you would write this:

  W3Button1.OnMouseEnter:=Procedure (sender:TObject; Shift: TShiftState; X, Y: Integer)
  Begin
    //grow the button by 4x4 pixels in 0.2 seconds
    w3Button1.fxScaleUp(4,0.2);
  end;

  w3button1.OnMouseExit:=procedure (sender:TObject; Shift: TShiftState; X, Y: Integer)
  Begin
    // Shrink button back to original size
    w3Button1.fxScaleDown(4,0.2);
  end;

Effect stack

What I have been playing with lately (thought only for now) is an effect stack. Basically a “mini” effect language that you can use to script effect chains inside your SMS application.

For instance, a script could look like:

var script:String := #"fadeout(0);
  fadeIn(0.6);
  moveTo(100,100);
  rotate(-30,-60,-70);
  scale(200,200);
  Scew3d(-90,-90-36);
  warpOut(0.9);";
FStack.push(script,w3button1);
FStack.execute(esImmediate);

Reminds me a bit about the old Amos Basic “sprite language” that we used in the 90’s for writing shoot’em up enemies for games and demos.