Welcome, guest ( Login )

WikiHome » Dojo2D » VML Notes

VML Notes

Version 3, changed by eugene 08/16/2006.   Show version history

Transformation

From Gavin:

I think what you're going to have to do is decompose the matrix into rotation and skew/scale. The skew matrix doesn't look like a complete 3x3 matrix, but rather just scale and perspective.

On the bright side, you *can* omit your DOM calls to create a skew element and just do:

this.rawNode.skew.matrix = (your matrix string)

Which seems to work OK in my samples.

Your code was searching for existing "skew" tags rather than "o:skew" tags, and thus was creating new nodes with each setTransform.

Here's the code I found on the net for doing rotation extraction:

For a homogeneous geometrical transformation matrix, you can get the roll, pitch and yaw angles, following the TRPY convention, using the following formulas:

roll (rotation around z) : atan(xy, xx)
pitch (rotation around y) : -arcsin(xz)
yaw (rotation around x) : atan(yz,zz)

where the matrix is defined in the form:

[
xx, yx, zx, px;
xy, yy, zy, py;
xz, yz, zz, pz;
0, 0, 0, 1
]

(VML's matrix is a string in the form "/sxx/, /sxy/, /syx/, /syy/, /px/, /py/" where /s /is scale, /p /is perspective, and /x /and /y /are /x /and /y / values. If *Offset <http://msdn.microsoft.com/workshop/author/vml/shape/skew/skew_offset.asp> *is in absolute units, then /px /and /py /are in emu-1 units <http://msdn.microsoft.com/workshop/author/vml/shape/skew/..%5Cdata%5Cunits.asp> (otherwise they are an inverse fraction of the shape size). The default value is "1,0,0,1,0,0".)

From Gavin:

You've probably seen these. They're in Japanese, but the code is still useful (particularly for doing correct radial gradient fills in VML).

http://newing.qee.jp/vml/vml_fill.html
http://newing.qee.jp/vml/vml_skew.htm
http://newing.qee.jp/vml/vml_stroke.htm

From Gavin:

What you're seeing is conversion to "emu" units --  the smallest unit VML can deal with. The reason stuff is looking crazy is that you weren't specifying units for the offset value. Here's the revised method:

   // set an absolute transformation matrix
   setTransform: function(matrix){
     this.matrix = dojo.gfx.normalizeMatrix(matrix);
     // generate the attribute
     if(this.matrix){
       var skew = this.rawNode.skew;
       var mt = "" + this.matrix.xx + "," + this.matrix.xy +
         "," + this.matrix.yx + "," + this.matrix.yy +
         ", 0, 0";
       var offset = "" + this.matrix.dx + "px," + this.matrix.dy + "px"; // Note pixel spec on offset
       dojo.debug( "mt = " + mt + " offset = " + offset );
       skew.matrix =  mt;
       skew.offset = offset;
       skew.on = "t";
       dojo.debug( "skew : matrix = " + skew.matrix + " offset = " + skew.offset );
     }
       // support for chaining
       return this;
   },

The whole file is attached.

I also notice that using *no* offset makes the VML match the SVG better, so that's a subject for investigation. The MSDN VML doc says:

*Remarks*

The matrix is a string in the form "/sxx/, /sxy/, /syx/, /syy/, /px/, /py/" where /s /is scale, /p /is perspective, and /x /and /y /are /x /and /y / values. If *Offset <http://msdn.microsoft.com/workshop/author/vml/SHAPE/SKEW/skew_offset.asp> *is in absolute units, then /px /and /py /are in emu-1 units <http://msdn.microsoft.com/workshop/author/vml/SHAPE/SKEW/..%5Cdata%5Cunits.asp> (otherwise they are an inverse fraction of the shape size). The default value is "1,0,0,1,0,0".

(from http://msdn.microsoft.com/library/default.asp?url=/workshop/author/vml/SHAPE/SKEW/skew.asp)

Finally, I had to disable the pattern test in VML because not all of the Javascript methods were defined to make it work.

From Gavin:

Here's the missing bit:

Offset:

Determines the amount of /x /and /y / offset from the shape's original location. Values are defined in absolute measurement or fractional values of a shape (ranging from -0.5 to +0.5). Default is 0,0.


If you don't specify the unit of measurement, you need to measure the shape and convert the offset to a relative value. Ugh.

From Gavin:

http://www.developer.com/xml/article.php/10929_793961_2

Some lucid explanations of units used to transform group elements


From Gavin:

Argh. The "skew" element doesn't change the "group" element's transform, only "shape" elements and types derived from shape.

The group element *does* support the standard css "rotation" translation, scale features of shape, however.

So, my modest proposal is:

1) When applying a transform matrix to a group in VML, crack out the Rotation, Translation, and Scale components and apply them to the style of the group element.

2) If there's anything left in the matrix (i.e., it's something besides identity), then it's actually skewing the shapes inside the group. This skew needs to be applied to the shapes within the group -- and if they already have skew matrices of their own, it needs to be accumulated in each shape.

3) Tom -- do you have the math for this handy?
4) Kun -- does this make sense?
5) Microsoft-- what *were* you thinking?

From Eugene:

One way to handle VML cases is to decompose a matrix we set on the fly using something like eigen decomposition (http://mathworld.wolfram.com/EigenDecomposition.html), which produces two matrices. IIRC one of them is a scale matrix (diagonal one of eigenvalues), and another is a rotation matrix (of eigenvectors) --- see (10). I believe the 2D case of affine transformations is rather simple to implement, and it doesn't cost too much performance-wise. It may be a ticket for our problem without complicating the API.

Update: My post had a mistake: it should be three matrices: rotation-scaling-rotation. It can be easily done using SVD decomposition, which is similar to eigen decomposition.

Nevertheless it doesn't help VML, because apparently it implements scaling and rotation in two steps (assuming a tree composed of embedded groups and shapes serving as leaves):
  1. All coordinates (coordsize/coordorigin) are calculated first without taking rotation parameter into considiration. Basically it means that all scaling/translation matrices are applied first using top-down recusion.
  2. All rotations are applied using bottom-up recursion. Rotations are done using a geometric center of the shape.
It appears that it is impossible to apply a rotation before a scaling/translation matrix. For example, you cannot make a diamond shape by rotating a square 45 degrees and scaling it along y axis --- it will always be scaled first, then rotated leaving you with rotated rectangle. :-(

All these mean that shapes can be transformed using skew sub-element. (The documentation states that it is a Microsoft Office extension, but it works even when Microsoft Office is not present making it safe to use for us.) But groups cannot use skew, and restricted to transformations, which can be represented with scaling-rotating pair only. I'll continue my research to verify these findings, and possibly find a way around these restrictions.


Gradients

From Gavin:

Also, I was thinking that what we might end up needing to do for radial gradients is create an oval shape with a radial gradient and clip it with the shape that is actually getting filled. That way we don't get that boxy radial gradient fill in IE and it matches SVG on Firefox.  Take a look at the VMLFrame element to see how to do clipping. Maybe.

From Eugene:

Shape transformations do not affect gradient fills --- shape is transformed, and then filled with an original unmodivied fill.


Attachments (0)

  File By Size Attached Ver.