Mon, 12 Mar 2012 11:30:19 -0600
Hyperlink two CSS2.1 definitions
vhardy@3672 | 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"> |
vhardy@3672 | 4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
vhardy@3719 | 5 | <title>CSS Transforms</title> |
simon@4357 | 6 | <link rel="stylesheet" type="text/css" href="../default.css" /> |
simon@4357 | 7 | <link rel="stylesheet" type="text/css" href="http://www.w3.org/StyleSheets/TR/W3C-ED.css" /> |
vhardy@3672 | 8 | |
vhardy@3732 | 9 | <style type="text/css"> |
simon@4376 | 10 | .term { |
simon@4376 | 11 | font-style: italic; |
simon@4376 | 12 | } |
simon@4363 | 13 | |
dschulze@4321 | 14 | .todo { |
dschulze@4321 | 15 | font-weight: bold; |
dschulze@4321 | 16 | border-left: 0.5em solid #f44; |
dschulze@4321 | 17 | padding-left: 1em; |
dschulze@4321 | 18 | margin-top: 0.5em; |
dschulze@4321 | 19 | color: #a0a0a0; |
dschulze@4321 | 20 | } |
dschulze@4321 | 21 | |
dschulze@4321 | 22 | .todo:before { |
dschulze@4321 | 23 | content: "TO DO : "; |
dschulze@4321 | 24 | color: #f44; |
dschulze@4321 | 25 | } |
vhardy@3672 | 26 | </style> |
vhardy@3672 | 27 | |
vhardy@3672 | 28 | </head> |
vhardy@3672 | 29 | <body> |
vhardy@3672 | 30 | <div id="div-head" class="head"> |
vhardy@3672 | 31 | <!--logo--> |
vhardy@3672 | 32 | |
simon@4357 | 33 | <h1>CSS Transforms</h1> |
vhardy@3672 | 34 | |
vhardy@3672 | 35 | <h2 class="no-num no-toc">[LONGSTATUS] [DATE]</h2> |
vhardy@3672 | 36 | <dl> |
vhardy@3672 | 37 | <dt>This version: |
vhardy@3672 | 38 | <dd> |
simon@4357 | 39 | <a href="[VERSION]">http://dev.w3.org/csswg/css3-transforms/</a> |
vhardy@3672 | 40 | <!--http://www.w3.org/TR/[YEAR]/WD-[SHORTNAME]-[CDATE]--> |
vhardy@3672 | 41 | <dt>Latest version: |
vhardy@3672 | 42 | <dd><a |
simon@4357 | 43 | href="http://www.w3.org/TR/css3-transforms">[LATEST]</a> |
simon@4583 | 44 | <dt>Editor's draft: |
simon@4583 | 45 | <dd><a href="http://dev.w3.org/csswg/[SHORTNAME]/">http://dev.w3.org/csswg/[SHORTNAME]/</a> |
vhardy@3672 | 46 | <dt>Previous version: |
simon@4357 | 47 | <dd>None |
vhardy@3672 | 48 | <dt id="editors-list">Editors: |
vhardy@3672 | 49 | <dd>Simon Fraser (<a href="http://www.apple.com/">Apple Inc</a>) <simon.fraser @apple.com> |
vhardy@3672 | 50 | <dd>Dean Jackson (<a href="http://www.apple.com/">Apple Inc</a>) <dino @apple.com> |
vhardy@3672 | 51 | <dd>David Hyatt (<a href="http://www.apple.com/">Apple Inc</a>) <hyatt @apple.com> |
vhardy@3672 | 52 | <dd>Chris Marrin (<a href="http://www.apple.com/">Apple Inc</a>) <cmarrin @apple.com> |
vhardy@3672 | 53 | <dd>Edward O'Connor (<a href="http://www.apple.com/">Apple Inc</a>) <eoconnor @apple.com> |
dschulze@4323 | 54 | <dd>Dirk Schulze (<a href="http://www.adobe.com/">Adobe Systems, Inc</a>) <dschulze @adobe.com> |
simon@4581 | 55 | <dd>Aryeh Gregor (<a href="http://www.mozilla.org/">Mozilla</a>) <ayg @aryeh.name> |
simon@4581 | 56 | |
simon@4581 | 57 | <dt>Issues list: |
simon@4581 | 58 | <dd><a href="https://www.w3.org/Bugs/Public/buglist.cgi?query_format=advanced&product=CSS&component=Transforms&resolution=---&cmdtype=doit">in Bugzilla</a> |
simon@4581 | 59 | |
simon@4581 | 60 | <dt>Test suite: |
simon@4581 | 61 | <dd>none yet |
simon@4581 | 62 | </dl> |
vhardy@3672 | 63 | |
vhardy@3672 | 64 | <!--copyright--> |
vhardy@3672 | 65 | |
vhardy@3672 | 66 | <hr title="Separator for header"> |
vhardy@3672 | 67 | </div> |
vhardy@3672 | 68 | |
vhardy@3672 | 69 | <h2 class="no-num no-toc" id="abstract">Abstract</h2> |
vhardy@3672 | 70 | |
vhardy@3672 | 71 | <p>CSS transforms allows elements styled with CSS to be transformed |
dschulze@4321 | 72 | in two-dimensional or three-dimensional space. This specification is the convergence of the |
vhardy@3672 | 73 | <a href="http://www.w3.org/TR/css3-2d-transforms/">CSS 2D transforms</a>, |
vhardy@3672 | 74 | <a href="http://www.w3.org/TR/css3-3d-transforms/">CSS 3D transforms</a> |
vhardy@3672 | 75 | and <a href="http://www.w3.org/TR/2009/WD-SVG-Transforms-20090320/">SVG transforms</a> |
vhardy@3672 | 76 | specifications.</p> |
vhardy@3672 | 77 | |
vhardy@3672 | 78 | <h2 class="no-num no-toc" id="status">Status of this document</h2> |
vhardy@4360 | 79 | |
vhardy@4360 | 80 | <p class="note"> |
vhardy@4360 | 81 | This specification merges the former CSS 2D Transforms and CSS 3D Transforms specifications and |
vhardy@4360 | 82 | will also merge CSS Transforms and SVG Transforms. The merge is in progress and the specification |
vhardy@4360 | 83 | is not yet ready for review. |
vhardy@4360 | 84 | </p> |
vhardy@4360 | 85 | |
vhardy@3672 | 86 | <!--status--> |
vhardy@3672 | 87 | |
vhardy@3672 | 88 | <p> |
vhardy@3672 | 89 | The <a href="ChangeLog">list of changes made to this specification</a> is |
vhardy@3672 | 90 | available. |
vhardy@3672 | 91 | </p> |
vhardy@3672 | 92 | |
vhardy@3672 | 93 | <h2 class="no-num no-toc" id="contents">Table of contents</h2> |
vhardy@3672 | 94 | <!--toc--> |
vhardy@3672 | 95 | |
vhardy@3672 | 96 | |
vhardy@3672 | 97 | <h2>Introduction</h2> |
vhardy@3672 | 98 | |
simon@4345 | 99 | <p><em>This section is not normative.</em></p> |
simon@4345 | 100 | <p> |
simon@4345 | 101 | The CSS <a href="http://www.w3.org/TR/REC-CSS2/visuren.html">visual |
dschulze@4511 | 102 | formatting model</a> describes a coordinate system within each |
simon@4345 | 103 | element is positioned. Positions and sizes in this coordinate space can |
dschulze@4511 | 104 | be thought of as being expressed in pixels, starting in the origin of point |
dschulze@4511 | 105 | with positive values proceeding to the right and down. |
simon@4345 | 106 | </p> |
simon@4345 | 107 | <p> |
dschulze@4602 | 108 | This coordinate space can be modified with the '<code |
dschulze@4602 | 109 | class="property">transform</code>' property. Using transform, elements |
simon@4345 | 110 | can be translated, rotated and scaled in two or three dimensional space. |
simon@4345 | 111 | </p> |
simon@4345 | 112 | <p> |
simon@4345 | 113 | Additional properties make working with transforms easier, and allow the |
simon@4345 | 114 | author to control how nested three-dimensional transforms interact. |
simon@4345 | 115 | </p> |
simon@4345 | 116 | <ul> |
simon@4345 | 117 | <li> |
dschulze@4602 | 118 | The '<code class="property">transform-origin</code>' property |
simon@4345 | 119 | provides a convenient way to control the origin about which transforms on |
simon@4345 | 120 | an element are applied. |
simon@4345 | 121 | </li> |
simon@4345 | 122 | <li> |
dschulze@4602 | 123 | The '<code class="property">perspective</code>' property allows the author |
simon@4345 | 124 | to make child elements with three-dimensional transforms appear as if they live in a common |
simon@4345 | 125 | three-dimensional space. |
dschulze@4602 | 126 | The '<code class="property">perspective-origin</code>' property provides control |
simon@4345 | 127 | over the origin at which perspective is applied, effectively changing the location of |
simon@4345 | 128 | the "vanishing point". |
simon@4345 | 129 | </li> |
simon@4345 | 130 | <li> |
dschulze@4602 | 131 | The '<code class="property">transform-style</code>' property allows 3D-transformed |
simon@4345 | 132 | elements and their 3D-transformed descendants to share a common three-dimensional |
simon@4345 | 133 | space, allowing the construction of hierarchies of three-dimensional objects. |
simon@4345 | 134 | </li> |
simon@4345 | 135 | <li> |
dschulze@4602 | 136 | The '<code class="property">backface-visibility</code>' property comes into play |
simon@4345 | 137 | when an element is flipped around via three-dimensional transforms such that its |
simon@4345 | 138 | reverse side is visible to the viewer. In some situations it is desirable to |
simon@4345 | 139 | hide the element in this situation, which is possible using the value of 'hidden' |
simon@4345 | 140 | for this property. |
simon@4345 | 141 | </li> |
simon@4345 | 142 | </ul> |
simon@4345 | 143 | <p> |
dschulze@4602 | 144 | Note that while some values of the '<code class="property">transform</code>' property |
simon@4345 | 145 | allow an element to be transformed in a three-dimensional coordinate system, the elements |
simon@4345 | 146 | themselves are not three-dimensional objects. Instead, they exist on a two-dimensional |
simon@4345 | 147 | plane (a flat surface) and have no depth. |
simon@4345 | 148 | </p> |
vhardy@3672 | 149 | |
simon@4345 | 150 | <div class="issue"> |
simon@4345 | 151 | There are two roles for transformations in layout: (1) transformations |
simon@4345 | 152 | that adjust the position of the affected content without changing the |
simon@4345 | 153 | normal layout of that content (much like relative positioning) and (2) |
simon@4345 | 154 | transformation of the content prior to layout that affects the layout |
simon@4345 | 155 | of that content. See <a |
simon@4345 | 156 | href="http://lists.w3.org/Archives/Public/www-style/2007Oct/0209">http://lists.w3.org/Archives/Public/www-style/2007Oct/0209</a> |
simon@4345 | 157 | for examples of both cases. The "transform" property (as defined in |
simon@4345 | 158 | this document) is equally useful for both roles. This document is |
simon@4345 | 159 | focused on satisfying the first role. There is, however, an |
simon@4345 | 160 | architectural question that arises because there needs to be a way to |
simon@4345 | 161 | distinguish which role an author of a stylesheet wants. The key |
simon@4345 | 162 | question is which is the default behavior/role for the "transform" |
simon@4345 | 163 | property and how is the other behavior/role indicated by a stylesheet |
simon@4345 | 164 | author. If you have an opinion on this topic, please send feedback. |
simon@4345 | 165 | </div> |
simon@4345 | 166 | <div class="issue"> |
simon@4345 | 167 | What do fixed backgrounds do in transforms? They should probably ignore |
simon@4345 | 168 | the transform completely, since - even transformed - the object should |
simon@4345 | 169 | be acting as "porthole" through which the fixed background can be viewed |
simon@4345 | 170 | in its original form. |
simon@4345 | 171 | </div> |
simon@4345 | 172 | |
simon@4345 | 173 | <!-- ======================================================================================================= --> |
vhardy@3672 | 174 | |
simon@4345 | 175 | <h2 id="module-interactions">Module Interactions</h2> |
simon@4345 | 176 | <p>Write me</p> |
simon@4345 | 177 | |
simon@4365 | 178 | <h2 id="css-values">CSS Values</h2> |
simon@4345 | 179 | <p>Write me</p> |
simon@4345 | 180 | |
simon@4345 | 181 | |
simon@4345 | 182 | <h2 id="definitions">Definitions</h2> |
simon@4345 | 183 | <p> When used in this specification, terms have the meanings assigned in |
simon@4345 | 184 | this section. |
simon@4345 | 185 | </p> |
simon@4345 | 186 | <dl> |
dschulze@4483 | 187 | <dt id="TermBoundingBox"><dfn>bounding box</dfn></dt> |
dschulze@4483 | 188 | <dd> |
dschulze@4483 | 189 | <p> |
dschulze@4483 | 190 | A bounding box is the object bounding box for all SVG elements without an associated CSS layout box and |
dschulze@4483 | 191 | the border box for all other elements. |
dschulze@4483 | 192 | </p> |
dschulze@4483 | 193 | </dd> |
dschulze@4483 | 194 | |
simon@4365 | 195 | <dt id="TermTransformableElement"><dfn>transformable element</dfn></dt> |
simon@4345 | 196 | <dd> |
vhardy@3672 | 197 | <p> |
ayg@4736 | 198 | A transformable element in the HTML namespace which is either a |
ayg@4736 | 199 | <a href="http://www.w3.org/TR/CSS2/visuren.html#block-level">block-level</a> |
ayg@4736 | 200 | or <a href="http://www.w3.org/TR/CSS2/visuren.html#x13">atomic |
ayg@4736 | 201 | inline-level element</a>, or an element in the SVG namespace |
ayg@4736 | 202 | (see [[SVG11]]) which has the attributes '<code |
ayg@4736 | 203 | class="property">transform</code>', |
simon@4345 | 204 | 'patternTransform' or 'gradientTransform'. |
vhardy@3672 | 205 | </p> |
simon@4345 | 206 | </dd> |
simon@4345 | 207 | |
simon@4365 | 208 | <dt id="TermPerspectiveMatrix"><dfn>perpsective matrix</dfn></dt> |
simon@4345 | 209 | <dd> |
simon@4345 | 210 | <p> |
dschulze@4602 | 211 | A matrix computed from the values of the '<code class="property">perspective</code>' and '<code class="property">perspective-origin</code>' properties as described <a href="#perspective-matrix-computation">below</a>. |
simon@4365 | 212 | </p> |
simon@4365 | 213 | </dd> |
simon@4365 | 214 | |
simon@4366 | 215 | <dt id="TermTransformationMatrix"><dfn>transformation matrix</dfn></dt> |
simon@4365 | 216 | <dd> |
simon@4365 | 217 | <p> |
dschulze@4602 | 218 | A matrix computed from the values of the '<code class="property">transform</code>' and '<code class="property">transform-origin</code>' properties as described <a href="#transformation-matrix-computation">below</a>. |
simon@4365 | 219 | </p> |
simon@4365 | 220 | </dd> |
simon@4365 | 221 | |
simon@4365 | 222 | <dt id="Term3DRenderingContext"><dfn>3D rendering context</dfn></dt> |
simon@4365 | 223 | <dd> |
simon@4365 | 224 | <p> |
simon@4365 | 225 | A containing block hierarchy of one or more levels, instantiated by elements with a computed value for |
dschulze@4602 | 226 | the '<code class="property">transform-style</code>' property of '<code class="css">preserve-3d</code>', |
simon@4365 | 227 | whose elements share a common three-dimensional coordinate system. |
dschulze@4321 | 228 | </p> |
simon@4345 | 229 | </dd> |
simon@4345 | 230 | <!-- Define "three-dimensional transform" ? --> |
simon@4345 | 231 | </dl> |
simon@4345 | 232 | |
simon@4345 | 233 | <!-- ======================================================================================================= --> |
simon@4345 | 234 | |
simon@4345 | 235 | <h2 id="transform-rendering">The Transform Rendering Model</h2> |
simon@4345 | 236 | <!-- This section is normative --> |
vhardy@3672 | 237 | <p> |
dschulze@4602 | 238 | Specifying a value other than '<code class="css">none</code>' for the '<code class="property">transform</code>' |
vhardy@3672 | 239 | property establishes a new <em>local coordinate system</em> at the element that it is |
simon@4366 | 240 | applied to. The mapping from where the element would have rendered into that local coordinate system |
simon@4366 | 241 | is given by the element's <a href="#TermTransformationMatrix"><i>transformation matrix</i></a>. |
simon@4366 | 242 | Transformations are cumulative. That is, elements establish their local |
vhardy@3672 | 243 | coordinate system within the coordinate system of their parent. From the perspective of the |
dschulze@4602 | 244 | user, an element effectively accumulates all the '<code class="property">transform</code>' |
vhardy@3672 | 245 | properties of its ancestors as well as any local transform applied to it. The accumulation |
vhardy@3672 | 246 | of these transforms defines a <em>current transformation matrix (CTM)</em> for the element. |
vhardy@3672 | 247 | </p> |
vhardy@3672 | 248 | <p> |
simon@4345 | 249 | The coordinate space behaves as described in the <a |
simon@4345 | 250 | href="http://www.w3.org/TR/SVG/coords.html#EstablishingANewUserSpace">coordinate |
simon@4345 | 251 | system transformations</a> section of the SVG 1.1 specification. This is |
simon@4345 | 252 | a coordinate system with two axes: the X axis increases horizontally to |
simon@4345 | 253 | the right; the Y axis increases vertically downwards. Three-dimensional |
simon@4345 | 254 | transform functions extent this coordinate space into three dimensions, |
simon@4345 | 255 | adding a Z axis perpendicular to the plane of the screen, that increases towards the viewer. |
simon@4345 | 256 | </p> |
simon@4453 | 257 | <p id="transformation-matrix-computation"> |
simon@4366 | 258 | The <a href="#TermTransformationMatrix"><i>transformation matrix</i></a> is computed |
dschulze@4602 | 259 | from the '<code class="property">transform</code>' and '<code class="property">transform-origin</code>' properties |
simon@4366 | 260 | as follows: |
simon@4366 | 261 | <ol> |
simon@4366 | 262 | <li>Start with the identity matrix.</li> |
dschulze@4602 | 263 | <li>Translate by the computed X, Y and Z values of '<code class="property">transform-origin</code>'</li> |
dschulze@4602 | 264 | <li>Multiply by each of the transform functions in '<code class="property">transform</code>' property in turn</li> |
dschulze@4602 | 265 | <li>Translate by the negated computed X, Y and Z values of '<code class="property">transform-origin</code>'</li> |
simon@4366 | 266 | </ol> |
simon@4366 | 267 | </p> |
simon@4366 | 268 | <p> |
dschulze@4602 | 269 | Transforms apply to <span class="term">transformable elements</span>. |
simon@4345 | 270 | </p> |
simon@4358 | 271 | |
simon@4358 | 272 | <div class="example"> |
simon@4358 | 273 | <pre> |
simon@4358 | 274 | div { |
simon@4358 | 275 | transform: translate(100px, 100px); |
simon@4358 | 276 | } |
simon@4358 | 277 | </pre> |
simon@4358 | 278 | <p>This transform moves the element by 100 pixels in both the X and Y directions.</p> |
simon@4358 | 279 | <div class="figure"> |
simon@4358 | 280 | <img src="transform1.png" alt="The 100px translation in X and Y"> |
simon@4358 | 281 | </div> |
simon@4358 | 282 | </div> |
simon@4358 | 283 | |
simon@4358 | 284 | <div class="example"> |
simon@4358 | 285 | <pre> |
simon@4358 | 286 | div { |
simon@4358 | 287 | height: 100px; width: 100px; |
simon@4358 | 288 | transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg); |
simon@4358 | 289 | } |
simon@4358 | 290 | </pre> |
dschulze@4602 | 291 | <p>This transform moves the element by 80 pixels in both the X and Y directions, then scales the element by 150%, then rotates it 45° clockwise about the Z axis. Note that the scale and rotation operate about the center of the element, since the element has the default transform-origin of '<code class="css">50% 50%</code>'.</p> |
simon@4358 | 292 | <div class="figure"> |
simon@4358 | 293 | <img src="compound_transform.png" alt="The transform specified above"> |
simon@4358 | 294 | </div> |
simon@4358 | 295 | |
simon@4358 | 296 | <p>Note that an identical rendering can be obtained by nesting elements with the equivalent transforms: |
simon@4358 | 297 | <pre> |
simon@4358 | 298 | <div style="transform: translate(80px, 80px)"> |
dschulze@4602 | 299 | <div style="transform: scale(1.5, 1.5)"> |
dschulze@4602 | 300 | <div style="transform: rotate(45deg)"></div> |
dschulze@4602 | 301 | </div> |
simon@4358 | 302 | </div> |
simon@4358 | 303 | </pre> |
simon@4358 | 304 | </div> |
simon@4358 | 305 | |
simon@4345 | 306 | <!-- This "in the HTML namespace" is awkward. Is there a better way? --> |
simon@4345 | 307 | <p> |
simon@4345 | 308 | In the HTML namespace, the transform property does not affect the flow of the content |
simon@4363 | 309 | surrounding the transformed element. However, the extent of the overflow |
vhardy@3672 | 310 | area takes into account transformed elements. This behavior is similar |
simon@4363 | 311 | to what happens when elements are offset via relative positioning. |
dschulze@4602 | 312 | Therefore, if the value of the '<code class="property">overflow</code>' |
dschulze@4602 | 313 | property is '<code class="css">scroll</code>' or '<code class="css">auto</code>', |
simon@4365 | 314 | scrollbars will appear as needed to see content that is transformed outside the visible area. |
vhardy@3672 | 315 | </p> |
vhardy@3672 | 316 | <p> |
dschulze@4602 | 317 | In the HTML namespace, any value other than '<code class="css">none</code>' for the transform results in the creation of |
vhardy@3672 | 318 | both a stacking context and a containing block. The object acts as a |
vhardy@3672 | 319 | containing block for fixed positioned descendants. |
vhardy@3672 | 320 | </p> |
simon@4345 | 321 | <p class="issue"> |
simon@4345 | 322 | Is this affect on position:fixed necessary? If so, need to go into more detail here |
simon@4345 | 323 | about why fixed positioned objects should do this, i.e., that it's much harder to implement otherwise. |
dschulze@4321 | 324 | </p> |
simon@4345 | 325 | |
simon@4345 | 326 | <h3 id="transform-3d-rendering">3D Transform Rendering</h3> |
simon@4345 | 327 | |
simon@4345 | 328 | <!-- Maybe define "tranform container" in the definitions, and use it everywhere |
simon@4345 | 329 | in place of "containing block"? I'm not sure if "containing block" is exactly right. --> |
simon@4345 | 330 | <p> |
simon@4345 | 331 | Normally, elements render as flat planes, and are rendered into the same plane |
simon@4345 | 332 | as their containing block. Often this is the plane shared by the rest of the page. |
simon@4345 | 333 | Two-dimensional transform functions can alter the appearance of an element, but |
simon@4363 | 334 | that element is still rendered into the same plane as its containing block. |
simon@4345 | 335 | </p> |
simon@4345 | 336 | <p> |
simon@4345 | 337 | Three-dimensional transforms can result in transformation matrices with a non-zero |
simon@4345 | 338 | Z component<!-- clarify -->, potentially lifting them off the plane of their |
simon@4345 | 339 | containing block. Because of this, elements with three-dimensional transformations |
simon@4345 | 340 | could potentially render in an front-to-back order that different from the normal CSS rendering order, |
simon@4345 | 341 | and intersect with each other. Whether they do so depends on whether the element is a member |
simon@4363 | 342 | of a <span class="term">3D rendering context</span>, as described below. |
simon@4345 | 343 | </p> |
simon@4366 | 344 | <div class="issue"> |
simon@4345 | 345 | <p class="desc">This description does not exactly match what WebKit implements. Perhaps |
simon@4345 | 346 | it should be changed to match current implementations?</p> |
vhardy@3672 | 347 | </div> |
simon@4366 | 348 | |
simon@4345 | 349 | <div class="example"> |
simon@4356 | 350 | <p>This example shows the effect of three-dimensional transform applied to an element. |
simon@4356 | 351 | </p> |
simon@4345 | 352 | <pre> |
simon@4364 | 353 | <style> |
dschulze@4602 | 354 | div { |
dschulze@4602 | 355 | height: 150px; |
dschulze@4602 | 356 | width: 150px; |
dschulze@4602 | 357 | } |
dschulze@4602 | 358 | .container { |
dschulze@4602 | 359 | border: 1px solid black; |
dschulze@4602 | 360 | } |
dschulze@4602 | 361 | .transformed { |
dschulze@4602 | 362 | transform: rotateY(50deg); |
dschulze@4602 | 363 | } |
simon@4364 | 364 | </style> |
simon@4366 | 365 | |
simon@4356 | 366 | <div class="container"> |
simon@4356 | 367 | <div class="transformed"></div> |
simon@4356 | 368 | </div> |
simon@4356 | 369 | </pre> |
simon@4366 | 370 | <div class="figure"> |
simon@4366 | 371 | <img src="examples/simple-3d-example.png" width="210" height="190" alt="Div with a rotateY transform."> |
simon@4366 | 372 | </div> |
simon@4358 | 373 | <p>The transform is a 50° rotation about the vertical, Y axis. Note how this makes the blue box appear |
simon@4356 | 374 | narrower, but not three-dimensional. |
simon@4345 | 375 | </p> |
simon@4345 | 376 | </div> |
simon@4366 | 377 | |
simon@4366 | 378 | <p> |
dschulze@4602 | 379 | The '<code class="property">perspective</code>' and '<code class="property">perspective-origin</code>' |
simon@4366 | 380 | properties can be used to add a feeling of depth to a scene by making elements higher on the Z axis |
dschulze@4602 | 381 | (closer to the viewer) appear larger, and those further away to appear smaller. |
simon@4366 | 382 | </p> |
simon@4453 | 383 | <p id="perspective-matrix-computation"> |
simon@4366 | 384 | The <a href="#TermPerspectiveMatrix"><i>perspective matrix</i></a> is computed as follows: |
simon@4366 | 385 | <!-- Make this more mathy, with matrices? --> |
simon@4366 | 386 | <ol> |
simon@4366 | 387 | <li>Start with the identity matrix.</li> |
dschulze@4602 | 388 | <li>Translate by the computed X and Y values of '<code class="property">perspective-origin</code>'</li> |
dschulze@4602 | 389 | <li>Multiply by the matrix that would be obtained from the '<a href="#perspective-function"><code class="css">perspective(<length>)</code></a>' transform function, where the length is provided by the value of the '<code class="property">perspective</code>' property</li> |
dschulze@4602 | 390 | <li>Translate by the negated computed X and Y values of '<code class="property">perspective-origin</code>'</li> |
simon@4366 | 391 | </ol> |
simon@4366 | 392 | </p> |
simon@4345 | 393 | |
simon@4356 | 394 | <div class="example"> |
simon@4356 | 395 | <p>This example shows how perspective can be used to cause three-dimensional transforms to appear more realistic. |
simon@4356 | 396 | </p> |
simon@4356 | 397 | <pre> |
simon@4364 | 398 | <style> |
dschulze@4602 | 399 | div { |
dschulze@4602 | 400 | height: 150px; |
dschulze@4602 | 401 | width: 150px; |
dschulze@4602 | 402 | } |
dschulze@4602 | 403 | .container { |
dschulze@4602 | 404 | perspective: 500px; |
dschulze@4602 | 405 | border: 1px solid black; |
dschulze@4602 | 406 | } |
dschulze@4602 | 407 | .transformed { |
dschulze@4602 | 408 | transform: rotateY(50deg); |
dschulze@4602 | 409 | } |
simon@4364 | 410 | </style> |
simon@4366 | 411 | |
simon@4356 | 412 | <div class="container"> |
simon@4356 | 413 | <div class="transformed"></div> |
simon@4356 | 414 | </div> |
simon@4356 | 415 | </pre> |
simon@4366 | 416 | <div class="figure"> |
simon@4366 | 417 | <img src="examples/simple-perspective-example.png" width="210" height="190" alt="Div with a rotateY transform, |
simon@4366 | 418 | and perspective on its container"> |
simon@4366 | 419 | </div> |
simon@4366 | 420 | <p>The inner element has the same transform as in the previous example, but its rendering is now influenced by the perspective |
simon@4356 | 421 | property on its parent element. Perspective causes vertices that have positive Z coordinates (closer to the viewer) |
dschulze@4602 | 422 | 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 | 423 | </p> |
simon@4356 | 424 | </div> |
simon@4356 | 425 | |
simon@4345 | 426 | <p> |
simon@4366 | 427 | An element with a three-dimensional transform that is not contained in a |
simon@4366 | 428 | <span class="term">3D rendering context</span> renders with the appropriate |
simon@4366 | 429 | transform applied, but does not intersect with any other elements. The three-dimensional |
simon@4366 | 430 | transform in this case can be considered just as a painting effect, like two-dimensional |
simon@4366 | 431 | transforms. Similarly, the transform does not affect painting order. For example, a transform with a |
simon@4366 | 432 | positive Z translation may make an element look larger, but does not cause that element |
simon@4366 | 433 | to render in front of elements with no translation in Z. |
simon@4366 | 434 | </p> |
simon@4366 | 435 | <p> |
simon@4345 | 436 | An element with a three-dimensional transform that is contained in a |
simon@4345 | 437 | <span class="term">3D rendering context</span> can visibly interact with other elements |
simon@4345 | 438 | in that same 3D rendering context; the set of elements participating in the same |
simon@4345 | 439 | <span class="term">3D rendering context</span> may obscure each other or intersect, |
simon@4345 | 440 | based on their computed transforms. They are rendered as if they are all siblings, |
simon@4345 | 441 | positioned in a common 3D coordinate space. The position of each element in that three-dimensional |
simon@4345 | 442 | space is determined by accumulating the transformation matrices |
simon@4345 | 443 | up from the element that establishes the <span class="term">3D rendering context</span> |
simon@4345 | 444 | through each element that is a containing block for the given element, as described below. |
simon@4345 | 445 | <!-- More detail required, probably with matrices --> |
simon@4345 | 446 | </p> |
simon@4345 | 447 | |
simon@4366 | 448 | <div class="example"> |
simon@4366 | 449 | <pre> |
simon@4366 | 450 | <style> |
dschulze@4602 | 451 | div { |
dschulze@4602 | 452 | height: 150px; |
dschulze@4602 | 453 | width: 150px; |
dschulze@4602 | 454 | } |
dschulze@4602 | 455 | .container { |
dschulze@4602 | 456 | perspective: 500px; |
dschulze@4602 | 457 | border: 1px solid black; |
dschulze@4602 | 458 | } |
dschulze@4602 | 459 | .transformed { |
dschulze@4602 | 460 | transform: rotateY(50deg); |
dschulze@4602 | 461 | background-color: blue; |
dschulze@4602 | 462 | } |
dschulze@4602 | 463 | .child { |
dschulze@4602 | 464 | transform-origin: top left; |
dschulze@4602 | 465 | transform: rotateX(40deg); |
dschulze@4602 | 466 | background-color: lime; |
dschulze@4602 | 467 | } |
simon@4366 | 468 | </style> |
simon@4366 | 469 | |
simon@4366 | 470 | <div class="container"> |
dschulze@4602 | 471 | <div class="transformed"> |
dschulze@4602 | 472 | <div class="child"></div> |
dschulze@4602 | 473 | </div> |
simon@4366 | 474 | </div> |
simon@4366 | 475 | </pre> |
dschulze@4602 | 476 | <p>This example shows how nested 3D transforms are rendered in the absence of '<code class="css">transform-style: preserve-3d</code>'. 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 | 477 | </p> |
simon@4366 | 478 | <div class="figure"> |
simon@4366 | 479 | <img src="examples/3d-rendering-context-flat.png" width="240" height="200" alt="Nested 3D transforms, with flattening"> |
simon@4366 | 480 | </div> |
simon@4366 | 481 | </div> |
simon@4366 | 482 | |
simon@4365 | 483 | <p>Elements establish and participate in 3D rendering contexts as follows:</p> |
simon@4365 | 484 | <ul> |
simon@4365 | 485 | <li> |
simon@4365 | 486 | A <span class="term">3D rendering context</span> is established by a |
dschulze@4602 | 487 | a <span class="term">transformable element</span> whose computed value for '<code class="property">transform-style</code>' is |
dschulze@4602 | 488 | '<code class="css">preserve-3d</code>', and which itself is not part of a 3D rendering context. |
simon@4365 | 489 | Note that such an element is always a containing block. An element that establishes a 3D rendering context |
simon@4365 | 490 | also participates in that context. |
simon@4365 | 491 | </li> |
simon@4365 | 492 | <li> |
dschulze@4602 | 493 | An element whose computed value for '<code class="property">transform-style</code>' is |
dschulze@4602 | 494 | '<code class="css">preserve-3d</code>', and which itself participates in a |
simon@4365 | 495 | <span class="term">3D rendering context</span>, extends that 3D rendering context rather than establishing |
simon@4365 | 496 | a new one. |
simon@4365 | 497 | </li> |
simon@4365 | 498 | <li> |
simon@4365 | 499 | An element participates in a <span class="term">3D rendering context</span> if its containing block |
simon@4365 | 500 | establishes or extends a <span class="term">3D rendering context</span>. |
simon@4365 | 501 | </li> |
simon@4365 | 502 | </ul> |
simon@4345 | 503 | <p> |
simon@4345 | 504 | The final value of the transform used to render an element in a <span class="term">3D rendering context</span> |
simon@4366 | 505 | is computed by accumulating a matrix as follows: |
simon@4345 | 506 | </p> |
simon@4345 | 507 | <ol> |
simon@4366 | 508 | <li>Start with the identity matrix</li> |
simon@4366 | 509 | <li>For each containing block between the root of the <span class="term">3D rendering context</span> |
simon@4366 | 510 | and the element in question: |
simon@4365 | 511 | <ol> |
simon@4366 | 512 | <li>multiply the accumulated matrix with the <a href="#TermPerspectiveMatrix"><i>perspective matrix</i></a> |
simon@4366 | 513 | on the element's containing block (if any). That contining block is not necessarily a member |
simon@4366 | 514 | of the 3D rendering context.</li> |
simon@4366 | 515 | <li>apply to the accumulated matrix a translation equivalent to the horizontal and vertical offset of the element relative to |
simon@4366 | 516 | its containing block as specified by the CSS visual formatting model. <!-- (tighten this!) --></li> |
simon@4366 | 517 | <li>multiply the accumulated matrix with the <a href="#TermTransformationMatrix"><i>transformation matrix</i></a>.</li> |
simon@4365 | 518 | </ol> |
simon@4345 | 519 | </li> |
simon@4345 | 520 | </ol> |
simon@4366 | 521 | |
simon@4345 | 522 | <div class="example"> |
simon@4345 | 523 | <pre> |
simon@4364 | 524 | <style> |
dschulze@4602 | 525 | div { |
dschulze@4602 | 526 | height: 150px; |
dschulze@4602 | 527 | width: 150px; |
dschulze@4602 | 528 | } |
dschulze@4602 | 529 | .container { |
dschulze@4602 | 530 | perspective: 500px; |
dschulze@4602 | 531 | border: 1px solid black; |
dschulze@4602 | 532 | } |
dschulze@4602 | 533 | .transformed { |
dschulze@4602 | 534 | <b>transform-style: preserve-3d</b>; |
dschulze@4602 | 535 | transform: rotateY(50deg); |
dschulze@4602 | 536 | background-color: blue; |
dschulze@4602 | 537 | } |
dschulze@4602 | 538 | .child { |
dschulze@4602 | 539 | transform-origin: top left; |
dschulze@4602 | 540 | transform: rotateX(40deg); |
dschulze@4602 | 541 | background-color: lime; |
dschulze@4602 | 542 | } |
simon@4364 | 543 | </style> |
simon@4345 | 544 | </pre> |
dschulze@4602 | 545 | <p>This example is identical to the previous example, with the addition of '<code class="css">transform-style: preserve-3d</code>' on the blue element. The blue element now establishes a 3D rendering context, of which the lime element is a member. Now both blue and lime elements share a common three-dimensional space, so the lime element renders as tilting out from its parent, influenced by the perspective on the container. |
simon@4345 | 546 | </p> |
simon@4345 | 547 | <div class="figure"> |
simon@4364 | 548 | <img src="examples/3d-rendering-context-3d.png" width="240" height="200" alt="Nested 3D transforms, with preserve-3d."> |
simon@4345 | 549 | </div> |
simon@4345 | 550 | </div> |
simon@4345 | 551 | |
simon@4366 | 552 | <p> |
simon@4701 | 553 | Elements in the same <span class="term">3D rendering context</span> may intersect with each other. User agents must |
simon@4702 | 554 | render intersection by subdividing the planes of intersecting elements as described by |
simon@4701 | 555 | <a href="http://en.wikipedia.org/wiki/Newell's_algorithm">Newell's algorithm</a>. |
simon@4366 | 556 | </p> |
simon@4366 | 557 | <p> |
simon@4366 | 558 | Untransformed elements in a <span class="term">3D rendering context</span> render on the Z=0 plane, yet may still |
simon@4366 | 559 | intersect with transformed elements. |
simon@4366 | 560 | </p> |
simon@4366 | 561 | <p> |
simon@4366 | 562 | Within a <span class="term">3D rendering context</span>, the rendering order of non-intersecting elements is |
simon@4366 | 563 | based on their position on the Z axis after the application of the accumulated transform. Elements at the same |
simon@4366 | 564 | Z position render in <a href="http://www.w3.org/TR/CSS2/zindex.html#painting-order">stacking context order</a>. |
simon@4366 | 565 | </p> |
simon@4366 | 566 | |
simon@4364 | 567 | <div class="example"> |
simon@4345 | 568 | <pre> |
simon@4364 | 569 | <style> |
simon@4364 | 570 | .container { |
simon@4364 | 571 | background-color: rgba(0, 0, 0, 0.3); |
simon@4364 | 572 | transform-style: preserve-3d; |
simon@4364 | 573 | perspective: 500px; |
simon@4364 | 574 | } |
simon@4364 | 575 | .container > div { |
simon@4364 | 576 | position: absolute; |
simon@4364 | 577 | left: 0; |
simon@4364 | 578 | } |
simon@4364 | 579 | .container > :first-child { |
simon@4364 | 580 | transform: rotateY(45deg); |
simon@4364 | 581 | background-color: orange; |
simon@4364 | 582 | top: 10px; |
simon@4364 | 583 | height: 135px; |
simon@4364 | 584 | } |
simon@4364 | 585 | .container > :last-child { |
simon@4364 | 586 | transform: translateZ(40px); |
simon@4364 | 587 | background-color: rgba(0, 0, 255, 0.75); |
simon@4364 | 588 | top: 50px; |
simon@4364 | 589 | height: 100px; |
simon@4364 | 590 | } |
simon@4364 | 591 | </style> |
simon@4364 | 592 | |
simon@4364 | 593 | <div class="container"> |
simon@4364 | 594 | <div></div> |
simon@4364 | 595 | <div></div> |
simon@4364 | 596 | </div> |
simon@4345 | 597 | </pre> |
simon@4364 | 598 | <p> |
simon@4364 | 599 | This example shows show elements in a 3D rendering context can intersect. The container element establishes |
simon@4364 | 600 | a 3D rendering context for itself and its two children. The children intersect with eachother, and |
simon@4364 | 601 | the orange element also intersects with the container. |
simon@4364 | 602 | </p> |
simon@4364 | 603 | <div class="figure"> |
simon@4364 | 604 | <img src="examples/3d-intersection.png" width="200" height="200" alt="Intersecting sibling elements."> |
simon@4364 | 605 | </div> |
simon@4345 | 606 | </div> |
simon@4367 | 607 | |
simon@4367 | 608 | <p> |
simon@4367 | 609 | Using three-dimensional transforms, it's possible to transform an element such that its reverse side |
simon@4367 | 610 | is towards the viewer. 3D-tranformed elements show the same content on both sides, so the reverse side |
simon@4701 | 611 | looks like a mirror-image of the front side (as if the element were projected onto a sheet of glass). |
simon@4367 | 612 | Normally, elements whose reverse side is towards the viewer remain visible. However, the |
dschulze@4602 | 613 | '<code class="property">backface-visibility</code>' property allows the author to make an element invisible |
simon@4367 | 614 | when its reverse side is towards the viewer. This behavior is "live"; if an element with |
dschulze@4602 | 615 | '<code class="css">backface-visibility: hidden</code>' were animating, |
simon@4367 | 616 | such that its front and reverse sides were alternately visible, then it would only be visible when the |
simon@4367 | 617 | front side were towards the viewer. |
simon@4367 | 618 | </p> |
simon@4364 | 619 | |
simon@4345 | 620 | <!-- ======================================================================================================= --> |
dschulze@4321 | 621 | |
vhardy@3672 | 622 | <h2 id="transform-property"> |
dschulze@4602 | 623 | The '<code class="property">transform</code>' Property |
vhardy@3672 | 624 | </h2> |
vhardy@3672 | 625 | <p> |
simon@4345 | 626 | A transformation is applied to the coordinate system an element |
dschulze@4602 | 627 | renders in through the '<code class="property">transform</code>' property. This property contains a |
vhardy@3672 | 628 | list of <a href="#transform-functions">transform functions</a>. The |
vhardy@3672 | 629 | final transformation value for a coordinate system is obtained by converting |
dschulze@4511 | 630 | each function in the list to its corresponding matrix like defined in <a href="#mathematical-description">Mathematical |
dschulze@4511 | 631 | Description of Transformation Functions</a>, then multiplying the matrices. |
vhardy@3672 | 632 | </p> |
vhardy@3672 | 633 | <table class="propdef"> |
vhardy@3672 | 634 | <tbody> |
vhardy@3672 | 635 | <tr> |
vhardy@3672 | 636 | <td> |
vhardy@3672 | 637 | <em>Name:</em> |
vhardy@3672 | 638 | </td> |
vhardy@3672 | 639 | <td> |
vhardy@3672 | 640 | <dfn id="effects">transform</dfn> |
vhardy@3672 | 641 | </td> |
vhardy@3672 | 642 | </tr> |
vhardy@3672 | 643 | <tr> |
vhardy@3672 | 644 | <td> |
vhardy@3672 | 645 | <em>Value:</em> |
vhardy@3672 | 646 | </td> |
vhardy@3672 | 647 | <td> |
vhardy@3672 | 648 | none | <transform-function> [ <transform-function> ]* |
vhardy@3672 | 649 | </td> |
vhardy@3672 | 650 | </tr> |
vhardy@3672 | 651 | <tr> |
vhardy@3672 | 652 | <td> |
vhardy@3672 | 653 | <em>Initial:</em> |
vhardy@3672 | 654 | </td> |
vhardy@3672 | 655 | <td> |
vhardy@3672 | 656 | none |
vhardy@3672 | 657 | </td> |
vhardy@3672 | 658 | </tr> |
vhardy@3672 | 659 | <tr> |
vhardy@3672 | 660 | <td> |
vhardy@3672 | 661 | <em>Applies to:</em> |
vhardy@3672 | 662 | </td> |
vhardy@3672 | 663 | <td> |
dschulze@4321 | 664 | <a href="#TermTransformableElement">transformable elements</a> |
vhardy@3672 | 665 | </td> |
vhardy@3672 | 666 | </tr> |
vhardy@3672 | 667 | <tr> |
vhardy@3672 | 668 | <td> |
vhardy@3672 | 669 | <em>Inherited:</em> |
vhardy@3672 | 670 | </td> |
vhardy@3672 | 671 | <td> |
vhardy@3672 | 672 | no |
vhardy@3672 | 673 | </td> |
vhardy@3672 | 674 | </tr> |
vhardy@3672 | 675 | <tr> |
vhardy@3672 | 676 | <td> |
vhardy@3672 | 677 | <em>Percentages:</em> |
vhardy@3672 | 678 | </td> |
vhardy@3672 | 679 | <td> |
dschulze@4483 | 680 | refer to the size of the element's bounding box |
vhardy@3672 | 681 | </td> |
vhardy@3672 | 682 | </tr> |
vhardy@3672 | 683 | <tr> |
vhardy@3672 | 684 | <td> |
vhardy@3672 | 685 | <em>Media:</em> |
vhardy@3672 | 686 | </td> |
vhardy@3672 | 687 | <td> |
vhardy@3672 | 688 | visual |
vhardy@3672 | 689 | </td> |
vhardy@3672 | 690 | </tr> |
vhardy@3672 | 691 | <tr> |
vhardy@3672 | 692 | <td> |
vhardy@3672 | 693 | <em>Computed value:</em> |
vhardy@3672 | 694 | </td> |
vhardy@3672 | 695 | <td> |
simon@4334 | 696 | See below. |
vhardy@3672 | 697 | </td> |
vhardy@3672 | 698 | </tr> |
vhardy@3672 | 699 | </tbody> |
simon@4334 | 700 | </table> |
simon@4334 | 701 | |
simon@4366 | 702 | <div class="issue"> |
simon@4345 | 703 | <p class="desc">We need to resolve whether the computed value is the same as the specified value, or matrix().</p> |
simon@4345 | 704 | </div> |
simon@4334 | 705 | <p>The computed value of the transform property is a matrix() or matrix3d() value that describes the matrix that results from concatenating the individual transform functions. If the resulting matrix can be represented as a two-dimensional matrix with no loss of information, then a matrix() value is returned, otherwise a matrix3d() value. For elements with no transform applied, the computed value is 'none'.</p> |
simon@4345 | 706 | |
dschulze@4602 | 707 | <p>Any value other than '<code class="css">none</code>' for the transform results in the creation of both a stacking context and a containing block. The object acts as a containing block for fixed positioned descendants.</p> |
simon@4363 | 708 | |
simon@4334 | 709 | <!-- ======================================================================================================= --> |
vhardy@3672 | 710 | |
dschulze@4598 | 711 | <h2 id="svg-transform"> |
dschulze@4602 | 712 | The SVG '<code class="property">transform</code>' Attribute |
dschulze@4598 | 713 | </h2> |
vhardy@3672 | 714 | |
dschulze@4598 | 715 | <p> |
dschulze@4598 | 716 | The <a href="http://www.w3.org/TR/2011/REC-SVG11-20110816/">SVG 1.1 specification</a> did not |
dschulze@4602 | 717 | specify the attributes '<code class="property">transform</code>', 'gradientTransform' or 'patternTransform' as |
dschulze@4602 | 718 | <a href="http://www.w3.org/TR/2011/REC-SVG11-20110816/styling.html#UsingPresentationAttributes"><em>presentation attributes</em></a>. |
dschulze@4598 | 719 | In order to improve the integration of SVG and HTML, this specification makes these SVG attributes to |
dschulze@4602 | 720 | 'presentation attributes' and makes the '<code class="property">transform</code>' property one that applies to <span class="term">transformable elements</span> in the SVG namespace. |
dschulze@4598 | 721 | </p> |
vhardy@3672 | 722 | |
dschulze@4598 | 723 | <p> |
dschulze@4602 | 724 | This specification will also introduce the new presentation attributes '<code class="property">transform-origin</code>', |
dschulze@4602 | 725 | '<code class="property">perspective</code>', '<code class="property">perspective-origin</code>', |
dschulze@4602 | 726 | '<code class="property">transform-style</code>' and '<code class="property">backface-visibility</code>' |
dschulze@4598 | 727 | in the SVG namespace. All new introduced presentation attributes are animateable. |
dschulze@4598 | 728 | </p> |
dschulze@4598 | 729 | |
dschulze@4602 | 730 | <h3 id="transform-attribute-specificity">SVG '<code class="property">transform</code>' attribute specificity</h3> |
dschulze@4598 | 731 | |
dschulze@4598 | 732 | <p>Since the previously named SVG attributes become presentation attributes, their participation to the CSS |
vhardy@3672 | 733 | cascade is determined by the specificity of presentation attributes, as |
vhardy@3672 | 734 | <a href="http://www.w3.org/TR/2011/REC-SVG11-20110816/styling.html#UsingPresentationAttributes">explained</a> |
dschulze@4598 | 735 | in the SVG specification. |
dschulze@4598 | 736 | </p> |
dschulze@4598 | 737 | |
dschulze@4598 | 738 | <div class="example"> |
dschulze@4598 | 739 | <p> |
dschulze@4602 | 740 | This example shows the combination of the '<code class="property">transform</code>' style property and the '<code class="property">transform</code>' presentation attribute. |
dschulze@4598 | 741 | </p> |
dschulze@4598 | 742 | |
dschulze@4598 | 743 | <pre><svg> |
dschulze@4598 | 744 | <style> |
dschulze@4598 | 745 | .container { |
dschulze@4598 | 746 | transform: translate(100px, 100px); |
dschulze@4598 | 747 | } |
dschulze@4598 | 748 | </style> |
dschulze@4598 | 749 | |
dschulze@4598 | 750 | <g class="container" transform="translate (200 200)"> |
dschulze@4598 | 751 | <rect width="100" height="100" fill="blue" /> |
dschulze@4598 | 752 | </g> |
dschulze@4598 | 753 | </svg></pre> |
dschulze@4598 | 754 | |
dschulze@4598 | 755 | <div class="figure"> |
dschulze@4598 | 756 | <img src="examples/svg-translate.png" width="200" height="200" alt="Translated SVG container element."> |
dschulze@4598 | 757 | </div> |
dschulze@4598 | 758 | |
dschulze@4598 | 759 | <p> |
dschulze@4602 | 760 | Because of the participation to the CSS cascade, the '<code class="property">transform</code>' style property overrides the |
dschulze@4602 | 761 | '<code class="property">transform</code>' presentation attribute. Therefore the container gets translated by '<code class="css">100px</code>' in horizontal and vertical direction, instead of '<code class="css">200px</code>'. |
dschulze@4598 | 762 | </p> |
dschulze@4598 | 763 | </div> |
dschulze@4598 | 764 | |
dschulze@4602 | 765 | <h3 id="svg-syntax">Syntax of the SVG '<code class="property">transform</code>' attribute</h3> |
dschulze@4598 | 766 | |
dschulze@4598 | 767 | <p> |
dschulze@4602 | 768 | To provide backward compatibility, the syntax of the '<code class="property">transform</code>' presentation attribute differs from |
dschulze@4602 | 769 | the syntax of the '<code class="property">transform</code>' style property like shown in the example above. However, the syntax |
dschulze@4602 | 770 | used for the '<code class="property">transform</code>' style property can be used for a '<code class="property">transform</code>' presentation attribute value. |
dschulze@4598 | 771 | Authors are advised to follow the rules of <a href="http://www.w3.org/TR/css3-values/#functional-notation">CSS Values and Units Module</a>. |
dschulze@4602 | 772 | Therefore an author should write '<code class="css">transform="translate(200px, 200px)"</code>' instead of |
dschulze@4602 | 773 | '<code class="css">transform="translate (200 200)"</code>' because the second example with the spaces before the '<code class="css">(</code>', |
dschulze@4598 | 774 | the missing comma between the arguments and the values without the explicit unit notation would be valid for |
dschulze@4598 | 775 | the attribute only. |
dschulze@4598 | 776 | </p> |
dschulze@4598 | 777 | |
dschulze@4598 | 778 | <h4 id="svg-transform-list">Transform List</h4> |
dschulze@4598 | 779 | |
dschulze@4598 | 780 | <p> |
dschulze@4602 | 781 | The value for the '<code class="property">transform</code>' attribute consists of a transform list with zero or more transform functions |
dschulze@4598 | 782 | in the <a href="#svg-functional-notation">functional notation</a>. If the transform list consists of more than one |
dschulze@4602 | 783 | transform function, these functions are separated by either a comma (‘<code class="css">,</code>’) with optional whitespace |
dschulze@4598 | 784 | before and after the comma or one or more whitespaces. The transform list can have |
dschulze@4598 | 785 | optional whitespaces before and after the list. |
dschulze@4598 | 786 | </p> |
dschulze@4598 | 787 | |
dschulze@4598 | 788 | <h4 id="svg-functional-notation">Functional Notations</h4> |
dschulze@4598 | 789 | |
dschulze@4598 | 790 | <p> |
dschulze@4598 | 791 | The syntax starts with the name of the function followed by optional whitespaces followed by a left |
dschulze@4598 | 792 | parenthesis followed by optional whitespace followed by the argument(s) to the notation followed by |
dschulze@4598 | 793 | optional whitespace followed by a right parenthesis. If a function takes more than one argument, the |
dschulze@4602 | 794 | arguments are either separated by a comma (‘<code class="css">,</code>’) with optional whitespace before and after the comma |
dschulze@4598 | 795 | or one or more whitespaces. |
dschulze@4598 | 796 | </p> |
dschulze@4598 | 797 | |
dschulze@4598 | 798 | <h4 id="svg-data-types">SVG Data Types</h4> |
dschulze@4598 | 799 | |
dschulze@4598 | 800 | <p> |
dschulze@4601 | 801 | Arguments of transform functions consists of data types in the sense of |
dschulze@4598 | 802 | <a href="http://www.w3.org/TR/css3-values/#functional-notation">CSS Values and Units Module</a>. The definitions of |
dschulze@4598 | 803 | data types in CSS Values and Units Module gets enhanced as follows: |
dschulze@4598 | 804 | </p> |
dschulze@4598 | 805 | |
dschulze@4602 | 806 | <h5 id="svg-transform-value">The <var><translation-value></var> and <var><length></var> type</h5> |
dschulze@4598 | 807 | |
dschulze@4598 | 808 | <p> |
dschulze@4602 | 809 | A translation-value or length can be a <var><number></var> without an unit identifier. In this case |
dschulze@4602 | 810 | the <a href="#svg-number"><var>number</var></a> gets interpreted as "user unit". A user unit in the the |
dschulze@4598 | 811 | <a href="http://www.w3.org/TR/2003/REC-SVG11-20030114/coords.html#InitialCoordinateSystem">initial |
dschulze@4602 | 812 | coordinate system</a> is equivalenced to the parent environment's notion of a pixel unit. |
dschulze@4598 | 813 | </p> |
dschulze@4598 | 814 | |
dschulze@4602 | 815 | <h5 id="svg-angle">The <var><angle></var> type</h5> |
dschulze@4598 | 816 | |
dschulze@4598 | 817 | <p> |
dschulze@4602 | 818 | An angle can be a <var><number></var> without an unit identifier. In this case the <a href="#svg-number"><i>number</i></a> |
dschulze@4598 | 819 | gets interpreted as a value in degrees. |
dschulze@4598 | 820 | </p> |
dschulze@4598 | 821 | |
dschulze@4602 | 822 | <h5 id="svg-number">The <var><number></var> type</h5> |
dschulze@4598 | 823 | |
dschulze@4598 | 824 | <p> |
dschulze@4602 | 825 | SVG supports scientific notations for numbers. Therefore a <var>number</var> gets parsed like described in SVG |
dschulze@4598 | 826 | <a href="http://www.w3.org/TR/SVG/types.html#DataTypeNumber">Basic data types</a> for SVG attributes. |
dschulze@4598 | 827 | </p> |
dschulze@4598 | 828 | |
dschulze@4598 | 829 | <h3 id="svg-gradient-transform-pattern-transform">The SVG 'gradientTransform' and 'patternTransform' attributes</h3> |
dschulze@4598 | 830 | |
dschulze@4598 | 831 | <p> |
dschulze@4598 | 832 | SVG specifies the attributes 'gradientTransform' and 'patternTransform'. This specification |
dschulze@4598 | 833 | makes both attributes to presentation attributes. Both attributes use the same <a href="#svg-syntax">syntax</a> as |
dschulze@4602 | 834 | the SVG '<code class="property">transform</code>' attribute. This specification won't introduce corresponding CSS style properties. Instead the |
dschulze@4602 | 835 | style can be set by the '<code class="property">transform</code>' style property. |
dschulze@4598 | 836 | </p> |
dschulze@4598 | 837 | |
dschulze@4598 | 838 | <h3 id="svg-transformation-functions">SVG transformation functions</h3> |
dschulze@4598 | 839 | |
dschulze@4598 | 840 | <p> |
dschulze@4601 | 841 | For backward compatibility to existing SVG content, this specification must support all transform functions |
dschulze@4602 | 842 | defined by <a href="http://www.w3.org/TR/SVG/coords.html#TransformAttribute">The '<code class="property">transform</code>' attribute</a> in SVG 1.1. |
dschulze@4602 | 843 | Therefore the two-dimensional transform function '<code class="css">rotate(<angle>)</code>' gets extended as follows: |
dschulze@4598 | 844 | </p> |
dschulze@4598 | 845 | |
dschulze@4598 | 846 | <dl> |
dschulze@4598 | 847 | <dt> |
dschulze@4598 | 848 | <code class="css">rotate(<angle>[, <translation-value>, <translation-value>])</code> |
dschulze@4598 | 849 | </dt> |
dschulze@4598 | 850 | <dd> |
dschulze@4598 | 851 | specifies a <a href="#RotateDefined">2D rotation</a> by the angle specified in the parameter about the origin of the element, as defined |
dschulze@4602 | 852 | by the '<code class="property">transform-origin</code>' property. If the optional translation values are specified, the transform origin is translated by that amount |
dschulze@4598 | 853 | (using the current transformation matrix) for the duration of the rotate operation. |
dschulze@4602 | 854 | For example '<code class="css">rotate(90deg, 100px, 100px)</code>' would elements cause to appear rotated one-quarter of a turn in the clockwise direction after a translation |
dschulze@4602 | 855 | of 100 pixel in the vertical and horizontal direction. |
dschulze@4598 | 856 | </dd> |
dschulze@4598 | 857 | </dl> |
dschulze@4598 | 858 | |
dschulze@4598 | 859 | <p> |
dschulze@4598 | 860 | User agents are just required to support the two optional arguments for translation on elements in the SVG namespace. |
dschulze@4598 | 861 | </p> |
dschulze@4601 | 862 | |
dschulze@4601 | 863 | <h3 id="svg-three-dimensional-functions">SVG and 3D transformation functions</h3> |
dschulze@4601 | 864 | |
dschulze@4601 | 865 | <p> |
dschulze@4601 | 866 | This specification explicitly allows to apply three-dimensional transform functions to the |
dschulze@4602 | 867 | <a href="http://www.w3.org/TR/SVG/intro.html#TermContainerElement"><em>container elements</em></a>: |
dschulze@4602 | 868 | 'a', 'g', 'svg', all <a href="http://www.w3.org/TR/SVG/intro.html#TermGraphicsElement"><em>graphics elements</em></a>, all |
dschulze@4602 | 869 | <a href="http://www.w3.org/TR/SVG/intro.html#TermGraphicsReferencingElement"><em>graphics referencing elements</em></a> |
dschulze@4601 | 870 | and the SVG <a href="http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement">'foreignObject'</a> element. |
dschulze@4601 | 871 | </p> |
dschulze@4601 | 872 | |
dschulze@4601 | 873 | <p> |
dschulze@4602 | 874 | Three-dimensional transform functions and the properties '<code class="property">perspective</code>', |
dschulze@4602 | 875 | '<code class="property">perspective-origin</code>', '<code class="property">transform-style</code>' |
dschulze@4602 | 876 | and '<code class="property">backface-visibility</code>' can not be used for the elements: 'clipPath', 'mask', 'linearGradient', |
dschulze@4601 | 877 | 'radialGradient' and 'pattern'. If a transform list includes a three-dimensional transform function, the complete |
dschulze@4601 | 878 | transform list must be ignored. The values of every previously named property must be ignored. |
dschulze@4602 | 879 | <span class="term">Transformable elements</span> that are contained by one of these elements can have three-dimensional transform functions. |
dschulze@4601 | 880 | Before a 'clipPath', 'mask' or 'pattern' element can get applied to a target element, user agents must take the drawn results as static |
dschulze@4601 | 881 | images in analogue of "flattening" the elements and taking the rendered content as a two-dimensional canvas. |
dschulze@4601 | 882 | </p> |
dschulze@4598 | 883 | |
dschulze@4598 | 884 | <h3 id="svg-object-bounding-box">Object bounding box units</h3> |
dschulze@4598 | 885 | |
dschulze@4598 | 886 | <p> |
dschulze@4598 | 887 | Percentage or fractional values in SVG are either relative to the elements viewport units or to the elements |
dschulze@4598 | 888 | <a href="http://www.w3.org/TR/SVG/coords.html#ObjectBoundingBoxUnits">object bounding box units</a> like |
dschulze@4598 | 889 | specified in SVG 1.1. To align with HTML, all percentage values for all properties defined in this specification |
dschulze@4598 | 890 | are relative to the object bounding box units. |
dschulze@4598 | 891 | </p> |
dschulze@4598 | 892 | |
dschulze@4598 | 893 | <p> |
dschulze@4598 | 894 | If an SVG element does not provide an object bounding box (like for the 'pattern', 'mask' or 'clipPath' elements), the bounding box |
dschulze@4598 | 895 | is the same like if the position x, y and the dimensions width and height are zero. Percentage values or keywords won't affect the |
dschulze@4601 | 896 | rendering and are treated as if zero was specified. |
dschulze@4598 | 897 | </p> |
dschulze@4598 | 898 | |
dschulze@4598 | 899 | <div class="example"> |
dschulze@4598 | 900 | <p> |
dschulze@4602 | 901 | The '<code class="property">transform-origin</code>' property on the pattern in the following example specifies a '<code class="css">50%</code>' translation of the origin in the horizontal and vertical dimension. |
dschulze@4602 | 902 | The '<code class="property">transform</code>' property specifies a translation as well, but in absolute lengths. |
dschulze@4598 | 903 | </p> |
dschulze@4598 | 904 | |
dschulze@4598 | 905 | <pre><svg> |
dschulze@4598 | 906 | <style> |
dschulze@4598 | 907 | pattern { |
dschulze@4598 | 908 | transform: translate(50px, 50px) rotate(45deg); |
dschulze@4598 | 909 | transform-origin: 50% 50%; |
dschulze@4598 | 910 | } |
dschulze@4598 | 911 | </style> |
dschulze@4598 | 912 | |
dschulze@4598 | 913 | <defs> |
dschulze@4598 | 914 | <pattern id="pattern-1"> |
dschulze@4598 | 915 | <rect id="rect1" width="100" height="100" fill="blue" /> |
dschulze@4598 | 916 | </pattern> |
dschulze@4598 | 917 | </defs> |
dschulze@4598 | 918 | |
dschulze@4598 | 919 | <rect width="100" height="100" fill="url(#pattern-1)" /> |
dschulze@4598 | 920 | </svg></pre> |
dschulze@4598 | 921 | |
dschulze@4598 | 922 | <p> |
dschulze@4601 | 923 | A SVG 'pattern' element doesn't have an object bounding box. Therefore the relative values of the |
dschulze@4602 | 924 | '<code class="property">transform-origin</code>' property don't affect the rendering and are treated |
dschulze@4602 | 925 | as if zero was specified. The translation on the '<code class="property">transform</code>' property is in |
dschulze@4598 | 926 | absolute coordinates and translate the coordinate system by 50 pixel in each direction. |
dschulze@4598 | 927 | </p> |
dschulze@4598 | 928 | </div> |
dschulze@4598 | 929 | |
dschulze@4602 | 930 | <h3 id="transform-attribute-dom">SVG DOM interface for the '<code class="property">transform</code>' attribute</h3> |
dschulze@4598 | 931 | |
dschulze@4598 | 932 | <p> |
dschulze@4601 | 933 | The SVG specification defines the |
dschulze@4602 | 934 | '<a href="http://www.w3.org/TR/2011/REC-SVG11-20110816/coords.html#InterfaceSVGAnimatedTransformList"><code class="property">SVGAnimatedTransformList</code></a>' |
dschulze@4601 | 935 | interface in SVG DOM to access the animated and the base value of the SVG transform attribute. To ensure backwards compatibility, |
dschulze@4601 | 936 | this API must still be supported by user agents. |
dschulze@4598 | 937 | </p> |
dschulze@4598 | 938 | |
dschulze@4601 | 939 | <p> |
dschulze@4602 | 940 | The '<code class="property">transform</code>' property contributes to the CSS cascade. According to SVG 1.1 user agents conceptually insert a |
dschulze@4601 | 941 | <a href="http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes">new author |
dschulze@4601 | 942 | style sheet</a> for presentation attributes, which is the first in the author style sheet collection. |
dschulze@4602 | 943 | '<code class="property">baseVal</code>' gives the author the possibility to access and modify the values of the SVG '<code class="property">transform</code>' attribute. |
dschulze@4602 | 944 | To provide the necessary backward compatibility to SVG DOM, '<code class="property">baseVal</code>' must reflect the values of this author style sheet. |
dschulze@4602 | 945 | All modifications to SVG DOM objects of '<code class="property">baseVal</code>' must affect this author style sheet immediately. |
dschulze@4601 | 946 | </p> |
dschulze@4601 | 947 | |
dschulze@4601 | 948 | <p> |
dschulze@4602 | 949 | '<code class="property">animVal</code>' represents the computed style of the '<code class="property">transform</code>' property. Therefore it includes all applied |
dschulze@4601 | 950 | <a href="http://www.w3.org/TR/css3-transitions/">CSS3 Transitions</a>, <a href="http://www.w3.org/TR/css3-animations/">CSS3 |
dschulze@4601 | 951 | Animations</a> or <a href="#svg-animation">SVG Animations</a> if any of those are underway. The computed style and SVG DOM |
dschulze@4602 | 952 | objects of '<code class="property">animVal</code>' can not be modified. |
dschulze@4601 | 953 | </p> |
dschulze@4601 | 954 | |
dschulze@4601 | 955 | <p> |
dschulze@4602 | 956 | The attribute '<a href="http://www.w3.org/TR/SVG/coords.html#__svg__SVGTransform__type"><code class="property">type</code></a>' of |
dschulze@4602 | 957 | <a href="http://www.w3.org/TR/SVG/coords.html#InterfaceSVGTransform">'SVGTransform'</a> |
dschulze@4602 | 958 | must return '<a href="http://www.w3.org/TR/SVG/coords.html#__svg__SVGTransform__SVG_TRANSFORM_UNKNOWN"> |
dschulze@4602 | 959 | <code class="css">SVG_TRANSFORM_UNKNOWN</code></a>' for <a href="#transformation-functions">Transformation Functions</a> or unit types that |
dschulze@4601 | 960 | are not supported by this interface. It might still be possible to get the |
dschulze@4602 | 961 | '<a href="http://www.w3.org/TR/SVG/coords.html#InterfaceSVGMatrix"><code class="property">SVGMatrix</code></a>' by the attribute |
dschulze@4602 | 962 | '<a href="http://www.w3.org/TR/SVG/coords.html#__svg__SVGTransform__matrix"><code class="property">matrix</code></a>'. |
dschulze@4601 | 963 | </p> |
vhardy@3672 | 964 | |
dschulze@4598 | 965 | <h3 id="svg-animation">SVG Animation</h3> |
vhardy@3672 | 966 | |
dschulze@4598 | 967 | <h4 id="svg-animate-element">The SVG 'animate' and 'set' element</h4> |
dschulze@4598 | 968 | |
dschulze@4598 | 969 | <p> |
dschulze@4602 | 970 | The SVG 1.1 specification did not define animations of the '<code class="property">transform</code>' attribute for the SVG |
dschulze@4601 | 971 | <a href="http://www.w3.org/TR/SVG/animate.html#AnimateElement">'animate'</a> element or the SVG |
dschulze@4601 | 972 | <a href="http://www.w3.org/TR/SVG/animate.html#SetElement">'set'</a> element. |
dschulze@4602 | 973 | This specification explicitly allows the animation of the presentation attributes '<code class="property">transform</code>', 'gradientTransform' and 'patternTransform' |
dschulze@4598 | 974 | for the 'animate' and 'set' elements. SVG animation must run the same animation steps as described in section |
dschulze@4598 | 975 | <a href="#animation">Transitions and Animations between Transform Values</a>. |
dschulze@4598 | 976 | </p> |
dschulze@4598 | 977 | |
dschulze@4598 | 978 | <h4 id="svg-attribute-name">The SVG 'attributeName' attribute</h4> |
dschulze@4598 | 979 | |
dschulze@4598 | 980 | <p> |
dschulze@4598 | 981 | <a href="http://www.w3.org/TR/SVG/animate.html">SVG 1.1 Animation</a> defines the <a href="http://www.w3.org/TR/SVG/animate.html#TargetAttributes">'attributeName'</a> attribute to specify the |
dschulze@4598 | 982 | name of the target attribute. For the presentation attributes 'gradientTransform' and 'patternTransform' it will also be possible to use |
dschulze@4602 | 983 | the value '<code class="property">transform</code>'. The same presentation attribute style will get animated. |
dschulze@4598 | 984 | </p> |
dschulze@4598 | 985 | |
dschulze@4598 | 986 | <div class="example"> |
dschulze@4598 | 987 | <p> |
dschulze@4598 | 988 | In this example the gradient transformation of the linear gradient gets animated. |
dschulze@4598 | 989 | </p> |
dschulze@4598 | 990 | |
dschulze@4598 | 991 | <pre><linearGradient gradientTransform="scale(2)"> |
dschulze@4598 | 992 | <animate attributeName="gradientTransform" from="scale(2)" to="scale(4)" |
dschulze@4598 | 993 | dur="3s" additive="sum"/> |
dschulze@4598 | 994 | <animate attributeName="transform" from="translate(0, 0)" to="translate(100px, 100px)" |
dschulze@4598 | 995 | dur="3s" additive="sum"/> |
dschulze@4598 | 996 | </linearGradient></pre> |
dschulze@4598 | 997 | |
dschulze@4598 | 998 | <p>The 'linearGradient' element specifies the 'gradientTransform' presentation attribute. The two 'animate' elements address the target attribute |
dschulze@4602 | 999 | 'gradientTransform' and '<code class="property">transform</code>'. Even so all animations apply to the same gradient transformation by taking the value of the 'gradientTransform' |
dschulze@4598 | 1000 | presentation attribute, applying the scaling of the first animation and applying the translation of the second animation one after the other.</p> |
vhardy@3672 | 1001 | </div> |
vhardy@3672 | 1002 | |
dschulze@4598 | 1003 | <h4 id="svg-attribute-type">The SVG 'attributeType' attribute</h4> |
dschulze@4598 | 1004 | |
dschulze@4598 | 1005 | <p> |
dschulze@4598 | 1006 | <a href="http://www.w3.org/TR/SVG/animate.html">SVG 1.1 Animation</a> defines the <a href="http://www.w3.org/TR/SVG/animate.html#TargetAttributes">'attributeType'</a> attribute to specify the |
dschulze@4602 | 1007 | namespace in which the target attribute and its associated values are defined. The attribute can have the values '<code class="css">CSS</code>', '<code class="css">XML</code>' or |
dschulze@4602 | 1008 | '<code class="css">auto</code>', where '<code class="css">auto</code>' is the default value. |
dschulze@4598 | 1009 | </p> |
dschulze@4598 | 1010 | |
dschulze@4598 | 1011 | <p> |
dschulze@4602 | 1012 | However, in the combination with the '<code class="property">transform</code>', 'patternTransform' and 'gradientTransform' presentation attributes, 'attributeType' |
dschulze@4602 | 1013 | can just be used to indicate the syntax rules used for the transform attribute values. A value of '<code class="css">CSS</code>' indicates that the transform values should |
dschulze@4602 | 1014 | be parsed according to the CSS syntax. A value of '<code class="css">XML</code>' indicates that the transform values should be parsed according to the |
dschulze@4602 | 1015 | SVG '<code class="property">transform</code>' <a href="#svg-syntax">syntax</a>. |
dschulze@4598 | 1016 | </p> |
dschulze@4598 | 1017 | |
dschulze@4598 | 1018 | <p> |
dschulze@4602 | 1019 | User agents are recommended to use the more tolerant SVG '<code class="property">transform</code>' <a href="#svg-syntax">syntax</a> for a value of '<code class="css">auto</code>' to parse transform values. |
dschulze@4598 | 1020 | </p> |
dschulze@4598 | 1021 | |
dschulze@4598 | 1022 | <h4 id="svg-animateTransform-extension">The SVG 'animateTransform' element</h4> |
dschulze@4598 | 1023 | |
dschulze@4598 | 1024 | <p> |
dschulze@4601 | 1025 | This specification introduces new transform functions that are not supported by <a href="http://www.w3.org/TR/SVG/animate.html">SVG 1.1 Animation</a>. The |
dschulze@4602 | 1026 | SVG '<a href="http://www.w3.org/TR/SVG/animate.html#AnimateTransformElement"><code class="property">type</code></a>' attribute gets extended by all |
dschulze@4601 | 1027 | transform functions listed in <a href="#two-d-transform-functions">2D Transformation Functions</a>, |
dschulze@4598 | 1028 | <a href="#three-d-transform-functions">3D Transformation Functions</a> and <a href="#svg-transformation-functions">SVG |
dschulze@4598 | 1029 | Transformation Functions</a>. |
dschulze@4598 | 1030 | </p> |
dschulze@4598 | 1031 | |
simon@4345 | 1032 | <!-- ======================================================================================================= --> |
simon@4345 | 1033 | |
vhardy@3672 | 1034 | <h2 id="transform-origin-property"> |
dschulze@4602 | 1035 | The '<code class="property">transform-origin</code>' Property |
vhardy@3672 | 1036 | </h2> |
vhardy@3672 | 1037 | <table class="propdef"> |
vhardy@3672 | 1038 | <tbody> |
vhardy@3672 | 1039 | <tr> |
vhardy@3672 | 1040 | <td> |
vhardy@3672 | 1041 | <em>Name:</em> |
vhardy@3672 | 1042 | </td> |
vhardy@3672 | 1043 | <td> |
vhardy@3672 | 1044 | <dfn id="transform-origin">transform-origin</dfn> |
vhardy@3672 | 1045 | </td> |
vhardy@3672 | 1046 | </tr> |
vhardy@3672 | 1047 | <tr> |
vhardy@3672 | 1048 | <td> |
vhardy@3672 | 1049 | <em>Value:</em> |
vhardy@3672 | 1050 | </td> |
vhardy@3672 | 1051 | <td> |
ayg@4703 | 1052 | [ <percentage> | <length> | left | center | right | top | bottom]<br> |
ayg@4703 | 1053 | |<br> |
ayg@4703 | 1054 | [<br> |
ayg@4703 | 1055 | [ <percentage> | <length> | left | center | right ]<br> |
ayg@4703 | 1056 | &&<br> |
ayg@4703 | 1057 | [ <percentage> | <length> | top | center | bottom ]<br> |
ayg@4703 | 1058 | ] <length>?<br> |
vhardy@3672 | 1059 | </td> |
vhardy@3672 | 1060 | </tr> |
vhardy@3672 | 1061 | <tr> |
vhardy@3672 | 1062 | <td> |
vhardy@3672 | 1063 | <em>Initial:</em> |
vhardy@3672 | 1064 | </td> |
vhardy@3672 | 1065 | <td> |
dschulze@4483 | 1066 | 0 0 for SVG elements without associated CSS layout box, 50% 50% for all other elements |
vhardy@3672 | 1067 | </td> |
vhardy@3672 | 1068 | </tr> |
vhardy@3672 | 1069 | <tr> |
vhardy@3672 | 1070 | <td> |
vhardy@3672 | 1071 | <em>Applies to:</em> |
vhardy@3672 | 1072 | </td> |
vhardy@3672 | 1073 | <td> |
simon@4366 | 1074 | <a href="#TermTransformableElement">transformable elements</a> |
vhardy@3672 | 1075 | </td> |
vhardy@3672 | 1076 | </tr> |
vhardy@3672 | 1077 | <tr> |
vhardy@3672 | 1078 | <td> |
vhardy@3672 | 1079 | <em>Inherited:</em> |
vhardy@3672 | 1080 | </td> |
vhardy@3672 | 1081 | <td> |
vhardy@3672 | 1082 | no |
vhardy@3672 | 1083 | </td> |
vhardy@3672 | 1084 | </tr> |
vhardy@3672 | 1085 | <tr> |
vhardy@3672 | 1086 | <td> |
vhardy@3672 | 1087 | <em>Percentages:</em> |
vhardy@3672 | 1088 | </td> |
vhardy@3672 | 1089 | <td> |
dschulze@4483 | 1090 | refer to the size of the element's bounding box |
vhardy@3672 | 1091 | </td> |
vhardy@3672 | 1092 | </tr> |
vhardy@3672 | 1093 | <tr> |
vhardy@3672 | 1094 | <td> |
vhardy@3672 | 1095 | <em>Media:</em> |
vhardy@3672 | 1096 | </td> |
vhardy@3672 | 1097 | <td> |
vhardy@3672 | 1098 | visual |
vhardy@3672 | 1099 | </td> |
vhardy@3672 | 1100 | </tr> |
vhardy@3672 | 1101 | <tr> |
vhardy@3672 | 1102 | <td> |
vhardy@3672 | 1103 | <em>Computed value:</em> |
vhardy@3672 | 1104 | </td> |
vhardy@3672 | 1105 | <td> |
vhardy@3672 | 1106 | For <length> the absolute value, otherwise a percentage |
vhardy@3672 | 1107 | </td> |
vhardy@3672 | 1108 | </tr> |
vhardy@3672 | 1109 | </tbody> |
vhardy@3672 | 1110 | </table> |
simon@4366 | 1111 | |
simon@4366 | 1112 | <p> |
dschulze@4602 | 1113 | The values of the '<code class="property">transform</code>' and |
dschulze@4602 | 1114 | '<code class="property">transform-origin</code>' properties are used to compute the |
simon@4366 | 1115 | <a href="#TermTransformationMatrix"><i>transformation matrix</i></a>, as described above. |
simon@4366 | 1116 | </p> |
simon@4366 | 1117 | |
simon@4366 | 1118 | <p>If only one value is specified, the second value is assumed to be |
ayg@4703 | 1119 | 'center'. If one or two values are specified, the third value is |
ayg@4703 | 1120 | assumed to be '0px'. |
dschulze@4483 | 1121 | </p> |
dschulze@4483 | 1122 | |
ayg@4703 | 1123 | <p>If at least one of the first two values is not a keyword, then |
ayg@4703 | 1124 | the first value represents the horizontal position (or offset) |
ayg@4703 | 1125 | and the second represents the vertical position (or offset). The |
ayg@4703 | 1126 | third value always represents the Z position (or offset). |
ayg@4703 | 1127 | </p> |
ayg@4703 | 1128 | |
ayg@4703 | 1129 | <p><var><percentage></var> and <var><length></var> |
ayg@4703 | 1130 | for the first two values represent an offset of the transform |
ayg@4703 | 1131 | origin from the top left corner of the element's bounding box. |
ayg@4703 | 1132 | </p> |
ayg@4703 | 1133 | |
dschulze@4483 | 1134 | <p>For SVG elements without an associated CSS layout box the <var><length></var> |
dschulze@4483 | 1135 | values represent an offset from the point of origin of the element's local coordinate space. |
dschulze@4483 | 1136 | </p> |
simon@4366 | 1137 | |
simon@4345 | 1138 | <!-- ======================================================================================================= --> |
simon@4345 | 1139 | |
simon@4345 | 1140 | <h2 id="transform-style-property"> |
dschulze@4602 | 1141 | The '<code class="property">transform-style</code>' Property |
simon@4345 | 1142 | </h2> |
simon@4345 | 1143 | <table class="propdef"> |
simon@4345 | 1144 | <tbody> |
simon@4345 | 1145 | <tr> |
simon@4345 | 1146 | <td> |
simon@4345 | 1147 | <em>Name:</em> |
simon@4345 | 1148 | </td> |
simon@4345 | 1149 | <td> |
simon@4345 | 1150 | <dfn id="transform-style">transform-style</dfn> |
simon@4345 | 1151 | </td> |
simon@4345 | 1152 | </tr> |
simon@4345 | 1153 | <tr> |
simon@4345 | 1154 | <td> |
simon@4345 | 1155 | <em>Value:</em> |
simon@4345 | 1156 | </td> |
simon@4345 | 1157 | <td> |
simon@4345 | 1158 | flat | preserve-3d |
simon@4345 | 1159 | </td> |
simon@4345 | 1160 | </tr> |
simon@4345 | 1161 | <tr> |
simon@4345 | 1162 | <td> |
simon@4345 | 1163 | <em>Initial:</em> |
simon@4345 | 1164 | </td> |
simon@4345 | 1165 | <td> |
simon@4345 | 1166 | flat |
simon@4345 | 1167 | </td> |
simon@4345 | 1168 | </tr> |
simon@4345 | 1169 | <tr> |
simon@4345 | 1170 | <td> |
simon@4345 | 1171 | <em>Applies to:</em> |
simon@4345 | 1172 | </td> |
simon@4345 | 1173 | <td> |
simon@4345 | 1174 | <a href="#TermTransformableElement">transformable elements</a> |
simon@4345 | 1175 | </td> |
simon@4345 | 1176 | </tr> |
simon@4345 | 1177 | <tr> |
simon@4345 | 1178 | <td> |
simon@4345 | 1179 | <em>Inherited:</em> |
simon@4345 | 1180 | </td> |
simon@4345 | 1181 | <td> |
simon@4345 | 1182 | no |
simon@4345 | 1183 | </td> |
simon@4345 | 1184 | </tr> |
simon@4345 | 1185 | <tr> |
simon@4345 | 1186 | <td> |
simon@4345 | 1187 | <em>Percentages:</em> |
simon@4345 | 1188 | </td> |
simon@4345 | 1189 | <td> |
simon@4345 | 1190 | N/A |
simon@4345 | 1191 | </td> |
simon@4345 | 1192 | </tr> |
simon@4345 | 1193 | <tr> |
simon@4345 | 1194 | <td> |
simon@4345 | 1195 | <em>Media:</em> |
simon@4345 | 1196 | </td> |
simon@4345 | 1197 | <td> |
simon@4345 | 1198 | visual |
simon@4345 | 1199 | </td> |
simon@4345 | 1200 | </tr> |
simon@4345 | 1201 | <tr> |
simon@4345 | 1202 | <td> |
simon@4345 | 1203 | <em>Computed value:</em> |
simon@4345 | 1204 | </td> |
simon@4345 | 1205 | <td> |
simon@4345 | 1206 | Same as specified value. |
simon@4345 | 1207 | </td> |
simon@4345 | 1208 | </tr> |
simon@4345 | 1209 | </tbody> |
simon@4345 | 1210 | </table> |
simon@4345 | 1211 | |
simon@4345 | 1212 | <p> |
dschulze@4602 | 1213 | A value of '<code class="css">preserve-3d</code>' for '<code class="property">transform-style</code>' |
simon@4345 | 1214 | establishes a stacking context. |
simon@4345 | 1215 | </p> |
simon@4345 | 1216 | |
simon@4345 | 1217 | <p> |
simon@4345 | 1218 | The following CSS property values require the user agent to create a flattened representation of |
simon@4345 | 1219 | the descendant elements before they can be applied, and therefore override the behavior of |
dschulze@4602 | 1220 | '<code class="property">transform-style</code>': '<code class="css">preserve-3d</code>': |
simon@4345 | 1221 | <ul> |
dschulze@4602 | 1222 | <li>'<code class="property">overflow</code>': any value other than '<code class="property">visible</code>'.</li> |
dschulze@4602 | 1223 | <li>'<code class="property">opacity</code>': any value other than 1.</li> |
dschulze@4602 | 1224 | <li>'<code class="property">filter</code>': any value other than '<code class="property">none</code>'.</li> |
simon@4345 | 1225 | <!-- Others? --> |
simon@4345 | 1226 | </ul> |
simon@4345 | 1227 | </p> |
simon@4366 | 1228 | <div class="issue"> |
simon@4366 | 1229 | <p class="desc">Should this affect the computed value of transform-style?</p> |
simon@4366 | 1230 | </div> |
simon@4366 | 1231 | <p> |
dschulze@4602 | 1232 | The values of the '<code class="property">transform</code>' and |
dschulze@4602 | 1233 | '<code class="property">transform-origin</code>' properties are used to compute the |
simon@4366 | 1234 | <a href="#TermTransformationMatrix"><i>transformation matrix</i></a>, as described above. |
simon@4366 | 1235 | </p> |
simon@4345 | 1236 | |
simon@4345 | 1237 | <!-- ======================================================================================================= --> |
simon@4345 | 1238 | |
simon@4345 | 1239 | <h2 id="perspective-property"> |
dschulze@4602 | 1240 | The '<code class="property">perspective</code>' Property |
simon@4345 | 1241 | </h2> |
simon@4345 | 1242 | <table class="propdef"> |
simon@4345 | 1243 | <tbody> |
simon@4345 | 1244 | <tr> |
simon@4345 | 1245 | <td> |
simon@4345 | 1246 | <em>Name:</em> |
simon@4345 | 1247 | </td> |
simon@4345 | 1248 | <td> |
simon@4345 | 1249 | <dfn id="perspective">perspective</dfn> |
simon@4345 | 1250 | </td> |
simon@4345 | 1251 | </tr> |
simon@4345 | 1252 | <tr> |
simon@4345 | 1253 | <td> |
simon@4345 | 1254 | <em>Value:</em> |
simon@4345 | 1255 | </td> |
simon@4345 | 1256 | <td> |
simon@4345 | 1257 | none | <length> |
simon@4345 | 1258 | </td> |
simon@4345 | 1259 | </tr> |
simon@4345 | 1260 | <tr> |
simon@4345 | 1261 | <td> |
simon@4345 | 1262 | <em>Initial:</em> |
simon@4345 | 1263 | </td> |
simon@4345 | 1264 | <td> |
simon@4345 | 1265 | none |
simon@4345 | 1266 | </td> |
simon@4345 | 1267 | </tr> |
simon@4345 | 1268 | <tr> |
simon@4345 | 1269 | <td> |
simon@4345 | 1270 | <em>Applies to:</em> |
simon@4345 | 1271 | </td> |
simon@4345 | 1272 | <td> |
simon@4345 | 1273 | <a href="#TermTransformableElement">transformable elements</a> |
simon@4345 | 1274 | </td> |
simon@4345 | 1275 | </tr> |
simon@4345 | 1276 | <tr> |
simon@4345 | 1277 | <td> |
simon@4345 | 1278 | <em>Inherited:</em> |
simon@4345 | 1279 | </td> |
simon@4345 | 1280 | <td> |
simon@4345 | 1281 | no |
simon@4345 | 1282 | </td> |
simon@4345 | 1283 | </tr> |
simon@4345 | 1284 | <tr> |
simon@4345 | 1285 | <td> |
simon@4345 | 1286 | <em>Percentages:</em> |
simon@4345 | 1287 | </td> |
simon@4345 | 1288 | <td> |
simon@4345 | 1289 | N/A |
simon@4345 | 1290 | </td> |
simon@4345 | 1291 | </tr> |
simon@4345 | 1292 | <tr> |
simon@4345 | 1293 | <td> |
simon@4345 | 1294 | <em>Media:</em> |
simon@4345 | 1295 | </td> |
simon@4345 | 1296 | <td> |
simon@4345 | 1297 | visual |
simon@4345 | 1298 | </td> |
simon@4345 | 1299 | </tr> |
simon@4345 | 1300 | <tr> |
simon@4345 | 1301 | <td> |
simon@4345 | 1302 | <em>Computed value:</em> |
simon@4345 | 1303 | </td> |
simon@4345 | 1304 | <td> |
simon@4345 | 1305 | Same as specified value. |
simon@4345 | 1306 | </td> |
simon@4345 | 1307 | </tr> |
simon@4345 | 1308 | </tbody> |
simon@4345 | 1309 | </table> |
simon@4345 | 1310 | |
simon@4345 | 1311 | <p> |
dschulze@4602 | 1312 | If the value is '<code class="css">none</code>', less than or equal to 0 no |
simon@4365 | 1313 | perspective transform is applied. |
simon@4345 | 1314 | </p> |
simon@4345 | 1315 | <p> |
dschulze@4602 | 1316 | The use of this property with any value other than '<code class="css">none</code>' establishes a |
simon@4345 | 1317 | stacking context. It also establishes a containing block (somewhat |
dschulze@4602 | 1318 | similar to '<code class="css">position: relative</code>'), just like the '<code class="property">transform</code>' property does. |
simon@4345 | 1319 | </p> |
simon@4366 | 1320 | <p> |
dschulze@4602 | 1321 | The values of the '<code class="property">perspective</code>' and '<code class="property">perspective-origin</code>' |
simon@4366 | 1322 | properties are used to compute the <a href="#TermPerspectiveMatrix"><i>perspective matrix</i></a>, as described above. |
simon@4366 | 1323 | </p> |
simon@4345 | 1324 | |
simon@4345 | 1325 | <!-- ======================================================================================================= --> |
simon@4345 | 1326 | |
simon@4345 | 1327 | <h2 id="perspective-origin-property"> |
dschulze@4602 | 1328 | The '<code class="property">perspective-origin</code>' Property |
simon@4345 | 1329 | </h2> |
simon@4345 | 1330 | <p> |
dschulze@4602 | 1331 | The '<code class="property">perspective-origin</code>' property |
simon@4345 | 1332 | establishes the origin for the <em>perspective</em> property. It |
simon@4345 | 1333 | effectively sets the X and Y position at which the viewer appears to be |
simon@4345 | 1334 | looking at the children of the element. |
simon@4345 | 1335 | </p> |
simon@4345 | 1336 | <table class="propdef"> |
simon@4345 | 1337 | <tbody> |
simon@4345 | 1338 | <tr> |
simon@4345 | 1339 | <td> |
simon@4345 | 1340 | <em>Name:</em> |
simon@4345 | 1341 | </td> |
simon@4345 | 1342 | <td> |
simon@4345 | 1343 | <dfn id="perspective-origin">perspective-origin</dfn> |
simon@4345 | 1344 | </td> |
simon@4345 | 1345 | </tr> |
simon@4345 | 1346 | <tr> |
simon@4345 | 1347 | <td> |
simon@4345 | 1348 | <em>Value:</em> |
simon@4345 | 1349 | </td> |
simon@4345 | 1350 | <td> |
simon@4345 | 1351 | [ [ <percentage> | <length> | left | center | right ] [ |
simon@4345 | 1352 | <percentage> | <length> | top | center | bottom ]? ] | [ [ left | |
simon@4345 | 1353 | center | right ] || [ top | center | bottom ] ] |
simon@4345 | 1354 | </td> |
simon@4345 | 1355 | </tr> |
simon@4345 | 1356 | <tr> |
simon@4345 | 1357 | <td> |
simon@4345 | 1358 | <em>Initial:</em> |
simon@4345 | 1359 | </td> |
simon@4345 | 1360 | <td> |
simon@4345 | 1361 | 50% 50% |
simon@4345 | 1362 | </td> |
simon@4345 | 1363 | </tr> |
simon@4345 | 1364 | <tr> |
simon@4345 | 1365 | <td> |
simon@4345 | 1366 | <em>Applies to:</em> |
simon@4345 | 1367 | </td> |
simon@4345 | 1368 | <td> |
simon@4345 | 1369 | <a href="#TermTransformableElement">transformable elements</a> |
simon@4345 | 1370 | </td> |
simon@4345 | 1371 | </tr> |
simon@4345 | 1372 | <tr> |
simon@4345 | 1373 | <td> |
simon@4345 | 1374 | <em>Inherited:</em> |
simon@4345 | 1375 | </td> |
simon@4345 | 1376 | <td> |
simon@4345 | 1377 | no |
simon@4345 | 1378 | </td> |
simon@4345 | 1379 | </tr> |
simon@4345 | 1380 | <tr> |
simon@4345 | 1381 | <td> |
simon@4345 | 1382 | <em>Percentages:</em> |
simon@4345 | 1383 | </td> |
simon@4345 | 1384 | <td> |
dschulze@4483 | 1385 | refer to the size of the element's bounding box |
simon@4345 | 1386 | </td> |
simon@4345 | 1387 | </tr> |
simon@4345 | 1388 | <tr> |
simon@4345 | 1389 | <td> |
simon@4345 | 1390 | <em>Media:</em> |
simon@4345 | 1391 | </td> |
simon@4345 | 1392 | <td> |
simon@4345 | 1393 | visual |
simon@4345 | 1394 | </td> |
simon@4345 | 1395 | </tr> |
simon@4345 | 1396 | <tr> |
simon@4345 | 1397 | <td> |
simon@4345 | 1398 | <em>Computed value:</em> |
simon@4345 | 1399 | </td> |
simon@4345 | 1400 | <td> |
simon@4345 | 1401 | Same as specified value. |
simon@4345 | 1402 | </td> |
simon@4345 | 1403 | </tr> |
simon@4345 | 1404 | </tbody> |
simon@4345 | 1405 | </table> |
simon@4365 | 1406 | <p> |
dschulze@4602 | 1407 | The values of the '<code class="property">perspective</code>' and '<code class="property">perspective-origin</code>' |
simon@4366 | 1408 | properties are used to compute the <a href="#TermPerspectiveMatrix"><i>perspective matrix</i></a>, as described above. |
simon@4365 | 1409 | </p> |
simon@4345 | 1410 | |
simon@4345 | 1411 | <!-- ======================================================================================================= --> |
simon@4345 | 1412 | |
simon@4345 | 1413 | <h2 id="backface-visibility-property"> |
dschulze@4602 | 1414 | The '<code class="property">backface-visibility</code>' Property |
simon@4345 | 1415 | </h2> |
simon@4345 | 1416 | <p> |
dschulze@4602 | 1417 | The '<code class="property">backface-visibility</code>' property |
simon@4345 | 1418 | determines whether or not the "back" side of a transformed element is |
simon@4345 | 1419 | visible when facing the viewer. With an identity transform, the front |
simon@4345 | 1420 | side of an element faces the viewer. Applying a rotation about Y of 180 |
simon@4345 | 1421 | degrees (for instance) would cause the back side of the element to face |
simon@4345 | 1422 | the viewer. |
simon@4345 | 1423 | </p> |
simon@4345 | 1424 | <!-- This should not be in a normative section. --> |
simon@4345 | 1425 | <p> |
simon@4345 | 1426 | This property is useful when you place two elements back-to-back, as you |
simon@4345 | 1427 | would to create a playing card. Without this property, the front and |
simon@4345 | 1428 | back elements could switch places at times during an animation to flip |
simon@4345 | 1429 | the card. Another example is creating a box out of 6 elements, but where |
simon@4345 | 1430 | you want to see the inside faces of the box. This is useful when |
simon@4345 | 1431 | creating the backdrop for a 3 dimensional stage. |
simon@4345 | 1432 | </p> |
simon@4345 | 1433 | <table class="propdef"> |
simon@4345 | 1434 | <tbody> |
simon@4345 | 1435 | <tr> |
simon@4345 | 1436 | <td> |
simon@4345 | 1437 | <em>Name:</em> |
simon@4345 | 1438 | </td> |
simon@4345 | 1439 | <td> |
simon@4345 | 1440 | <dfn id="backface-visibility">backface-visibility</dfn> |
simon@4345 | 1441 | </td> |
simon@4345 | 1442 | </tr> |
simon@4345 | 1443 | <tr> |
simon@4345 | 1444 | <td> |
simon@4345 | 1445 | <em>Value:</em> |
simon@4345 | 1446 | </td> |
simon@4345 | 1447 | <td> |
simon@4345 | 1448 | visible | hidden |
simon@4345 | 1449 | </td> |
simon@4345 | 1450 | </tr> |
simon@4345 | 1451 | <tr> |
simon@4345 | 1452 | <td> |
simon@4345 | 1453 | <em>Initial:</em> |
simon@4345 | 1454 | </td> |
simon@4345 | 1455 | <td> |
simon@4345 | 1456 | visible |
simon@4345 | 1457 | </td> |
simon@4345 | 1458 | </tr> |
simon@4345 | 1459 | <tr> |
simon@4345 | 1460 | <td> |
simon@4345 | 1461 | <em>Applies to:</em> |
simon@4345 | 1462 | </td> |
simon@4345 | 1463 | <td> |
simon@4366 | 1464 | <a href="#TermTransformableElement">transformable elements</a> |
simon@4345 | 1465 | </td> |
simon@4345 | 1466 | </tr> |
simon@4345 | 1467 | <tr> |
simon@4345 | 1468 | <td> |
simon@4345 | 1469 | <em>Inherited:</em> |
simon@4345 | 1470 | </td> |
simon@4345 | 1471 | <td> |
simon@4345 | 1472 | no |
simon@4345 | 1473 | </td> |
simon@4345 | 1474 | </tr> |
simon@4345 | 1475 | <tr> |
simon@4345 | 1476 | <td> |
simon@4345 | 1477 | <em>Percentages:</em> |
simon@4345 | 1478 | </td> |
simon@4345 | 1479 | <td> |
simon@4345 | 1480 | N/A |
simon@4345 | 1481 | </td> |
simon@4345 | 1482 | </tr> |
simon@4345 | 1483 | <tr> |
simon@4345 | 1484 | <td> |
simon@4345 | 1485 | <em>Media:</em> |
simon@4345 | 1486 | </td> |
simon@4345 | 1487 | <td> |
simon@4345 | 1488 | visual |
simon@4345 | 1489 | </td> |
simon@4345 | 1490 | </tr> |
simon@4345 | 1491 | <tr> |
simon@4345 | 1492 | <td> |
simon@4345 | 1493 | <em>Computed value:</em> |
simon@4345 | 1494 | </td> |
simon@4345 | 1495 | <td> |
simon@4345 | 1496 | Same as specified value. |
simon@4345 | 1497 | </td> |
simon@4345 | 1498 | </tr> |
simon@4345 | 1499 | </tbody> |
simon@4345 | 1500 | </table> |
simon@4367 | 1501 | <p> |
dschulze@4602 | 1502 | The visibility of an element with '<code class="css">backface-visibility: hidden</code>' is determined |
simon@4367 | 1503 | as follows: |
simon@4367 | 1504 | <ol> |
simon@4367 | 1505 | <li>Compute a matrix representing the accumulated transform from the viewport, taking the translations |
simon@4376 | 1506 | due to the CSS visual formatting mode, the perpsective and transformation matrices into account, |
simon@4367 | 1507 | in a similar manner to the computation of the accumulated transform for an element in a |
simon@4367 | 1508 | 3D rendering context. |
simon@4367 | 1509 | </li> |
simon@4367 | 1510 | <li> |
simon@4367 | 1511 | If the component of the matrix in row 3, column 3 is negative, then the element should be hidden, |
simon@4367 | 1512 | otherwise it is visible. |
simon@4367 | 1513 | </li> |
simon@4367 | 1514 | </ol> |
simon@4367 | 1515 | <div class="issue"> |
simon@4367 | 1516 | Is the relevant matrix here really relative to the viewport, or to the root of the 3D rendering context? |
simon@4367 | 1517 | </div> |
simon@4367 | 1518 | </p> |
vhardy@3672 | 1519 | |
vhardy@3672 | 1520 | <!-- ======================================================================================================= --> |
vhardy@3672 | 1521 | |
vhardy@3672 | 1522 | <h2 id="transform-functions"> |
vhardy@3672 | 1523 | The Transformation Functions |
vhardy@3672 | 1524 | </h2> |
vhardy@3672 | 1525 | <p> |
simon@4365 | 1526 | The value of the <code class="property">transform</code> property is a |
dschulze@4602 | 1527 | list of <var><transform-functions></var> applied in the order provided. The |
vhardy@3672 | 1528 | individual transform functions are separated by whitespace. The |
vhardy@3672 | 1529 | set of allowed transform functions is given below. In this list the |
dschulze@4602 | 1530 | type <var><translation-value></var> is defined as a <var><length></var> or |
dschulze@4602 | 1531 | <var><percentage></var> value, and the <var><angle></var> type is defined by <a |
dschulze@4598 | 1532 | href="http://www.w3.org/TR/css3-values/">CSS Values and Units Module.</a> |
dschulze@4602 | 1533 | Wherever <var><angle></var> is used in this specification, a <var><number></var> that is equal to |
simon@4334 | 1534 | zero is also allowed, which is treated the same as an angle of zero degrees. |
vhardy@3672 | 1535 | </p> |
simon@4358 | 1536 | |
simon@4358 | 1537 | <h3 id="two-d-transform-functions">2D Transformation Functions</h3> |
vhardy@3672 | 1538 | <dl> |
vhardy@3672 | 1539 | <dt> |
simon@4365 | 1540 | <code class="css">matrix(<number>, <number>, <number>, <number>, <number>, <number>)</code> |
vhardy@3672 | 1541 | </dt> |
vhardy@3672 | 1542 | <dd> |
dschulze@4491 | 1543 | specifies a 2D transformation in the form of a <a href="#MatrixDefined">transformation matrix</a> of the six values a-f. |
vhardy@3672 | 1544 | </dd> |
vhardy@3672 | 1545 | <dt> |
simon@4365 | 1546 | <code class="css">translate(<translation-value>[, <translation-value>])</code> |
vhardy@3672 | 1547 | </dt> |
vhardy@3672 | 1548 | <dd> |
dschulze@4491 | 1549 | 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><ty></em> is not provided, ty has zero as a value. |
vhardy@3672 | 1550 | </dd> |
vhardy@3672 | 1551 | <dt> |
simon@4365 | 1552 | <code class="css">translateX(<translation-value>)</code> |
vhardy@3672 | 1553 | </dt> |
vhardy@3672 | 1554 | <dd> |
dschulze@4491 | 1555 | specifies a <a href="#TranslateDefined">translation</a> by the given amount in the X direction. |
vhardy@3672 | 1556 | </dd> |
vhardy@3672 | 1557 | <dt> |
simon@4365 | 1558 | <code class="css">translateY(<translation-value>)</code> |
vhardy@3672 | 1559 | </dt> |
vhardy@3672 | 1560 | <dd> |
dschulze@4491 | 1561 | specifies a <a href="#TranslateDefined">translation</a> by the given amount in the Y direction. |
vhardy@3672 | 1562 | </dd> |
vhardy@3672 | 1563 | <dt> |
simon@4365 | 1564 | <code class="css">scale(<number>[, <number>])</code> |
vhardy@3672 | 1565 | </dt> |
vhardy@3672 | 1566 | <dd> |
dschulze@4491 | 1567 | 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 is 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 | 1568 | and Y axes, or four times its typical geometric size. |
vhardy@3672 | 1569 | </dd> |
vhardy@3672 | 1570 | <dt> |
simon@4365 | 1571 | <code class="css">scaleX(<number>)</code> |
vhardy@3672 | 1572 | </dt> |
vhardy@3672 | 1573 | <dd> |
dschulze@4491 | 1574 | specifies a <a href="#ScaleDefined">2D scale</a> operation using the [sx,1] scaling vector, where sx is given as the parameter. |
vhardy@3672 | 1575 | </dd> |
vhardy@3672 | 1576 | <dt> |
simon@4365 | 1577 | <code class="css">scaleY(<number>)</code> |
vhardy@3672 | 1578 | </dt> |
vhardy@3672 | 1579 | <dd> |
dschulze@4491 | 1580 | specifies a <a href="#ScaleDefined">2D scale</a> operation using the [1,sy] scaling vector, where sy is given as the parameter. |
vhardy@3672 | 1581 | </dd> |
vhardy@3672 | 1582 | <dt> |
dschulze@4598 | 1583 | <code class="css">rotate(<angle>)</code> |
vhardy@3672 | 1584 | </dt> |
vhardy@3672 | 1585 | <dd> |
dschulze@4598 | 1586 | specifies a <a href="#RotateDefined">2D rotation</a> by the angle specified in the parameter about the origin of the element, as |
dschulze@4602 | 1587 | defined by the '<code class="property">transform-origin</code>' property. For example, '<code class="css">rotate(90deg)</code>' |
dschulze@4602 | 1588 | would cause elements to appear rotated one-quarter of a turn in the clockwise direction. |
vhardy@3672 | 1589 | </dd> |
vhardy@3672 | 1590 | <dt> |
dschulze@4491 | 1591 | <code class="css">skew(<angle>[, <angle>])</code> |
simon@4399 | 1592 | </dt> |
simon@4399 | 1593 | <dd> |
dschulze@4491 | 1594 | specifies a <a href="#SkewDefined">2D skew</a> by [ax,ay] for X and Y. If the second parameter is not provided, it is has a zero value. |
simon@4399 | 1595 | </dd> |
simon@4399 | 1596 | <dt> |
simon@4365 | 1597 | <code class="css">skewX(<angle>)</code> |
vhardy@3672 | 1598 | </dt> |
vhardy@3672 | 1599 | <dd> |
dschulze@4491 | 1600 | specifies a <a href="#SkewDefined">2D skew transformation along the X axis</a> by the given angle. The skew vector is [ax,0]. |
vhardy@3672 | 1601 | </dd> |
vhardy@3672 | 1602 | <dt> |
simon@4365 | 1603 | <code class="css">skewY(<angle>)</code> |
vhardy@3672 | 1604 | </dt> |
vhardy@3672 | 1605 | <dd> |
dschulze@4491 | 1606 | specifies a <a href="#SkewDefined">2D skew transformation along the Y axis</a> by the given angle. The skew vector is [0,ay]. |
vhardy@3672 | 1607 | </dd> |
vhardy@3672 | 1608 | </dl> |
simon@4358 | 1609 | |
simon@4358 | 1610 | |
simon@4358 | 1611 | <h3 id="three-d-transform-functions">3D Transformation Functions</h3> |
simon@4358 | 1612 | <dl> |
simon@4358 | 1613 | <dt> |
simon@4365 | 1614 | <code class="css">matrix3d(<number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>, <number>)</code> |
simon@4358 | 1615 | </dt> |
simon@4358 | 1616 | <dd> |
simon@4358 | 1617 | specifies a 3D transformation as a 4x4 homogeneous matrix of 16 values in column-major order. |
simon@4358 | 1618 | </dd> |
simon@4358 | 1619 | <dt> |
dschulze@4483 | 1620 | <code class="css">translate3d(<translation-value>, <translation-value>, <length>)</code> |
simon@4358 | 1621 | </dt> |
simon@4358 | 1622 | <dd> |
dschulze@4491 | 1623 | 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 | 1624 | </dd> |
simon@4358 | 1625 | <dt> |
dschulze@4483 | 1626 | <code class="css">translateZ(<length>)</code> |
simon@4358 | 1627 | </dt> |
simon@4358 | 1628 | <dd> |
dschulze@4491 | 1629 | specifies a <a href="#Translate3dDefined">3D translation</a> by the vector [0,0,tz] with the given amount in the Z direction. |
simon@4358 | 1630 | </dd> |
simon@4358 | 1631 | <dt> |
simon@4365 | 1632 | <code class="css">scale3d(<number>, <number>, <number>)</code> |
simon@4358 | 1633 | </dt> |
simon@4358 | 1634 | <dd> |
dschulze@4491 | 1635 | specifies a <a href="#Scale3dDefined">3D scale</a> operation by the [sx,sy,sz] scaling vector described by the 3 parameters. |
simon@4358 | 1636 | </dd> |
simon@4358 | 1637 | <dt> |
simon@4365 | 1638 | <code class="css">scaleZ(<number>)</code> |
simon@4358 | 1639 | </dt> |
simon@4358 | 1640 | <dd> |
dschulze@4491 | 1641 | 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 | 1642 | </dd> |
simon@4358 | 1643 | <dt> |
simon@4365 | 1644 | <code class="css">rotate3d(<number>, <number>, <number>, <angle>)</code> |
simon@4358 | 1645 | </dt> |
simon@4358 | 1646 | <div class="todo">Clarify "clockwise". Describe in terms of right-hand rule?</div> |
simon@4358 | 1647 | <dd> |
dschulze@4491 | 1648 | specifies a clockwise <a href="#Rotate3dDefined">3D rotation</a> by the angle specified in last |
simon@4358 | 1649 | parameter about the [x,y,z] direction vector described by the first 3 |
simon@4358 | 1650 | parameters. If the direction vector is not of unit length, it will be |
dschulze@4491 | 1651 | normalized. A direction vector that cannot be normalized, such as [0,0,0], will cause the rotation to not be applied. |
dschulze@4491 | 1652 | </dd> |
simon@4358 | 1653 | <dt> |
simon@4365 | 1654 | <code class="css">rotateX(<angle>)</code> |
simon@4358 | 1655 | </dt> |
simon@4358 | 1656 | <dd> |
dschulze@4491 | 1657 | specifies a clockwise <a href="#RotateXDefined">3D rotation</a> by the given angle about the X axis. |
simon@4358 | 1658 | </dd> |
simon@4358 | 1659 | <dt> |
simon@4365 | 1660 | <code class="css">rotateY(<angle>)</code> |
simon@4358 | 1661 | </dt> |
simon@4358 | 1662 | <dd> |
dschulze@4491 | 1663 | specifies a clockwise <a href="#RotateYDefined">3D rotation</a> by the given angle about the Y axis. |
simon@4358 | 1664 | </dd> |
simon@4358 | 1665 | <dt> |
simon@4365 | 1666 | <code class="css">rotateZ(<angle>)</code> |
simon@4358 | 1667 | </dt> |
simon@4358 | 1668 | <dd> |
dschulze@4491 | 1669 | specifies a clockwise <a href="#RotateZDefined">3D rotation</a> by the given angle about the Z axis. This is a synonym for <code class="css">rotate(<angle>)</code>. |
simon@4358 | 1670 | </dd> |
simon@4577 | 1671 | <dt id="perspective-function"> |
simon@4365 | 1672 | <code class="css">perspective(<length>)</code> |
simon@4358 | 1673 | </dt> |
simon@4358 | 1674 | <dd> |
simon@4700 | 1675 | specifies a <a href="#PerspectiveDefined">perspective projection matrix</a>. This matrix scales points in |
simon@4700 | 1676 | X and Y based on their Z value, scaling points with positive Z values away from the origin, and those with |
simon@4700 | 1677 | negative Z values towards the origin. Points on the z=0 plane are unchanged. The parameter represents the |
simon@4700 | 1678 | distance of the z=0 plane from the viewer. Lower values give a more flattened pyramid and therefore a more |
simon@4700 | 1679 | pronounced perspective effect. For example, a value of 1000px gives a moderate amount of foreshortening |
simon@4700 | 1680 | and a value of 200px gives an extreme amount. The value for depth must be greater than zero, otherwise the |
simon@4700 | 1681 | function is invalid. |
simon@4358 | 1682 | </dd> |
simon@4358 | 1683 | </dl> |
simon@4358 | 1684 | |
simon@4358 | 1685 | <!-- ======================================================================================================= --> |
simon@4358 | 1686 | |
vhardy@3672 | 1687 | <h2 id="transform-values"> |
vhardy@3672 | 1688 | Transform Values and Lists |
vhardy@3672 | 1689 | </h2> |
vhardy@3672 | 1690 | <p> |
vhardy@3672 | 1691 | The <translation-value> values are defined as [<percentage> | <length>]. All other value types are described <a href="http://www.w3.org/TR/REC-CSS2/syndata.html#values">as CSS types</a>. If a list of transforms is provided, then the net effect is as if each transform had been specified separately in the order provided. For example, |
vhardy@3672 | 1692 | </p> |
simon@4358 | 1693 | <pre> |
simon@4358 | 1694 | <div style="transform:translate(-10px,-20px) scale(2) rotate(45deg) translate(5px,10px)"/> |
simon@4358 | 1695 | </pre> |
vhardy@3672 | 1696 | <p> |
vhardy@3672 | 1697 | is functionally equivalent to: |
vhardy@3672 | 1698 | </p> |
simon@4358 | 1699 | <pre> |
simon@4358 | 1700 | <div style="transform:translate(-10px,-20px)"> |
simon@4358 | 1701 | <div style="transform:scale(2)"> |
simon@4358 | 1702 | <div style="transform:rotate(45deg)"> |
simon@4358 | 1703 | <div style="transform:translate(5px,10px)"> |
simon@4358 | 1704 | </div> |
simon@4358 | 1705 | </div> |
simon@4358 | 1706 | </div> |
simon@4358 | 1707 | </div> |
simon@4358 | 1708 | </pre> |
vhardy@3672 | 1709 | <p> |
vhardy@3672 | 1710 | That is, in the absence of other styling that affects position and dimensions, a nested set of transforms is equivalent to a single list of transform functions, applied from the outside in. The resulting transform is the matrix multiplication of the list of transforms. |
vhardy@3672 | 1711 | </p> |
vhardy@3672 | 1712 | <!-- ======================================================================================================= --> |
vhardy@3672 | 1713 | |
vhardy@3672 | 1714 | <h2 id="animation"> |
dschulze@4511 | 1715 | Transitions and Animations between Transform Values |
vhardy@3672 | 1716 | </h2> |
vhardy@3672 | 1717 | |
vhardy@3672 | 1718 | <p> |
vhardy@3672 | 1719 | When animating or transitioning the value of a transform property |
vhardy@3672 | 1720 | the rules described below are applied. The 'from' transform is |
vhardy@3672 | 1721 | the transform at the start of the transition or current keyframe. The |
vhardy@3672 | 1722 | 'end' transform is the transform at the end of the transition or |
vhardy@3672 | 1723 | current keyframe. |
vhardy@3672 | 1724 | </p> |
vhardy@3672 | 1725 | |
vhardy@3672 | 1726 | <ul> |
vhardy@3672 | 1727 | <li> |
vhardy@3672 | 1728 | If the 'from' and 'to' transforms are both single functions |
vhardy@3672 | 1729 | of the same type: |
vhardy@3672 | 1730 | <ul> |
vhardy@3672 | 1731 | <li> |
dschulze@4484 | 1732 | For translate, translate3d, translateX, translateY, translateZ, scale, |
dschulze@4484 | 1733 | scale3d, scaleX, scaleY, scaleZ, rotate, rotateX, rotateY, rotateZ, skew, skewX |
dschulze@4484 | 1734 | and skewY functions: |
vhardy@3672 | 1735 | <ul> |
vhardy@3672 | 1736 | <li> |
vhardy@3672 | 1737 | the individual components of the function are |
vhardy@3672 | 1738 | interpolated numerically. |
vhardy@3672 | 1739 | </li> |
vhardy@3672 | 1740 | </ul> |
vhardy@3672 | 1741 | </li> |
vhardy@3672 | 1742 | <li> |
dschulze@4484 | 1743 | For perspective, matrix, matrix3d and rotate3d: |
vhardy@3672 | 1744 | <ul> |
vhardy@3672 | 1745 | <li> |
dschulze@4484 | 1746 | the values are first converted to a 4x4 matrix, then |
vhardy@3672 | 1747 | decomposed using <a |
dschulze@4484 | 1748 | href="#unmatrix">the |
vhardy@3672 | 1749 | method described by unmatrix</a> into separate translation, |
dschulze@4484 | 1750 | scale, rotation, skew and perspective matrices, then each |
vhardy@3672 | 1751 | decomposed matrix is interpolated numerically, and finally |
dschulze@4484 | 1752 | combined in order to produce a resulting 4x4 matrix. |
vhardy@3672 | 1753 | </li> |
vhardy@3672 | 1754 | </ul> |
vhardy@3672 | 1755 | </li> |
vhardy@3672 | 1756 | </ul> |
vhardy@3672 | 1757 | </li> |
vhardy@3672 | 1758 | <li> |
vhardy@3672 | 1759 | If both the 'from' and 'to' transforms are "none": |
vhardy@3672 | 1760 | <ul> |
vhardy@3672 | 1761 | <li> |
vhardy@3672 | 1762 | There is no interpolation necessary |
vhardy@3672 | 1763 | </li> |
vhardy@3672 | 1764 | </ul> |
vhardy@3672 | 1765 | </li> |
vhardy@3672 | 1766 | <li> |
vhardy@3672 | 1767 | If one of the 'from' or 'to' transforms is "none": |
vhardy@3672 | 1768 | <ul> |
vhardy@3672 | 1769 | <li> |
vhardy@3672 | 1770 | The 'none' is replaced by an equivalent identity function list for |
vhardy@3672 | 1771 | the corresponding transform function list. |
vhardy@3672 | 1772 | <p> |
vhardy@3672 | 1773 | For example, if the 'from' transform is "scale(2)" and the 'to' |
vhardy@3672 | 1774 | transform is "none" then the value "scale(1)" will be used as the |
vhardy@3672 | 1775 | 'to' value, and animation will proceed using the rule above. |
vhardy@3672 | 1776 | Similarly, if the 'from' transform is "none" and the 'to' transform |
vhardy@3672 | 1777 | is "scale(2) rotate(50deg)" then the animation will execute as |
vhardy@3672 | 1778 | if the 'from' value is "scale(1) rotate(0)". |
vhardy@3672 | 1779 | </p> |
vhardy@3672 | 1780 | <p> |
dschulze@4484 | 1781 | The identity functions are translate(0), translate3d(0, 0, 0), |
dschulze@4484 | 1782 | translateX(0), translateY(0), translateZ(0), scale(1), scale3d(1, 1, 1), |
dschulze@4484 | 1783 | scaleX(1), scaleY(1), scaleZ(1), rotate(0), rotate3d(1, 1, 1, 0), |
dschulze@4484 | 1784 | rotateX(0), rotateY(0), rotateZ(0), skew(0), skewX(0), skewY(0), |
dschulze@4484 | 1785 | matrix(1, 0, 0, 1, 0, 0) and |
dschulze@4484 | 1786 | matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1). |
vhardy@3672 | 1787 | </p> |
vhardy@3672 | 1788 | </li> |
vhardy@3672 | 1789 | </ul> |
vhardy@3672 | 1790 | </li> |
vhardy@3672 | 1791 | <li> |
vhardy@3672 | 1792 | If both the 'from' and 'to' transforms have the same number of |
vhardy@3672 | 1793 | transform functions and corresponding functions in each transform |
vhardy@3672 | 1794 | list are of the same type: |
vhardy@3672 | 1795 | <ul> |
vhardy@3672 | 1796 | <li> |
vhardy@3672 | 1797 | Each transform function is animated with its corresponding |
vhardy@3672 | 1798 | destination function in isolation using the rules described above. |
dschulze@4484 | 1799 | The individual values are then applied as a list to produce |
vhardy@3672 | 1800 | resulting transform value. |
vhardy@3672 | 1801 | </li> |
vhardy@3672 | 1802 | </ul> |
vhardy@3672 | 1803 | </li> |
vhardy@3672 | 1804 | <li> |
vhardy@3672 | 1805 | Otherwise: |
vhardy@3672 | 1806 | <ul> |
vhardy@3672 | 1807 | <li> |
vhardy@3672 | 1808 | The transform function lists are each converted into the |
dschulze@4484 | 1809 | equivalent matrix3d value and animation proceeds using the rule |
vhardy@3672 | 1810 | for a single function above. |
vhardy@3672 | 1811 | </li> |
vhardy@3672 | 1812 | </ul> |
vhardy@3672 | 1813 | </li> |
vhardy@3672 | 1814 | </ul> |
vhardy@3672 | 1815 | |
vhardy@3672 | 1816 | <p> |
vhardy@3672 | 1817 | In some cases, an animation might cause a transformation matrix to |
vhardy@3672 | 1818 | be singular or non-invertible. For example, an animation in which |
vhardy@3672 | 1819 | scale moves from 1 to -1. At the time when the matrix is in such |
vhardy@3672 | 1820 | a state, the transformed element is not rendered. |
vhardy@3672 | 1821 | </p> |
vhardy@3672 | 1822 | |
vhardy@3672 | 1823 | <h2 id="matrix-decomposition"> |
dschulze@4511 | 1824 | Matrix Decomposition for Animation |
vhardy@3672 | 1825 | </h2> |
vhardy@3672 | 1826 | |
vhardy@3672 | 1827 | <p> |
vhardy@3672 | 1828 | When interpolating between 2 matrices, each is decomposed into the |
dschulze@4484 | 1829 | corresponding translation, rotation, scale, skew and perspective |
vhardy@3672 | 1830 | values. Not all matrices can be accurately described by these values. |
vhardy@3672 | 1831 | Those that can't are decomposed into the most accurate representation |
dschulze@4484 | 1832 | possible, using the technique below. This technique is taken from the |
dschulze@4484 | 1833 | "unmatrix" method in "Graphics Gems II, edited by Jim Arvo". |
dschulze@4493 | 1834 | The pseudocode below works on a 4x4 homogeneous matrix. |
vhardy@3672 | 1835 | </p> |
vhardy@3672 | 1836 | |
vhardy@3672 | 1837 | <h3 id="unmatrix">Unmatrix</h3> |
vhardy@3672 | 1838 | <pre> |
dschulze@4484 | 1839 | Input: matrix ; a 4x4 matrix |
dschulze@4484 | 1840 | Output: translation ; a 3 component vector |
dschulze@4484 | 1841 | rotation ; Euler angles, represented as a 3 component vector |
dschulze@4484 | 1842 | scale ; a 3 component vector |
dschulze@4484 | 1843 | skew ; skew factors XY,XZ,YZ represented as a 3 component vector |
dschulze@4484 | 1844 | perspective ; a 4 component vector |
vhardy@3672 | 1845 | Returns false if the matrix cannot be decomposed, true if it can |
vhardy@3672 | 1846 | |
dschulze@4484 | 1847 | Supporting functions (point is a 3 component vector, matrix is a 4x4 matrix): |
dschulze@4484 | 1848 | double determinant(matrix) returns the 4x4 determinant of the matrix |
dschulze@4484 | 1849 | matrix inverse(matrix) returns the inverse of the passed matrix |
dschulze@4484 | 1850 | matrix transpose(matrix) returns the transpose of the passed matrix |
dschulze@4484 | 1851 | point multVecMatrix(point, matrix) multiplies the passed point by the passed matrix |
dschulze@4484 | 1852 | and returns the transformed point |
dschulze@4484 | 1853 | double length(point) returns the length of the passed vector |
vhardy@3672 | 1854 | point normalize(point) normalizes the length of the passed point to 1 |
dschulze@4484 | 1855 | double dot(point, point) returns the dot product of the passed points |
dschulze@4484 | 1856 | double cos(double) returns the cosine of the passed angle in radians |
dschulze@4484 | 1857 | double asin(double) returns the arcsine in radians of the passed value |
dschulze@4484 | 1858 | double atan2(double y, double x) returns the principal value of the arc tangent of |
vhardy@3672 | 1859 | y/x, using the signs of both arguments to determine |
vhardy@3672 | 1860 | the quadrant of the return value |
vhardy@3672 | 1861 | |
vhardy@3672 | 1862 | Decomposition also makes use of the following function: |
dschulze@4484 | 1863 | point combine(point a, point b, double ascl, double bscl) |
vhardy@3672 | 1864 | result[0] = (ascl * a[0]) + (bscl * b[0]) |
vhardy@3672 | 1865 | result[1] = (ascl * a[1]) + (bscl * b[1]) |
dschulze@4484 | 1866 | result[2] = (ascl * a[2]) + (bscl * b[2]) |
vhardy@3672 | 1867 | return result |
vhardy@3672 | 1868 | |
dschulze@4484 | 1869 | // Normalize the matrix. |
dschulze@4484 | 1870 | if (matrix[3][3] == 0) |
dschulze@4484 | 1871 | return false |
vhardy@3672 | 1872 | |
dschulze@4484 | 1873 | for (i = 0; i < 4; i++) |
dschulze@4484 | 1874 | for (j = 0; j < 4; j++) |
dschulze@4484 | 1875 | matrix[i][j] /= matrix[3][3] |
dschulze@4484 | 1876 | |
dschulze@4484 | 1877 | // perspectiveMatrix is used to solve for perspective, but it also provides |
dschulze@4484 | 1878 | // an easy way to test for singularity of the upper 3x3 component. |
dschulze@4484 | 1879 | perspectiveMatrix = matrix |
dschulze@4484 | 1880 | |
dschulze@4484 | 1881 | for (i = 0; i < 3; i++) |
dschulze@4484 | 1882 | perspectiveMatrix[i][3] = 0 |
dschulze@4484 | 1883 | |
dschulze@4484 | 1884 | perspectiveMatrix[3][3] = 1 |
dschulze@4484 | 1885 | |
dschulze@4484 | 1886 | if (determinant(perspectiveMatrix) == 0) |
dschulze@4484 | 1887 | return false |
dschulze@4484 | 1888 | |
dschulze@4484 | 1889 | // First, isolate perspective. |
dschulze@4484 | 1890 | if (matrix[0][3] != 0 || matrix[1][3] != 0 || matrix[2][3] != 0) |
dschulze@4484 | 1891 | // rightHandSide is the right hand side of the equation. |
dschulze@4484 | 1892 | rightHandSide[0] = matrix[0][3]; |
dschulze@4484 | 1893 | rightHandSide[1] = matrix[1][3]; |
dschulze@4484 | 1894 | rightHandSide[2] = matrix[2][3]; |
dschulze@4484 | 1895 | rightHandSide[3] = matrix[3][3]; |
dschulze@4484 | 1896 | |
dschulze@4484 | 1897 | // Solve the equation by inverting perspectiveMatrix and multiplying |
dschulze@4484 | 1898 | // rightHandSide by the inverse. |
dschulze@4484 | 1899 | inversePerspectiveMatrix = inverse(perspectiveMatrix) |
dschulze@4484 | 1900 | transposedInversePerspectiveMatrix = transposeMatrix4(inversePerspectiveMatrix) |
dschulze@4484 | 1901 | perspective = multVecMatrix(rightHandSide, transposedInversePerspectiveMatrix) |
dschulze@4484 | 1902 | |
dschulze@4484 | 1903 | // Clear the perspective partition |
dschulze@4484 | 1904 | matrix[0][3] = matrix[1][3] = matrix[2][3] = 0 |
dschulze@4484 | 1905 | matrix[3][3] = 1 |
dschulze@4484 | 1906 | else |
dschulze@4484 | 1907 | // No perspective. |
dschulze@4484 | 1908 | perspective[0] = perspective[1] = perspective[2] = 0 |
dschulze@4484 | 1909 | perspective[3] = 1 |
dschulze@4484 | 1910 | |
dschulze@4484 | 1911 | // Next take care of translation |
dschulze@4484 | 1912 | translate[0] = matrix[3][0] |
dschulze@4484 | 1913 | matrix[3][0] = 0 |
vhardy@3672 | 1914 | translate[1] = matrix[3][1] |
dschulze@4484 | 1915 | matrix[3][1] = 0 |
dschulze@4484 | 1916 | translate[2] = matrix[3][2] |
dschulze@4484 | 1917 | matrix[3][2] = 0 |
vhardy@3672 | 1918 | |
dschulze@4484 | 1919 | // Now get scale and shear. 'row' is a 3 element array of 3 component vectors |
dschulze@4484 | 1920 | for (i = 0; i < 3; i++) |
dschulze@4484 | 1921 | row[i][0] = matrix[i][0] |
dschulze@4484 | 1922 | row[i][1] = matrix[i][1] |
dschulze@4484 | 1923 | row[i][2] = matrix[i][2] |
vhardy@3672 | 1924 | |
vhardy@3672 | 1925 | // Compute X scale factor and normalize first row. |
vhardy@3672 | 1926 | scale[0] = length(row[0]) |
vhardy@3672 | 1927 | row[0] = normalize(row[0]) |
vhardy@3672 | 1928 | |
dschulze@4484 | 1929 | // Compute XY shear factor and make 2nd row orthogonal to 1st. |
dschulze@4484 | 1930 | skew[0] = dot(row[0], row[1]) |
dschulze@4484 | 1931 | row[1] = combine(row[1], row[0], 1.0, -skew[0]) |
vhardy@3672 | 1932 | |
vhardy@3672 | 1933 | // Now, compute Y scale and normalize 2nd row. |
vhardy@3672 | 1934 | scale[1] = length(row[1]) |
vhardy@3672 | 1935 | row[1] = normalize(row[1]) |
dschulze@4484 | 1936 | skew[0] /= scale[1]; |
vhardy@3672 | 1937 | |
dschulze@4484 | 1938 | // Compute XZ and YZ shears, orthogonalize 3rd row |
dschulze@4484 | 1939 | skew[1] = dot(row[0], row[2]) |
dschulze@4484 | 1940 | row[2] = combine(row[2], row[0], 1.0, -skew[1]) |
dschulze@4484 | 1941 | skew[2] = dot(row[1], row[2]) |
dschulze@4484 | 1942 | row[2] = combine(row[2], row[1], 1.0, -skew[2]) |
dschulze@4484 | 1943 | |
dschulze@4484 | 1944 | // Next, get Z scale and normalize 3rd row. |
dschulze@4484 | 1945 | scale[2] = length(row[2]) |
dschulze@4484 | 1946 | row[2] = normalize(row[2]) |
dschulze@4484 | 1947 | skew[1] /= scale[2] |
dschulze@4484 | 1948 | skew[2] /= scale[2] |
dschulze@4484 | 1949 | |
dschulze@4484 | 1950 | // At this point, the matrix (in rows) is orthonormal. |
dschulze@4484 | 1951 | // Check for a coordinate system flip. If the determinant |
dschulze@4484 | 1952 | // is -1, then negate the matrix and the scaling factors. |
dschulze@4484 | 1953 | pdum3 = cross(row[1], row[2]) |
dschulze@4484 | 1954 | if (dot(row[0], pdum3) < 0) |
dschulze@4484 | 1955 | for (i = 0; i < 3; i++) { |
dschulze@4484 | 1956 | scale[0] *= -1; |
dschulze@4484 | 1957 | row[i][0] *= -1 |
dschulze@4484 | 1958 | row[i][1] *= -1 |
dschulze@4484 | 1959 | row[i][2] *= -1 |
dschulze@4484 | 1960 | |
dschulze@4484 | 1961 | // Now, get the rotations ou |
dschulze@4484 | 1962 | rotate[1] = asin(-row[0][2]); |
dschulze@4484 | 1963 | if (cos(rotate[1]) != 0) |
dschulze@4484 | 1964 | rotate[0] = atan2(row[1][2], row[2][2]); |
dschulze@4484 | 1965 | rotate[2] = atan2(row[0][1], row[0][0]); |
dschulze@4484 | 1966 | else |
dschulze@4484 | 1967 | rotate[0] = atan2(-row[2][0], row[1][1]); |
dschulze@4484 | 1968 | rotate[2] = 0; |
vhardy@3672 | 1969 | |
vhardy@3672 | 1970 | return true;</pre> |
vhardy@3672 | 1971 | |
vhardy@3672 | 1972 | <h3>Animating the components</h3> |
vhardy@3672 | 1973 | <p> |
vhardy@3672 | 1974 | Once decomposed, each component of each returned value of the source matrix is linearly interpolated |
vhardy@3672 | 1975 | with the corresponding component of the destination matrix. For instance, the translate[0] and |
vhardy@3672 | 1976 | translate[1] values are interpolated numerically, and the result is used to set the |
vhardy@3672 | 1977 | translation of the animating element. |
vhardy@3672 | 1978 | </p> |
vhardy@3672 | 1979 | <h3>Recomposing the matrix</h3> |
vhardy@3672 | 1980 | <p><em>This section is not normative.</em></p> |
vhardy@3672 | 1981 | <p> |
vhardy@3672 | 1982 | After interpolation the resulting values are used to position the element. One way to use these values |
dschulze@4601 | 1983 | is to recompose them into a 4x4 matrix. This can be done using the transform functions of the |
dschulze@4602 | 1984 | 'transform' property. This can be done by the following pseudo code. The |
vhardy@3672 | 1985 | values passed in are the output of the Unmatrix function above: |
vhardy@3672 | 1986 | </p> |
vhardy@3672 | 1987 | <pre> |
dschulze@4484 | 1988 | matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, perspective[0], perspective[1], perspective[2], perspective[3]) |
dschulze@4484 | 1989 | translate3d(translation[0], translation[1], translation[2]) |
dschulze@4484 | 1990 | rotateX(rotation[0]) rotateY(rotation[1]) rotateZ(rotation[2]) |
dschulze@4484 | 1991 | matrix3d(1,0,0,0, 0,1,0,0, 0,skew[2],1,0, 0,0,0,1) |
dschulze@4484 | 1992 | matrix3d(1,0,0,0, 0,1,0,0, skew[1],0,1,0, 0,0,0,1) |
dschulze@4484 | 1993 | matrix3d(1,0,0,0, skew[0],1,0,0, 0,0,1,0, 0,0,0,1) |
dschulze@4484 | 1994 | scale3d(scale[0], scale[1], scale[2])</pre> |
dschulze@4491 | 1995 | |
dschulze@4491 | 1996 | <h2 id="mathematical-description"> |
dschulze@4511 | 1997 | Mathematical Description of Transformation Functions |
dschulze@4491 | 1998 | </h2> |
dschulze@4491 | 1999 | <p> |
dschulze@4601 | 2000 | Mathematically, all transform functions can be represented as 4x4 transformation matrices of the following form: |
dschulze@4491 | 2001 | </p> |
simon@4583 | 2002 | <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@4491 | 2003 | |
dschulze@4491 | 2004 | <ul> |
dschulze@4491 | 2005 | <li id="MatrixDefined"> |
dschulze@4491 | 2006 | <p> |
dschulze@4491 | 2007 | 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 to the matrix: |
dschulze@4491 | 2008 | </p> |
simon@4583 | 2009 | <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 | 2010 | </li> |
dschulze@4491 | 2011 | <li id="TranslateDefined"> |
dschulze@4491 | 2012 | <p> |
dschulze@4491 | 2013 | 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 | 2014 | </p> |
dschulze@4491 | 2015 | </li> |
dschulze@4491 | 2016 | <li id="ScaleDefined"> |
dschulze@4491 | 2017 | <p> |
dschulze@4491 | 2018 | 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 | 2019 | </p> |
dschulze@4491 | 2020 | </li> |
dschulze@4491 | 2021 | <li id="RotateDefined"> |
dschulze@4491 | 2022 | <p> |
dschulze@4491 | 2023 | A 2D rotation with the parameter <em>alpha</em> is equivalent to a <a href="#RotateZDefined">rotation around the Z axis</a>. |
dschulze@4491 | 2024 | </p> |
dschulze@4491 | 2025 | </li> |
dschulze@4491 | 2026 | <li id="SkewDefined"> |
dschulze@4491 | 2027 | <p> |
dschulze@4491 | 2028 | A 2D skew transformation with the parameters <em>alpha</em> and <em>beta</em> is equivalent to the matrix: |
dschulze@4491 | 2029 | </p> |
simon@4583 | 2030 | <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@4491 | 2031 | </li> |
dschulze@4491 | 2032 | <li id="Translate3dDefined"> |
dschulze@4491 | 2033 | <p> |
dschulze@4491 | 2034 | A 3D translation with the parameters <em>tx</em>, <em>ty</em> and <em>tz</em> is equivalent to the matrix: |
dschulze@4491 | 2035 | </p> |
simon@4584 | 2036 | <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"> |
dschulze@4491 | 2037 | </li> |
dschulze@4491 | 2038 | <li id="Scale3dDefined"> |
dschulze@4491 | 2039 | <p> |
dschulze@4491 | 2040 | A 3D scaling with the parameters <em>sx</em>, <em>sy</em> and <em>sz</em> is equivalent to the matrix: |
dschulze@4491 | 2041 | </p> |
simon@4583 | 2042 | <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 | 2043 | </li> |
dschulze@4491 | 2044 | <li id="Rotate3dDefined"> |
dschulze@4491 | 2045 | <p> |
dschulze@4491 | 2046 | A 3D rotation with the vector [x,y,z] and the parameter <em>alpha</em> is equivalent to the matrix: |
dschulze@4491 | 2047 | </p> |
simon@4583 | 2048 | <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 | 2049 | <p> |
dschulze@4491 | 2050 | where: |
dschulze@4491 | 2051 | </p> |
simon@4584 | 2052 | <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 | 2053 | </li> |
dschulze@4491 | 2054 | <li id="RotateXDefined"> |
dschulze@4491 | 2055 | <p> |
dschulze@4491 | 2056 | A 3D rotation about the X axis with the parameter <em>alpha</em> is equivalent to the matrix: |
dschulze@4491 | 2057 | </p> |
simon@4583 | 2058 | <img src="rotateX.png" alt="\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\alpha) & -\sin(\alpha) & 0 \\ 0 & \sin(\alpha) & \cos(\alpha) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="220" height="106"> |
dschulze@4491 | 2059 | </li> |
dschulze@4491 | 2060 | <li id="RotateYDefined"> |
dschulze@4491 | 2061 | <p> |
dschulze@4491 | 2062 | A 3D rotation about the Y axis with the parameter <em>alpha</em> is equivalent to the matrix: |
dschulze@4491 | 2063 | </p> |
simon@4583 | 2064 | <img src="rotateY.png" alt="\begin{bmatrix} \cos(\alpha) & 0 & \sin(\alpha) & 0 \\ 0 & 1 & 0 & 0 \\ -\sin(\alpha) & 0 & \cos(\alpha) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="220" height="106"> |
dschulze@4491 | 2065 | </li> |
dschulze@4491 | 2066 | <li id="RotateZDefined"> |
dschulze@4491 | 2067 | <p> |
dschulze@4491 | 2068 | A 3D rotation about the Z axis with the parameter <em>alpha</em> is equivalent to the matrix: |
dschulze@4491 | 2069 | </p> |
simon@4583 | 2070 | <img src="rotateZ.png" alt="\begin{bmatrix} \cos(\alpha) & -\sin(\alpha) & 0 & 0 \\ \sin(\alpha) & \cos(\alpha) & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}" width="220" height="106"> |
dschulze@4491 | 2071 | </li> |
dschulze@4491 | 2072 | <li id="PerspectiveDefined"> |
dschulze@4491 | 2073 | <p> |
dschulze@4491 | 2074 | A perspective projection matrix with the parameter <em>d</em> is equivalent to the matrix: |
dschulze@4491 | 2075 | </p> |
simon@4583 | 2076 | <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 | 2077 | </li> |
dschulze@4491 | 2078 | </ul> |
vhardy@3672 | 2079 | |
vhardy@3672 | 2080 | |
vhardy@3672 | 2081 | <h2>References</h2> |
vhardy@3672 | 2082 | |
vhardy@3672 | 2083 | <h3 class="no-num">Normative references</h3> |
vhardy@3672 | 2084 | <!--normative--> |
vhardy@3672 | 2085 | |
vhardy@3672 | 2086 | <h3 class="no-num">Other references</h3> |
vhardy@3672 | 2087 | <!--informative--> |
vhardy@3672 | 2088 | |
vhardy@3672 | 2089 | |
vhardy@3672 | 2090 | |
vhardy@3672 | 2091 | <h2 class="no-num">Property index</h2> |
vhardy@3672 | 2092 | <!-- properties --> |
vhardy@3672 | 2093 | |
vhardy@3672 | 2094 | |
vhardy@3672 | 2095 | |
vhardy@3672 | 2096 | <h2 class="no-num" id="index">Index</h2> |
vhardy@3672 | 2097 | <!--index--> |
vhardy@3672 | 2098 | |
vhardy@3672 | 2099 | </body> |
vhardy@3672 | 2100 | </html> |
vhardy@3672 | 2101 | <!-- Keep this comment at the end of the file |
vhardy@3672 | 2102 | Local variables: |
vhardy@3672 | 2103 | mode: sgml |
vhardy@3672 | 2104 | sgml-declaration:"~/SGML/HTML4.decl" |
vhardy@3672 | 2105 | sgml-default-doctype-name:"html" |
vhardy@3672 | 2106 | sgml-minimize-attributes:t |
vhardy@3672 | 2107 | sgml-nofill-elements:("pre" "style" "br") |
vhardy@3672 | 2108 | sgml-live-element-indicator:t |
vhardy@3672 | 2109 | sgml-omittag:nil |
vhardy@3672 | 2110 | sgml-shorttag:nil |
vhardy@3672 | 2111 | sgml-namecase-general:t |
vhardy@3672 | 2112 | sgml-general-insert-case:lower |
vhardy@3672 | 2113 | sgml-always-quote-attributes:t |
vhardy@3672 | 2114 | sgml-indent-step:nil |
vhardy@3672 | 2115 | sgml-indent-data:t |
vhardy@3672 | 2116 | sgml-parent-document:nil |
vhardy@3672 | 2117 | sgml-exposed-tags:nil |
vhardy@3672 | 2118 | sgml-local-catalogs:nil |
vhardy@3672 | 2119 | sgml-local-ecat-files:nil |
vhardy@3672 | 2120 | End: |
vhardy@3672 | 2121 | --> |
vhardy@3672 | 2122 |