HTML5 Canvas 3D WebGL (TM) javaScript Library
 

HTML Elements on Canvas - taccGL Tutorial

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.

Using map

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.

Please Add a Comment or Question, click here!