Home > OP4JS, Smart Mobile Studio > CSS powered scrolltext for Smart Mobile Studio

CSS powered scrolltext for Smart Mobile Studio

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.
Advertisements
  1. woutervannifterick
    August 16, 2014 at 7:49 am

    I’m reading this on an ipad. Having to walk to my pc to compile and run it there kind of defeats the purpose of writing this code with a browser as a target platform. So… Any online demo available? 🙂

    • Jon Lennart Aasenden
      August 16, 2014 at 11:16 am

      That goes without saying (it has bugged me to), but sadly wordpress doesnt allow JS hosting so there is no way to do it.
      I have been thinking that maybe i could use dropbox or google-drive as a host, but for google at least i have to register each “executable” demo as a mobile app — yet still, there is no way of embedding it on this website due to the same-origin policy.

  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: