Advanced 3D Animations and Transitions

image
This page demonstrates how you could use the Backbase Client Framework to code generic cross-browser implementations of several animation and transition techniques that deliver smooth 3D-like animation effects.

Animation Techniques

There are several technologies that can be used for animation. Support for these technologies is browser dependent. For example, there is native support for Scalable Vector Graphics (SVG) in Safari, Firefox, Opera, while CSS Filters have been supported in Internet Explorer (IE) since version 5:

  • IE CSS Filters—proprietory CSS transformation technology. For more information, see IE CSS Filters.
  • IE Vector Markup Language (VML)—similar to CSS filters because it applies the same transformation mechanisms. For more information, see VML.
  • Safari CSS tranformations—proprietory CSS transformation technology. For more information, see Webkit CSS Transforms.
  • SVG—Safari, Firefox, Opera native support. For more information, see SVG Wiki.

For this animation example, the focus will be CSS Filters and SVG. Although these technologies are designed to perform 2D transformations, this examples page demonstrates how to achieve 3D effects.

Transformation Fundamentals

In 2D, content can be transformed in different ways, including translating, scaling, rotating, and skewing:

  • Translation—involves shifting the origin of the current coordinate system horizontally and vertically by a specific amount.
  • Scaling—stretches or shrinks the units of the user space along the x and y axes independently.
  • Rotation—changes the orientation of the coordinate axes by rotating them around the current origin.
  • Skew—specifies a skew transformation along the x or y-axis by the given angle.

For more information, see 2D Transformations.
All the listed tranformations can be represented by following mathematical matrix:

scaleX skewX
skewY scaleY
offsetX offsetY

SVG and CSS Filters basically apply this transformation to HTML content, as demonstrated in the following code fragments:

SVG example:

<svg xmlns:svg="http://www.w3.org/2000/svg">
        <!-- Let's make it smaller! -->
        <g transform="matrix(0.5 0.5 0 0 0 0)">
                <foreignObject>
                        <div xmlns="xmlns="http://www.w3.org/1999/xhtml">Hello transformations!</div>
                </foreignObject>
        </g>
</svg>

Internet Explorer CSS Filters example:

<div id="my_div" style="width: 100%; height: 100%; filter:progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto auto')">Hello IE!</div>
<script language="JavaScript>
        var oMyDiv = document.getElementById('my_div');
        oMyDiv.filters.item(0).M11 = 0.5;
        oMyDiv.filters.item(0).M21 = 0;
        oMyDiv.filters.item(0).M12 = 0;
        oMyDiv.filters.item(0).M22 = 0.5;
        oMyDiv.filters.item(0).Dx = 0;
        oMyDiv.filters.item(0).Dy = 0;
</script>

The result for both the SVG and CSS Filter examples is the same, meaning that a cross-browser component can be implemented that will perform perform an identical tranformation on HTML content.

Component Implementation

There are two key requirements. The first is the implementation of a cross-browser wrapper for the different technologies:

<d:handler event="DOMNodeInsertedIntoDocument" type="text/javascript"><![CDATA[
        // Define initial matrix
        this._.matrix = [1, 1, 0, 0, 0, 0];
        if (bb.browser.ie) {
                // Bring IE support
                this.viewGate.innerHTML = '<div style="width: 100%; height: 100%; filter:progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto auto\')">' + this.viewGate.innerHTML + '</div>';
                this.viewGate = this.viewGate.firstChild;
                // Define an element that will be transformed
                this.animationElement = this.viewGate;
        } else {
                var oSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                var oForeignObject = oSvg.appendChild(
                        document.createElementNS('http://www.w3.org/2000/svg', 'g')
                ).appendChild(
                        document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')
                );
                oForeignObject.setAttribute('width', '100%');
                oForeignObject.setAttribute('height', '100%');
                oSvg = this.viewNode.appendChild(oSvg);
                if (bb.browser.opera) {
                        // Opera doesn't let us to insert HTML content directly to the SVG foreignObject, let's hack this
                        // Load empty document into foreignObject
                        oForeignObject.setAttributeNS('http://www.w3.org/1999/xlink', 'href:href', 'about:blank');
                        var oThis = this;
                        setTimeout(function() {
                                // Now we can use inner SVG - document body as the view gate
                                oForeignObject.getSVGDocument().body.style.margin = '0px';
                                oForeignObject.getSVGDocument().body.appendChild(oThis.viewGate);
                        }, 0);
                } else oForeignObject.appendChild(this.viewGate);
                // Define an element that will be transformed
                this.animationElement = oSvg.getElementsByTagName('g')[0];
        }
]]></d:handler>

The second requirement is the implementation of the core transformation function:

<d:method name="setMatrix">
        <d:argument name="scaleX" type="number" required="true" />
        <d:argument name="scaleY" type="number" required="true" />
        <d:argument name="skewX" type="number" required="true" />
        <d:argument name="skewY" type="number" required="true" />
        <d:argument name="offsetX" type="number" required="true" />
        <d:argument name="offsetY" type="number" required="true" />
        <d:body type="text/javascript"><![CDATA[
                // Modify matrix
                this._.matrix = [scaleX, scaleY, skewX, skewY, offsetX, offsetY];
                if (bb.browser.ie) {
                        // Perform matrix transformation
                        this.animationElement.filters.item(0).M11 = scaleX;
                        this.animationElement.filters.item(0).M21 = skewY;
                        this.animationElement.filters.item(0).M12 = skewX;
                        this.animationElement.filters.item(0).M22 = scaleY;
                        this.animationElement.filters.item(0).Dx = offsetX;
                        this.animationElement.filters.item(0).Dy = offsetY;
                } else {
                        // Perform matrix transformation
                        this.animationElement.setAttribute('transform', 'matrix('+scaleX+' '+skewY+' '+skewX+' '+scaleY+' '+offsetX+' '+offsetY+')');
                }
        ]]></d:body>
</d:method>

Component Features

The animation component (implemented in animation.xml) provides two elements:

group - container for layer elements.

  • Attributes:
    • cols - count of columns
    • rows - count of rows
    • debug - shows / hides line guides, to make an effects development easier
  • Methods:
    • animate(iAngleStep, iDuration, sEffect) - starts animation.

layer - main purpose of this element is to be used as child element for group element.

  • Attributes:
    • left - Define layer's left
    • top - Define layer's top
    • width - Define layer's width
    • height - Define layer's height

Example of using cols / rows / debug attributes:

<animation:group cols="4" rows="4" debug="true">
        <animation:layer left="50" top="50" width="146" height="146">
                <div style="background-image: url('images/clock.gif'); background-repeat: no-repeat; width: 146px; height: 146px;"></div>
        </animation:layer>
</animation:group>

Example of using several layers to define 3 - phase animation

<animation:group cols="1" rows="1" e:onmousedown="this.animate(1, 0, 'zoom');">
        <animation:layer left="50" top="50" width="210" height="214">
                <div style="background-color: gray; width: 210px; height: 214px;">First layer</div>
        </animation:layer>
        <animation:layer left="50" top="50" width="210" height="214">
                <div style="background-color: gray; width: 210px; height: 214px;">Second layer</div>
        </animation:layer>
        <animation:layer left="50" top="50" width="210" height="214">
                <div style="background-color: gray; width: 210px; height: 214px;">Third layer</div>
        </animation:layer>
</animation:group>

Next layer changes the previous one, when the animation function passes 45 degrees (half way here).

Examples of Using Built-in Transformation Effects

Flip

<animation:group cols="2" rows="1" e:onmousedown="this.animate(1, 0, 'flip');">
        <animation:layer left="50" top="50" width="391" height="174">
                <div style="background-image: url('images/widget.gif'); background-repeat: no-repeat; width: 391px; height: 174px;"></div>
        </animation:layer>
</animation:group>

Cross

<animation:group cols="4" rows="4" debug="true" e:onmousedown="this.animate(1, 0, 'cross');">
        <animation:layer left="50" top="50" width="146" height="146">
                <div style="background-image: url('images/clock.gif'); background-repeat: no-repeat; width: 146px; height: 146px;"></div>
        </animation:layer>
        <animation:layer left="50" top="50" width="146" height="146">
                <div style="background-image: url('images/clock_cover.gif'); background-repeat: no-repeat; width: 146px; height: 146px;"></div>
        </animation:layer>
</animation:group>

skewX

<animation:group cols="1" rows="1" e:onmousedown="this.animate(1, 0, 'skewX');">
        <animation:layer left="50" top="50" width="158" height="336">
                <div style="background-image: url('images/calculator.gif'); background-repeat: no-repeat; width: 158px; height: 236px;"></div>
        </animation:layer>
</animation:group>

skewY

<animation:group cols="1" rows="1" e:onmousedown="this.animate(1, 0, 'skewY');">
        <animation:layer left="50" top="50" width="485" height="152">
                <div style="margin-left: 50px; background-image: url('images/calendar.gif'); background-repeat: no-repeat; width: 325px; height: 152px;"></div>
        </animation:layer>
</animation:group>

Zoom

<animation:group cols="1" rows="1" e:onmousedown="this.animate(1, 0, 'zoom');">
        <animation:layer left="50" top="50" width="210" height="214">
                <div style="background-image: url('images/backbase-webinar.png'); background-repeat: no-repeat; width: 210px; height: 214px;"></div>
        </animation:layer>
</animation:group>

How to use

You will need to have or download The Backbase Client Framework

1. Download the widget implementation (animation.zip) at the bottom of this page

2. Extract the archive and try to open a demo page (index.html)

3. Add the following into document head section:

...
<script type="text/javascript" src="/Backbase_4_2_1/engine/boot.js"></script>
...

4. Put this into document body section:

...
<script type="text/backbase+xml"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        xmlns:b="http://www.backbase.com/2006/btl"
        xmlns:e="http://www.backbase.com/2006/xel"
        xmlns:animation="http://www.backbase.com/2008/animation">

        <!-- Include xhtml elements definitions -->
        <xi:include href="/Backbase_4_2_1/bindings/www.w3.org.1999.xhtml/xhtml.xml" />
        <!-- Include animation component -->
        <xi:include href="animation/animation.xml" />
        <!-- Define simple transformation -->
        <animation:group cols="2" rows="1" e:onmousedown="this.animate(1, 0, 'flip');">
                <animation:layer left="100" top="100" width="391" height="174">
                        <div>Any xhtml - valid code are going to be here...</div>
                </animation:layer>
        </animation:group>
</script>
...

Requirements

  • Backbase Client Framework 4.x

Compatibility

  • Internet Explorer 6, 7
  • Firefox 3.x
  • Safari 3.x
  • Opera 8.x, 9.x
AttachmentSize
animation.zip115.22 KB

Comments

Smooth

I guess smooth is a relative term, but then again explorer users are probably used to lag