HTML Elements on Canvas - taccGL™ Tutorial
Note: This page is outdated and contains information about version 0.61 that is no longer valid for version 0.62 and up.
Although it looks like taccgl™ animating HTML elements, in fact
images of HTML elements are animated. The following example takes
four images of the testimg and moves them each to another direction.
taccgl.actor("testimg"). from(300,500,0). to(-200,500,0).start(); taccgl.actor("testimg"). from(300,500,0). to(1000,500,0).start(); taccgl.actor("testimg"). from(300,500,0). to(300,0,0).start(); taccgl.actor("testimg"). from(300,500,0). to(300,1000,0).start(); | RUN |
taccgl™ uses a new HTML 5 feature named Canvas, if
available 3D Canvas or WebGL™. All drawing takes place on the
canvas and so animation does not affect the "real" HTML
elements. After the animation finished HTML elements appear in
their usual position.
The "real" HTML element may be (as is in many examples so far)
hidden while the animation is playing. This can be controlled by using
actor or a as discussed in section
Integration of HTML and WebGL.
The process of taking an image of an HTML element for later
use by the animation we call Element Painting, or just painting.
Element Painting
The actor method does the painting implicitly. In addition there is
the paint method to initiate painting explicitly.
Obviously painting is required before an element can be shown in an animation.
It is sufficent to paint an element once, even if used in multiple
transitions. So the example above can be written more efficiently using
the a method:
taccgl.actor("testimg") .from(300,500,0) .to(-200,500,0).start(); taccgl.a("testimg") .from(300,500,0) .to(1000,500,0).start(); taccgl.a("testimg") .from(300,500,0) .to(300,0,0).start(); taccgl.a("testimg") .from(300,500,0) .to(300,1000,0).start(); | RUN |
The first use of actor takes care of the painting while afterwards
a is sufficient. One important difference of
the actor and a methods is that actor
automatically paints the image of the element to be animated,
while a does not.
Nested Elements
Painting an element also paints the visible elements nested inside. Consequently
after painting an outer element there is no need to paint the
inner elements.
If an element has visibility:hidden, painting does nothing (since the element is hidden),
however, the paint method by default ignores that rule for the
element to be painted (but not for any elements nested inside.)
Painting only refers to the element specified, not to any outer or sibling elements
that extend to the same screen area as the painted element. So for example, if an
outer element has a background, this wont be painted.
Dynamic HTML and Window Resize
If you are using dynamic HTML, i.e. HTML elements that change over time,
it can be important when painting takes place. Also possibly
repainting is necessary after a change. However, very often
also positions of HTML elements change that the animation relies on.
Then it is easiest to just restart animations (which includes repainting).
Also if the window size changes, most HTML elements change due
to reflow and reformatting of the complete page and elements need
to be repainted. In this case it is usually best to restart animations.
Overlapping Elements
Up to this point in the tutorial, the recommendation was not to
use overlapping HTML elements in animations. More precisely this
means to avoid using 2 different paint (implicit or explicit)
calls for different HTML elements that take up the same space in the
document. This is the best thing to do, since overlapping
often causes problems, however for bigger animations overlapping is
probably not to avoid.
Note that all HTML elements to be painted need to be
located in the upper left rectangle of the document being 1200px
wide and 1424px high (you can change these default values).
This space is limited and so sometimes one needs to
reuse space by overlapping HTML elements being used in
different parts of an animation.
You can increase the default values, however, many mobile phones
have a limit of 4094x4096 when used with a device pixel ratio (dpr) of
one. For a dpr of 2 the limit is 2048x2048 and for 4 its
1024x1024. taccgl™ will use a smaller dpr, if this does not fit
at the cost of quality.
So what is left for bigger animations is to understand overlapping
and to use it carefully. Before we can describe it in detail, we need
to explain some more about the working of taccgl™ and WebGL™.
Texture Canvas
In order to display an image with WebGL™ this image needs to be
downloaded into the GPU. In this context it is called a texture.
Unfortunately the number of textures, the size of textures, and
the GPU memory as a whole is limited by the GPU, with big limits
on gaming desktops and rather low limits on smart phones.
To meet these limitations taccgl™ just uses just 2 textures
(whereby the second one is discussed below) both having the
discussed default size of 1200x1424. All HTML elements are
painted per default on the first texture and all HTML elements
thereby share a single texture.
Each HTML element is painted (per default) to its
normal HTML position on the texture. As long as HTML
elements do not overlap, each has its own part of the texture.
With this default multiple transitions for the same HTML element
share the same texture space. Also transitions of nested
HTML elements share texture space with enclosing elements.
In the case of overlapping elements they are painted over
each other: the element painted last covers the element painted first.
On some HTML designs this is intended and so looks as intended.
A problem, however, are hidden HTML elements just used in an animation.
Examples for Problems and Features of Animating Overlapping HTML elements
The following examples are based on two HTML DIV elements,
whereby the yellow one is on top of the red one, but not nested inside the red one.
First we want to animate the id="red" one. But what does this
mean? Animate the red one as it looks on the screen (with the yellow
box on it) or animate as HTML (without the yellow box). taccgl™
supports both:
<div id="both" style="position:relative; height:150px"> .....<div id="red" style="position:absolute; top:0px; left:0px; width:100px; height:100px; background-color:red"></div> .....<div id="yellow" style="position:absolute; top:25px; left:25px; width:50px; height:50px; background-color:yellow"></div> </div> | |
taccgl.actor("red").to({ox:300,oy:300}).dur(5).start() | RUN |
taccgl.begin(); taccgl.a("red").paint(); taccgl.a("yellow").paint(); taccgl.a("red") .to({ox:300,oy:300}) .dur(5).start() | RUN |
The first example just paints (via actor) and animates the
red box. The second example shows how to animate the image as it
appears on the screen. It paints the red and yellow elements using
a and paint, whereby start is not
called and so the created transitions do not appear and are for
painting only. Also see paintElement as an alternative.
Because yellow is painted after red it goes on top. Then a
is used to animate the red element as painted. actor could
not be used in this case, because it would paint the red element again
on top of the yellow one.
The following examples show that using actor on overlapping
elements might result in unexpected and complicated results.
taccgl.actor("red") .to({ox:300,oy:300}) .dur(5).start(); taccgl.actor("yellow") .to({ox:300,oy:800}) .dur(5).start() | RUN |
taccgl.actor("yellow") .to({ox:300,oy:800}) .dur(5).start(); taccgl.actor("red") .to({ox:300,oy:300}) .dur(5).start(); | RUN |
taccgl.actor("both") .to({ox:300,oy:300}) .dur(5).start(); taccgl.actor("red") .to({ox:300,oy:800}) .dur(5).start() | RUN |
taccgl.actor("both") .to({ox:300,oy:300}) .dur(5).start(); taccgl.a("red").to({ox:300,oy:800}) .dur(5).start() | RUN |
The first example contains transitions to animate the red and the yellow element. Still it animates
the red element with the yellow painted on top, because the taccgl.actor("yellow") paints
the yellow element on top of the red one. The second example paints the red element over the yellow
one. So the transition animating the yellow one shows the shape of the yellow one but in red color.
The third example first correctly paints the enclosing "both" element but then overpaints it in red.
The fourth example uses a to avoid the overpainting and so animates the "both" and the
red element, still the red element looks as the "both" element since the red was not painted.
Animate an Element as it appears on the Screen
It is useful to animate an HTML element as it appears on the
screen with other elements overlapping it, e.g. for animations
that hide or reveal the element, where it is imortant that the
animated image looks as close as possible to the browser
display. In fact this means taking an image of the area of the
screen the HTML element occupies. You can do this by painting
the relevant HTML elements in the right order and then using
a to do the animation. The first red and yellow
example above shows how to do this.
Use Overlapping Elements in different Animations
As long as overlapping elements are not used in the same
animation at the same time, they do not effect each other. For
transpartent elements, however, the texture canvas needs to be
cleard before reuse, see texClearAll
and texClear.
taccgl.actor("blue") .to({ox:300,oy:100}) .dur(5).start(); | RUN |
taccgl.actor("green") .to({ox:300,oy:100}) .dur(5).start() | RUN |
taccgl.a("green") .texClear().paint().to({ox:300,oy:100}) .dur(5).start() | RUN |
The (Second) Texture Canvas
taccgl™ has two independent texture canvases. Overlapping
elements can be painted on different canvases, which solves the problem:
taccgl.actor("blue",null,null,1) .to({ox:300,oy:600}) .dur(5).start(); taccgl.actor("green",null,null,2) .to({ox:300,oy:1000}) .dur(5).start() | RUN |
The fourth parameter of actor specifies, which canvas
should be used. The above example uses this parameter to paint both
elements each on a different texture canvas. This way both elements
can be animated separately.
With the map function to portion of the texture canvas used can be set.
In the following example both elements are mapped to different places and
therefore overlapping is no longer a problem.
taccgl.a("blue",null,null,1).map(0,0).paint().to({ox:300,oy:600}) .dur(5).start(); taccgl.a("green",null,null,2).map(200,0).paint().to({ox:300,oy:1000}) .dur(5).start() | RUN |
Shortcomings of Element Painting
A very important and quite unpleasant point is that current
browsers do not provide (or explicitly disable) a feature to take an
image on an HTML element. This apparently has security reasons. So
what taccgl™ does, is to paint the image on its own (with help
of the browser). This means that unfortunately an animated image might
look slightly different than the "real" HTML element.
taccgl.a("testsection") .paint() .to({oy:300}) .dur(5) .start(); | RUN |
This example moves a text block. So when you click
run, taccgl™ paints an image of the text block and then animates this
image. You might notice than the image is very close to the "real"
HTML element, however, links are displayed slightly different.
Bigger differences appear if the HTML contains form fields or
buttons, since these cannot currently be painted by taccgl™. Because
you are normally animating HTML code you wrote yourself, it should be
possible to test for these problems and to avoid them by modifying the
HTML code or the animation.
WebGL™ is a trademark of the Khronos Group Inc.
|