CSS powered scrolltext for Smart Mobile Studio
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.
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.