css3-transforms/Transforms.src.html

Mon, 25 Mar 2013 12:06:12 -0700

author
Dirk Schulze <dschulze@adobe.com>
date
Mon, 25 Mar 2013 12:06:12 -0700
changeset 7808
546a3f53d20e
parent 7701
74e801dd7a86
child 7817
3f38cf047a7e
permissions
-rwxr-xr-x

[css3-transforms] Fix syntax of transform-origin/perspective-origin properties.

bert@5324 1 <!DOCTYPE html public '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>
vhardy@3672 2 <html lang="en">
vhardy@3672 3 <head profile="http://www.w3.org/2006/03/hcard">
bert@6704 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
vhardy@3719 5 <title>CSS Transforms</title>
bert@6704 6 <link rel="stylesheet" type="text/css" href="../default.css" >
dschulze@5541 7 <script src='http://test.csswg.org/harness/annotate.js#CSS3-TRANSFORMS_DEV' type='text/javascript' defer></script>
vhardy@3672 8
vhardy@3732 9 <style type="text/css">
simon@4376 10 .term {
simon@4376 11 font-style: italic;
simon@4376 12 }
vhardy@3672 13 </style>
bert@6704 14 <link rel="stylesheet" type="text/css" href="http://www.w3.org/StyleSheets/TR/W3C-ED.css" >
vhardy@3672 15
vhardy@3672 16 </head>
vhardy@3672 17 <body>
vhardy@3672 18 <div id="div-head" class="head">
vhardy@3672 19 <!--logo-->
vhardy@3672 20
simon@4357 21 <h1>CSS Transforms</h1>
vhardy@3672 22
vhardy@3672 23 <h2 class="no-num no-toc">[LONGSTATUS] [DATE]</h2>
vhardy@3672 24 <dl>
vhardy@3672 25 <dt>This version:
vhardy@3672 26 <dd>
simon@4357 27 <a href="[VERSION]">http://dev.w3.org/csswg/css3-transforms/</a>
bert@5324 28 <!--http://www.w3.org/TR/[YEAR]/WD-[SHORTNAME]-[CDATE]/-->
vhardy@3672 29 <dt>Latest version:
vhardy@3672 30 <dd><a
bert@5324 31 href="http://www.w3.org/TR/css3-transforms/">[LATEST]</a>
simon@4583 32 <dt>Editor's draft:
simon@4583 33 <dd><a href="http://dev.w3.org/csswg/[SHORTNAME]/">http://dev.w3.org/csswg/[SHORTNAME]/</a>
bert@6704 34 <dt>Previous version:
bert@6704 35 <dd><a href='http://www.w3.org/TR/2012/WD-css3-transforms-20120911/'>http://www.w3.org/TR/2012/WD-css3-transforms-20120911/</a>
vhardy@3672 36 <dt id="editors-list">Editors:
vhardy@3672 37 <dd>Simon Fraser (<a href="http://www.apple.com/">Apple Inc</a>) &lt;simon.fraser &#64;apple.com&gt;
vhardy@3672 38 <dd>Dean Jackson (<a href="http://www.apple.com/">Apple Inc</a>) &lt;dino &#64;apple.com&gt;
vhardy@3672 39 <dd>Edward O'Connor (<a href="http://www.apple.com/">Apple Inc</a>) &lt;eoconnor &#64;apple.com&gt;
dschulze@4323 40 <dd>Dirk Schulze (<a href="http://www.adobe.com/">Adobe Systems, Inc</a>) &lt;dschulze &#64;adobe.com&gt;
simon@4581 41 <dd>Aryeh Gregor (<a href="http://www.mozilla.org/">Mozilla</a>) &lt;ayg &#64;aryeh.name&gt;
simon@4581 42
bert@6704 43 <dt id="former-editors-list">Former Editors:
simon@6214 44 <dd>David Hyatt (<a href="http://www.apple.com/">Apple Inc</a>) &lt;hyatt &#64;apple.com&gt;
simon@6214 45 <dd>Chris Marrin (<a href="http://www.apple.com/">Apple Inc</a>) &lt;cmarrin &#64;apple.com&gt;
simon@6214 46
simon@4581 47 <dt>Issues list:
simon@4581 48 <dd><a href="https://www.w3.org/Bugs/Public/buglist.cgi?query_format=advanced&amp;product=CSS&amp;component=Transforms&amp;resolution=---&amp;cmdtype=doit">in Bugzilla</a>
simon@4581 49
simon@4581 50 <dt>Test suite:
simon@4581 51 <dd>none yet
simon@4581 52 </dl>
vhardy@3672 53
vhardy@3672 54 <!--copyright-->
vhardy@3672 55
vhardy@3672 56 <hr title="Separator for header">
vhardy@3672 57 </div>
vhardy@3672 58
vhardy@3672 59 <h2 class="no-num no-toc" id="abstract">Abstract</h2>
ayg@5129 60
vhardy@3672 61 <p>CSS transforms allows elements styled with CSS to be transformed
ayg@5129 62 in two-dimensional or three-dimensional space. This specification is the convergence of the
ayg@5129 63 <a href="http://www.w3.org/TR/css3-2d-transforms/">CSS 2D transforms</a>,
vhardy@3672 64 <a href="http://www.w3.org/TR/css3-3d-transforms/">CSS 3D transforms</a>
ayg@5129 65 and <a href="http://www.w3.org/TR/2009/WD-SVG-Transforms-20090320/">SVG transforms</a>
vhardy@3672 66 specifications.</p>
vhardy@3672 67
vhardy@3672 68 <h2 class="no-num no-toc" id="status">Status of this document</h2>
vhardy@4360 69
bert@5324 70 <!--status-->
bert@5324 71
simon@5274 72 <p>
simon@5274 73 This specification replaces the former <a href="http://www.w3.org/TR/css3-2d-transforms/" title="CSS 2D Transforms">CSS 2D Transforms</a> and <a href="http://www.w3.org/TR/css3-3d-transforms/" title="CSS 3D Transforms Module Level 3">CSS 3D Transforms</a> specifications, as well
dschulze@5743 74 as <a href="http://www.w3.org/TR/SVG-Transforms/" title="SVG Transforms 1.0">SVG Transforms</a>.
vhardy@4360 75 </p>
vhardy@4360 76
vhardy@3672 77 <p>
vhardy@3672 78 The <a href="ChangeLog">list of changes made to this specification</a> is
vhardy@3672 79 available.
vhardy@3672 80 </p>
vhardy@3672 81
vhardy@3672 82 <h2 class="no-num no-toc" id="contents">Table of contents</h2>
vhardy@3672 83 <!--toc-->
vhardy@3672 84
vhardy@3672 85 <h2>Introduction</h2>
vhardy@3672 86
simon@4345 87 <p><em>This section is not normative.</em></p>
simon@4345 88 <p>
simon@4345 89 The CSS <a href="http://www.w3.org/TR/REC-CSS2/visuren.html">visual
dschulze@4511 90 formatting model</a> describes a coordinate system within each
simon@4345 91 element is positioned. Positions and sizes in this coordinate space can
dschulze@4511 92 be thought of as being expressed in pixels, starting in the origin of point
dschulze@4511 93 with positive values proceeding to the right and down.
simon@4345 94 </p>
simon@4345 95 <p>
dschulze@5740 96 This coordinate space can be modified with the 'transform' property. Using transform,
dschulze@5740 97 elements can be translated, rotated and scaled in two or three dimensional space.
simon@4345 98 </p>
simon@4345 99 <p>
simon@4345 100 Additional properties make working with transforms easier, and allow the
simon@4345 101 author to control how nested three-dimensional transforms interact.
simon@4345 102 </p>
simon@4345 103 <ul>
simon@4345 104 <li>
dschulze@5740 105 The 'transform-origin' property provides a convenient way to control the origin about
dschulze@5740 106 which transforms on an element are applied.
simon@4345 107 </li>
simon@4345 108 <li>
dschulze@5740 109 The 'perspective' property allows the author to make child elements with
dschulze@5740 110 three-dimensional transforms appear as if they live in a common three-dimensional
dschulze@5740 111 space.
dschulze@5740 112 The 'perspective-origin' property provides control over the origin at which
dschulze@5740 113 perspective is applied, effectively changing the location of the "vanishing point".
simon@4345 114 </li>
simon@4345 115 <li>
dschulze@5740 116 The 'transform-style' property allows 3D-transformed elements and their 3D-transformed
dschulze@5740 117 descendants to share a common three-dimensional space, allowing the construction of
dschulze@5740 118 hierarchies of three-dimensional objects.
simon@4345 119 </li>
simon@4345 120 <li>
dschulze@5740 121 The 'backface-visibility' property comes into play when an element is flipped around
dschulze@5740 122 via three-dimensional transforms such that its reverse side is visible to the viewer.
dschulze@5740 123 In some situations it is desirable to hide the element in this situation, which is
dschulze@5740 124 possible using the value of ''hidden'' for this property.
simon@4345 125 </li>
simon@4345 126 </ul>
simon@4345 127 <p>
dschulze@5740 128 Note that while some values of the 'transform' property allow an element to be
dschulze@5740 129 transformed in a three-dimensional coordinate system, the elements themselves are not
dschulze@5740 130 three-dimensional objects. Instead, they exist on a two-dimensional plane (a flat
dschulze@5740 131 surface) and have no depth.
simon@4345 132 </p>
vhardy@3672 133
simon@4345 134 <!-- ======================================================================================================= -->
vhardy@3672 135
simon@4345 136 <h2 id="module-interactions">Module Interactions</h2>
simon@5274 137 <p>This module defines a set of CSS properties that affect the visual rendering of elements to which
simon@5274 138 those properties are applied; these effects are applied after elements have been sized and positioned according
simon@5274 139 to the <a href="http://www.w3.org/TR/CSS2/visuren.html" title="Visual formatting model">Visual formatting model</a>
simon@5274 140 from [[!CSS21]]. Some values of these properties result in the creation of a <a href="http://www.w3.org/TR/CSS2/visuren.html#containing-block" title="Visual formatting model">containing block</a>, and/or the creation of a <a href="http://www.w3.org/TR/CSS2/visuren.html#z-index" title="Visual formatting model">stacking context</a>.
simon@5274 141 </p>
simon@5274 142 <p>
simon@5274 143 Three-dimensional transforms can also affect the visual layering of elements, and thus override the back-to-front
simon@5274 144 painting order described in <a href="http://www.w3.org/TR/CSS2/zindex.html" title="Elaborate description of Stacking Contexts">Appendix E</a> of [[!CSS21]].
simon@5274 145 </p>
simon@6214 146 <p>
dschulze@6300 147 Transforms affect the rendering of backgounds on elements with a value of ''fixed'' for the
dschulze@6300 148 '<code class="property"><a href="http://www.w3.org/TR/css3-background/#the-background-attachment">background-attachment</a></code>' property,
simon@6214 149 which is specified in [[!CSS3BG]].
simon@6214 150 </p>
simon@4345 151
simon@4365 152 <h2 id="css-values">CSS Values</h2>
simon@5274 153
simon@5274 154 <p>This specification follows the <a href="http://www.w3.org/TR/CSS21/about.html#property-defs">CSS property definition conventions</a> from [[!CSS21]]. Value types not defined in this specification are defined in CSS LevelĀ 2 RevisionĀ 1 [[!CSS21]].</p>
simon@5274 155
simon@5274 156 <p>In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the <a href="http://www.w3.org/TR/CSS21/cascade.html#value-def-inherit">inherit</a> keyword as their property value. For readability it has not been repeated explicitly.
simon@4345 157
simon@4345 158
simon@4345 159 <h2 id="definitions">Definitions</h2>
simon@4345 160 <p> When used in this specification, terms have the meanings assigned in
simon@4345 161 this section.
simon@4345 162 </p>
simon@4345 163 <dl>
dschulze@4483 164 <dt id="TermBoundingBox"><dfn>bounding box</dfn></dt>
dschulze@4483 165 <dd>
dschulze@4483 166 <p>
ayg@4742 167 A bounding box is the object bounding box for all SVG elements
ayg@4742 168 without an associated CSS layout box and the border box for all
ayg@4742 169 other elements. The bounding box of a table is the border box
ayg@4742 170 of its
ayg@4742 171 <a href="http://www.w3.org/TR/CSS21/tables.html#model">table wrapper box</a>,
ayg@4742 172 not its table box.
dschulze@4483 173 </p>
dschulze@4483 174 </dd>
dschulze@4483 175
simon@4365 176 <dt id="TermTransformableElement"><dfn>transformable element</dfn></dt>
simon@4345 177 <dd>
vhardy@3672 178 <p>
eoconnor@6894 179 A transformable element is an element in one of these
eoconnor@6894 180 categories:
vhardy@3672 181 </p>
eoconnor@6894 182 <ul>
eoconnor@6894 183 <li>
eoconnor@6894 184 an element whose
eoconnor@6894 185 layout is governed by the CSS box model which is either
eoconnor@6894 186 a
eoconnor@6894 187 <a href="http://www.w3.org/TR/CSS2/visuren.html#block-level">block-level</a>
eoconnor@6894 188 or
eoconnor@6894 189 <a href="http://www.w3.org/TR/CSS2/visuren.html#x13">atomic inline-level element</a>,
eoconnor@6894 190 or whose 'display' property
eoconnor@6894 191 computes to ''table-row'',
eoconnor@6894 192 ''table-row-group'',
eoconnor@6894 193 ''table-header-group'',
eoconnor@6894 194 ''table-footer-group'',
eoconnor@6894 195 ''table-cell'', or
eoconnor@6894 196 ''table-caption'' [[!CSS21]]
eoconnor@6894 197 </li>
eoconnor@6894 198 <li>
dschulze@6901 199 an element in the SVG namespace and not governed by the CSS box model which has
dschulze@6901 200 the attributes 'transform', 'patternTransform' or 'gradientTransform' [[!SVG11]]
eoconnor@6894 201 </li>
eoconnor@6894 202 </ul>
simon@4345 203 </dd>
simon@4345 204
dschulze@5931 205 <dt id="TermLocalCoordinateSystem"><dfn>local coordinate system</dfn></dt>
dschulze@5931 206 <dd>
dschulze@5931 207 <p>
dschulze@5931 208 In general, a coordinate system defines locations and distances on the current
dschulze@5931 209 canvas. The current local coordinate system (also user coordinate system) is the
dschulze@5931 210 coordinate system that is currently active and which is used to define how
dschulze@5931 211 coordinates and lengths are located and computed, respectively, on the current
dschulze@5931 212 canvas.
dschulze@5931 213 </p>
dschulze@5931 214 </dd>
dschulze@6300 215 <dt id="TermUserCoordinateSystem"><dfn>user coordinate system</dfn></dt>
dschulze@6300 216 <dd>
dschulze@6300 217 <p>
dschulze@6300 218 See definition of <span class="term">local coordinate system</span>.
dschulze@6300 219 </p>
dschulze@6300 220 </dd>
ayg@4750 221 <dt id="TermPerspectiveMatrix"><dfn>perspective matrix</dfn></dt>
simon@4345 222 <dd>
simon@4345 223 <p>
dschulze@5931 224 A matrix computed from the values of the 'perspective' and 'perspective-origin' properties as described <a href="#perspective-matrix-computation">below</a>.
simon@4365 225 </p>
simon@4365 226 </dd>
simon@4365 227
simon@4366 228 <dt id="TermTransformationMatrix"><dfn>transformation matrix</dfn></dt>
simon@4365 229 <dd>
simon@4365 230 <p>
dschulze@5931 231 A matrix that defines the mathematical mapping from one coordinate system into another. It is computed from the values of the 'transform' and 'transform-origin' properties as described <a href="#transformation-matrix-computation">below</a>.
dschulze@5931 232 </p>
dschulze@5931 233 </dd>
dschulze@5931 234
dschulze@5931 235 <dt id="TermCurrentTransformationMatrix"><dfn>current transformation matrix (CTM)</dfn></dt>
dschulze@5931 236 <dd>
dschulze@5931 237 <p>
dschulze@5931 238 A matrix that defines the mapping from the local coordinate system into the viewport coordinate system.
simon@4365 239 </p>
simon@4365 240 </dd>
simon@4365 241
ayg@5127 242 <dt id="TermAccumulated3DTransformationMatrix">
ayg@5127 243 <dfn>accumulated 3D transformation matrix</dfn>
ayg@5127 244 </dt>
ayg@5127 245 <dd>
ayg@5127 246 <p>
ayg@5127 247 A matrix computed for elements in a
ayg@5127 248 <a href="#d-rendering-context">3D rendering context</a>, as
ayg@5127 249 described
ayg@5127 250 <a href="#accumulated-3d-transformation-matrix-computation">below</a>.
ayg@5127 251 </p>
ayg@5127 252 </dd>
dschulze@5690 253
dschulze@5690 254 <dt id="TermIdentityTransformFunction">
dschulze@5931 255 <dfn>identity transform function</dfn>
dschulze@5690 256 </dt>
dschulze@5690 257 <dd>
dschulze@5690 258 <p>
dschulze@5690 259 A <a href="#transform-functions">transform function</a> that is equivalent to a
dschulze@5690 260 identity 4x4 matrix (see <a href="#mathematical-description">Mathematical
dschulze@5690 261 Description of Transform Functions</a>). Examples for identity transform functions
dschulze@5740 262 are ''translate(0)'', ''translate3d(0, 0, 0)'', ''translateX(0)'',
dschulze@5740 263 ''translateY(0)'', ''translateZ(0)'', ''scale(1)'', ''scaleX(1)'', ''scaleY(1)'',
dschulze@5740 264 ''scaleZ(1)'', ''rotate(0)'', ''rotate3d(1, 1, 1, 0)'', ''rotateX(0)'',
dschulze@6608 265 ''rotateY(0)'', ''rotateZ(0)'', ''skew(0, 0)'', ''skewX(0)'', ''skewY(0)'', ''matrix(1, 0, 0, 1, 0,
dschulze@5740 266 0)'' and ''matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)''. A special
dschulze@5900 267 case is perspective: ''perspective(infinity)''. The value of m<sub>34</sub>
dschulze@5740 268 becomes infinitesimal small and the transform function is therefore assumed to be
dschulze@5740 269 equal to the identity matrix.
dschulze@5690 270 </p>
dschulze@5690 271 </dd>
ayg@5127 272
simon@4365 273 <dt id="Term3DRenderingContext"><dfn>3D rendering context</dfn></dt>
simon@4365 274 <dd>
simon@4365 275 <p>
dschulze@6300 276 A containing block hierarchy of one or more levels, instantiated by elements with a
dschulze@6300 277 computed value for the 'transform-style' property of ''preserve-3d'', whose elements
dschulze@6300 278 share a common three-dimensional coordinate system.
dschulze@4321 279 </p>
simon@4345 280 </dd>
simon@4345 281 </dl>
simon@4345 282
simon@4345 283 <!-- ======================================================================================================= -->
ayg@5129 284
dschulze@5740 285 <h2 id="two-dimensional-subset">
dschulze@5726 286 Two Dimensional Subset
dschulze@5726 287 </h2>
dschulze@5726 288
dschulze@5726 289 <p>
dschulze@5726 290 UAs may not always be able to render three-dimensional transforms and then just
dschulze@5726 291 support a two-dimensional subset of this specification. In this case <a
dschulze@5726 292 href="#three-d-transform-functions">three-dimensional transforms</a> and the
dschulze@5726 293 properties 'transform-style', 'perspective', 'perspective-origin' and
dschulze@5726 294 'backface-visibility' must not be supported. Section <a
dschulze@5726 295 href="#transform-3d-rendering">3D Transform Rendering</a> does not apply.
dschulze@5726 296 Matrix decomposing uses the technique taken from the "unmatrix" method in "Graphics
dschulze@5726 297 Gems II, edited by Jim Arvo", simplified for the 2D case. Section
dschulze@5900 298 <a href="#mathematical-description">Mathematical Description of Transform Functions</a>
dschulze@5900 299 is still effective but can be reduced by using a 3x3 transformation matrix where
dschulze@5900 300 <em>a</em> equals <em>m<sub>11</sub></em>, <em>b</em> equals <em>m<sub>12</sub></em>,
dschulze@5900 301 <em>c</em> equals <em>m<sub>21</sub></em>, <em>d</em> equals <em>m<sub>22</sub></em>,
dschulze@5900 302 <em>e</em> equals <em>m<sub>41</sub></em> and <em>f</em> equals <em>m<sub>42</sub></em>
dschulze@5900 303 (see <a href="#MatrixDefined">A 2D 3x2 matrix with six parameter</a>).
dschulze@5726 304 </p>
dschulze@5726 305
dschulze@5726 306 <div class="figure">
dschulze@5726 307 <img src="3x3matrix.png" alt="3x3 matrix" title="\begin{bmatrix} a & c & e \\ b
dschulze@5726 308 & d & f \\ 0 & 0 & 1 \end{bmatrix}" width="82" height="79">
dschulze@5726 309 <p class="caption">
dschulze@5726 310 3x3 matrix for two-dimensional transformations.
dschulze@5726 311 </p>
dschulze@5726 312 </div>
dschulze@5726 313
dschulze@5726 314 <div class="example">
dschulze@5726 315 <p>
dschulze@5726 316 Authors can easily provide a fallback if UAs do not provide support for
dschulze@5726 317 three-dimensional transforms. The following example has two property definitions
dschulze@5726 318 for 'transform'. The first one consists of two two-dimensional transform
dschulze@5726 319 functions. The second one has a two-dimensional and a three-dimensional transform
dschulze@5726 320 function.
dschulze@5726 321 </p>
dschulze@5726 322 <pre>div {
dschulze@5726 323 transform: scale(2) rotate(45deg);
dschulze@5726 324 transform: scale(2) rotate3d(0, 0, 1, 45deg);
dschulze@5726 325 }</pre>
dschulze@5726 326
dschulze@5726 327 <p>
dschulze@5726 328 With 3D support, the second definition will override the first one. Without 3D
dschulze@5726 329 support, the second definition is invalid and a UA falls back to the first
dschulze@5726 330 definition.
dschulze@5726 331 </p>
dschulze@5726 332 </div>
dschulze@5726 333
dschulze@5726 334 <!-- ======================================================================================================= -->
dschulze@5726 335
simon@4345 336 <h2 id="transform-rendering">The Transform Rendering Model</h2>
dschulze@6908 337 <p><em>This section is normative.</em></p>
dschulze@5740 338 <p>
dschulze@5931 339 Specifying a value other than ''none'' for the ''transform'' property establishes a
dschulze@5931 340 new <span class="term">local coordinate system</span> at the element that it is
dschulze@5931 341 applied to. The mapping from where the element would have rendered into that local
dschulze@5931 342 coordinate system is given by the element's <span class="term">transformation
dschulze@5931 343 matrix</span>. Transformations are cumulative. That is, elements establish their local
dschulze@5931 344 coordinate system within the coordinate system of their parent. From the perspective
dschulze@5931 345 of the user, an element effectively accumulates all the 'transform' properties of its
dschulze@5931 346 ancestors as well as any local transform applied to it. The accumulation of these
dschulze@5931 347 transforms defines a <span class="term">current transformation matrix (CTM)</span> for
dschulze@5931 348 the element.
dschulze@5740 349 </p>
dschulze@5740 350 <p>
dschulze@5932 351 The coordinate space is a
dschulze@5740 352 coordinate system with two axes: the X axis increases horizontally to the right; the
eoconnor@6037 353 Y axis increases vertically downwards. Three-dimensional transform functions extend
dschulze@5740 354 this coordinate space into three dimensions, adding a Z axis perpendicular to the
dschulze@5740 355 plane of the screen, that increases towards the viewer.
dschulze@5740 356 </p>
dschulze@5937 357
dschulze@5936 358 <div class="figure">
dschulze@5937 359 <img src="coordinates.svg" width="270" height="240" alt="Demonstration of the initial coordinate space">
dschulze@5936 360 <p class="caption">
dschulze@5936 361 Demonstration of the initial coordinate space.
dschulze@5936 362 </p>
dschulze@5936 363 </div>
dschulze@5937 364
dschulze@5740 365 <p id="transformation-matrix-computation">
dschulze@5931 366 The <span class="term">transformation matrix</span> is computed
dschulze@5740 367 from the 'transform' and 'transform-origin' properties as follows:
dschulze@5740 368 <ol>
dschulze@5740 369 <li>Start with the identity matrix.</li>
dschulze@5740 370 <li>Translate by the computed X, Y and Z values of 'transform-origin'</li>
dschulze@6960 371 <li>Multiply by each of the transform functions in 'transform' property from left to right</li>
dschulze@5740 372 <li>Translate by the negated computed X, Y and Z values of 'transform-origin'</li>
dschulze@5740 373 </ol>
bert@6704 374
dschulze@5740 375 <p>
dschulze@5740 376 Transforms apply to <span class="term">transformable elements</span>.
dschulze@5740 377 </p>
simon@4358 378
dschulze@5740 379 <div class="example">
dschulze@5740 380 <pre>
simon@4358 381 div {
simon@4358 382 transform: translate(100px, 100px);
simon@4358 383 }
simon@4358 384 </pre>
simon@4358 385 <p>This transform moves the element by 100 pixels in both the X and Y directions.</p>
simon@4358 386 <div class="figure">
dschulze@5740 387 <img src="examples/translate1.svg" alt="The 100px translation in X and Y"
dschulze@5740 388 width="470" height="250">
simon@4358 389 </div>
simon@4358 390 </div>
dschulze@5625 391
dschulze@5625 392 <div class="example">
dschulze@5740 393 <pre>div {
dschulze@5625 394 height: 100px; width: 100px;
dschulze@5625 395 transform-origin: 50px 50px;
dschulze@5625 396 transform: rotate(45deg);
dschulze@5740 397 }</pre>
dschulze@5625 398
dschulze@5740 399 <p>
dschulze@5740 400 The 'transform-origin' property moves the point of origin by 50 pixels in both
dschulze@5740 401 the X and Y directions. The transform rotates the element clockwise by 45Ā° about
dschulze@5740 402 the point of origin. After all transform functions were applied, the translation
dschulze@5740 403 of the origin gets translated back by -50 pixels in both the X and Y directions.
dschulze@5740 404 </p>
dschulze@5625 405
dschulze@5740 406 <div class="figure">
dschulze@5740 407 <img alt="The point of origin gets translated temporary" src="examples/origin1.svg"
dschulze@5740 408 width="735" height="250">
dschulze@5740 409 </div>
dschulze@5625 410 </div>
ayg@5129 411
simon@4358 412 <div class="example">
dschulze@5740 413 <pre>
simon@4358 414 div {
simon@4358 415 height: 100px; width: 100px;
simon@4358 416 transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg);
simon@4358 417 }
simon@4358 418 </pre>
dschulze@5740 419 <p>
dschulze@5740 420 This transform moves the element by 80 pixels in both the X and Y directions, then
dschulze@5740 421 scales the element by 150%, then rotates it 45&deg; clockwise about the Z axis.
dschulze@5740 422 Note that the scale and rotation operate about the center of the element, since
dschulze@5740 423 the element has the default transform-origin of ''50% 50%''.
dschulze@5740 424 </p>
simon@4358 425
dschulze@5740 426 <div class="figure">
dschulze@5740 427 <img src="examples/compound_transform.svg" alt="The transform specified above"
dschulze@5740 428 width="270" height="270">
dschulze@5740 429 </div>
dschulze@5740 430
dschulze@5740 431 <p>
dschulze@5740 432 Note that an identical rendering can be obtained by nesting elements with the
dschulze@5740 433 equivalent transforms:
dschulze@5740 434 </p>
dschulze@5740 435
dschulze@5740 436 <pre>
simon@4358 437 &lt;div style="transform: translate(80px, 80px)"&gt;
dschulze@4602 438 &lt;div style="transform: scale(1.5, 1.5)"&gt;
dschulze@4602 439 &lt;div style="transform: rotate(45deg)"&gt;&lt;/div&gt;
dschulze@4602 440 &lt;/div&gt;
dschulze@5740 441 &lt;/div&gt;</pre>
dschulze@5740 442 </div>
simon@4358 443
simon@4345 444 <p>
dschulze@6901 445 For elements whose layout is governed by the CSS box model, the transform property
dschulze@6901 446 does not affect the flow of the
dschulze@5740 447 content surrounding the transformed element. However, the extent of the overflow
dschulze@5740 448 area takes into account transformed elements. This behavior is similar to what
dschulze@5740 449 happens when elements are offset via relative positioning. Therefore, if the value
dschulze@5740 450 of the 'overflow' property is ''scroll'' or ''auto'', scrollbars will appear as
dschulze@5740 451 needed to see content that is transformed outside the visible area.
vhardy@3672 452 </p>
vhardy@3672 453 <p>
dschulze@6901 454 For elements whose layout is governed by the CSS box model, any value other than
dschulze@6901 455 ''none'' for the transform results in
dschulze@5740 456 the creation of both a stacking context and a containing block. The object acts as a
vhardy@3672 457 containing block for fixed positioned descendants.
vhardy@3672 458 </p>
simon@4345 459 <p class="issue">
ayg@5090 460 Is this effect on position:fixed necessary? If so, need to go into more detail here
dschulze@5740 461 about why fixed positioned objects should do this, i.e., that it's much harder to
dschulze@6900 462 implement otherwise. See <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=16328">Bug 16328</a>.
dschulze@4321 463 </p>
ayg@5088 464 <p>
simon@6214 465 <a href="http://www.w3.org/TR/css3-background/#fixed0">Fixed backgrounds</a>
simon@6214 466 on the root element are affected by any transform specified for that element.
simon@6214 467 For all other elements that are effected by a transform (i.e. have a transform
dschulze@6300 468 applied to them, or to any of their ancestor elements), a value of ''fixed'' for the
dschulze@6904 469 'background-attachment' property is treated as if it had a value of ''scroll''. The
dschulze@6904 470 computed value of 'background-attachment' is not affected.
bert@6704 471
ayg@5088 472 <p class="note">
ayg@5106 473 If the root element is transformed, the transformation applies
ayg@5106 474 to the entire canvas, including any background specified for
simon@6214 475 the root element. Since <a href="http://www.w3.org/TR/css3-background/#special-backgrounds">
simon@6214 476 the background painting area for the root element</a> is the entire
ayg@5106 477 canvas, which is infinite, the transformation might cause parts
ayg@5106 478 of the background that were originally off-screen to appear.
ayg@5106 479 For example, if the root element's background were repeating
dschulze@6300 480 dots, and a transformation of ''scale(0.5)'' were specified on the
ayg@5106 481 root element, the dots would shrink to half their size, but
ayg@5106 482 there will be twice as many, so they still cover the whole
ayg@5106 483 viewport.
ayg@5106 484 </p>
ayg@5129 485
simon@4345 486 <h3 id="transform-3d-rendering">3D Transform Rendering</h3>
simon@4345 487
simon@4345 488 <p>
simon@4345 489 Normally, elements render as flat planes, and are rendered into the same plane
simon@4345 490 as their containing block. Often this is the plane shared by the rest of the page.
simon@4345 491 Two-dimensional transform functions can alter the appearance of an element, but
simon@4363 492 that element is still rendered into the same plane as its containing block.
simon@4345 493 </p>
simon@4345 494 <p>
simon@4345 495 Three-dimensional transforms can result in transformation matrices with a non-zero
simon@6215 496 Z component (where the Z axis projects out of the plane of the screen). This can result
simon@6215 497 in an element rendering on a different plane than that of its containing block. This
simon@6215 498 may affect the front-to-back rendering order of that element relative to other elements,
simon@6215 499 as well as causing it to intersect with other elements. This behavior depends on whether the
simon@6215 500 element is a member of a <span class="term">3D rendering context</span>, as described below.
simon@4345 501 </p>
simon@4366 502 <div class="issue">
simon@4345 503 <p class="desc">This description does not exactly match what WebKit implements. Perhaps
dschulze@6900 504 it should be changed to match current implementations? See
dschulze@6900 505 <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=19637">Bug 19637</a>.</p>
vhardy@3672 506 </div>
simon@4366 507
simon@4345 508 <div class="example">
simon@4356 509 <p>This example shows the effect of three-dimensional transform applied to an element.
simon@4356 510 </p>
simon@4345 511 <pre>
simon@4364 512 &lt;style&gt;
dschulze@4602 513 div {
dschulze@4602 514 height: 150px;
dschulze@4602 515 width: 150px;
dschulze@4602 516 }
dschulze@4602 517 .container {
dschulze@4602 518 border: 1px solid black;
dschulze@4602 519 }
dschulze@4602 520 .transformed {
dschulze@4602 521 transform: rotateY(50deg);
dschulze@4602 522 }
simon@4364 523 &lt;/style&gt;
simon@4366 524
simon@4356 525 &lt;div class="container"&gt;
simon@4356 526 &lt;div class="transformed"&gt;&lt;/div&gt;
simon@4356 527 &lt;/div&gt;
ayg@5129 528 </pre>
simon@4366 529 <div class="figure">
simon@4366 530 <img src="examples/simple-3d-example.png" width="210" height="190" alt="Div with a rotateY transform.">
simon@4366 531 </div>
simon@4358 532 <p>The transform is a 50&deg; rotation about the vertical, Y axis. Note how this makes the blue box appear
simon@4356 533 narrower, but not three-dimensional.
simon@4345 534 </p>
simon@4345 535 </div>
simon@4366 536
simon@4366 537 <p>
dschulze@6300 538 The 'perspective' and 'perspective-origin' properties can be used to add a feeling
dschulze@6300 539 of depth to a scene by making elements higher on the Z axis (closer to the viewer)
dschulze@6300 540 appear larger, and those further away to appear smaller. The scaling is proportional
dschulze@6300 541 to <var>d</var>/(<var>d</var> &minus; <var>Z</var>) where <var>d</var>, the value of
dschulze@6300 542 'perspective', is the distance from the drawing plane to the the assumed position of
dschulze@6300 543 the viewer's eye.
simon@4366 544 </p>
ayg@5128 545
ayg@5128 546 <div class="figure">
ayg@5128 547 <img alt="Diagram of scale vs. Z position" src="perspective_distance.png">
ayg@5128 548 <p class="caption">
dschulze@6300 549 Diagrams showing how scaling depends on the 'perspective' property and Z position.
dschulze@6300 550 In the top diagram, <var>Z</var> is half of <var>d</var>. In order to make it
dschulze@6300 551 appear that the original circle (solid outline) appears at <var>Z</var> (dashed
dschulze@6300 552 circle), the circle is scaled up by a factor of two, resulting in the light blue
dschulze@6300 553 circle. In the bottom diagram, the circle is scaled down by a factor of one-third
dschulze@6300 554 to make it appear behind the original position.
ayg@5128 555 </p>
ayg@5128 556 </div>
ayg@5128 557
ayg@5128 558 <p>
ayg@5128 559 Normally the assumed position of the viewer's eye is
ayg@5128 560 centered on a drawing. This position can be moved if
ayg@5128 561 desired &ndash; for example, if a web page contains
ayg@5128 562 multiple drawings that should share a common perspective
dschulze@6300 563 &ndash; by setting 'perspective-origin'.
ayg@5128 564 </p>
ayg@5128 565
ayg@5128 566 <div class="figure">
ayg@5128 567 <img alt="Diagram of different perspective-origin" src="perspective_origin.png">
ayg@5128 568 <p class="caption">
ayg@5128 569 Diagram showing the effect of moving the perspective origin upward.
ayg@5128 570 </p>
ayg@5128 571 </div>
ayg@5128 572
simon@4453 573 <p id="perspective-matrix-computation">
simon@4366 574 The <a href="#TermPerspectiveMatrix"><i>perspective matrix</i></a> is computed as follows:
simon@4366 575 <ol>
simon@4366 576 <li>Start with the identity matrix.</li>
dschulze@6300 577 <li>Translate by the computed X and Y values of 'perspective-origin'</li>
dschulze@6300 578 <li>Multiply by the matrix that would be obtained from the '<a href="#perspective-function"><code class="css">perspective(&lt;length&gt;)</code></a>' transform function, where the length is provided by the value of the 'perspective' property</li>
dschulze@6300 579 <li>Translate by the negated computed X and Y values of 'perspective-origin'</li>
simon@4366 580 </ol>
bert@6704 581
ayg@5129 582
simon@4356 583 <div class="example">
simon@4356 584 <p>This example shows how perspective can be used to cause three-dimensional transforms to appear more realistic.
simon@4356 585 </p>
simon@4356 586 <pre>
simon@4364 587 &lt;style&gt;
dschulze@4602 588 div {
dschulze@4602 589 height: 150px;
dschulze@4602 590 width: 150px;
dschulze@4602 591 }
dschulze@4602 592 .container {
dschulze@4602 593 perspective: 500px;
dschulze@4602 594 border: 1px solid black;
dschulze@4602 595 }
dschulze@4602 596 .transformed {
dschulze@4602 597 transform: rotateY(50deg);
dschulze@4602 598 }
simon@4364 599 &lt;/style&gt;
simon@4366 600
simon@4356 601 &lt;div class="container"&gt;
simon@4356 602 &lt;div class="transformed"&gt;&lt;/div&gt;
simon@4356 603 &lt;/div&gt;
ayg@5129 604 </pre>
simon@4366 605 <div class="figure">
simon@4366 606 <img src="examples/simple-perspective-example.png" width="210" height="190" alt="Div with a rotateY transform,
simon@4366 607 and perspective on its container">
simon@4366 608 </div>
simon@4366 609 <p>The inner element has the same transform as in the previous example, but its rendering is now influenced by the perspective
simon@4356 610 property on its parent element. Perspective causes vertices that have positive Z coordinates (closer to the viewer)
dschulze@4602 611 to be scaled up in X and Y, and those further away (negative Z coordinates) to be scaled down, giving an appearance of depth.
simon@4356 612 </p>
simon@4356 613 </div>
simon@4356 614
simon@4345 615 <p>
simon@4366 616 An element with a three-dimensional transform that is not contained in a
simon@4366 617 <span class="term">3D rendering context</span> renders with the appropriate
simon@4366 618 transform applied, but does not intersect with any other elements. The three-dimensional
simon@4366 619 transform in this case can be considered just as a painting effect, like two-dimensional
ayg@5129 620 transforms. Similarly, the transform does not affect painting order. For example, a transform with a
simon@4366 621 positive Z translation may make an element look larger, but does not cause that element
simon@4366 622 to render in front of elements with no translation in Z.
simon@4366 623 </p>
simon@4366 624 <p>
simon@4345 625 An element with a three-dimensional transform that is contained in a
simon@4345 626 <span class="term">3D rendering context</span> can visibly interact with other elements
ayg@5129 627 in that same 3D rendering context; the set of elements participating in the same
simon@4345 628 <span class="term">3D rendering context</span> may obscure each other or intersect,
simon@4345 629 based on their computed transforms. They are rendered as if they are all siblings,
simon@4345 630 positioned in a common 3D coordinate space. The position of each element in that three-dimensional
simon@4345 631 space is determined by accumulating the transformation matrices
simon@4345 632 up from the element that establishes the <span class="term">3D rendering context</span>
simon@4345 633 through each element that is a containing block for the given element, as described below.
simon@4345 634 </p>
simon@4345 635
simon@4366 636 <div class="example">
simon@4366 637 <pre>
simon@4366 638 &lt;style&gt;
dschulze@4602 639 div {
dschulze@4602 640 height: 150px;
dschulze@4602 641 width: 150px;
dschulze@4602 642 }
dschulze@4602 643 .container {
dschulze@4602 644 perspective: 500px;
dschulze@4602 645 border: 1px solid black;
dschulze@4602 646 }
dschulze@4602 647 .transformed {
dschulze@4602 648 transform: rotateY(50deg);
dschulze@4602 649 background-color: blue;
dschulze@4602 650 }
dschulze@4602 651 .child {
dschulze@4602 652 transform-origin: top left;
dschulze@4602 653 transform: rotateX(40deg);
dschulze@4602 654 background-color: lime;
dschulze@4602 655 }
simon@4366 656 &lt;/style&gt;
simon@4366 657
simon@4366 658 &lt;div class="container"&gt;
dschulze@4602 659 &lt;div class="transformed"&gt;
dschulze@4602 660 &lt;div class="child"&gt;&lt;/div&gt;
dschulze@4602 661 &lt;/div&gt;
simon@4366 662 &lt;/div&gt;
simon@4366 663 </pre>
dschulze@6300 664 <p>This example shows how nested 3D transforms are rendered in the absence of ''transform-style: preserve-3d''. The blue div is transformed as in the previous example, with its rendering influenced by the perspective on its parent element. The lime element also has a 3D transform, which is a rotation about the X axis (anchored at the top, by virtue of the transform-origin). However, the lime element is being rendered into the plane of its parent because it is not a member of a 3D rendering context; the parent is "flattening".
simon@4366 665 </p>
simon@4366 666 <div class="figure">
simon@4366 667 <img src="examples/3d-rendering-context-flat.png" width="240" height="200" alt="Nested 3D transforms, with flattening">
simon@4366 668 </div>
simon@4366 669 </div>
simon@4366 670
simon@4365 671 <p>Elements establish and participate in 3D rendering contexts as follows:</p>
simon@4365 672 <ul>
simon@4365 673 <li>
simon@4365 674 A <span class="term">3D rendering context</span> is established by a
dschulze@6300 675 a <span class="term">transformable element</span> whose computed value for 'transform-style' is
dschulze@6300 676 ''preserve-3d'', and which itself is not part of a 3D rendering context.
simon@4365 677 Note that such an element is always a containing block. An element that establishes a 3D rendering context
simon@4365 678 also participates in that context.
simon@4365 679 </li>
simon@4365 680 <li>
dschulze@6300 681 An element whose computed value for 'transform-style' is
dschulze@6300 682 ''preserve-3d'', and which itself participates in a
simon@4365 683 <span class="term">3D rendering context</span>, extends that 3D rendering context rather than establishing
simon@4365 684 a new one.
simon@4365 685 </li>
simon@4365 686 <li>
simon@4365 687 An element participates in a <span class="term">3D rendering context</span> if its containing block
simon@4365 688 establishes or extends a <span class="term">3D rendering context</span>.
simon@4365 689 </li>
simon@4365 690 </ul>
ayg@5127 691 <p id="accumulated-3d-transformation-matrix-computation">
simon@4345 692 The final value of the transform used to render an element in a <span class="term">3D rendering context</span>
ayg@5127 693 is computed by accumulating an
ayg@5127 694 <a href="#TermAccumulated3DTransformationMatrix">
ayg@5127 695 accumulated 3D transformation matrix</a> as follows:
simon@4345 696 </p>
simon@4345 697 <ol>
ayg@5127 698 <li>Start with the identity matrix.</li>
ayg@5129 699 <li>For each containing block between the root of the <span class="term">3D rendering context</span>
simon@4366 700 and the element in question:
simon@4365 701 <ol>
dschulze@6300 702 <li>multiply the accumulated matrix with the <span class="term">perspective matrix</span>
ayg@4751 703 on the element's containing block (if any). That containing block is not necessarily a member
simon@4366 704 of the 3D rendering context.</li>
simon@4366 705 <li>apply to the accumulated matrix a translation equivalent to the horizontal and vertical offset of the element relative to
dschulze@6893 706 its containing block as specified by the CSS visual formatting model.</li>
dschulze@6300 707 <li>multiply the accumulated matrix with the <span class="term">transformation matrix</span>.</li>
simon@4365 708 </ol>
simon@4345 709 </li>
simon@4345 710 </ol>
ayg@5129 711
simon@4345 712 <div class="example">
simon@4345 713 <pre>
simon@4364 714 &lt;style&gt;
dschulze@4602 715 div {
dschulze@4602 716 height: 150px;
dschulze@4602 717 width: 150px;
dschulze@4602 718 }
dschulze@4602 719 .container {
dschulze@4602 720 perspective: 500px;
dschulze@4602 721 border: 1px solid black;
dschulze@4602 722 }
dschulze@4602 723 .transformed {
dschulze@4602 724 <b>transform-style: preserve-3d</b>;
dschulze@4602 725 transform: rotateY(50deg);
dschulze@4602 726 background-color: blue;
dschulze@4602 727 }
dschulze@4602 728 .child {
dschulze@4602 729 transform-origin: top left;
dschulze@4602 730 transform: rotateX(40deg);
dschulze@4602 731 background-color: lime;
dschulze@4602 732 }
simon@4364 733 &lt;/style&gt;
simon@4345 734 </pre>
dschulze@6300 735 <p>
dschulze@6300 736 This example is identical to the previous example, with the addition of
dschulze@6300 737 ''transform-style: preserve-3d'' on the blue element. The blue element now
dschulze@6300 738 establishes a 3D rendering context, of which the lime element is a member. Now
dschulze@6300 739 both blue and lime elements share a common three-dimensional space, so the lime
dschulze@6300 740 element renders as tilting out from its parent, influenced by the perspective on
dschulze@6300 741 the container.
simon@4345 742 </p>
simon@4345 743 <div class="figure">
simon@4364 744 <img src="examples/3d-rendering-context-3d.png" width="240" height="200" alt="Nested 3D transforms, with preserve-3d.">
simon@4345 745 </div>
simon@4345 746 </div>
simon@4345 747
simon@4366 748 <p>
simon@4701 749 Elements in the same <span class="term">3D rendering context</span> may intersect with each other. User agents must
simon@4702 750 render intersection by subdividing the planes of intersecting elements as described by
simon@4701 751 <a href="http://en.wikipedia.org/wiki/Newell's_algorithm">Newell's algorithm</a>.
simon@4366 752 </p>
simon@4366 753 <p>
simon@4366 754 Untransformed elements in a <span class="term">3D rendering context</span> render on the Z=0 plane, yet may still
simon@4366 755 intersect with transformed elements.
simon@4366 756 </p>
simon@4366 757 <p>
simon@4366 758 Within a <span class="term">3D rendering context</span>, the rendering order of non-intersecting elements is
simon@4366 759 based on their position on the Z axis after the application of the accumulated transform. Elements at the same
simon@4366 760 Z position render in <a href="http://www.w3.org/TR/CSS2/zindex.html#painting-order">stacking context order</a>.
simon@4366 761 </p>
simon@4366 762
simon@4364 763 <div class="example">
simon@4345 764 <pre>
simon@4364 765 &lt;style&gt;
simon@4364 766 .container {
simon@4364 767 background-color: rgba(0, 0, 0, 0.3);
simon@4364 768 transform-style: preserve-3d;
simon@4364 769 perspective: 500px;
simon@4364 770 }
simon@4364 771 .container > div {
simon@4364 772 position: absolute;
simon@4364 773 left: 0;
simon@4364 774 }
simon@4364 775 .container > :first-child {
simon@4364 776 transform: rotateY(45deg);
simon@4364 777 background-color: orange;
simon@4364 778 top: 10px;
simon@4364 779 height: 135px;
simon@4364 780 }
simon@4364 781 .container > :last-child {
simon@4364 782 transform: translateZ(40px);
simon@4364 783 background-color: rgba(0, 0, 255, 0.75);
simon@4364 784 top: 50px;
simon@4364 785 height: 100px;
simon@4364 786 }
simon@4364 787 &lt;/style&gt;
simon@4364 788
simon@4364 789 &lt;div class="container"&gt;
simon@4364 790 &lt;div&gt;&lt;/div&gt;
simon@4364 791 &lt;div&gt;&lt;/div&gt;
simon@4364 792 &lt;/div&gt;
simon@4345 793 </pre>
simon@4364 794 <p>
simon@4364 795 This example shows show elements in a 3D rendering context can intersect. The container element establishes
simon@4364 796 a 3D rendering context for itself and its two children. The children intersect with eachother, and
simon@4364 797 the orange element also intersects with the container.
simon@4364 798 </p>
simon@4364 799 <div class="figure">
simon@4364 800 <img src="examples/3d-intersection.png" width="200" height="200" alt="Intersecting sibling elements.">
simon@4364 801 </div>
simon@4345 802 </div>
ayg@5129 803
simon@4367 804 <p>
simon@4367 805 Using three-dimensional transforms, it's possible to transform an element such that its reverse side
ayg@5901 806 is towards the viewer. 3D-transformed elements show the same content on both sides, so the reverse side
simon@4701 807 looks like a mirror-image of the front side (as if the element were projected onto a sheet of glass).
simon@4367 808 Normally, elements whose reverse side is towards the viewer remain visible. However, the
dschulze@6300 809 'backface-visibility' property allows the author to make an element invisible
simon@4367 810 when its reverse side is towards the viewer. This behavior is "live"; if an element with
dschulze@6300 811 ''backface-visibility: hidden'' were animating,
simon@4367 812 such that its front and reverse sides were alternately visible, then it would only be visible when the
simon@4367 813 front side were towards the viewer.
simon@4367 814 </p>
simon@4364 815
ayg@5901 816 <h3 id="processing-of-perspective-transformed-boxes">
ayg@5901 817 Processing of Perspective-Transformed Boxes
ayg@5901 818 </h3>
ayg@5901 819
ayg@5901 820 <div class="issue">
ayg@5901 821 <p class="desc">
ayg@5901 822 This is a first pass at an attempt to precisely specify how
ayg@5901 823 exactly to transform elements using the provided matrices.
ayg@5901 824 It might not be ideal, and implementer feedback is
ayg@5901 825 encouraged. See <a
ayg@5901 826 href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=15605">bug
ayg@5901 827 15605</a>.
ayg@5901 828 </p>
ayg@5901 829 </div>
ayg@5901 830
ayg@5901 831 <p>
dschulze@6300 832 The <span class="term">accumulated
dschulze@6300 833 3D transformation matrix</span> is a 4&times;4 matrix, while the
dschulze@6300 834 objects to be transformed are two-dimensional boxes. To
dschulze@6300 835 transform each corner (<var>a</var>, <var>b</var>) of a box, the
dschulze@6300 836 matrix must first be applied to (<var>a</var>, <var>b</var>, 0,
dschulze@6300 837 1), which will result in a four-dimensional point (<var>x</var>,
dschulze@6300 838 <var>y</var>, <var>z</var>, <var>w</var>). This is transformed
dschulze@6300 839 back to a three-dimensional point (<var>x</var>&prime;, <var>y</var>&prime;,
dschulze@6300 840 <var>z</var>&prime;) as follows:
ayg@5901 841 </p>
ayg@5901 842
ayg@5901 843 <p>
dschulze@6300 844 If <var>w</var> &gt; 0, (<var>x</var>&prime;,
dschulze@6300 845 <var>y</var>&prime;, <var>z</var>&prime;) =
dschulze@6300 846 (<var>x</var>/<var>w</var>, <var>y</var>/<var>w</var>,
dschulze@6300 847 <var>z</var>/<var>w</var>).
ayg@5901 848 </p>
ayg@5901 849
ayg@5901 850 <p>
dschulze@6300 851 If <var>w</var> = 0, (<var>x</var>&prime;, <var>y</var>&prime;,
dschulze@6300 852 <var>z</var>&prime;) = (<var>x</var> &sdot; <var>n</var>,
dschulze@6300 853 <var>y</var> &sdot; <var>n</var>, <var>z</var> &sdot;
dschulze@6300 854 <var>n</var>). <var>n</var> is an implementation-dependent value
dschulze@6300 855 that should be chosen so that <var>x</var>&prime; or
dschulze@6300 856 <var>y</var>&prime; is much larger than the viewport size, if
dschulze@6300 857 possible. For example, (5px, 22px, 0px, 0) might become (5000px,
dschulze@6300 858 22000px, 0px), with <var>n</var> = 1000, but this value of
dschulze@6300 859 <var>n</var> would be too small for (0.1px, 0.05px, 0px, 0).
dschulze@6300 860 This specification does not define the value of <var>n</var>
dschulze@6300 861 exactly. Conceptually, (<var>x</var>&prime;,
dschulze@6300 862 <var>y</var>&prime;, <var>z</var>&prime;) is <a
dschulze@6300 863 href="http://en.wikipedia.org/wiki/Plane_at_infinity">infinitely
dschulze@6300 864 far</a> in the direction (<var>x</var>, <var>y</var>,
dschulze@6300 865 <var>z</var>).
ayg@5901 866 </p>
ayg@5901 867
ayg@5901 868 <p>
dschulze@6300 869 If <var>w</var> &lt; 0 for all four corners of the transformed
dschulze@6300 870 box, the box is not rendered.
ayg@5901 871 </p>
ayg@5901 872
ayg@5901 873 <p>
dschulze@6300 874 If <var>w</var> &lt; 0 for one to three corners of the
dschulze@6300 875 transformed box, the box must be replaced by a polygon that has
dschulze@6300 876 any parts with <var>w</var> &lt; 0 cut out. This will in general
dschulze@6300 877 be a polygon with three to five vertices, of which exactly two
dschulze@6300 878 will have <var>w</var> = 0 and the rest <var>w</var> &gt; 0.
dschulze@6300 879 These vertices are then transformed to three-dimensional points
dschulze@6300 880 using the rules just stated. Conceptually, a point with
dschulze@6300 881 <var>w</var> &lt; 0 is "behind" the viewer, so should not be
dschulze@6300 882 visible.
ayg@5901 883 </p>
ayg@5901 884
ayg@5901 885 <div class="example">
ayg@5901 886 <pre>&lt;style&gt;
ayg@5901 887 .transformed {
ayg@5901 888 height: 100px;
ayg@5901 889 width: 100px;
ayg@5901 890 background: lime;
ayg@5901 891 transform: perspective(50px) translateZ(100px);
ayg@5901 892 }
ayg@5901 893 &lt;/style&gt;</pre>
ayg@5901 894
ayg@5901 895 <p>
dschulze@6300 896 All of the box's corners have <var>z</var>-coordinates greater
dschulze@6300 897 than the perspective. This means that the box is behind the
dschulze@6300 898 viewer and will not display. Mathematically, the point
dschulze@6300 899 (<var>x</var>, <var>y</var>) first becomes (<var>x</var>,
dschulze@6300 900 <var>y</var>, 0, 1), then is translated to (<var>x</var>,
dschulze@6300 901 <var>y</var>, 100, 1), and then applying the perspective
dschulze@6300 902 results in (<var>x</var>, <var>y</var>, 100, &minus;1). The
dschulze@6300 903 <var>w</var>-coordinate is negative, so it does not display.
dschulze@6300 904 An implementation that doesn't handle the <var>w</var> &lt; 0
dschulze@6300 905 case separately might incorrectly display this point as
dschulze@6300 906 (&minus;<var>x</var>, &minus;<var>y</var>, &minus;100),
dschulze@6300 907 dividing by &minus;1 and mirroring the box.
ayg@5901 908 </p>
ayg@5901 909 </div>
ayg@5901 910
ayg@5901 911 <div class="example">
ayg@5901 912 <pre>&lt;style&gt;
ayg@5901 913 .transformed {
ayg@5901 914 height: 100px;
ayg@5901 915 width: 100px;
ayg@5901 916 background: radial-gradient(yellow, blue);
ayg@5901 917 transform: perspective(50px) translateZ(50px);
ayg@5901 918 }
ayg@5901 919 &lt;/style&gt;</pre>
ayg@5901 920
ayg@5901 921 <p>
dschulze@6300 922 Here, the box is translated upward so that it sits at the same
dschulze@6300 923 place the viewer is looking from. This is like bringing the
dschulze@6300 924 box closer and closer to one's eye until it fills the entire
dschulze@6300 925 field of vision. Since the default transform-origin is at the
dschulze@6300 926 center of the box, which is yellow, the screen will be filled
dschulze@6300 927 with yellow.
ayg@5901 928 </p>
ayg@5901 929
ayg@5901 930 <p>
dschulze@6300 931 Mathematically, the point (<var>x</var>, <var>y</var>) first
dschulze@6300 932 becomes (<var>x</var>, <var>y</var>, 0, 1), then is translated
dschulze@6300 933 to (<var>x</var>, <var>y</var>, 50, 1), then becomes
dschulze@6300 934 (<var>x</var>, <var>y</var>, 50, 0) after applying perspective.
dschulze@6300 935 Relative to the transform-origin at the center, the upper-left
dschulze@6300 936 corner was (&minus;50, &minus;50), so it becomes (&minus;50,
dschulze@6300 937 &minus;50, 50, 0). This is transformed to something
dschulze@6300 938 very far to the upper left, such as (&minus;5000, &minus;5000,
dschulze@6300 939 5000). Likewise the other corners are sent very far away. The
dschulze@6300 940 radial gradient is stretched over the whole box, now enormous,
dschulze@6300 941 so the part that's visible without scrolling should be the
dschulze@6300 942 color of the middle pixel: yellow. However, since the box is
dschulze@6300 943 not actually infinite, the user can still scroll to the edges
dschulze@6300 944 to see the blue parts.
ayg@5901 945 </p>
ayg@5901 946 </div>
ayg@5901 947
ayg@5901 948 <div class="example">
ayg@5901 949 <pre>&lt;style&gt;
ayg@5901 950 .transformed {
ayg@5901 951 height: 50px;
ayg@5901 952 width: 50px;
ayg@5901 953 background: lime;
ayg@5901 954 border: 25px solid blue;
ayg@5901 955 transform-origin: left;
ayg@5901 956 transform: perspective(50px) rotateY(-45deg);
ayg@5901 957 }
ayg@5901 958 &lt;/style&gt;</pre>
ayg@5901 959
ayg@5901 960 <p>
dschulze@6300 961 The box will be rotated toward the viewer, with the left edge
dschulze@6300 962 staying fixed while the right edge swings closer. The right
dschulze@6300 963 edge will be at about <var>z</var> = 70.7px, which is closer
dschulze@6300 964 than the perspective of 50px. Therefore, the rightmost edge
dschulze@6300 965 will vanish ("behind" the viewer), and the visible part will
dschulze@6300 966 stretch out infinitely far to the right.
ayg@5901 967 </p>
ayg@5901 968
ayg@5901 969 <p>
dschulze@6300 970 Mathematically, the top right vertex of the box was originally
dschulze@6300 971 (100, &minus;50), relative to the transform-origin. It is first
dschulze@6300 972 expanded to (100, &minus;50, 0, 1). After applying the
dschulze@6300 973 transform specified, this will get mapped to about (70.71,
dschulze@6300 974 &minus;50, 70.71, &minus;0.4142). This has <var>w</var> =
dschulze@6300 975 &minus;0.4142 &lt; 0, so we need to slice away the part of the
dschulze@6300 976 box with <var>w</var> &lt; 0. This results in the new
dschulze@6300 977 top-right vertex being (50, &minus;50, 50, 0). This is then
dschulze@6300 978 mapped to some faraway point in the same direction, such as
dschulze@6300 979 (5000, &minus;5000, 5000), which is up and to the right from
dschulze@6300 980 the transform-origin. Something similar is done to the lower
dschulze@6300 981 right corner, which gets mapped far down and to the right. The
dschulze@6300 982 resulting box stretches far past the edge of the screen.
ayg@5901 983 </p>
ayg@5901 984
ayg@5901 985 <p>
dschulze@6300 986 Again, the rendered box is still finite, so the user can scroll
dschulze@6300 987 to see the whole thing if he or she chooses. However, the
dschulze@6300 988 right part has been chopped off. No matter how far the user
dschulze@6300 989 scrolls, the rightmost 30px or so of the original box will not
dschulze@6300 990 be visible. The blue border was only 25px wide, so it will be
dschulze@6300 991 visible on the left, top, and bottom, but not the right.
ayg@5901 992 </p>
ayg@5901 993
ayg@5901 994 <p>
dschulze@6300 995 The same basic procedure would apply if one or three vertices
dschulze@6300 996 had <var>w</var> &lt; 0. However, in that case the result of
dschulze@6300 997 truncating the <var>w</var> &lt; 0 part would be a triangle or
dschulze@6300 998 pentagon instead of a quadrilateral.
ayg@5901 999 </p>
ayg@5901 1000 </div>
ayg@5901 1001
simon@4345 1002 <!-- ======================================================================================================= -->
dschulze@4321 1003
vhardy@3672 1004 <h2 id="transform-property">
dschulze@6300 1005 The 'transform' Property
vhardy@3672 1006 </h2>
vhardy@3672 1007 <p>
simon@4345 1008 A transformation is applied to the coordinate system an element
dschulze@6300 1009 renders in through the 'transform' property. This property contains a
vhardy@3672 1010 list of <a href="#transform-functions">transform functions</a>. The
vhardy@3672 1011 final transformation value for a coordinate system is obtained by converting
dschulze@6300 1012 each function in the list to its corresponding matrix like defined in <a
dschulze@6300 1013 href="#mathematical-description">Mathematical Description of Transform
dschulze@6300 1014 Functions</a>, then multiplying the matrices.
vhardy@3672 1015 </p>
vhardy@3672 1016 <table class="propdef">
vhardy@3672 1017 <tbody>
vhardy@3672 1018 <tr>
vhardy@3672 1019 <td>
vhardy@3672 1020 <em>Name:</em>
vhardy@3672 1021 </td>
vhardy@3672 1022 <td>
vhardy@3672 1023 <dfn id="effects">transform</dfn>
vhardy@3672 1024 </td>
vhardy@3672 1025 </tr>
vhardy@3672 1026 <tr>
vhardy@3672 1027 <td>
vhardy@3672 1028 <em>Value:</em>
vhardy@3672 1029 </td>
vhardy@3672 1030 <td>
vhardy@3672 1031 none | &lt;transform-function&gt; [ &lt;transform-function&gt; ]*
vhardy@3672 1032 </td>
vhardy@3672 1033 </tr>
vhardy@3672 1034 <tr>
vhardy@3672 1035 <td>
vhardy@3672 1036 <em>Initial:</em>
vhardy@3672 1037 </td>
vhardy@3672 1038 <td>
vhardy@3672 1039 none
vhardy@3672 1040 </td>
vhardy@3672 1041 </tr>
vhardy@3672 1042 <tr>
vhardy@3672 1043 <td>
dbaron@7338 1044 <em>Applies to:</em>
vhardy@3672 1045 </td>
vhardy@3672 1046 <td>
dschulze@4321 1047 <a href="#TermTransformableElement">transformable elements</a>
vhardy@3672 1048 </td>
vhardy@3672 1049 </tr>
vhardy@3672 1050 <tr>
vhardy@3672 1051 <td>
vhardy@3672 1052 <em>Inherited:</em>
vhardy@3672 1053 </td>
vhardy@3672 1054 <td>
vhardy@3672 1055 no
vhardy@3672 1056 </td>
vhardy@3672 1057 </tr>
vhardy@3672 1058 <tr>
vhardy@3672 1059 <td>
vhardy@3672 1060 <em>Percentages:</em>
vhardy@3672 1061 </td>
vhardy@3672 1062 <td>
dschulze@7030 1063 refer to the size of
dschulze@7030 1064 <var>bounding box</var>
vhardy@3672 1065 </td>
vhardy@3672 1066 </tr>
vhardy@3672 1067 <tr>
vhardy@3672 1068 <td>
vhardy@3672 1069 <em>Media:</em>
vhardy@3672 1070 </td>
vhardy@3672 1071 <td>
vhardy@3672 1072 visual
vhardy@3672 1073 </td>
vhardy@3672 1074 </tr>
vhardy@3672 1075 <tr>
vhardy@3672 1076 <td>
vhardy@3672 1077 <em>Computed value:</em>
vhardy@3672 1078 </td>
vhardy@3672 1079 <td>
ayg@4747 1080 As specified, but with relative lengths converted into
ayg@4747 1081 absolute lengths.
vhardy@3672 1082 </td>
vhardy@3672 1083 </tr>
dbaron@7349 1084 <tr>
dbaron@7349 1085 <td>
dbaron@7349 1086 <em>Animatable:</em>
dbaron@7349 1087 </td>
dbaron@7349 1088 <td>
dbaron@7349 1089 as <a href="#animation">transform</a>
dbaron@7349 1090 </td>
dbaron@7349 1091 </tr>
vhardy@3672 1092 </tbody>
simon@4334 1093 </table>
ayg@5129 1094
dschulze@6300 1095 <p>
dschulze@6300 1096 Any value other than ''none'' for the transform results in the creation of both a
dschulze@6300 1097 stacking context and a containing block. The object acts as a containing block for
dschulze@6300 1098 fixed positioned descendants.
dschulze@6300 1099 </p>
simon@4363 1100
simon@4334 1101 <!-- ======================================================================================================= -->
ayg@5129 1102
vhardy@3672 1103 <h2 id="transform-origin-property">
dschulze@6300 1104 The 'transform-origin' Property
vhardy@3672 1105 </h2>
vhardy@3672 1106 <table class="propdef">
vhardy@3672 1107 <tbody>
vhardy@3672 1108 <tr>
vhardy@3672 1109 <td>
vhardy@3672 1110 <em>Name:</em>
vhardy@3672 1111 </td>
vhardy@3672 1112 <td>
vhardy@3672 1113 <dfn id="transform-origin">transform-origin</dfn>
vhardy@3672 1114 </td>
vhardy@3672 1115 </tr>
vhardy@3672 1116 <tr>
vhardy@3672 1117 <td>
vhardy@3672 1118 <em>Value:</em>
vhardy@3672 1119 </td>
vhardy@3672 1120 <td>
dschulze@7808 1121 &nbsp;&nbsp;[ left | center | right | top | bottom | <var>&lt;percentage></var> | <var>&lt;length></var> ]<br>
dschulze@7808 1122 |<br>
dschulze@7808 1123 &nbsp;&nbsp;[ left | center | right | <var>&lt;percentage></var> | <var>&lt;length></var> ]<br>
dschulze@7808 1124 &nbsp;&nbsp;[ top | center | bottom | <var>&lt;percentage></var> | <var>&lt;length></var> ] <var>&lt;length></var>?
vhardy@3672 1125 </td>
vhardy@3672 1126 </tr>
vhardy@3672 1127 <tr>
vhardy@3672 1128 <td>
vhardy@3672 1129 <em>Initial:</em>
vhardy@3672 1130 </td>
vhardy@3672 1131 <td>
dschulze@5740 1132 50% 50%
vhardy@3672 1133 </td>
vhardy@3672 1134 </tr>
vhardy@3672 1135 <tr>
vhardy@3672 1136 <td>
dbaron@7338 1137 <em>Applies to:</em>
vhardy@3672 1138 </td>
vhardy@3672 1139 <td>
simon@4366 1140 <a href="#TermTransformableElement">transformable elements</a>
vhardy@3672 1141 </td>
vhardy@3672 1142 </tr>
vhardy@3672 1143 <tr>
vhardy@3672 1144 <td>
vhardy@3672 1145 <em>Inherited:</em>
vhardy@3672 1146 </td>
vhardy@3672 1147 <td>
vhardy@3672 1148 no
vhardy@3672 1149 </td>
vhardy@3672 1150 </tr>
vhardy@3672 1151 <tr>
vhardy@3672 1152 <td>
vhardy@3672 1153 <em>Percentages:</em>
vhardy@3672 1154 </td>
vhardy@3672 1155 <td>
dschulze@7030 1156 refer to the size of
dschulze@7030 1157 <var>bounding box</var>
vhardy@3672 1158 </td>
vhardy@3672 1159 </tr>
vhardy@3672 1160 <tr>
vhardy@3672 1161 <td>
vhardy@3672 1162 <em>Media:</em>
vhardy@3672 1163 </td>
vhardy@3672 1164 <td>
vhardy@3672 1165 visual
vhardy@3672 1166 </td>
vhardy@3672 1167 </tr>
vhardy@3672 1168 <tr>
vhardy@3672 1169 <td>
vhardy@3672 1170 <em>Computed value:</em>
vhardy@3672 1171 </td>
vhardy@3672 1172 <td>
vhardy@3672 1173 For &lt;length&gt; the absolute value, otherwise a percentage
vhardy@3672 1174 </td>
vhardy@3672 1175 </tr>
dbaron@7349 1176 <tr>
dbaron@7349 1177 <td>
dbaron@7349 1178 <em>Animatable:</em>
dbaron@7349 1179 </td>
dbaron@7349 1180 <td>
dbaron@7349 1181 as <a href="http://dev.w3.org/csswg/css3-transitions/#animtype-simple-list">simple list</a> of <a href="http://dev.w3.org/csswg/css3-transitions/#animtype-lpcalc">length, percentage, or calc</a>
dbaron@7349 1182 </td>
dbaron@7349 1183 </tr>
vhardy@3672 1184 </tbody>
vhardy@3672 1185 </table>
dschulze@5740 1186
dschulze@5740 1187 <p>
dschulze@5740 1188 The default value for SVG elements without associated CSS layout box is ''0 0''.
dschulze@5740 1189 </p>
simon@4366 1190
simon@4366 1191 <p>
dschulze@5658 1192 The values of the 'transform' and 'transform-origin' properties are used to compute
dschulze@6300 1193 the <span class="term">transformation matrix</span>, as
dschulze@5658 1194 described above.
simon@4366 1195 </p>
simon@4366 1196
dschulze@5658 1197 <p>
dschulze@5740 1198 If only one value is specified, the second value is assumed to be ''center''. If one
dschulze@5740 1199 or two values are specified, the third value is assumed to be ''0px''.
dschulze@4483 1200 </p>
ayg@5129 1201
dschulze@5658 1202 <p>
dschulze@5658 1203 If two or more values are defined and either no value is a keyword, or the only
dschulze@5740 1204 used keyword is ''center'', then the first value represents the horizontal position
dschulze@5740 1205 (or offset) and the second represents the vertical position (or offset). A third
dschulze@5740 1206 value always represents the Z position (or offset) and must be of type
dschulze@5740 1207 <var>&lt;length&gt;</var>.
ayg@4703 1208 </p>
ayg@4703 1209
dschulze@7030 1210 <dl>
dschulze@7030 1211 <dt><var>&lt;percentage&gt;</var>
dschulze@7030 1212
dschulze@7030 1213 <dd><p>A percentage for the horizontal offset is relative to the width of the
dschulze@7030 1214 <var>bounding box</var>.
dschulze@7030 1215 A percentage for the vertical offset is relative to height of the
dschulze@7030 1216 <var>bounding box</var>. The value for the horizontal
dschulze@7030 1217 and vertical offset represent an offset from the top left corner of the
dschulze@7030 1218 <var>bounding box</var>.
dschulze@7030 1219 </p>
dschulze@7030 1220
dschulze@7030 1221 <dt><var>&lt;length&gt;</var>
dschulze@7030 1222
dschulze@7030 1223 <dd>
dschulze@7030 1224 <p>A length value gives a fixed length as the offset. The value for the horizontal
dschulze@7030 1225 and vertical offset represent an offset from the top left corner of the
dschulze@7030 1226 <var>bounding box</var>.
dschulze@7030 1227 </p>
dschulze@7030 1228
dschulze@7030 1229 <p>For SVG elements without an associated CSS layout box the horizontal
dschulze@7030 1230 and vertical offset represent an offset from the point of origin of
dschulze@7030 1231 the element's local coordinate space.
dschulze@7030 1232 </p>
dschulze@7030 1233 </dd>
dschulze@7030 1234
dschulze@7030 1235 <dt><dfn title="''top''!!'transform-origin' value">''top''</dfn>
dschulze@7030 1236
dschulze@7030 1237 <dd>Computes to ''0%'' for the vertical position.
dschulze@7030 1238
dschulze@7030 1239 <dt><dfn title="''right''!!'transform-origin' value">''right''</dfn>
dschulze@7030 1240
dschulze@7030 1241 <dd>Computes to ''100%'' for the horizontal position.
dschulze@7030 1242
dschulze@7030 1243 <dt><dfn title="''bottom''!!'transform-origin' value">''bottom''</dfn>
dschulze@7030 1244
dschulze@7030 1245 <dd>Computes to ''100%'' for the vertical position.
dschulze@7030 1246
dschulze@7030 1247 <dt><dfn title="''left''!!'transform-origin' value">''left''</dfn>
dschulze@7030 1248
dschulze@7030 1249 <dd>Computes to ''0%'' for the horizontal position.
dschulze@7030 1250
dschulze@7030 1251 <dt><dfn title="''center''!!'transform-origin' value">''center''</dfn>
dschulze@7030 1252
dschulze@7030 1253 <dd>Computes to ''50%'' (''left 50%'') for the
dschulze@7030 1254 horizontal position if the horizontal position is not otherwise
dschulze@7030 1255 specified, or ''50%'' (''top 50%'') for the vertical position if
dschulze@7030 1256 it is.
dschulze@7030 1257 </dl>
simon@4366 1258
ayg@4737 1259 <p>
bert@5324 1260 The <a href="http://www.w3.org/TR/cssom/#resolved-value">resolved value</a>
dschulze@6300 1261 of 'transform-origin' is the
ayg@4737 1262 <a href="http://www.w3.org/TR/CSS21/cascade.html#used-value">used value</a>
ayg@4737 1263 (i.e., percentages are resolved to absolute lengths).
ayg@4737 1264 </p>
ayg@4737 1265
simon@4345 1266 <!-- ======================================================================================================= -->
simon@4345 1267
simon@4345 1268 <h2 id="transform-style-property">
dschulze@6300 1269 The 'transform-style' Property
simon@4345 1270 </h2>
simon@4345 1271 <table class="propdef">
simon@4345 1272 <tbody>
simon@4345 1273 <tr>
simon@4345 1274 <td>
simon@4345 1275 <em>Name:</em>
simon@4345 1276 </td>
simon@4345 1277 <td>
simon@4345 1278 <dfn id="transform-style">transform-style</dfn>
simon@4345 1279 </td>
simon@4345 1280 </tr>
simon@4345 1281 <tr>
simon@4345 1282 <td>
simon@4345 1283 <em>Value:</em>
simon@4345 1284 </td>
simon@4345 1285 <td>
simon@4345 1286 flat | preserve-3d
simon@4345 1287 </td>
simon@4345 1288 </tr>
simon@4345 1289 <tr>
simon@4345 1290 <td>
simon@4345 1291 <em>Initial:</em>
simon@4345 1292 </td>
simon@4345 1293 <td>
simon@4345 1294 flat
simon@4345 1295 </td>
simon@4345 1296 </tr>
simon@4345 1297 <tr>
simon@4345 1298 <td>
dbaron@7338 1299 <em>Applies to:</em>
simon@4345 1300 </td>
simon@4345 1301 <td>
simon@4345 1302 <a href="#TermTransformableElement">transformable elements</a>
simon@4345 1303 </td>
simon@4345 1304 </tr>
simon@4345 1305 <tr>
simon@4345 1306 <td>
simon@4345 1307 <em>Inherited:</em>
simon@4345 1308 </td>
simon@4345 1309 <td>
simon@4345 1310 no
simon@4345 1311 </td>
simon@4345 1312 </tr>
simon@4345 1313 <tr>
simon@4345 1314 <td>
simon@4345 1315 <em>Percentages:</em>
simon@4345 1316 </td>
simon@4345 1317 <td>
simon@4345 1318 N/A
simon@4345 1319 </td>
simon@4345 1320 </tr>
simon@4345 1321 <tr>
simon@4345 1322 <td>
simon@4345 1323 <em>Media:</em>
simon@4345 1324 </td>
simon@4345 1325 <td>
simon@4345 1326 visual
simon@4345 1327 </td>
simon@4345 1328 </tr>
simon@4345 1329 <tr>
simon@4345 1330 <td>
simon@4345 1331 <em>Computed value:</em>
simon@4345 1332 </td>
simon@4345 1333 <td>
simon@4345 1334 Same as specified value.
simon@4345 1335 </td>
simon@4345 1336 </tr>
dbaron@7349 1337 <tr>
dbaron@7349 1338 <td>
dbaron@7349 1339 <em>Animatable:</em>
dbaron@7349 1340 </td>
dbaron@7349 1341 <td>
dbaron@7349 1342 no
dbaron@7349 1343 </td>
dbaron@7349 1344 </tr>
simon@4345 1345 </tbody>
simon@4345 1346 </table>
simon@4345 1347
simon@4345 1348 <p>
dschulze@6300 1349 A value of ''preserve-3d'' for 'transform-style' establishes a stacking context.
simon@4345 1350 </p>
simon@4345 1351
simon@4345 1352 <p>
simon@4345 1353 The following CSS property values require the user agent to create a flattened representation of
ayg@5129 1354 the descendant elements before they can be applied, and therefore override the behavior of
dschulze@6904 1355 ''transform-style: preserve-3d'':</p>
dschulze@6904 1356 <ul>
dschulze@6904 1357 <li>'overflow': any value other than ''visible''.</li>
dschulze@6904 1358 <li>'opacity': any value other than ''1''.</li>
dschulze@6904 1359 <li>'filter': any value other than ''none''.</li>
dschulze@6904 1360 </ul>
bert@6704 1361
dschulze@6904 1362 <p>
dschulze@6904 1363 The computed value of 'transform-style' is not affected.
dschulze@6904 1364 </p>
dschulze@6904 1365
simon@4366 1366 <p>
dschulze@6300 1367 The values of the 'transform' and 'transform-origin' properties are used to compute
dschulze@6300 1368 the <span class="term">transformation matrix</span>, as described above.
simon@4366 1369 </p>
simon@4345 1370
simon@4345 1371 <!-- ======================================================================================================= -->
simon@4345 1372
simon@4345 1373 <h2 id="perspective-property">
dschulze@6300 1374 The 'perspective' Property
simon@4345 1375 </h2>
simon@4345 1376 <table class="propdef">
simon@4345 1377 <tbody>
simon@4345 1378 <tr>
simon@4345 1379 <td>
simon@4345 1380 <em>Name:</em>
simon@4345 1381 </td>
simon@4345 1382 <td>
simon@4345 1383 <dfn id="perspective">perspective</dfn>
simon@4345 1384 </td>
simon@4345 1385 </tr>
simon@4345 1386 <tr>
simon@4345 1387 <td>
simon@4345 1388 <em>Value:</em>
simon@4345 1389 </td>
simon@4345 1390 <td>
simon@4345 1391 none | &lt;length&gt;
simon@4345 1392 </td>
simon@4345 1393 </tr>
simon@4345 1394 <tr>
simon@4345 1395 <td>
simon@4345 1396 <em>Initial:</em>
simon@4345 1397 </td>
simon@4345 1398 <td>
simon@4345 1399 none
simon@4345 1400 </td>
simon@4345 1401 </tr>
simon@4345 1402 <tr>
simon@4345 1403 <td>
dbaron@7338 1404 <em>Applies to:</em>
simon@4345 1405 </td>
simon@4345 1406 <td>
simon@4345 1407 <a href="#TermTransformableElement">transformable elements</a>
simon@4345 1408 </td>
simon@4345 1409 </tr>
simon@4345 1410 <tr>
simon@4345 1411 <td>
simon@4345 1412 <em>Inherited:</em>
simon@4345 1413 </td>
simon@4345 1414 <td>
simon@4345 1415 no
simon@4345 1416 </td>
simon@4345 1417 </tr>
simon@4345 1418 <tr>
simon@4345 1419 <td>
simon@4345 1420 <em>Percentages:</em>
simon@4345 1421 </td>
simon@4345 1422 <td>
simon@4345 1423 N/A
simon@4345 1424 </td>
simon@4345 1425 </tr>
simon@4345 1426 <tr>
simon@4345 1427 <td>
simon@4345 1428 <em>Media:</em>
simon@4345 1429 </td>
simon@4345 1430 <td>
simon@4345 1431 visual
simon@4345 1432 </td>
simon@4345 1433 </tr>
simon@4345 1434 <tr>
simon@4345 1435 <td>
simon@4345 1436 <em>Computed value:</em>
simon@4345 1437 </td>
simon@4345 1438 <td>
ayg@4741 1439 Absolute length or "none".
simon@4345 1440 </td>
simon@4345 1441 </tr>
dbaron@7349 1442 <tr>
dbaron@7349 1443 <td>
dbaron@7349 1444 <em>Animatable:</em>
dbaron@7349 1445 </td>
dbaron@7349 1446 <td>
dbaron@7349 1447 as <a href="http://dev.w3.org/csswg/css3-transitions/#animtype-length">length</a>
dbaron@7349 1448 </td>
dbaron@7349 1449 </tr>
simon@4345 1450 </tbody>
simon@4345 1451 </table>
simon@4345 1452
simon@4345 1453 <p>
dschulze@6300 1454 If the value is ''none'', no perspective
ayg@4744 1455 transform is applied. Lengths must be positive.
simon@4345 1456 </p>
simon@4345 1457 <p>
dschulze@6300 1458 The use of this property with any value other than ''none'' establishes a
simon@4345 1459 stacking context. It also establishes a containing block (somewhat
dschulze@6300 1460 similar to ''position: relative''), just like the 'transform' property does.
simon@4345 1461 </p>
simon@4366 1462 <p>
dschulze@6300 1463 The values of the 'perspective' and 'perspective-origin' properties are used to
dschulze@6300 1464 compute the <span class="term">perspective matrix</span>, as described above.
simon@4366 1465 </p>
ayg@5129 1466
simon@4345 1467 <!-- ======================================================================================================= -->
ayg@5129 1468
simon@4345 1469 <h2 id="perspective-origin-property">
dschulze@6300 1470 The 'perspective-origin' Property
simon@4345 1471 </h2>
simon@4345 1472 <p>
dschulze@6300 1473 The 'perspective-origin' property establishes the origin for the
dschulze@6300 1474 <em>perspective</em> property. It effectively sets the X and Y position at which the
dschulze@6300 1475 viewer appears to be looking at the children of the element.
simon@4345 1476 </p>
simon@4345 1477 <table class="propdef">
simon@4345 1478 <tbody>
simon@4345 1479 <tr>
simon@4345 1480 <td>
simon@4345 1481 <em>Name:</em>
simon@4345 1482 </td>
simon@4345 1483 <td>
simon@4345 1484 <dfn id="perspective-origin">perspective-origin</dfn>
simon@4345 1485 </td>
simon@4345 1486 </tr>
simon@4345 1487 <tr>
simon@4345 1488 <td>
simon@4345 1489 <em>Value:</em>
simon@4345 1490 </td>
simon@4345 1491 <td>
dschulze@7808 1492 &nbsp;&nbsp;[ left | center | right | top | bottom | <var>&lt;percentage></var> | <var>&lt;length></var> ]<br>
dschulze@7808 1493 |<br>
dschulze@7808 1494 &nbsp;&nbsp;[ left | center | right | <var>&lt;percentage></var> | <var>&lt;length></var> ]<br>
dschulze@7808 1495 &nbsp;&nbsp;[ top | center | bottom | <var>&lt;percentage></var> | <var>&lt;length></var> ]
simon@4345 1496 </td>
simon@4345 1497 </tr>
simon@4345 1498 <tr>
simon@4345 1499 <td>
simon@4345 1500 <em>Initial:</em>
simon@4345 1501 </td>
simon@4345 1502 <td>
simon@4345 1503 50% 50%
simon@4345 1504 </td>
simon@4345 1505 </tr>
simon@4345 1506 <tr>
simon@4345 1507 <td>
dbaron@7338 1508 <em>Applies to:</em>
simon@4345 1509 </td>
simon@4345 1510 <td>
simon@4345 1511 <a href="#TermTransformableElement">transformable elements</a>
simon@4345 1512 </td>
simon@4345 1513 </tr>
simon@4345 1514 <tr>
simon@4345 1515 <td>
simon@4345 1516 <em>Inherited:</em>
simon@4345 1517 </td>
simon@4345 1518 <td>
simon@4345 1519 no
simon@4345 1520 </td>
simon@4345 1521 </tr>
simon@4345 1522 <tr>
simon@4345 1523 <td>
simon@4345 1524 <em>Percentages:</em>
simon@4345 1525 </td>
simon@4345 1526 <td>
dschulze@7030 1527 refer to the size of the
dschulze@7030 1528 <var>bounding box</var>
simon@4345 1529 </td>
simon@4345 1530 </tr>
simon@4345 1531 <tr>
simon@4345 1532 <td>
simon@4345 1533 <em>Media:</em>
simon@4345 1534 </td>
simon@4345 1535 <td>
simon@4345 1536 visual
simon@4345 1537 </td>
simon@4345 1538 </tr>
simon@4345 1539 <tr>
simon@4345 1540 <td>
simon@4345 1541 <em>Computed value:</em>
simon@4345 1542 </td>
simon@4345 1543 <td>
ayg@4741 1544 For &lt;length&gt; the absolute value, otherwise a
ayg@4741 1545 percentage.
simon@4345 1546 </td>
simon@4345 1547 </tr>
dbaron@7349 1548 <tr>
dbaron@7349 1549 <td>
dbaron@7349 1550 <em>Animatable:</em>
dbaron@7349 1551 </td>
dbaron@7349 1552 <td>
dbaron@7349 1553 as <a href="http://dev.w3.org/csswg/css3-transitions/#animtype-simple-list">simple list</a> of <a href="http://dev.w3.org/csswg/css3-transitions/#animtype-lpcalc">length, percentage, or calc</a>
dbaron@7349 1554 </td>
dbaron@7349 1555 </tr>
simon@4345 1556 </tbody>
simon@4345 1557 </table>
simon@4365 1558 <p>
dschulze@6300 1559 The values of the 'perspective' and 'perspective-origin' properties are used to
dschulze@6300 1560 compute the <span class="term">perspective matrix</span>, as described above.
simon@4365 1561 </p>
ayg@4737 1562
dschulze@6300 1563 <p>
dschulze@6300 1564 If only one value is specified, the second value is assumed to be ''center''.
ayg@4743 1565 </p>
ayg@4743 1566
dschulze@6300 1567 <p>
dschulze@6300 1568 If at least one of the two values is not a keyword, then the
dschulze@6300 1569 first value represents the horizontal position (or offset) and
dschulze@6300 1570 the second represents the vertical position (or offset).
ayg@4743 1571 </p>
ayg@4743 1572
dschulze@6300 1573 <p>
dschulze@7030 1574 The values for 'perspective-origin' represent an offset of the perspective origin
dschulze@7030 1575 from the top
dschulze@7030 1576 left corner of the <var>bounding box</var>.
ayg@4743 1577 </p>
ayg@4743 1578
dschulze@7030 1579 <dl>
dschulze@7030 1580 <dt><var>&lt;percentage&gt;</var>
dschulze@7030 1581
dschulze@7030 1582 <dd><p>A percentage for the horizontal perspctive offset is relative to the width of the
dschulze@7030 1583 <var>bounding box</var>.
dschulze@7030 1584 A percentage for the vertical offset is relative to height of the
dschulze@7030 1585 <var>bounding box</var>. The value for the horizontal
dschulze@7030 1586 and vertical offset represent an offset from the top left corner of the
dschulze@7030 1587 <var>bounding box</var>.
dschulze@7030 1588 </p>
dschulze@7030 1589
dschulze@7030 1590 <dt><var>&lt;length&gt;</var>
dschulze@7030 1591
dschulze@7030 1592 <dd>
dschulze@7030 1593 <p>A length value gives a fixed length as the offset. The value for the horizontal
dschulze@7030 1594 and vertical offset represent an offset from the top left corner of the
dschulze@7030 1595 <var>bounding box</var>.
dschulze@7030 1596 </dd>
dschulze@7030 1597
dschulze@7030 1598 <dt><dfn title="''top''!!'perspective-origin' value">''top''</dfn>
dschulze@7030 1599
dschulze@7030 1600 <dd>Computes to ''0%'' for the vertical position.
dschulze@7030 1601
dschulze@7030 1602 <dt><dfn title="''right''!!'perspective-origin' value">''right''</dfn>
dschulze@7030 1603
dschulze@7030 1604 <dd>Computes to ''100%'' for the horizontal position.
dschulze@7030 1605
dschulze@7030 1606 <dt><dfn title="''bottom''!!'perspective-origin' value">''bottom''</dfn>
dschulze@7030 1607
dschulze@7030 1608 <dd>Computes to ''100%'' for the vertical position.
dschulze@7030 1609
dschulze@7030 1610 <dt><dfn title="''left''!!'perspective-origin' value">''left''</dfn>
dschulze@7030 1611
dschulze@7030 1612 <dd>Computes to ''0%'' for the horizontal position.
dschulze@7030 1613
dschulze@7030 1614 <dt><dfn title="''center''!!'perspective-origin' value">''center''</dfn>
dschulze@7030 1615
dschulze@7030 1616 <dd>Computes to ''50%'' (''left 50%'') for the
dschulze@7030 1617 horizontal position if the horizontal position is not otherwise
dschulze@7030 1618 specified, or ''50%'' (''top 50%'') for the vertical position if
dschulze@7030 1619 it is.
dschulze@7030 1620 </dl>
dschulze@7030 1621
ayg@4737 1622 <p>
bert@5324 1623 The <a href="http://www.w3.org/TR/cssom/#resolved-value">resolved value</a>
dschulze@6300 1624 of 'perspective-origin' is the
ayg@4737 1625 <a href="http://www.w3.org/TR/CSS21/cascade.html#used-value">used value</a>
ayg@4737 1626 (i.e., percentages are resolved to absolute lengths).
ayg@4737 1627 </p>
ayg@4737 1628
simon@4345 1629 <!-- ======================================================================================================= -->
simon@4345 1630
simon@4345 1631 <h2 id="backface-visibility-property">
dschulze@6300 1632 The 'backface-visibility' Property
simon@4345 1633 </h2>
simon@4345 1634 <p>
dschulze@6300 1635 The 'backface-visibility' property
simon@4345 1636 determines whether or not the "back" side of a transformed element is
simon@4345 1637 visible when facing the viewer. With an identity transform, the front
simon@4345 1638 side of an element faces the viewer. Applying a rotation about Y of 180
simon@4345 1639 degrees (for instance) would cause the back side of the element to face
simon@4345 1640 the viewer.
simon@4345 1641 </p>
dschulze@6893 1642 <p class="note">
dschulze@6893 1643 Note that this property is useful when you place two elements back-to-back, as you
simon@4345 1644 would to create a playing card. Without this property, the front and
simon@4345 1645 back elements could switch places at times during an animation to flip
simon@4345 1646 the card. Another example is creating a box out of 6 elements, but where
simon@4345 1647 you want to see the inside faces of the box. This is useful when
simon@4345 1648 creating the backdrop for a 3 dimensional stage.
simon@4345 1649 </p>
simon@4345 1650 <table class="propdef">
simon@4345 1651 <tbody>
simon@4345 1652 <tr>
simon@4345 1653 <td>
simon@4345 1654 <em>Name:</em>
simon@4345 1655 </td>
simon@4345 1656 <td>
simon@4345 1657 <dfn id="backface-visibility">backface-visibility</dfn>
simon@4345 1658 </td>
simon@4345 1659 </tr>
simon@4345 1660 <tr>
simon@4345 1661 <td>
simon@4345 1662 <em>Value:</em>
simon@4345 1663 </td>
simon@4345 1664 <td>
simon@4345 1665 visible | hidden
simon@4345 1666 </td>
simon@4345 1667 </tr>
simon@4345 1668 <tr>
simon@4345 1669 <td>
simon@4345 1670 <em>Initial:</em>
simon@4345 1671 </td>
simon@4345 1672 <td>
simon@4345 1673 visible
simon@4345 1674 </td>
simon@4345 1675 </tr>
simon@4345 1676 <tr>
simon@4345 1677 <td>
dbaron@7338 1678 <em>Applies to:</em>
simon@4345 1679 </td>
simon@4345 1680 <td>
simon@4366 1681 <a href="#TermTransformableElement">transformable elements</a>
simon@4345 1682 </td>
simon@4345 1683 </tr>
simon@4345 1684 <tr>
simon@4345 1685 <td>
simon@4345 1686 <em>Inherited:</em>
simon@4345 1687 </td>
simon@4345 1688 <td>
simon@4345 1689 no
simon@4345 1690 </td>
simon@4345 1691 </tr>
simon@4345 1692 <tr>
simon@4345 1693 <td>
simon@4345 1694 <em>Percentages:</em>
simon@4345 1695 </td>
simon@4345 1696 <td>
simon@4345 1697 N/A
simon@4345 1698 </td>
simon@4345 1699 </tr>
simon@4345 1700 <tr>
simon@4345 1701 <td>
simon@4345 1702 <em>Media:</em>
simon@4345 1703 </td>
simon@4345 1704 <td>
simon@4345 1705 visual
simon@4345 1706 </td>
simon@4345 1707 </tr>
simon@4345 1708 <tr>
simon@4345 1709 <td>
simon@4345 1710 <em>Computed value:</em>
simon@4345 1711 </td>
simon@4345 1712 <td>
simon@4345 1713 Same as specified value.
simon@4345 1714 </td>
simon@4345 1715 </tr>
dbaron@7349 1716 <tr>
dbaron@7349 1717 <td>
dbaron@7349 1718 <em>Animatable:</em>
dbaron@7349 1719 </td>
dbaron@7349 1720 <td>
dbaron@7349 1721 no
dbaron@7349 1722 </td>
dbaron@7349 1723 </tr>
simon@4345 1724 </tbody>
simon@4345 1725 </table>
simon@4367 1726 <p>
dschulze@6300 1727 The visibility of an element with ''backface-visibility: hidden'' is determined
simon@4367 1728 as follows:
simon@4367 1729 <ol>
ayg@5127 1730 <li>
ayg@5127 1731 For an element in a
dschulze@5921 1732 <span class="term">3D rendering context</span>,
ayg@5127 1733 compute its
dschulze@5921 1734 <span class="term">
dschulze@5921 1735 accumulated 3D transformation matrix</span>. For an element
ayg@5127 1736 not in a
dschulze@5921 1737 <span class="term">3D rendering context</span>,
ayg@5127 1738 compute its
dschulze@5921 1739 <span class="term">transformation matrix</span>.
simon@4367 1740 </li>
simon@4367 1741 <li>
ayg@5127 1742 If the component of the matrix in row 3, column 3 is
ayg@5127 1743 negative, then the element should be hidden. Otherwise it
ayg@5127 1744 is visible.
simon@4367 1745 </li>
simon@4367 1746 </ol>
bert@6704 1747
ayg@5081 1748 <p class="note">
ayg@5081 1749 The reasoning for this definition is as follows. Assume
ayg@5081 1750 elements are rectangles in the <var>x</var>&ndash;<var>y</var>
ayg@5081 1751 plane with infinitesimal thickness. The front of the
ayg@5081 1752 untransformed element has coordinates like (<var>x</var>,
ayg@5081 1753 <var>y</var>, <var>&epsilon;</var>), and the back is
ayg@5081 1754 (<var>x</var>, <var>y</var>, &minus;<var>&epsilon;</var>), for
ayg@5081 1755 some very small <var>&epsilon;</var>. We want to know if after
ayg@5081 1756 the transformation, the front of the element is closer to the
ayg@5081 1757 viewer than the back (higher <var>z</var>-value) or further
ayg@5081 1758 away. The <var>z</var>-coordinate of the front will be
ayg@5081 1759 <var>M</var><sub>13</sub><var>x</var> +
ayg@5081 1760 <var>M</var><sub>23</sub><var>y</var> +
ayg@5081 1761 <var>M</var><sub>33</sub><var>&epsilon;</var> +
ayg@5081 1762 <var>M</var><sub>43</sub>, before accounting for perspective,
ayg@5081 1763 and the back will be <var>M</var><sub>13</sub><var>x</var> +
ayg@5081 1764 <var>M</var><sub>23</sub><var>y</var> &minus;
ayg@5081 1765 <var>M</var><sub>33</sub><var>&epsilon;</var> +
ayg@5081 1766 <var>M</var><sub>43</sub>. The first quantity is greater than
ayg@5081 1767 the second if and only if <var>M</var><sub>33</sub> > 0. (If
ayg@5081 1768 it equals zero, the front and back are equally close to the
ayg@5081 1769 viewer. This probably means something like a 90-degree
ayg@5081 1770 rotation, which makes the element invisible anyway, so we don't
ayg@5081 1771 really care whether it vanishes.)
ayg@5081 1772 </p>
dschulze@5642 1773
dschulze@5642 1774 <!-- ======================================================================================================= -->
dschulze@5642 1775
dschulze@5642 1776 <h2 id="svg-transform">
dschulze@5751 1777 The SVG 'transform' Attribute
dschulze@5642 1778 </h2>
dschulze@5642 1779
dschulze@5642 1780 <p>
dschulze@5751 1781 The <a href="http://www.w3.org/TR/2011/REC-SVG11-20110816/">SVG 1.1
dschulze@5751 1782 specification</a> did not specify the attributes 'transform', 'gradientTransform'
dschulze@5751 1783 or 'patternTransform' as <a
dschulze@5751 1784 href="http://www.w3.org/TR/2011/REC-SVG11-20110816/styling.html#UsingPresentationAttributes"><em>presentation
dschulze@5751 1785 attributes</em></a>. In order to improve the integration of SVG and HTML, this
dschulze@5751 1786 specification makes these SVG attributes 'presentation attributes' and makes the
dschulze@5751 1787 'transform' property one that applies to <span class="term">transformable
dschulze@5895 1788 elements</span> in the SVG namespace.
dschulze@5642 1789 </p>
dschulze@5642 1790
dschulze@5642 1791 <p>
dschulze@5751 1792 This specification will also introduce the new presentation attributes
dschulze@5751 1793 'transform-origin', 'perspective', 'perspective-origin', 'transform-style' and
dschulze@5751 1794 'backface-visibility'.
dschulze@5642 1795 </p>
dschulze@5642 1796
dschulze@5642 1797 <p>
dschulze@5751 1798 Values on new introduced presentation attributes get parsed following the syntax
dschulze@5923 1799 rules on <a href="#svg-data-types">SVG Data Types</a> [[SVG11]].
dschulze@5642 1800 </p>
dschulze@5642 1801
dschulze@5751 1802 <h3 id="transform-attribute-specificity">
dschulze@5751 1803 SVG 'transform' attribute specificity
dschulze@5751 1804 </h3>
dschulze@5642 1805
dschulze@5751 1806 <p>
dschulze@5751 1807 Since the previously named SVG attributes become presentation attributes, their
dschulze@5751 1808 participation in the CSS cascade is determined by the specificity of presentation
dschulze@5751 1809 attributes, as <a
dschulze@5751 1810 href="http://www.w3.org/TR/2011/REC-SVG11-20110816/styling.html#UsingPresentationAttributes">explained</a>
dschulze@5751 1811 in the SVG specification.
dschulze@5642 1812 </p>
dschulze@5642 1813
dschulze@5642 1814 <div class="example">
dschulze@5642 1815 <p>
dschulze@5751 1816 This example shows the combination of the 'transform' style property and the
dschulze@5751 1817 'transform' presentation attribute.
dschulze@5642 1818 </p>
dschulze@5642 1819
dschulze@5642 1820 <pre>&lt;svg xmlns="http://www.w3.org/2000/svg"&gt;
dschulze@5642 1821 &lt;style&gt;
dschulze@5642 1822 .container {
dschulze@5642 1823 transform: translate(100px, 100px);
dschulze@5642 1824 }
dschulze@5642 1825 &lt;/style&gt;
dschulze@5642 1826
dschulze@5642 1827 &lt;g class="container" transform="translate(200 200)"&gt;
dschulze@5642 1828 &lt;rect width="100" height="100" fill="blue" /&gt;
dschulze@5642 1829 &lt;/g&gt;
dschulze@5642 1830 &lt;/svg&gt;</pre>
dschulze@5642 1831
dschulze@5642 1832 <div class="figure">
dschulze@5751 1833 <img src="examples/svg-translate1.svg" width="470" height="240"
dschulze@5751 1834 alt="Translated SVG container element.">
dschulze@5642 1835 </div>
dschulze@5642 1836
dschulze@5642 1837 <p>
dschulze@5751 1838 Because of the participation to the CSS cascade, the 'transform' style property
dschulze@5751 1839 overrides the 'transform' presentation attribute. Therefore the container gets
dschulze@5751 1840 translated by ''100px'' in both the horizontal and the vertical directions,
dschulze@5751 1841 instead of ''200px''.
dschulze@5642 1842 </p>
dschulze@5642 1843 </div>
dschulze@5642 1844
dschulze@5751 1845 <h3 id="svg-syntax">
dschulze@5751 1846 Syntax of the SVG 'transform' attribute
dschulze@5751 1847 </h3>
dschulze@5642 1848
dschulze@5642 1849 <p>
dschulze@5751 1850 To provide backwards compatibility, the syntax of the 'transform' presentation
dschulze@5751 1851 attribute differs from the syntax of the 'transform' style property as shown in the
dschulze@5751 1852 example above. However, the syntax used for the 'transform' style property can be
dschulze@5751 1853 used for a 'transform' presentation attribute value. Authors are advised to follow
dschulze@5751 1854 the rules of <a href="http://www.w3.org/TR/css3-values/#functional-notation">CSS
dschulze@5751 1855 Values and Units Module</a>. Therefore an author should write
dschulze@5751 1856 ''transform="translate(200px, 200px)"'' instead of
dschulze@5751 1857 ''transform="translate (200 200)"'' because the second example with the spaces
dschulze@5751 1858 before the ''('', the missing comma between the arguments and the values without the
dschulze@5751 1859 explicit unit notation would be valid for the attribute only.
dschulze@5642 1860 </p>
dschulze@5642 1861
dschulze@5751 1862 <h4 id="svg-transform-list">
dschulze@5751 1863 Transform List
dschulze@5751 1864 </h4>
dschulze@5642 1865
dschulze@5642 1866 <p>
dschulze@5751 1867 The value for the 'transform' attribute consists of a transform list with zero or
dschulze@5751 1868 more transform functions using <a href="#svg-functional-notation">functional
dschulze@5751 1869 notation</a>. If the transform list consists of more than one transform function,
dschulze@5751 1870 these functions are separated by optional whitespace, an optional comma ('','')
dschulze@5751 1871 and optional whitespace. The transform list can have optional whitespace characters
dschulze@5751 1872 before and after the list.
dschulze@5642 1873 </p>
dschulze@5642 1874
dschulze@5751 1875 <h4 id="svg-functional-notation">
dschulze@5751 1876 Functional Notation
dschulze@5751 1877 </h4>
dschulze@5642 1878
dschulze@5642 1879 <p>
dschulze@5751 1880 The syntax starts with the name of the function followed by optional whitespace
dschulze@5751 1881 characters followed by a left parenthesis followed by optional whitespace followed
dschulze@5751 1882 by the argument(s) to the notation followed by optional whitespace followed by a
dschulze@5751 1883 right parenthesis. If a function takes more than one argument, the arguments are
dschulze@5751 1884 either separated by a comma ('','') with optional whitespace characters before and
dschulze@5751 1885 after the comma, or by one or more whitespace characters.
dschulze@5642 1886 </p>
dschulze@5642 1887
dschulze@5751 1888 <h4 id="svg-data-types">
dschulze@5751 1889 SVG Data Types
dschulze@5751 1890 </h4>
dschulze@5642 1891
dschulze@5642 1892 <p>
dschulze@5751 1893 Arguments on all new introduced presentation attributes consist of data types in the
dschulze@5751 1894 sense of <a href="http://www.w3.org/TR/css3-values/#functional-notation">CSS Values
dschulze@5751 1895 and Units Module</a>. The definitions of data types in CSS Values and Units Module
dschulze@5751 1896 are enhanced as follows:
dschulze@5642 1897 </p>
dschulze@5642 1898
dschulze@5751 1899 <h5 id="svg-transform-value">
dschulze@5751 1900 The <var>&lt;translation-value&gt;</var> and <var>&lt;length&gt;</var> type
dschulze@5751 1901 </h5>
dschulze@5642 1902
dschulze@5642 1903 <p>
dschulze@5751 1904 A translation-value or length can be a <var>&lt;number&gt;</var> without an unit
dschulze@5751 1905 identifier. In this case the <a href="#svg-number"><var>number</var></a> gets
dschulze@5751 1906 interpreted as "user unit". A user unit in the the <a
dschulze@5751 1907 href="http://www.w3.org/TR/2003/REC-SVG11-20030114/coords.html#InitialCoordinateSystem">initial
dschulze@5751 1908 coordinate system</a> is equivalent to the parent environment's notion of a pixel
dschulze@5751 1909 unit.
dschulze@5642 1910 </p>
dschulze@5642 1911
dschulze@5751 1912 <h5 id="svg-angle">
dschulze@5751 1913 The <var>&lt;angle&gt;</var> type
dschulze@5751 1914 </h5>
dschulze@5642 1915
dschulze@5642 1916 <p>
dschulze@5751 1917 An angle can be a <var>&lt;number&gt;</var> without an unit identifier. In this case
dschulze@5751 1918 the <a href="#svg-number"><i>number</i></a> gets interpreted as a value in degrees.
dschulze@5642 1919 </p>
dschulze@5642 1920
dschulze@5751 1921 <h5 id="svg-number">
dschulze@5751 1922 The <var>&lt;number&gt;</var> type
dschulze@5751 1923 </h5>
dschulze@5642 1924
dschulze@5642 1925 <p>
dschulze@5751 1926 SVG supports scientific notations for numbers. Therefore a <var>number</var> gets
dschulze@5751 1927 parsed like described in SVG <a
dschulze@5751 1928 href="http://www.w3.org/TR/SVG/types.html#DataTypeNumber">Basic data types</a> for
dschulze@5751 1929 SVG attributes.
dschulze@5642 1930 </p>
dschulze@5642 1931
dschulze@5751 1932 <h3 id="svg-gradient-transform-pattern-transform">
dschulze@5751 1933 The SVG 'gradientTransform' and 'patternTransform' attributes
dschulze@5751 1934 </h3>
dschulze@5642 1935
dschulze@5642 1936 <p>
dschulze@5751 1937 SVG specifies the attributes 'gradientTransform' and 'patternTransform'. This
dschulze@5751 1938 specification makes both attributes presentation attributes. Both attributes use the
dschulze@5751 1939 same <a href="#svg-syntax">syntax</a> as the SVG 'transform' attribute. This
dschulze@5751 1940 specification does not introduce corresponding CSS style properties. Both, the
dschulze@5751 1941 'gradientTransform' and the 'patternTransform' attribute, are presentation
dschulze@5751 1942 attributes for the 'transform' property.
dschulze@5642 1943 </p>
dschulze@5642 1944
dschulze@5658 1945 <h3 id="svg-transform-functions">
dschulze@5658 1946 SVG transform functions
dschulze@5658 1947 </h3>
dschulze@5642 1948
dschulze@5642 1949 <p>
dschulze@5658 1950 For backwards compatibility with existing SVG content, this specification supports
dschulze@5658 1951 all transform functions defined by <a
dschulze@6300 1952 href="http://www.w3.org/TR/SVG/coords.html#TransformAttribute">The 'transform'
dschulze@6300 1953 attribute</a> in [[SVG11]]. Therefore the two-dimensional transform function
dschulze@6300 1954 ''rotate(&lt;angle&gt;)'' is extended as follows:
dschulze@5642 1955 </p>
dschulze@5642 1956
dschulze@5642 1957 <dl>
dschulze@5743 1958 <dt id="rotate-three-function">
dschulze@5658 1959 <code class="css">rotate(&lt;angle&gt;[, &lt;translation-value&gt;,
dschulze@5658 1960 &lt;translation-value&gt;])</code>
dschulze@5642 1961 </dt>
dschulze@5642 1962 <dd>
dschulze@5658 1963 specifies a <a href="#RotateDefined">2D rotation</a> by the angle specified in the
dschulze@5658 1964 parameter about the origin of the element, as defined by the 'transform-origin'
dschulze@5658 1965 property. If the optional translation values are specified, the transform origin
dschulze@5658 1966 is translated by that amount (using the current transformation matrix) for the
dschulze@5921 1967 duration of the rotate operation. For example ''rotate(90deg, 100px, 100px)''
dschulze@5921 1968 would cause elements to appear rotated one-quarter of a turn in the clockwise
dschulze@6299 1969 direction after a translation of the transform-origin of 100 pixel in the
dschulze@6299 1970 horizontal and vertical directions.
dschulze@5642 1971 </dd>
dschulze@5642 1972 </dl>
dschulze@5642 1973
dschulze@5642 1974 <p>
dschulze@5658 1975 User agents are just required to support the two optional arguments for translation
dschulze@5658 1976 on elements in the SVG namespace.
dschulze@5642 1977 </p>
dschulze@5642 1978
dschulze@5642 1979 <h3 id="svg-three-dimensional-functions">SVG and 3D transform functions</h3>
dschulze@5642 1980
dschulze@5642 1981 <p>
dschulze@5751 1982 This specification explicitly requires three-dimensional transform functions to
dschulze@5751 1983 apply to the <a
dschulze@5751 1984 href="http://www.w3.org/TR/SVG/intro.html#TermContainerElement"><em>container
dschulze@5751 1985 elements</em></a>: 'a', 'g', 'svg', all <a
dschulze@5751 1986 href="http://www.w3.org/TR/SVG/intro.html#TermGraphicsElement"><em>graphics
dschulze@5751 1987 elements</em></a>, all <a
dschulze@5751 1988 href="http://www.w3.org/TR/SVG/intro.html#TermGraphicsReferencingElement"><em>graphics
dschulze@5751 1989 referencing elements</em></a> and the SVG '<a
dschulze@5751 1990 href="http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement">foreignObject</a>'
dschulze@5751 1991 element.
dschulze@5642 1992 </p>
dschulze@5642 1993
dschulze@5642 1994 <p>
dschulze@5751 1995 Three-dimensional transform functions and the properties 'perspective',
dschulze@5751 1996 'perspective-origin', 'transform-style' and 'backface-visibility' can not be used
dschulze@6897 1997 for the elements: 'clipPath', 'linearGradient', 'radialGradient' and
dschulze@5751 1998 'pattern'. If a transform list includes a three-dimensional transform function, the
dschulze@5751 1999 complete transform list must be ignored. The values of every previously named
dschulze@5751 2000 property must be ignored. <span class="term">Transformable elements</span> that are
dschulze@5751 2001 contained by one of these elements can have three-dimensional transform functions.
dschulze@5751 2002 Before a 'clipPath', 'mask' or 'pattern' element can get applied to a target
dschulze@5751 2003 element, user agents must take the drawn results as static images in analogue of
dschulze@5751 2004 "flattening" the elements and taking the rendered content as a two-dimensional
dschulze@5751 2005 canvas.
dschulze@5642 2006 </p>
dschulze@5909 2007
dschulze@5909 2008 <p>
dschulze@5909 2009 If the 'vector-effect' property is set to ''non-scaling-stroke'' and an object is
dschulze@5921 2010 within a <span class="term">3D rendering context</span>
dschulze@5909 2011 the property has no affect on stroking the object.
dschulze@5909 2012 </p>
dschulze@5642 2013
dschulze@5751 2014 <h3 id="svg-user-coordinate-space">
dschulze@5751 2015 User coordinate space
dschulze@5751 2016 </h3>
dschulze@6286 2017
dschulze@5642 2018 <p>
dschulze@6897 2019 For the 'pattern', 'linearGradient', 'radialGradient' and 'clipPath'
dschulze@6286 2020 elements the 'transform', 'patternTransform', 'gradientTransform' presentation
dschulze@6286 2021 attributes represents values in the current user coordinate system in place at the
dschulze@6286 2022 time when these elements are referenced (i.e., the user coordinate system for the
dschulze@6286 2023 element referencing the 'pattern' element via a 'fill' or 'stroke' property).
dschulze@6929 2024 Percentage values are relative to the <span>bounding box</span> of the
dschulze@6929 2025 referencing element.
dschulze@5642 2026 </p>
dschulze@5642 2027
dschulze@5642 2028 <p>
dschulze@6286 2029 In particualar the 'patternUnit', 'gradientUnit' and 'maskUnit' attributes
dschulze@6286 2030 don't affect the user coordinate system used for transformations [[SVG11]].
dschulze@5751 2031 </p>
dschulze@6286 2032
dschulze@5751 2033 <p>
dschulze@5921 2034 For all other <span class="term">transformable elements</span> the
dschulze@5751 2035 'transform' presentation attribute represents values in the current user coordinate
dschulze@5751 2036 system of the parent. All percentage values of the 'transform' presentation
dschulze@7030 2037 attribute are relative to the element's <var>bounding box</var>.
dschulze@5642 2038 </p>
dschulze@5642 2039
dschulze@5642 2040 <div class="example">
dschulze@5642 2041 <p>
dschulze@5751 2042 The 'transform-origin' property on the pattern in the following example specifies
dschulze@5751 2043 a ''50%'' translation of the origin in the horizontal and vertical dimension. The
dschulze@5751 2044 'transform' property specifies a translation as well, but in absolute lengths.
dschulze@5642 2045 </p>
dschulze@5642 2046
dschulze@5642 2047 <pre>&lt;svg xmlns="http://www.w3.org/2000/svg"&gt;
dschulze@5642 2048 &lt;style&gt;
dschulze@5642 2049 pattern {
dschulze@5751 2050 transform: rotate(45deg);
dschulze@5642 2051 transform-origin: 50% 50%;
dschulze@5642 2052 }
dschulze@5642 2053 &lt;/style&gt;
dschulze@5642 2054
dschulze@5642 2055 &lt;defs&gt;
dschulze@5642 2056 &lt;pattern id="pattern-1"&gt;
dschulze@5642 2057 &lt;rect id="rect1" width="100" height="100" fill="blue" /&gt;
dschulze@5642 2058 &lt;/pattern&gt;
dschulze@5642 2059 &lt;/defs&gt;
dschulze@5642 2060
dschulze@6929 2061 &lt;rect width="200" height="200" fill="url(#pattern-1)" /&gt;
dschulze@5642 2062 &lt;/svg&gt;</pre>
dschulze@5642 2063
dschulze@5642 2064 <p>
dschulze@7030 2065 An SVG 'pattern' element doesn't have a bounding box. The <var>bounding box</var>
dschulze@7030 2066 of the referencing 'rect' element is used
dschulze@5921 2067 instead to solve the relative values of the 'transform-origin' property. Therefore
dschulze@6929 2068 the point of origin will get translated by 100 pixels temporarily to rotate the
dschulze@5921 2069 user space of the 'pattern' elements content.
dschulze@5642 2070 </p>
dschulze@5642 2071 </div>
dschulze@5642 2072
dschulze@5751 2073 <h3 id="transform-attribute-dom">
dschulze@5751 2074 SVG DOM interface for the 'transform' attribute
dschulze@5751 2075 </h3>
dschulze@5642 2076
dschulze@5642 2077 <p>
dschulze@5751 2078 The SVG specification defines the '<a
dschulze@5751 2079 href="http://www.w3.org/TR/2011/REC-SVG11-20110816/coords.html#InterfaceSVGAnimatedTransformList">SVGAnimatedTransformList</a>'
dschulze@5751 2080 interface in the SVG DOM to provide access to the animated and the base value of the
dschulze@5751 2081 SVG 'transform', 'gradientTransform' and 'patternTransform' attributes. To ensure
dschulze@5751 2082 backwards compatibility, this API must still be supported by user agents.
dschulze@5642 2083 </p>
dschulze@5642 2084
dschulze@5642 2085 <p>
dschulze@5751 2086 The 'transform' property contributes to the CSS cascade. According to SVG 1.1 user
dschulze@5751 2087 agents conceptually insert a <a
dschulze@5751 2088 href="http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes">new author
dschulze@5751 2089 style sheet</a> for presentation attributes, which is the first in the author style
dschulze@5751 2090 sheet collection. 'baseVal' gives the author the possibility to access and modify
dschulze@5751 2091 the values of the SVG 'transform' attribute. To provide the necessary backwards
dschulze@5751 2092 compatibility to the SVG DOM, 'baseVal' must reflect the values of this author style
dschulze@5751 2093 sheet. All modifications to SVG DOM objects of 'baseVal' must affect this author
dschulze@5751 2094 style sheet immediately.
dschulze@5642 2095 </p>
dschulze@5642 2096
dschulze@5642 2097 <p>
dschulze@5751 2098 'animVal' represents the computed style of the 'transform' property. Therefore it
dschulze@5751 2099 includes all applied <a
dschulze@5751 2100 href="http://www.w3.org/TR/css3-transitions/">CSS3 Transitions</a>, <a
dschulze@5751 2101 href="http://www.w3.org/TR/css3-animations/">CSS3 Animations</a> or <a
dschulze@5751 2102 href="#svg-animation">SVG Animations</a> if any of those are underway. The computed
dschulze@5751 2103 style and SVG DOM objects of 'animVal' can not be modified.
dschulze@5642 2104 </p>
dschulze@5642 2105
dschulze@5642 2106 <p>
dschulze@5751 2107 The attribute '<a
dschulze@5751 2108 href="http://www.w3.org/TR/SVG/coords.html#__svg__SVGTransform__type">type</a>' of
dschulze@5751 2109 '<a
dschulze@5751 2110 href="http://www.w3.org/TR/SVG/coords.html#InterfaceSVGTransform">SVGTransform</a>'
dschulze@5751 2111 must return '<a
dschulze@5921 2112 href="http://www.w3.org/TR/SVG/coords.html#__svg__SVGTransform__SVG_TRANSFORM_UNKNOWN">SVG_TRANSFORM_UNKNOWN</a>'
dschulze@5921 2113 for <a href="#transform-functions">Transform Functions</a>
dschulze@5751 2114 or unit types that are not supported by this interface. If a two-dimensional
dschulze@5751 2115 transform function is not supported, the attribute '<a
dschulze@5751 2116 href="http://www.w3.org/TR/SVG/coords.html#__svg__SVGTransform__matrix">matrix</a>'
dschulze@5751 2117 must return a 3x2 '<a
dschulze@5751 2118 href="http://www.w3.org/TR/SVG/coords.html#InterfaceSVGMatrix">SVGMatrix</a>' with
dschulze@5751 2119 the corresponding values as described in the section <a
dschulze@5751 2120 href="#mathematical-description">Mathematical Description of Transform Functions</a>.
dschulze@5642 2121 </p>
dschulze@5642 2122
dschulze@5895 2123 <h2 id="svg-animation">
dschulze@5751 2124 SVG Animation
dschulze@5895 2125 </h2>
dschulze@5895 2126
dschulze@5895 2127 <h3 id="svg-animate-element">
dschulze@5921 2128 The 'animate' and 'set' element
dschulze@5751 2129 </h3>
dschulze@5895 2130
dschulze@5921 2131 <p>
dschulze@5921 2132 With this specification, the 'animate' element and the 'set' element can animate
dschulze@5921 2133 the data type <var>&lt;transform-list&gt;</var>.
dschulze@5921 2134 </p>
dschulze@5921 2135
dschulze@5921 2136 <p>
dschulze@5921 2137 The animation effect is post-multiplied to the underlying
dschulze@5921 2138 value for additive 'animate' animations (see below) instead of added to the
dschulze@5921 2139 underlying value, due to the specific behavior of <var>&lt;transform-list&gt;</var>
dschulze@5921 2140 animations.
dschulze@5921 2141 </p>
dschulze@5921 2142
dschulze@5921 2143 <p>
dschulze@5921 2144 <var>From-to</var>, <var>from-by</var> and <var>by</var> animations are defined in
dschulze@5921 2145 SMIL to be equivalent to a corresponding <var>values</var> animation. However,
dschulze@5921 2146 <var>to</var> animations are a mixture of additive and non-additive behavior
dschulze@5921 2147 [[SMIL3]].
dschulze@5921 2148 </p>
dschulze@5921 2149
dschulze@5921 2150 <p>
dschulze@5921 2151 <var>To</var> animations on 'animate' provide specific functionality to get a smooth
dschulze@5921 2152 change from the underlying value to the 'to' attribute value, which conflicts
dschulze@5921 2153 mathematically with the requirement for additive transform animations to be
dschulze@5921 2154 post-multiplied. As a consequence, the behavior of <var>to</var> animations for
dschulze@5921 2155 'animate' is undefined. Authors are suggested to use <var>from-to</var>,
dschulze@5921 2156 <var>from-by</var>, <var>by</var> or <var>values</var> animations to achieve any
dschulze@5921 2157 desired transform animation.
dschulze@5921 2158 </p>
dschulze@5921 2159
dschulze@5921 2160 <p>
dschulze@5921 2161 The value 'paced' is undefined for the attribute 'calcMode' on 'animate' for animations of the
dschulze@5921 2162 data type <var>&lt;transform-list&gt;</var>. If specified,
dschulze@5921 2163 UAs may choose the value 'linear' instead. Future versions of this specification
dschulze@5921 2164 may define how paced animations can be performed on
dschulze@5921 2165 <var>&lt;transform-list&gt;</var>.
dschulze@5921 2166 </p>
dschulze@5921 2167
dschulze@5921 2168 <p class="note">The following paragraphs extend <a
dschulze@5895 2169 href="http://www.w3.org/TR/SVG/animate.html#complexDistances">Elements, attributes
dschulze@5895 2170 and properties that can be animated</a> [[SVG11]].
dschulze@5895 2171 </p>
dschulze@5895 2172
dschulze@5895 2173 <p>
dschulze@5895 2174 The introduce presentation attributes 'transform', 'transform-origin', 'perspective',
dschulze@5895 2175 'perspective-origin', 'transform-style' and 'backface-visibility' are animatable.
dschulze@5895 2176 'transform-style' and 'backface-visibility' are non-additive.
dschulze@5895 2177 </p>
dschulze@5642 2178
dschulze@5642 2179 <p>
dschulze@5895 2180 With this specification the SVG basic data type <var>&lt;transform-list&gt;</var> is
dschulze@5895 2181 equivalent to a list of <var>&lt;transform-function&gt;</var>s.
dschulze@5895 2182 <var>&lt;transform-list&gt;</var> is animatable and additive. The data type can be
dschulze@5895 2183 animated using the SVG '<a
dschulze@5895 2184 href="http://www.w3.org/TR/SVG/animate.html#AnimateElement">animate</a>' element and
dschulze@5751 2185 the SVG '<a href="http://www.w3.org/TR/SVG/animate.html#SetElement">set</a>'
dschulze@5895 2186 element. SVG animations must run the same animation steps as described in section <a
dschulze@5895 2187 href="#animation">Transitions and Animations between Transform Values</a>.
dschulze@5895 2188 </p>
dschulze@5895 2189
dschulze@5895 2190 <p>
dschulze@5895 2191 The set of animatable data types gets extended by <em>&lt;translation-value&gt;</em>.
dschulze@5895 2192 The new data type is animatable and additive.
dschulze@5642 2193 </p>
dschulze@5642 2194
dschulze@5895 2195 <table class="data">
dschulze@5895 2196 <caption>Animatable data types</caption>
dschulze@5895 2197 <thead>
dschulze@5895 2198 <tr>
dschulze@5895 2199 <th>Data type</th>
dschulze@5895 2200 <th>Additive?</th>
dschulze@5895 2201 <th>'animate'</th>
dschulze@5895 2202 <th>'set'</th>
dschulze@5895 2203 <th>'animateColor'</th>
dschulze@5895 2204 <th>'animateTransform'</th>
dschulze@5895 2205 <th>Notes</th>
dschulze@5895 2206 </tr>
dschulze@5895 2207 </thead>
dschulze@5895 2208 <tbody>
dschulze@5895 2209 <tr>
dschulze@5902 2210 <th><var>&lt;transform-list&gt;</var></th>
dschulze@5895 2211 <td>yes</td>
dschulze@5895 2212 <td>yes</td>
dschulze@5895 2213 <td>yes</td>
dschulze@5895 2214 <td>no</td>
dschulze@5895 2215 <td>yes</td>
dschulze@5902 2216 <td>Additive for 'animateTransform' means that a transformation is post-multiplied to the base set of
dschulze@5900 2217 transformations.</td>
dschulze@5895 2218 </tr>
dschulze@5895 2219 <tr>
dschulze@5902 2220 <th><var>&lt;translation-value&gt;</var></th>
dschulze@5895 2221 <td>yes</td>
dschulze@5895 2222 <td>yes</td>
dschulze@5895 2223 <td>yes</td>
dschulze@5895 2224 <td>no</td>
dschulze@5895 2225 <td>no</td>
dschulze@5895 2226 <td>&nbsp;</td>
dschulze@5895 2227 </tr>
dschulze@5895 2228 </tbody>
dschulze@5895 2229 </table>
dschulze@5900 2230
dschulze@5900 2231 <h3 id="neutral-element">
dschulze@5900 2232 Neutral element for addition
dschulze@5900 2233 </h3>
dschulze@5900 2234
dschulze@5900 2235 <p>
dschulze@5921 2236 Some animations require a neutral element for addition. For transform functions
dschulze@5921 2237 this is a scalar or a list of scalars of 0. Examples of neutral elements for
dschulze@5921 2238 transform functions are ''translate(0)'', ''translate3d(0, 0, 0)'',
dschulze@5921 2239 ''translateX(0)'', ''translateY(0)'', ''translateZ(0)'', ''scale(0)'',
dschulze@5921 2240 ''scaleX(0)'', ''scaleY(0)'', ''scaleZ(0)'', ''rotate(0)'',
dschulze@5921 2241 ''rotate3d(v<sub>x</sub>, v<sub>y</sub>, v<sub>z</sub>, 0)'' (where <var>v</var> is
dschulze@5921 2242 a context dependent vector), ''rotateX(0)'', ''rotateY(0)'', ''rotateZ(0)'',
dschulze@6902 2243 ''skew(0, 0)'', ''skewX(0)'', ''skewY(0)'', ''matrix(0, 0, 0, 0, 0, 0)'', ''matrix3d(0, 0, 0, 0, 0,
dschulze@5921 2244 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)'' and ''perspective(0)''.
dschulze@5921 2245 </p>
dschulze@5921 2246
dschulze@5921 2247 <p class="note">
dschulze@5923 2248 Animations to or from the neutral element of additions ''matrix'', ''matrix3d'' and
dschulze@5923 2249 ''perspective'' fall back to discrete animations (See <a
dschulze@5923 2250 href="#matrix-interpolation">Interpolation of Matrices</a>).
dschulze@5900 2251 </p>
dschulze@5900 2252
dschulze@5900 2253 <div class="example">
dschulze@5900 2254 <p>
dschulze@5900 2255 A <var>by</var> animation with a by value v<sub>b</sub> is equivalent to the same
dschulze@5900 2256 animation with a values list with 2 values, the neutral element for addition for
dschulze@5900 2257 the domain of the target attribute (denoted 0) and v<sub>b</sub>, and
dschulze@5921 2258 ''additive="sum"''. [[SMIL3]]
dschulze@5900 2259 </p>
dschulze@5900 2260
dschulze@5900 2261 <pre>
dschulze@5900 2262 &lt;rect width="100" height="100"&gt;
dschulze@5900 2263 &lt;animateTransform attributeName="transform" attributeType="XML"
dschulze@5900 2264 type="scale" by="1" dur="5s" fill="freeze"/&gt;
dschulze@5900 2265 &lt;/rect&gt;</pre>
dschulze@5900 2266
dschulze@5900 2267 <p>
dschulze@5900 2268 The neutral element for addition when performing a <var>by</var> animation with
dschulze@5900 2269 ''type="scale"'' is the value 0. Thus, performing the animation of the example
dschulze@5900 2270 above causes the rectangle to be invisible at time 0s (since the animated
dschulze@5900 2271 transform list value is ''scale(0)''), and be scaled back to its original size at
dschulze@5900 2272 time 5s (since the animated transform list value is ''scale(1)'').
dschulze@5900 2273 </p>
dschulze@5900 2274
dschulze@5900 2275 </div>
dschulze@5895 2276
dschulze@5895 2277 <h3 id="svg-attribute-name">
dschulze@5751 2278 The SVG 'attributeName' attribute
dschulze@5895 2279 </h3>
dschulze@5642 2280
dschulze@5642 2281 <p>
dschulze@5751 2282 <a href="http://www.w3.org/TR/SVG/animate.html">SVG 1.1 Animation</a> defines the
dschulze@5751 2283 '<a href="http://www.w3.org/TR/SVG/animate.html#TargetAttributes">attributeName</a>'
dschulze@5751 2284 attribute to specify the name of the target attribute. For the presentation
dschulze@5751 2285 attributes 'gradientTransform' and 'patternTransform' it will also be possible to
dschulze@5751 2286 use the value 'transform'. The same 'transform' property will get animated.
dschulze@5642 2287 </p>
dschulze@5642 2288
dschulze@5642 2289 <div class="example">
dschulze@5642 2290 <p>
dschulze@5642 2291 In this example the gradient transformation of the linear gradient gets animated.
dschulze@5642 2292 </p>
dschulze@5642 2293
dschulze@5642 2294 <pre>&lt;linearGradient gradientTransform="scale(2)"&gt;
dschulze@5642 2295 &lt;animate attributeName="gradientTransform" from="scale(2)" to="scale(4)"
dschulze@5642 2296 dur="3s" additive="sum"/&gt;
dschulze@5642 2297 &lt;animate attributeName="transform" from="translate(0, 0)" to="translate(100px, 100px)"
dschulze@5642 2298 dur="3s" additive="sum"/&gt;
dschulze@5642 2299 &lt;/linearGradient&gt;</pre>
dschulze@5642 2300
dschulze@5751 2301 <p>The 'linearGradient' element specifies the 'gradientTransform' presentation
dschulze@5751 2302 attribute. The two 'animate' elements address the target attribute
dschulze@5751 2303 'gradientTransform' and 'transform'. Even so all animations apply to the same
dschulze@5751 2304 gradient transformation by taking the value of the 'gradientTransform'
dschulze@5751 2305 presentation attribute, applying the scaling of the first animation and applying
dschulze@5751 2306 the translation of the second animation one after the other.
dschulze@5751 2307 </p>
dschulze@5642 2308 </div>
dschulze@5642 2309
vhardy@3672 2310 <!-- ======================================================================================================= -->
vhardy@3672 2311
vhardy@3672 2312 <h2 id="transform-functions">
dschulze@5114 2313 The Transform Functions
vhardy@3672 2314 </h2>
vhardy@3672 2315 <p>
dschulze@5743 2316 The value of the 'transform' property is a list of
dschulze@5743 2317 <var>&lt;transform-functions&gt;</var>. The set of allowed transform functions is
dschulze@5743 2318 given below. For <var>&lt;transform-functions&gt;</var> the type
dschulze@5743 2319 <var>&lt;translation-value&gt;</var> is defined as a <var>&lt;length&gt;</var> or
dschulze@5743 2320 <var>&lt;percentage&gt;</var> value, and the <var>&lt;angle&gt;</var> type is
dschulze@5743 2321 defined by <a
dschulze@5743 2322 href="http://www.w3.org/TR/css3-values/">CSS Values and Units Module.</a> Wherever
dschulze@5743 2323 <var>&lt;angle&gt;</var> is used in this specification, a <var>&lt;number&gt;</var>
dschulze@5743 2324 that is equal to zero is also allowed, which is treated the same as an angle of zero
dschulze@5743 2325 degrees.
vhardy@3672 2326 </p>
simon@4358 2327
dschulze@5114 2328 <h3 id="two-d-transform-functions">2D Transform Functions</h3>
vhardy@3672 2329 <dl>
dschulze@5743 2330 <dt id="matrix-function">
simon@4365 2331 <code class="css">matrix(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;)</code>
vhardy@3672 2332 </dt>
vhardy@3672 2333 <dd>
dschulze@4491 2334 specifies a 2D transformation in the form of a <a href="#MatrixDefined">transformation matrix</a> of the six values a-f.
vhardy@3672 2335 </dd>
dschulze@5743 2336 <dt id="translate-function">
simon@4365 2337 <code class="css">translate(&lt;translation-value&gt;[, &lt;translation-value&gt;])</code>
vhardy@3672 2338 </dt>
vhardy@3672 2339 <dd>
dschulze@4491 2340 specifies a <a href="#TranslateDefined">2D translation</a> by the vector [tx, ty], where tx is the first translation-value parameter and ty is the optional second translation-value parameter. If <em>&lt;ty&gt;</em> is not provided, ty has zero as a value.
vhardy@3672 2341 </dd>
dschulze@5743 2342 <dt id="translateX-function">
simon@4365 2343 <code class="css">translateX(&lt;translation-value&gt;)</code>
vhardy@3672 2344 </dt>
vhardy@3672 2345 <dd>
dschulze@4491 2346 specifies a <a href="#TranslateDefined">translation</a> by the given amount in the X direction.
vhardy@3672 2347 </dd>
dschulze@5743 2348 <dt id="translateY-function">
simon@4365 2349 <code class="css">translateY(&lt;translation-value&gt;)</code>
vhardy@3672 2350 </dt>
vhardy@3672 2351 <dd>
dschulze@4491 2352 specifies a <a href="#TranslateDefined">translation</a> by the given amount in the Y direction.
vhardy@3672 2353 </dd>
dschulze@5743 2354 <dt id="scale-function">
simon@4365 2355 <code class="css">scale(&lt;number&gt;[, &lt;number&gt;])</code>
vhardy@3672 2356 </dt>
vhardy@3672 2357 <dd>
dschulze@6607 2358 specifies a <a href="#ScaleDefined">2D scale</a> operation by the [sx,sy] scaling vector described by the 2 parameters. If the second parameter is not provided, it takes a value equal to the first. For example, scale(1, 1) would leave an element unchanged, while scale(2, 2) would cause it to appear twice as long in both the X
vhardy@3672 2359 and Y axes, or four times its typical geometric size.
vhardy@3672 2360 </dd>
dschulze@5743 2361 <dt id="scaleX-function">
simon@4365 2362 <code class="css">scaleX(&lt;number&gt;)</code>
vhardy@3672 2363 </dt>
vhardy@3672 2364 <dd>
dschulze@4491 2365 specifies a <a href="#ScaleDefined">2D scale</a> operation using the [sx,1] scaling vector, where sx is given as the parameter.
vhardy@3672 2366 </dd>
dschulze@5743 2367 <dt id="scaleY-function">
simon@4365 2368 <code class="css">scaleY(&lt;number&gt;)</code>
vhardy@3672 2369 </dt>
vhardy@3672 2370 <dd>
dschulze@4491 2371 specifies a <a href="#ScaleDefined">2D scale</a> operation using the [1,sy] scaling vector, where sy is given as the parameter.
vhardy@3672 2372 </dd>
dschulze@5743 2373 <dt id="rotate-function">
dschulze@4598 2374 <code class="css">rotate(&lt;angle&gt;)</code>
vhardy@3672 2375 </dt>
vhardy@3672 2376 <dd>
dschulze@4598 2377 specifies a <a href="#RotateDefined">2D rotation</a> by the angle specified in the parameter about the origin of the element, as
dschulze@6608 2378 defined by the 'transform-origin' property. For example, ''rotate(90deg)''
dschulze@4602 2379 would cause elements to appear rotated one-quarter of a turn in the clockwise direction.
vhardy@3672 2380 </dd>
dschulze@6608 2381 <dt>
dschulze@6608 2382 <code class="css">skew(&lt;angle&gt;[, &lt;angle&gt;])</code>
dschulze@6608 2383 </dt>
dschulze@6608 2384 <dd>
dschulze@6608 2385 specifies a <a href="#SkewDefined">2D skew</a> by [ax,ay] for X and Y. If the second parameter is not provided, it has a zero value.
dschulze@6608 2386 <p class="note">Note that the behavior of ''skew'' is different from mutliplying ''skewX'' with ''skewY''. Implementations must support this function for compatibility with legacy content.</p>
dschulze@6608 2387 </dd>
dschulze@5743 2388 <dt id="skewX-function">
simon@4365 2389 <code class="css">skewX(&lt;angle&gt;)</code>
vhardy@3672 2390 </dt>
vhardy@3672 2391 <dd>
dschulze@5111 2392 specifies a <a href="#SkewXDefined">2D skew transformation along the X axis</a> by the given angle.
vhardy@3672 2393 </dd>
dschulze@5743 2394 <dt id="skewY-function">
simon@4365 2395 <code class="css">skewY(&lt;angle&gt;)</code>
vhardy@3672 2396 </dt>
vhardy@3672 2397 <dd>
dschulze@5111 2398 specifies a <a href="#SkewYDefined">2D skew transformation along the Y axis</a> by the given angle.
vhardy@3672 2399 </dd>
vhardy@3672 2400 </dl>
simon@4358 2401
simon@4358 2402
dschulze@5114 2403 <h3 id="three-d-transform-functions">3D Transform Functions</h3>
simon@4358 2404 <dl>
dschulze@5743 2405 <dt id="matrix3d-function">
simon@4365 2406 <code class="css">matrix3d(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;)</code>
simon@4358 2407 </dt>
simon@4358 2408 <dd>
simon@4358 2409 specifies a 3D transformation as a 4x4 homogeneous matrix of 16 values in column-major order.
simon@4358 2410 </dd>
dschulze@5743 2411 <dt id="translate3d-function">
dschulze@4483 2412 <code class="css">translate3d(&lt;translation-value&gt;, &lt;translation-value&gt;, &lt;length&gt;)</code>
simon@4358 2413 </dt>
simon@4358 2414 <dd>
dschulze@4491 2415 specifies a <a href="#Translate3dDefined">3D translation</a> by the vector [tx,ty,tz], with tx, ty and tz being the first, second and third translation-value parameters respectively.
simon@4358 2416 </dd>
dschulze@5743 2417 <dt id="translateZ-function">
dschulze@4483 2418 <code class="css">translateZ(&lt;length&gt;)</code>
simon@4358 2419 </dt>
simon@4358 2420 <dd>
dschulze@4491 2421 specifies a <a href="#Translate3dDefined">3D translation</a> by the vector [0,0,tz] with the given amount in the Z direction.
simon@4358 2422 </dd>
dschulze@5743 2423 <dt id="scale3d-function">
simon@4365 2424 <code class="css">scale3d(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;)</code>
simon@4358 2425 </dt>
simon@4358 2426 <dd>
dschulze@4491 2427 specifies a <a href="#Scale3dDefined">3D scale</a> operation by the [sx,sy,sz] scaling vector described by the 3 parameters.
simon@4358 2428 </dd>
dschulze@5743 2429 <dt id="scaleZ-function">
simon@4365 2430 <code class="css">scaleZ(&lt;number&gt;)</code>
simon@4358 2431 </dt>
simon@4358 2432 <dd>
dschulze@4491 2433 specifies a <a href="#Scale3dDefined">3D scale</a> operation using the [1,1,sz] scaling vector, where sz is given as the parameter.
simon@4358 2434 </dd>
dschulze@5743 2435 <dt id="rotate3d-function">
simon@4365 2436 <code class="css">rotate3d(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;angle&gt;)</code>
simon@4358 2437 </dt>
simon@4358 2438 <dd>
ayg@4745 2439 specifies a <a href="#Rotate3dDefined">3D rotation</a> by the
ayg@4745 2440 angle specified in last parameter about the [x,y,z] direction
dschulze@6607 2441 vector described by the first three parameters. A direction vector that cannot be normalized,
ayg@4745 2442 such as [0,0,0], will cause the rotation to not be applied.
dschulze@6402 2443 <p class="note">Note that the rotation is clockwise as one looks from the end of
dschulze@6402 2444 the vector toward the origin.</p>
dschulze@4491 2445 </dd>
dschulze@5743 2446 <dt id="rotateX-function">
simon@4365 2447 <code class="css">rotateX(&lt;angle&gt;)</code>
simon@4358 2448 </dt>
simon@4358 2449 <dd>
ayg@4745 2450 same as <code class="css">rotate3d(1, 0, 0, &lt;angle&gt;)</code>.
simon@4358 2451 </dd>
dschulze@5743 2452 <dt id="rotateY-function">
simon@4365 2453 <code class="css">rotateY(&lt;angle&gt;)</code>
simon@4358 2454 </dt>
simon@4358 2455 <dd>
ayg@4745 2456 same as <code class="css">rotate3d(0, 1, 0, &lt;angle&gt;)</code>.
simon@4358 2457 </dd>
dschulze@5743 2458 <dt id="rotateZ-function">
simon@4365 2459 <code class="css">rotateZ(&lt;angle&gt;)</code>
simon@4358 2460 </dt>
simon@4358 2461 <dd>
ayg@4745 2462 same as <code class="css">rotate3d(0, 0, 1, &lt;angle&gt;)</code>,
ayg@4745 2463 which is also the same as <code class="css">rotate(&lt;angle&gt;)</code>.
simon@4358 2464 </dd>
simon@4577 2465 <dt id="perspective-function">
simon@4365 2466 <code class="css">perspective(&lt;length&gt;)</code>
simon@4358 2467 </dt>
simon@4358 2468 <dd>
simon@4700 2469 specifies a <a href="#PerspectiveDefined">perspective projection matrix</a>. This matrix scales points in
simon@4700 2470 X and Y based on their Z value, scaling points with positive Z values away from the origin, and those with
simon@4700 2471 negative Z values towards the origin. Points on the z=0 plane are unchanged. The parameter represents the
simon@4700 2472 distance of the z=0 plane from the viewer. Lower values give a more flattened pyramid and therefore a more
simon@4700 2473 pronounced perspective effect. For example, a value of 1000px gives a moderate amount of foreshortening
simon@4700 2474 and a value of 200px gives an extreme amount. The value for depth must be greater than zero, otherwise the
simon@4700 2475 function is invalid.
simon@4358 2476 </dd>
simon@4358 2477 </dl>
simon@4358 2478
simon@4358 2479 <!-- ======================================================================================================= -->
simon@4358 2480
dschulze@5130 2481 <h2 id="transform-function-lists">
dschulze@5130 2482 The Transform Function Lists
vhardy@3672 2483 </h2>
dschulze@5910 2484
vhardy@3672 2485 <p>
dschulze@5130 2486 If a list of <var>&lt;transform-functions&gt;</var> is provided, then the net effect is as if each transform function had been specified separately in the order provided. For example,
vhardy@3672 2487 </p>
dschulze@5910 2488
simon@4358 2489 <pre>
simon@4358 2490 &lt;div style="transform:translate(-10px,-20px) scale(2) rotate(45deg) translate(5px,10px)"/&gt;
simon@4358 2491 </pre>
dschulze@5910 2492
vhardy@3672 2493 <p>
vhardy@3672 2494 is functionally equivalent to:
vhardy@3672 2495 </p>
simon@4358 2496 <pre>
simon@4358 2497 &lt;div style="transform:translate(-10px,-20px)"&gt;
simon@4358 2498 &lt;div style="transform:scale(2)"&gt;
simon@4358 2499 &lt;div style="transform:rotate(45deg)"&gt;
simon@4358 2500 &lt;div style="transform:translate(5px,10px)"&gt;
simon@4358 2501 &lt;/div&gt;
simon@4358 2502 &lt;/div&gt;
simon@4358 2503 &lt;/div&gt;
simon@4358 2504 &lt;/div&gt;
simon@4358 2505 </pre>
dschulze@5910 2506 <p>
dschulze@5910 2507 That is, in the absence of other styling that affects position and dimensions, a
dschulze@5910 2508 nested set of transforms is equivalent to a single list of transform functions,
dschulze@5910 2509 applied from the outside in. The resulting transform is the matrix multiplication of
dschulze@5910 2510 the list of transforms.
dschulze@5910 2511 </p>
dschulze@5910 2512
dschulze@5910 2513 <p>
dschulze@5931 2514 If a transform function causes the <span class="term">current transformation matrix
ayg@5989 2515 (CTM)</span> of an object to be non-invertible, the object and its content do not
dschulze@5931 2516 get displayed.
dschulze@5910 2517 </p>
dschulze@5910 2518
dschulze@5910 2519 <div class="example">
dschulze@5910 2520 <p>
dschulze@5910 2521 The object in the following example gets scaled by 0.
dschulze@5910 2522 </p>
dschulze@5910 2523
dschulze@5910 2524 <pre>&lt;style&gt;
dschulze@5910 2525 .box {
dschulze@5910 2526 transform: scale(0);
dschulze@5910 2527 }
dschulze@5910 2528 &lt;/style&gt;
dschulze@5910 2529
dschulze@5910 2530 &lt;div class="box"&gt;
dschulze@5910 2531 Not visible
dschulze@5910 2532 &lt;/div&gt;</pre>
dschulze@5910 2533
dschulze@5910 2534 <p>
dschulze@5910 2535 The scaling causes a non-invertible CTM for the coordinate space of the div box.
dschulze@5910 2536 Therefore neither the div box, nor the text in it get displayed.
dschulze@5910 2537 </p>
dschulze@5910 2538 </div>
dschulze@5690 2539
dschulze@5690 2540 <!-- ======================================================================================================= -->
vhardy@3672 2541
vhardy@3672 2542 <h2 id="animation">
dschulze@5690 2543 Interpolation of Transforms
vhardy@3672 2544 </h2>
vhardy@3672 2545
vhardy@3672 2546 <p>
dschulze@5690 2547 When animating or transitioning transforms, the transform function lists must be
dschulze@5690 2548 interpolated. For interpolation between one transform <em>from-transform</em> and
dschulze@5690 2549 a second transforms <em>to-transform</em>, the rules described below are applied.
vhardy@3672 2550 </p>
vhardy@3672 2551
vhardy@3672 2552 <ul>
dschulze@5743 2553 <li id="none-none-animation">
dschulze@5743 2554 If both the <em>from-</em> and <em>to-transform</em> are ''none'':
vhardy@3672 2555 <ul>
vhardy@3672 2556 <li>
dschulze@5743 2557 There is no interpolation necessary. The computed value stays ''none''.
vhardy@3672 2558 </li>
vhardy@3672 2559 </ul>
vhardy@3672 2560 </li>
dschulze@5743 2561 <li id="none-transform-animation">
dschulze@5743 2562 If one of the <em>from-</em> or <em>to-transforms</em> is ''none''.
vhardy@3672 2563 <ul>
vhardy@3672 2564 <li>
dschulze@5743 2565 The value ''none'' is replaced by an equivalent
dschulze@5690 2566 <a href="#TermIdentityTransformFunction"><i>identity transform
dschulze@5690 2567 function</i></a> list for the corresponding transform
dschulze@5690 2568 function list. Both transform function lists get interpolated following the
dschulze@5690 2569 next rule.
vhardy@3672 2570 </li>
vhardy@3672 2571 </ul>
dschulze@5690 2572 <div class="example">
dschulze@5690 2573 <p>
dschulze@5743 2574 For example, if <em>from-transform</em> is ''scale(2)'' and
dschulze@5743 2575 <em>to-transform</em> is ''none'' then the value ''scale(1)'' will be used for
dschulze@5743 2576 <em>to-transform</em> and animation will proceed using the next rule.
dschulze@5892 2577 Similarly, if <em>from-transform</em> is ''none'' and <em>to-transform</em> is
dschulze@5743 2578 ''scale(2) rotate(50deg)'' then the animation will execute as if
dschulze@5743 2579 <em>from-transform</em> is ''scale(1) rotate(0)''.
dschulze@5690 2580 </p>
dschulze@5690 2581 </div>
vhardy@3672 2582 </li>
dschulze@5743 2583 <li id="transform-transform-animation">
dschulze@5690 2584 If <em>from-</em> and <em>to-transform</em> have the same number of
dschulze@6402 2585 transform functions, each transform function pair has either the same name, or is
dschulze@6402 2586 a derivative of the same <a href="#transform-primitives">primitive</a>.
vhardy@3672 2587 <ul>
vhardy@3672 2588 <li>
dschulze@5690 2589 Interpolate each transform function pair as described in <a
dschulze@5690 2590 href="#interpolation-of-transform-functions">Interpolation of transform
dschulze@5690 2591 functions</a>. The computed value is the resulting transform function
dschulze@5690 2592 list.
vhardy@3672 2593 </li>
vhardy@3672 2594 </ul>
dschulze@5690 2595 <div class="example">
dschulze@5690 2596 <p>
dschulze@5743 2597 For example, if <em>from-transform</em> is ''scale(1) translate(0)'' and
dschulze@5743 2598 <em>to-transform</em> is ''translate(100px) scale(2)'' then ''scale(1)'' and
dschulze@5743 2599 ''translate(100px)'' as well as ''translate(0)'' and ''scale(2)'' don't share
dschulze@5743 2600 a common primitive and therefore can not get interpolated following this rule.
dschulze@5690 2601 </p>
dschulze@5690 2602 </div>
vhardy@3672 2603 </li>
dschulze@5743 2604 <li id="other-animation">
dschulze@5690 2605 In all other cases:
vhardy@3672 2606 <ul>
vhardy@3672 2607 <li>
dschulze@5690 2608 The transform functions of each transform function list on the
dschulze@5892 2609 <em>from-</em> and <em>to-transform</em> get post multiplied and
dschulze@5892 2610 converted into 4x4 matrices. Each of the matrices gets interpolated following
dschulze@5892 2611 the instructions in <a href="#matrix-interpolation">Interpolation of
dschulze@5892 2612 matrices</a>. The computed value is the transform function ''matrix'' if both
dschulze@5743 2613 initial matrices can be represented by a correlating 3x2 matrix and
dschulze@5743 2614 ''matrix3d'' otherwise.
vhardy@3672 2615 </li>
vhardy@3672 2616 </ul>
vhardy@3672 2617 </li>
vhardy@3672 2618 </ul>
vhardy@3672 2619
vhardy@3672 2620 <p>
dschulze@5690 2621 In some cases, an animation might cause a transformation matrix to be singular or
dschulze@5690 2622 non-invertible. For example, an animation in which scale moves from 1 to -1. At the
dschulze@5690 2623 time when the matrix is in such a state, the transformed element is not rendered.
vhardy@3672 2624 </p>
dschulze@5892 2625
dschulze@5892 2626 <!-- ======================================================================================================= -->
vhardy@3672 2627
dschulze@5892 2628 <h2 id="transform-primitives">
dschulze@5690 2629 Transform function primitives and derivatives
dschulze@5892 2630 </h2>
dschulze@5690 2631
dschulze@5690 2632 <p>
dschulze@5690 2633 Some transform functions can be represented by more generic transform functions.
dschulze@5690 2634 These transform functions are called derived transform functions, the generic
dschulze@5690 2635 transform functions primitives. Primitives for two-dimensional and
dschulze@5690 2636 three-dimensional transform functions are listed below.
dschulze@5690 2637 </p>
dschulze@5690 2638
dschulze@5690 2639 <p>
dschulze@6299 2640 Two-dimensional primitives with derived transform functions are:
dschulze@5690 2641 </p>
dschulze@5690 2642
dschulze@5690 2643 <dl>
dschulze@5743 2644 <dt id="translate-primitive">
dschulze@5690 2645 <code class="css">translate(&lt;translation-value&gt;,
dschulze@5690 2646 &lt;translation-value&gt;)</code>
dschulze@5690 2647 </dt>
dschulze@5690 2648 <dd>
dschulze@5690 2649 for <code class="css">translateX(&lt;translation-value&gt;)</code>,
dschulze@5690 2650 <code class="css">translateY(&lt;translation-value&gt;)</code> and
dschulze@5690 2651 <code class="css">translate(&lt;translation-value&gt;)</code>.
dschulze@5690 2652 </dd>
dschulze@5743 2653 <dt id="rotate-three-primitive">
dschulze@5690 2654 <code class="css">rotate(&lt;angle&gt;, &lt;translation-value&gt;,
dschulze@5690 2655 &lt;translation-value&gt;)</code>
dschulze@5690 2656 </dt>
dschulze@5690 2657 <dd>
dschulze@5690 2658 for <code class="css">rotate(&lt;angle&gt;)</code> if
dschulze@5690 2659 <a href="#svg-transform-functions">rotate with three arguments</a> is supported.
dschulze@5690 2660 </dd>
dschulze@5743 2661 <dt id="scale-primitive">
dschulze@5690 2662 <code class="css">scale(&lt;number&gt;, &lt;number&gt;)</code>
dschulze@5690 2663 </dt>
dschulze@5690 2664 <dd>
dschulze@5690 2665 for <code class="css">scaleX(&lt;number&gt;)</code>, <code
dschulze@5690 2666 class="css">scaleY(&lt;number&gt;)</code> and <code
dschulze@5690 2667 class="css">scale(&lt;number&gt;)</code>.
dschulze@5690 2668 </dd>
dschulze@5690 2669 </dl>
dschulze@5690 2670
dschulze@5690 2671 <p>
dschulze@6299 2672 Three-dimensional primitives with derived transform functions are:
dschulze@5690 2673 </p>
dschulze@5690 2674
dschulze@5690 2675 <dl>
dschulze@5743 2676 <dt id="translate3d-primitive">
dschulze@5690 2677 <code class="css">translate3d(&lt;translation-value&gt;,
dschulze@5690 2678 &lt;translation-value&gt;, &lt;length&gt;)</code>
dschulze@5690 2679 </dt>
dschulze@5690 2680 <dd>
dschulze@5690 2681 for <code class="css">translateX(&lt;translation-value&gt;)</code>, <code
dschulze@5690 2682 class="css">translateY(&lt;translation-value&gt;)</code>, <code
dschulze@5690 2683 class="css">translateZ(&lt;number&gt;)</code> and <code
dschulze@5690 2684 class="css">translate(&lt;translation-value&gt;[,
dschulze@5690 2685 &lt;translation-value&gt;])</code>.
dschulze@5690 2686 </dd>
dschulze@5743 2687 <dt id="scale3d-primitive">
dschulze@5690 2688 <code class="css">scale3d(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;)</code>
dschulze@5690 2689 </dt>
dschulze@5690 2690 <dd>
dschulze@5690 2691 for <code class="css">scaleX(&lt;number&gt;)</code>, <code
dschulze@5690 2692 class="css">scaleY(&lt;number&gt;)</code>, <code
dschulze@5690 2693 class="css">scaleZ(&lt;number&gt;)</code> and <code
dschulze@5690 2694 class="css">scale(&lt;number&gt;[, &lt;number&gt;])</code>.
dschulze@5690 2695 </dd>
dschulze@6402 2696 <dt id="rotate3d-primitive">
bert@6704 2697 <code class="css">rotate3d(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;angle&gt;)</code>
dschulze@6402 2698 </dt>
dschulze@6402 2699 <dd>
dschulze@6402 2700 for <code class="css">rotate(&lt;number&gt;)</code>, <code
dschulze@6402 2701 class="css">rotateX(&lt;number&gt;)</code>, <code
dschulze@6402 2702 class="css">rotateY(&lt;number&gt;)</code> and <code
dschulze@6402 2703 class="css">rotateZ(&lt;number&gt;)</code>.
dschulze@6402 2704 </dd>
dschulze@5690 2705 </dl>
dschulze@5690 2706
dschulze@5743 2707 <p id="interpolation-two-three-dimensional-function">
dschulze@5690 2708 For derived transform functions that have a two-dimensional primitive and a
dschulze@5690 2709 three-dimensional primitive, the context decides about the used primitive. See
dschulze@5690 2710 <a href="#interpolation-of-transform-functions">Interpolation of primitives and
dschulze@5690 2711 derived transform functions</a>.
dschulze@5690 2712 </p>
dschulze@5892 2713
dschulze@5892 2714 <!-- ======================================================================================================= -->
dschulze@5690 2715
dschulze@5892 2716 <h2 id="interpolation-of-transform-functions">
dschulze@5690 2717 Interpolation of primitives and derived transform functions
dschulze@5892 2718 </h2>
dschulze@5690 2719
dschulze@5690 2720 <p>
dschulze@6402 2721 Two transform functions with the same name and the same number of arguments are
dschulze@5690 2722 interpolated numerically without a former conversion. The calculated value will be
dschulze@6402 2723 of the same transform function type with the same number of arguments. Special rules
dschulze@6402 2724 apply to ''rotate3d'', ''matrix'', ''matrix3d'' and ''perspective''.
dschulze@5690 2725 </p>
dschulze@5690 2726
dschulze@5690 2727 <div class="example">
dschulze@5690 2728 <p>
dschulze@5743 2729 The two transform functions ''translate(0)'' and ''translate(100px)'' are of the
dschulze@5743 2730 same type, have the same number of arguments and therefore can get interpolated
dschulze@5743 2731 numerically. ''translateX(100px)'' is not of the same type and
dschulze@5743 2732 ''translate(100px, 0)'' does not have the same number of arguments, therefore
dschulze@5743 2733 these transform functions can not get interpolated without a former conversion
dschulze@5743 2734 step.
dschulze@5690 2735 </p>
dschulze@5690 2736 </div>
dschulze@5690 2737
dschulze@5690 2738 <p>
dschulze@5690 2739 Two different types of transform functions that share the same primitive, or
dschulze@5690 2740 transform functions of the same type with different number of arguments can be
dschulze@5690 2741 interpolated. Both transform functions need a former conversion to the common
dschulze@5690 2742 primitive first and get interpolated numerically afterwards. The computed value
dschulze@5690 2743 will be the primitive with the resulting interpolated arguments.
dschulze@5690 2744 </p>
dschulze@5690 2745
dschulze@5690 2746 <div class="example">
dschulze@5690 2747 <p>
dschulze@5743 2748 The following example describes a transition from ''translateX(100px)'' to
dschulze@5743 2749 ''translateY(100px)'' in 3 seconds on hovering over the div box. Both transform
dschulze@5743 2750 functions derive from the same primitive <code
dschulze@5690 2751 class="css">translate(&lt;translation-value&gt;, &lt;translation-value&gt;)</code>
dschulze@5690 2752 and therefore can be interpolated.
dschulze@5690 2753 </p>
dschulze@5690 2754
dschulze@5690 2755 <pre>div {
dschulze@5690 2756 transform: translateX(100px);
dschulze@5690 2757 }
dschulze@5690 2758
dschulze@5690 2759 div:hover {
dschulze@5690 2760 transform: translateY(100px);
dschulze@5690 2761 transition: transform 3s;
dschulze@5690 2762 }</pre>
dschulze@5690 2763
dschulze@5690 2764 <p>
dschulze@5690 2765 For the time of the transition both transform functions get transformed to the
dschulze@5743 2766 common primitive. ''translateX(100px)'' gets converted to ''translate(100px, 0)''
dschulze@5743 2767 and ''translateY(100px)'' gets converted to ''translate(0, 100px)''. Both
dschulze@5743 2768 transform functions can then get interpolated numerically.
dschulze@5690 2769 </p>
dschulze@5690 2770 </div>
dschulze@5690 2771
dschulze@5690 2772 <p>
dschulze@5690 2773 If both transform functions share a primitive in the two-dimensional space, both
dschulze@5690 2774 transform functions get converted to the two-dimensional primitive. If one or both
dschulze@5690 2775 transform functions are three-dimensional transform functions, the common
dschulze@5690 2776 three-dimensional primitive is used.
dschulze@5690 2777 </p>
dschulze@5690 2778
dschulze@5690 2779 <div class="example">
dschulze@5690 2780 <p>
dschulze@5690 2781 In this example a two-dimensional transform function gets animated to a
dschulze@5690 2782 three-dimensional transform function. The common primitive is <code
dschulze@5690 2783 class="css">translate3d</code>.
dschulze@5690 2784 </p>
dschulze@5690 2785
dschulze@5690 2786 <pre>div {
dschulze@5690 2787 transform: translateX(100px);
dschulze@5690 2788 }
dschulze@5690 2789
dschulze@5690 2790 div:hover {
dschulze@5690 2791 transform: translateZ(100px);
dschulze@5690 2792 transition: transform 3s;
dschulze@5690 2793 }</pre>
dschulze@5690 2794
dschulze@5690 2795 <p>
dschulze@5690 2796 First '<code class="css">translateX(100px)</code>' gets converted to '<code
dschulze@5690 2797 class="css">translate3d(100px, 0, 0)</code>' and '<code class="css">translateZ(100px)</code>' to '<code
dschulze@5690 2798 class="css">translate3d(0, 0, 100px)</code>' respectively. Then both converted transform
dschulze@5690 2799 functions get interpolated numerically.
dschulze@5690 2800 </p>
dschulze@5690 2801 </div>
dschulze@5690 2802
dschulze@6299 2803 <p>
dschulze@6607 2804 The transform functions ''matrix'', ''matrix3d'' and ''perspective''
dschulze@6299 2805 get converted into 4x4 matrices first and interpolated as defined in section <a
dschulze@6402 2806 href="#matrix-interpolation">Interpolation of Matrices</a> afterwards.
dschulze@6299 2807 </p>
dschulze@6299 2808
dschulze@6607 2809 <p>
dschulze@6607 2810 For interpolatations with the primitive ''rotate3d'', the direction vectors of the
dschulze@6607 2811 transform functions get normalized first. If the
dschulze@6607 2812 normalized vectors are equal, the rotation angle gets interpolated numerically.
dschulze@6607 2813 Otherwise the transform functions get converted into 4x4 matrices first and
dschulze@6607 2814 interpolated as defined in section <a href="#matrix-interpolation">Interpolation of
dschulze@6607 2815 Matrices</a> afterwards.
dschulze@6607 2816 </p>
dschulze@6468 2817
dschulze@5690 2818 <!-- ======================================================================================================= -->
dschulze@5690 2819
dschulze@5892 2820 <h2 id="matrix-interpolation">
dschulze@5892 2821 Interpolation of Matrices
vhardy@3672 2822 </h2>
vhardy@3672 2823
vhardy@3672 2824 <p>
dschulze@5892 2825 When interpolating between two matrices, each is decomposed into the corresponding
dschulze@5892 2826 translation, rotation, scale, skew and perspective values. Not all matrices can be
dschulze@5892 2827 accurately described by these values. Those that can't are decomposed into the most
dschulze@5892 2828 accurate representation possible, using the pseudocode in <a
bert@6704 2829 href="#matrix-decomposing">Decomposing the Matrix</a>. The resulting values get <a
bert@6704 2830 href="#matrix-values-interpolation">interpolated numerically</a> and <a
bert@6704 2831 href="#matrix-recomposing">recomposed back to a matrix</a> in a final step.
vhardy@3672 2832 </p>
vhardy@3672 2833
dschulze@5902 2834 <div class="note">
dschulze@5902 2835 <p>
dschulze@5902 2836 In the following example the element gets translated by 100 pixel in both the X
dschulze@5902 2837 and Y directions and rotated by 1170 degree on hovering. The initial
dschulze@5902 2838 transformation is 45 degree. With the usage of transition, an author might expect
dschulze@5902 2839 a animated, clockwise rotation by three and a quarter turn (1170 degree).
dschulze@5902 2840 </p>
dschulze@5902 2841
dschulze@5902 2842 <pre>
dschulze@5902 2843 &lt;style&gt;
dschulze@5902 2844 div {
dschulze@5902 2845 transform: rotate(45deg);
dschulze@5902 2846 }
dschulze@5902 2847 div:hover {
dschulze@5902 2848 transform: translate(100px, 100px) rotate(1215deg);
dschulze@5902 2849 transition: transform 3s;
dschulze@5902 2850 }
dschulze@5902 2851 &lt;/style&gt;
dschulze@5902 2852
dschulze@5902 2853 &lt;div&gt;&lt;/div&gt;</pre>
dschulze@5902 2854
dschulze@5902 2855 <p>
dschulze@5902 2856 The number of transform functions on the source transform
dschulze@5902 2857 ''rotate(45deg)'' differs from the number of transform functions on the
dschulze@5902 2858 destination transform ''translate(100px, 100px) rotate(1125deg)''.
dschulze@5902 2859 According to the last rule of <a href="#animation">Interpolation of
dschulze@5902 2860 Transforms</a>, both transforms must be interpolated by matrix interpolation.
dschulze@5902 2861 With converting the transformation functions to matrices, the information about
dschulze@5902 2862 the three turns gets lost and the element gets rotated by just a quarter turn (90
dschulze@5902 2863 degree).
dschulze@5902 2864 </p>
dschulze@5902 2865
dschulze@5902 2866 <p>
dschulze@5902 2867 To achieve the three and a quarter turns for the example above, source and
dschulze@5902 2868 destination transforms must fulfill the third rule of <a
dschulze@5902 2869 href="#animation">Interpolation of Transforms</a>. Source transform could look
dschulze@5902 2870 like ''translate(0, 0) rotate(45deg)'' for a linearly interpolation of
dschulze@5902 2871 the transform functions.
dschulze@5902 2872 </p>
dschulze@5902 2873 </div>
dschulze@5903 2874
dschulze@5903 2875 <p>
dschulze@5903 2876 If one of the matrices for interpolation is non-invertible, the used animation
dschulze@5903 2877 function must fallback to a discrete animation according to the rules of the
dschulze@5903 2878 respective animation specification.
dschulze@5903 2879 </p>
dschulze@5902 2880
dschulze@5892 2881 <h3 id="matrix-decomposing">Decomposing the Matrix</h3>
dschulze@5892 2882
dschulze@5892 2883 <p>
dschulze@5892 2884 The pseudocode below is based upon the "unmatrix" method in "Graphics Gems II,
dschulze@5892 2885 edited by Jim Arvo", but modified to use Quaternions instead of Euler angles to
dschulze@5892 2886 avoid the problem of Gimbal Locks.
dschulze@5892 2887 </p>
dschulze@5892 2888
dschulze@5892 2889 <p>
dschulze@5892 2890 The following pseudocode works on a 4x4 homogeneous matrix:
dschulze@5892 2891 </p>
dschulze@5892 2892
vhardy@3672 2893 <pre>
dschulze@5892 2894 Input: matrix ; a 4x4 matrix
dschulze@5892 2895 Output: translation ; a 3 component vector
dschulze@5892 2896 scale ; a 3 component vector
dschulze@5892 2897 skew ; skew factors XY,XZ,YZ represented as a 3 component vector
dschulze@5892 2898 perspective ; a 4 component vector
dschulze@5892 2899 quaternion ; a 4 component vector
dschulze@5892 2900 Returns false if the matrix cannot be decomposed, true if it can
vhardy@3672 2901
dschulze@5892 2902 Supporting functions (point is a 3 component vector, matrix is a 4x4 matrix):
dschulze@5892 2903 double determinant(matrix) returns the 4x4 determinant of the matrix
dschulze@5892 2904 matrix inverse(matrix) returns the inverse of the passed matrix
dschulze@5892 2905 matrix transpose(matrix) returns the transpose of the passed matrix
dschulze@5892 2906 point multVecMatrix(point, matrix) multiplies the passed point by the passed matrix
dschulze@5892 2907 and returns the transformed point
dschulze@5892 2908 double length(point) returns the length of the passed vector
dschulze@5892 2909 point normalize(point) normalizes the length of the passed point to 1
dschulze@5892 2910 double dot(point, point) returns the dot product of the passed points
dschulze@5892 2911 double sqrt(double) returns the root square of passed value
dschulze@5892 2912 double max(double y, double x) returns the bigger value of the two passed values
vhardy@3672 2913
dschulze@5892 2914 Decomposition also makes use of the following function:
dschulze@5892 2915 point combine(point a, point b, double ascl, double bscl)
dschulze@5892 2916 result[0] = (ascl * a[0]) + (bscl * b[0])
dschulze@5892 2917 result[1] = (ascl * a[1]) + (bscl * b[1])
dschulze@5892 2918 result[2] = (ascl * a[2]) + (bscl * b[2])
dschulze@5892 2919 return result
vhardy@3672 2920
dschulze@5892 2921 // Normalize the matrix.
dschulze@5892 2922 if (matrix[3][3] == 0)
dschulze@5892 2923 return false
vhardy@3672 2924
dschulze@5892 2925 for (i = 0; i < 4; i++)
dschulze@5892 2926 for (j = 0; j < 4; j++)
dschulze@5892 2927 matrix[i][j] /= matrix[3][3]
dschulze@4484 2928
dschulze@5892 2929 // perspectiveMatrix is used to solve for perspective, but it also provides
dschulze@5892 2930 // an easy way to test for singularity of the upper 3x3 component.
dschulze@5892 2931 perspectiveMatrix = matrix
dschulze@4484 2932
dschulze@5892 2933 for (i = 0; i < 3; i++)
dschulze@5892 2934 perspectiveMatrix[i][3] = 0
dschulze@4484 2935
dschulze@5892 2936 perspectiveMatrix[3][3] = 1
dschulze@4484 2937
dschulze@5892 2938 if (determinant(perspectiveMatrix) == 0)
dschulze@5892 2939 return false
dschulze@4484 2940
dschulze@5892 2941 // First, isolate perspective.
dschulze@5892 2942 if (matrix[0][3] != 0 || matrix[1][3] != 0 || matrix[2][3] != 0)
dschulze@5892 2943 // rightHandSide is the right hand side of the equation.
dschulze@5892 2944 rightHandSide[0] = matrix[0][3];
dschulze@5892 2945 rightHandSide[1] = matrix[1][3];
dschulze@5892 2946 rightHandSide[2] = matrix[2][3];
dschulze@5892 2947 rightHandSide[3] = matrix[3][3];
dschulze@4484 2948
dschulze@5892 2949 // Solve the equation by inverting perspectiveMatrix and multiplying
dschulze@5892 2950 // rightHandSide by the inverse.
dschulze@5892 2951 inversePerspectiveMatrix = inverse(perspectiveMatrix)
dschulze@5892 2952 transposedInversePerspectiveMatrix = transposeMatrix4(inversePerspectiveMatrix)
dschulze@5892 2953 perspective = multVecMatrix(rightHandSide, transposedInversePerspectiveMatrix)
dschulze@5892 2954 else
dschulze@5892 2955 // No perspective.
dschulze@5892 2956 perspective[0] = perspective[1] = perspective[2] = 0
dschulze@5892 2957 perspective[3] = 1
dschulze@4484 2958
dschulze@5892 2959 // Next take care of translation
dschulze@5892 2960 for (i = 0; i < 3; i++)
dschulze@5892 2961 translate[i] = matrix[3][i]
dschulze@4484 2962
dschulze@5892 2963 // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
dschulze@5892 2964 for (i = 0; i < 3; i++)
dschulze@5892 2965 row[i][0] = matrix[i][0]
dschulze@5892 2966 row[i][1] = matrix[i][1]
dschulze@5892 2967 row[i][2] = matrix[i][2]
vhardy@3672 2968
dschulze@5892 2969 // Compute X scale factor and normalize first row.
dschulze@5892 2970 scale[0] = length(row[0])
dschulze@5892 2971 row[0] = normalize(row[0])
vhardy@3672 2972
dschulze@5892 2973 // Compute XY shear factor and make 2nd row orthogonal to 1st.
dschulze@5892 2974 skew[0] = dot(row[0], row[1])
dschulze@5892 2975 row[1] = combine(row[1], row[0], 1.0, -skew[0])
vhardy@3672 2976
dschulze@5892 2977 // Now, compute Y scale and normalize 2nd row.
dschulze@5892 2978 scale[1] = length(row[1])
dschulze@5892 2979 row[1] = normalize(row[1])
dschulze@5892 2980 skew[0] /= scale[1];
vhardy@3672 2981
dschulze@5892 2982 // Compute XZ and YZ shears, orthogonalize 3rd row
dschulze@5892 2983 skew[1] = dot(row[0], row[2])
dschulze@5892 2984 row[2] = combine(row[2], row[0], 1.0, -skew[1])
dschulze@5892 2985 skew[2] = dot(row[1], row[2])
dschulze@5892 2986 row[2] = combine(row[2], row[1], 1.0, -skew[2])
vhardy@3672 2987
dschulze@5892 2988 // Next, get Z scale and normalize 3rd row.
dschulze@5892 2989 scale[2] = length(row[2])
dschulze@5892 2990 row[2] = normalize(row[2])
dschulze@5892 2991 skew[1] /= scale[2]
dschulze@5892 2992 skew[2] /= scale[2]
dschulze@4484 2993
dschulze@5892 2994 // At this point, the matrix (in rows) is orthonormal.
dschulze@5892 2995 // Check for a coordinate system flip. If the determinant
dschulze@5892 2996 // is -1, then negate the matrix and the scaling factors.
dschulze@5892 2997 pdum3 = cross(row[1], row[2])
dschulze@5892 2998 if (dot(row[0], pdum3) < 0)
dschulze@5892 2999 for (i = 0; i < 3; i++)
dschulze@6880 3000 scale[i] *= -1;
dschulze@5892 3001 row[i][0] *= -1
dschulze@5892 3002 row[i][1] *= -1
dschulze@5892 3003 row[i][2] *= -1
dschulze@4484 3004
dschulze@5892 3005 // Now, get the rotations out
dschulze@5892 3006 quaternion[0] = 0.5 * sqrt(max(1 + row[0][0] - row[1][1] - row[2][2], 0))
dschulze@5892 3007 quaternion[1] = 0.5 * sqrt(max(1 - row[0][0] + row[1][1] - row[2][2], 0))
dschulze@5892 3008 quaternion[2] = 0.5 * sqrt(max(1 - row[0][0] - row[1][1] + row[2][2], 0))
dschulze@5892 3009 quaternion[3] = 0.5 * sqrt(max(1 + row[0][0] + row[1][1] + row[2][2], 0))
dschulze@4484 3010
dschulze@5892 3011 if (row[2][1] > row[1][2])
dschulze@5892 3012 quaternion[0] = -quaternion[0]
dschulze@5892 3013 if (row[0][2] > row[2][0])
dschulze@5892 3014 quaternion[1] = -quaternion[1]
dschulze@5892 3015 if (row[1][0] > row[0][1])
dschulze@5892 3016 quaternion[2] = -quaternion[2]
vhardy@3672 3017
dschulze@5892 3018 return true</pre>
vhardy@3672 3019
dschulze@5892 3020 <h3 id="matrix-values-interpolation">
dschulze@5892 3021 Interpolation of decomposed matrix values
dschulze@5892 3022 </h3>
dschulze@5892 3023
vhardy@3672 3024 <p>
dschulze@5892 3025 Each component of the decomposed values translation, scale, skew and perspective of
dschulze@5892 3026 the source matrix get linearly interpolated with each corresponding component of the
dschulze@5892 3027 destination matrix.
vhardy@3672 3028 </p>
dschulze@5892 3029
dschulze@5892 3030 <p class="note">
dschulze@5892 3031 For instance, <code>translate[0]</code> of the source matrix and
dschulze@5892 3032 <code>translate[0]</code> of the destination matrix are interpolated numerically,
dschulze@5892 3033 and the result is used to set the translation of the animating element.
dschulze@5892 3034 </p>
dschulze@5892 3035
vhardy@3672 3036 <p>
dschulze@5892 3037 Quaternions of the decomposed source matrix are interpolated with quaternions of the
dschulze@5892 3038 decomposed destination matrix using the spherical linear interpolation (Slerp) as
dschulze@5892 3039 described by the pseudocode below:
vhardy@3672 3040 </p>
dschulze@5892 3041
vhardy@3672 3042 <pre>
dschulze@5892 3043 Input: quaternionA ; a 4 component vector
dschulze@5892 3044 quaternionB ; a 4 component vector
dschulze@5892 3045 t ; interpolation parameter with 0 <= t <= 1
dschulze@5892 3046 Output: quaternionDst ; a 4 component vector
dschulze@5892 3047
dschulze@5892 3048 Supporting functions (vector is a 4 component vector):
dschulze@5892 3049 double dot(vector, vector) returns the dot product of the passed vectors
dschulze@5892 3050 vector multVector(vector, vector) multiplies the passed vectors
dschulze@5892 3051 double sqrt(double) returns the root square of passed value
dschulze@5892 3052 double max(double y, double x) returns the bigger value of the two passed values
dschulze@5892 3053 double min(double y, double x) returns the smaller value of the two passed values
dschulze@5892 3054 double cos(double) returns the cosines of passed value
dschulze@5892 3055 double sin(double) returns the sine of passed value
dschulze@5892 3056 double acos(double) returns the inverse cosine of passed value
dschulze@5892 3057
dschulze@5892 3058
dschulze@5892 3059 product = dot(quaternionA, quaternionB)
dschulze@5892 3060
dschulze@5892 3061 // Clamp product to -1.0 <= product <= 1.0
dschulze@5892 3062 product = max(product, 1.0)
dschulze@5892 3063 product = min(product, -1.0)
dschulze@5892 3064
dschulze@5892 3065 if (product == 1.0)
dschulze@5892 3066 quaternionDst = quaternionA
dschulze@5892 3067 return
dschulze@5892 3068
dschulze@5892 3069 theta = acos(dot)
dschulze@5892 3070 w = sin(t * theta) * 1 / sqrt(1 - product * product)
dschulze@5892 3071
dschulze@5892 3072 for (i = 0; i < 4; i++)
dschulze@5892 3073 quaternionA[i] *= cos(t * theta) - product * w
dschulze@5892 3074 quaternionB[i] *= w
dschulze@5892 3075 quaternionDst[i] = quaternionA[i] + quaternionB[i]
dschulze@5892 3076
dschulze@5892 3077 return</pre>
dschulze@5892 3078
dschulze@5892 3079 <h3 id="matrix-recomposing">
dschulze@5892 3080 Recomposing the Matrix
dschulze@5892 3081 </h3>
dschulze@5892 3082
dschulze@5892 3083 <p>
dschulze@5892 3084 After interpolation the resulting values are used to transform the elements user
dschulze@5892 3085 space. One way to use these values is to recompose them into a 4x4 matrix. This can
dschulze@5892 3086 be done following the pseudocode below:
dschulze@5892 3087 </p>
dschulze@5892 3088
dschulze@5892 3089 <pre>
dschulze@5892 3090 Input: translation ; a 3 component vector
dschulze@5892 3091 scale ; a 3 component vector
dschulze@5892 3092 skew ; skew factors XY,XZ,YZ represented as a 3 component vector
dschulze@5892 3093 perspective ; a 4 component vector
dschulze@5892 3094 quaternion ; a 4 component vector
dschulze@5892 3095 Output: matrix ; a 4x4 matrix
dschulze@5892 3096
dschulze@5892 3097 Supporting functions (matrix is a 4x4 matrix):
dschulze@5892 3098 matrix multiply(matrix a, matrix b) returns the 4x4 matrix product of a * b
dschulze@5892 3099
dschulze@5892 3100 // apply perspective
dschulze@5892 3101 for (i = 0; i < 4; i++)
dschulze@5892 3102 matrix[i][3] = perspective[i]
dschulze@5892 3103
dschulze@5892 3104 // apply translation
dschulze@5892 3105 for (i = 0; i < 3; i++)
dschulze@5892 3106 for (j = 0; j < 3; j++)
dschulze@5892 3107 matrix[3][i] += translation[j] * matrix[j][i]
dschulze@5892 3108
dschulze@5892 3109 // apply rotation
dschulze@5892 3110 x = quaternion[0]
dschulze@5892 3111 y = quaternion[1]
dschulze@5892 3112 z = quaternion[2]
dschulze@5892 3113 w = quaternion[3]
dschulze@5892 3114
dschulze@5892 3115 // Construct a composite rotation matrix from the quaternion values
dschulze@5892 3116 // rotationMatrix is a identity 4x4 matrix initially
dschulze@5892 3117 rotationMatrix[0][0] = 1 - 2 * (y * y + z * z)
dschulze@5892 3118 rotationMatrix[0][1] = 2 * (x * y - z * w)
dschulze@5892 3119 rotationMatrix[0][2] = 2 * (x * z + y * w)
dschulze@5892 3120 rotationMatrix[1][0] = 2 * (x * y + z * w)
dschulze@5892 3121 rotationMatrix[1][1] = 1 - 2 * (x * x + z * z)
dschulze@5892 3122 rotationMatrix[1][2] = 2 * (y * z - x * w)
dschulze@5892 3123 rotationMatrix[2][0] = 2 * (x * z - y * w)
dschulze@5892 3124 rotationMatrix[2][1] = 2 * (y * z + x * w)
dschulze@5892 3125 rotationMatrix[2][2] = 1 - 2 * (x * x + y * y)
dschulze@5892 3126
dschulze@5892 3127 matrix = multiply(matrix, rotationMatrix)
dschulze@5892 3128
dschulze@5892 3129 // apply skew
dschulze@5892 3130 // temp is a identity 4x4 matrix initially
dschulze@5892 3131 if (skew[2])
dschulze@5892 3132 temp[2][1] = skew[2]
dschulze@5892 3133 matrix = multiply(matrix, temp)
dschulze@5892 3134
dschulze@5892 3135 if (skew[1])
dschulze@5892 3136 temp[2][1] = 0
dschulze@5892 3137 temp[2][0] = skew[1]
dschulze@5892 3138 matrix = multiply(matrix, temp)
dschulze@5892 3139
dschulze@5892 3140 if (skew[0])
dschulze@5892 3141 temp[2][0] = 0
dschulze@5892 3142 temp[1][0] = skew[0]
dschulze@5892 3143 matrix = multiply(matrix, temp)
dschulze@5892 3144
dschulze@5892 3145 // apply scale
dschulze@5892 3146 for (i = 0; i < 3; i++)
dschulze@5892 3147 for (j = 0; j < 3; j++)
dschulze@5892 3148 matrix[i][j] *= scale[i]
dschulze@5892 3149
dschulze@5892 3150 return</pre>
ayg@5129 3151
dschulze@4491 3152 <h2 id="mathematical-description">
dschulze@5114 3153 Mathematical Description of Transform Functions
dschulze@4491 3154 </h2>
dschulze@5892 3155
dschulze@4491 3156 <p>
dschulze@4601 3157 Mathematically, all transform functions can be represented as 4x4 transformation matrices of the following form:
dschulze@4491 3158 </p>
bert@6704 3159 <p>
simon@4583 3160 <img src="4x4matrix.png" alt="\begin{bmatrix} m11 & m21 & m31 & m41 \\ m12 & m22 & m32 & m42 \\ m13 & m23 & m33 & m43 \\ m14 & m24 & m34 & m44 \end{bmatrix}" width="222" height="106">
dschulze@6929 3161 <p>
dschulze@6929 3162 One translation unit on a matrix is equivalent to 1 pixel in the local coordinate system of the element.
dschulze@6929 3163 </p>
dschulze@4491 3164
dschulze@4491 3165 <ul>
dschulze@4491 3166 <li id="MatrixDefined">
dschulze@4491 3167 <p>
dschulze@6607 3168 A 2D 3x2 matrix with six parameters <em>a</em>, <em>b</em>, <em>c</em>, <em>d</em>, <em>e</em> and <em>f</em> is equivalent to the matrix:
dschulze@4491 3169 </p>
simon@4583 3170 <img src="matrix.png" alt="\begin{bmatrix} a & c & 0 & e \\ b & d & 0 & f \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="108" height="106">
dschulze@4491 3171 </li>
dschulze@4491 3172 <li id="TranslateDefined">
dschulze@4491 3173 <p>
dschulze@4491 3174 A 2D translation with the parameters <em>tx</em> and <em>ty</em> is equivalent to a <a href="#Translate3dDefined">3D translation</a> where <em>tz</em> has zero as a value.
dschulze@4491 3175 </p>
dschulze@4491 3176 </li>
dschulze@4491 3177 <li id="ScaleDefined">
dschulze@4491 3178 <p>
dschulze@4491 3179 A 2D scaling with the parameters <em>sx</em> and <em>sy</em> is equivalent to a <a href="#Scale3dDefined">3D scale</a> where <em>sz</em> has one as a value.
dschulze@4491 3180 </p>
dschulze@4491 3181 </li>
dschulze@4491 3182 <li id="RotateDefined">
dschulze@4491 3183 <p>
ayg@4745 3184 A 2D rotation with the parameter <em>alpha</em> is
ayg@4745 3185 equivalent to a <a href="#Rotate3dDefined">3D rotation</a>
ayg@4745 3186 with vector [0,0,1] and parameter <em>alpha</em>.
dschulze@4491 3187 </p>
dschulze@4491 3188 </li>
dschulze@6608 3189 <li id="SkewDefined">
dschulze@6608 3190 <p>
dschulze@6608 3191 A 2D skew like transformation with the parameters <em>alpha</em> and <em>beta</em> is equivalent to the matrix:
dschulze@6608 3192 </p>
dschulze@6608 3193 <img src="skew.png" alt="\begin{bmatrix} 1 & \tan(\alpha) & 0 & 0 \\ \tan(\beta) & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="205" height="106">
dschulze@6608 3194 </li>
dschulze@5111 3195 <li id="SkewXDefined">
dschulze@4491 3196 <p>
dschulze@5111 3197 A 2D skew transformation along the X axis with the parameter <em>alpha</em> is equivalent to the matrix:
dschulze@4491 3198 </p>
dschulze@5111 3199 <img src="skewX.png" alt="\begin{bmatrix} 1 & \tan(\alpha) & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="155" height="106">
dschulze@5111 3200 </li>
dschulze@5111 3201 <li id="SkewYDefined">
dschulze@5111 3202 <p>
dschulze@5111 3203 A 2D skew transformation along the Y axis with the parameter <em>beta</em> is equivalent to the matrix:
dschulze@5111 3204 </p>
dschulze@5111 3205 <img src="skewY.png" alt="\begin{bmatrix} 1 & 0 & 0 & 0 \\ \tan(\beta) & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="155" height="106">
dschulze@4491 3206 </li>
dschulze@4491 3207 <li id="Translate3dDefined">
dschulze@4491 3208 <p>
dschulze@4491 3209 A 3D translation with the parameters <em>tx</em>, <em>ty</em> and <em>tz</em> is equivalent to the matrix:
dschulze@4491 3210 </p>
simon@4584 3211 <img src="translate3d.png" alt="\begin{bmatrix} 1 & 0 & 0 & tx \\ 0 & 1 & 0 & ty \\ 0 & 0 & 1 & tz \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="114" height="106">
ayg@5129 3212 </li>
dschulze@4491 3213 <li id="Scale3dDefined">
dschulze@4491 3214 <p>
dschulze@4491 3215 A 3D scaling with the parameters <em>sx</em>, <em>sy</em> and <em>sz</em> is equivalent to the matrix:
dschulze@4491 3216 </p>
simon@4583 3217 <img src="scale3d.png" alt="\begin{bmatrix} sx & 0 & 0 & 0 \\ 0 & sy & 0 & 0 \\ 0 & 0 & sz & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="137" height="106">
dschulze@4491 3218 </li>
dschulze@4491 3219 <li id="Rotate3dDefined">
dschulze@4491 3220 <p>
dschulze@4491 3221 A 3D rotation with the vector [x,y,z] and the parameter <em>alpha</em> is equivalent to the matrix:
dschulze@4491 3222 </p>
simon@4583 3223 <img src="rotate3dmatrix.png" alt="\begin{bmatrix} 1 - 2 \cdot (y^2 + z^2) \cdot sq & 2 \cdot (x \cdot y \cdot sq - z \cdot sc) & 2 \cdot (x \cdot z \cdot sq + y \cdot sc) & 0 \\ 2 \cdot (x \cdot y \cdot sq + z \cdot sc) & 1 - 2 \cdot (x^2 + z^2) \cdot sq & 2 \cdot (y \cdot z \cdot sq - x \cdot sc) & 0 \\ 2 \cdot (x \cdot z \cdot sq - y \cdot sc) & 2 \cdot (y \cdot z \cdot sq + x \cdot sc) & 1 - 2 \cdot (x^2 + y^2) \cdot sq & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="647" height="106">
dschulze@4491 3224 <p>
dschulze@4491 3225 where:
dschulze@4491 3226 </p>
simon@4584 3227 <img src="rotate3dvariables.png" alt="\newline sc = \sin (\alpha/2) \cdot \cos (\alpha/2) \newline sq = \sin^2 (\alpha/2)" width="221" height="50">
dschulze@4491 3228 </li>
dschulze@4491 3229 <li id="PerspectiveDefined">
dschulze@4491 3230 <p>
dschulze@4491 3231 A perspective projection matrix with the parameter <em>d</em> is equivalent to the matrix:
dschulze@4491 3232 </p>
simon@4583 3233 <img src="perspective.png" alt="\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & -1/d & 1 \end{bmatrix}" width="143" height="106">
dschulze@4491 3234 </li>
dschulze@4491 3235 </ul>
vhardy@3672 3236
dschulze@7701 3237 <h2>Conformance</h2>
dschulze@7701 3238 <!--conformance-->
vhardy@3672 3239
vhardy@3672 3240 <h2>References</h2>
vhardy@3672 3241
vhardy@3672 3242 <h3 class="no-num">Normative references</h3>
vhardy@3672 3243 <!--normative-->
vhardy@3672 3244
vhardy@3672 3245 <h3 class="no-num">Other references</h3>
vhardy@3672 3246 <!--informative-->
vhardy@3672 3247
vhardy@3672 3248
vhardy@3672 3249
vhardy@3672 3250 <h2 class="no-num">Property index</h2>
vhardy@3672 3251 <!-- properties -->
vhardy@3672 3252
vhardy@3672 3253
vhardy@3672 3254
vhardy@3672 3255 <h2 class="no-num" id="index">Index</h2>
vhardy@3672 3256 <!--index-->
vhardy@3672 3257
vhardy@3672 3258 </body>
vhardy@3672 3259 </html>
vhardy@3672 3260 <!-- Keep this comment at the end of the file
vhardy@3672 3261 Local variables:
vhardy@3672 3262 mode: sgml
vhardy@3672 3263 sgml-declaration:"~/SGML/HTML4.decl"
vhardy@3672 3264 sgml-default-doctype-name:"html"
vhardy@3672 3265 sgml-minimize-attributes:t
vhardy@3672 3266 sgml-nofill-elements:("pre" "style" "br")
vhardy@3672 3267 sgml-live-element-indicator:t
vhardy@3672 3268 sgml-omittag:nil
vhardy@3672 3269 sgml-shorttag:nil
vhardy@3672 3270 sgml-namecase-general:t
vhardy@3672 3271 sgml-general-insert-case:lower
vhardy@3672 3272 sgml-always-quote-attributes:t
vhardy@3672 3273 sgml-indent-step:nil
vhardy@3672 3274 sgml-indent-data:t
vhardy@3672 3275 sgml-parent-document:nil
vhardy@3672 3276 sgml-exposed-tags:nil
vhardy@3672 3277 sgml-local-catalogs:nil
vhardy@3672 3278 sgml-local-ecat-files:nil
vhardy@3672 3279 End:
vhardy@3672 3280 -->
ayg@5129 3281

mercurial