Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Vml.html
index 7426ab9..96dc698 100644 (file)
@@ -1,4 +1,21 @@
-<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-draw.engine.Vml'>/**
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <title>The source code</title>
+  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
+  <style type="text/css">
+    .highlight { display: block; background-color: #ddd; }
+  </style>
+  <script type="text/javascript">
+    function highlight() {
+      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+    }
+  </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+  <pre class="prettyprint lang-js"><span id='Ext-draw-engine-Vml'>/**
 </span> * @class Ext.draw.engine.Vml
  * @extends Ext.draw.Surface
  * Provides specific methods to draw with VML.
@@ -10,7 +27,7 @@ Ext.define('Ext.draw.engine.Vml', {
 
     extend: 'Ext.draw.Surface',
 
-    requires: ['Ext.draw.Draw', 'Ext.draw.Color', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.core.Element'],
+    requires: ['Ext.draw.Draw', 'Ext.draw.Color', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],
 
     /* End Definitions */
 
@@ -32,6 +49,9 @@ Ext.define('Ext.draw.engine.Vml', {
     coordsize: 1000,
     coordorigin: '0 0',
 
+    // VML uses CSS z-index and therefore doesn't need sprites to be kept in zIndex order
+    orderSpritesByZIndex: false,
+
     // @private
     // Convert an SVG standard path into a VML path
     path2vml: function (path) {
@@ -185,7 +205,7 @@ Ext.define('Ext.draw.engine.Vml', {
             zoom = me.zoom,
             vml = sprite.vml || (sprite.vml = {}),
             round = Math.round,
-            el = (type === 'image') ? me.createNode('image') : me.createNode('shape'),
+            el = me.createNode('shape'),
             path, skew, textPath;
 
         el.coordsize = zoom + ' ' + zoom;
@@ -265,21 +285,6 @@ Ext.define('Ext.draw.engine.Vml', {
         // Apply minimum default attributes
         Ext.applyIf(scrubbedAttrs, me.minDefaults[sprite.type]);
 
-        if (sprite.type == 'image') {
-            Ext.apply(sprite.attr, {
-                x: scrubbedAttrs.x,
-                y: scrubbedAttrs.y,
-                width: scrubbedAttrs.width,
-                height: scrubbedAttrs.height
-            });
-            bbox = sprite.getBBox();
-            el.setStyle({
-                width: bbox.width + 'px',
-                height: bbox.height + 'px'
-            });
-            dom.src = scrubbedAttrs.src;
-        }
-
         if (dom.href) {
             dom.href = scrubbedAttrs.href;
         }
@@ -314,7 +319,7 @@ Ext.define('Ext.draw.engine.Vml', {
                             Math.round(cx * me.zoom));
                 sprite.dirtyPath = false;
             }
-            else if (sprite.type !== &quot;text&quot; &amp;&amp; sprite.type !== 'image') {
+            else if (sprite.type !== &quot;text&quot;) {
                 sprite.attr.path = scrubbedAttrs.path = me.setPaths(sprite, scrubbedAttrs) || scrubbedAttrs.path;
                 dom.path = me.path2vml(scrubbedAttrs.path);
                 sprite.dirtyPath = false;
@@ -332,7 +337,7 @@ Ext.define('Ext.draw.engine.Vml', {
         }
 
         // Handle fill and opacity
-        if (scrubbedAttrs.opacity  || scrubbedAttrs['stroke-opacity'] || scrubbedAttrs.fill) {
+        if (sprite.type == 'image' || scrubbedAttrs.opacity  || scrubbedAttrs['fill-opacity'] || scrubbedAttrs.fill) {
             me.setFill(sprite, scrubbedAttrs);
         }
 
@@ -374,7 +379,7 @@ Ext.define('Ext.draw.engine.Vml', {
             spriteAttr.ry = params.ry;
             return Ext.draw.Draw.ellipsePath(sprite);
         }
-        else if (sprite.type == 'rect') {
+        else if (sprite.type == 'rect' || sprite.type == 'image') {
             spriteAttr.rx = spriteAttr.ry = params.r;
             return Ext.draw.Draw.rectPath(sprite);
         }
@@ -386,23 +391,27 @@ Ext.define('Ext.draw.engine.Vml', {
 
     setFill: function(sprite, params) {
         var me = this,
-            el = sprite.el.dom,
-            fillEl = el.fill,
-            newfill = false,
+            el = sprite.el,
+            dom = el.dom,
+            fillEl = dom.getElementsByTagName('fill')[0],
             opacity, gradient, fillUrl, rotation, angle;
 
-        if (!fillEl) {
-            // NOT an expando (but it sure looks like one)...
-            fillEl = el.fill = me.createNode(&quot;fill&quot;);
-            newfill = true;
+        if (fillEl) {
+            dom.removeChild(fillEl);
+        } else {
+            fillEl = me.createNode('fill');
         }
         if (Ext.isArray(params.fill)) {
             params.fill = params.fill[0];
         }
-        if (params.fill == &quot;none&quot;) {
+        if (sprite.type == 'image') {
+            fillEl.on = true;
+            fillEl.src = params.src;
+            fillEl.type = &quot;tile&quot;;
+            fillEl.rotate = true;
+        } else if (params.fill == &quot;none&quot;) {
             fillEl.on = false;
-        }
-        else {
+        } else {
             if (typeof params.opacity == &quot;number&quot;) {
                 fillEl.opacity = params.opacity;
             }
@@ -429,24 +438,23 @@ Ext.define('Ext.draw.engine.Vml', {
                         fillEl.angle = angle;
                         fillEl.type = &quot;gradient&quot;;
                         fillEl.method = &quot;sigma&quot;;
-                        fillEl.colors.value = gradient.colors;
+                        fillEl.colors = gradient.colors;
                     }
                     // Otherwise treat it as an image
                     else {
                         fillEl.src = fillUrl;
                         fillEl.type = &quot;tile&quot;;
+                        fillEl.rotate = true;
                     }
                 }
                 else {
-                    fillEl.color = Ext.draw.Color.toHex(params.fill);
+                    fillEl.color = Ext.draw.Color.toHex(params.fill) || params.fill;
                     fillEl.src = &quot;&quot;;
                     fillEl.type = &quot;solid&quot;;
                 }
             }
         }
-        if (newfill) {
-            el.appendChild(fillEl);
-        }
+        dom.appendChild(fillEl);
     },
 
     setStroke: function(sprite, params) {
@@ -593,64 +601,77 @@ Ext.define('Ext.draw.engine.Vml', {
     },
 
     setSize: function(width, height) {
-        var me = this,
-            viewBox = me.viewBox,
-            scaleX, scaleY, items, i, len;
+        var me = this;
         width = width || me.width;
         height = height || me.height;
         me.width = width;
         me.height = height;
 
-        if (!me.el) {
-            return;
-        }
+        if (me.el) {
+            // Size outer div
+            if (width != undefined) {
+                me.el.setWidth(width);
+            }
+            if (height != undefined) {
+                me.el.setHeight(height);
+            }
 
-        // Size outer div
-        if (width != undefined) {
-            me.el.setWidth(width);
-        }
-        if (height != undefined) {
-            me.el.setHeight(height);
+            // Handle viewBox sizing
+            me.applyViewBox();
+
+            me.callParent(arguments);
         }
+    },
+
+    setViewBox: function(x, y, width, height) {
+        this.callParent(arguments);
+        this.viewBox = {
+            x: x,
+            y: y,
+            width: width,
+            height: height
+        };
+        this.applyViewBox();
+    },
+
+<span id='Ext-draw-engine-Vml-method-applyViewBox'>    /**
+</span>     * @private Using the current viewBox property and the surface's width and height, calculate the
+     * appropriate viewBoxShift that will be applied as a persistent transform to all sprites.
+     */
+    applyViewBox: function() {
+        var me = this,
+            viewBox = me.viewBox,
+            width = me.width,
+            height = me.height,
+            viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight,
+            relativeHeight, relativeWidth, size;
 
-        // Handle viewBox sizing
         if (viewBox &amp;&amp; (width || height)) {
-            var viewBoxX = viewBox.x,
-                viewBoxY = viewBox.y,
-                viewBoxWidth = viewBox.width,
-                viewBoxHeight = viewBox.height,
-                relativeHeight = height / viewBoxHeight,
-                relativeWidth = width / viewBoxWidth,
-                size;
+            viewBoxX = viewBox.x;
+            viewBoxY = viewBox.y;
+            viewBoxWidth = viewBox.width;
+            viewBoxHeight = viewBox.height;
+            relativeHeight = height / viewBoxHeight;
+            relativeWidth = width / viewBoxWidth;
+
             if (viewBoxWidth * relativeHeight &lt; width) {
                 viewBoxX -= (width - viewBoxWidth * relativeHeight) / 2 / relativeHeight;
             }
             if (viewBoxHeight * relativeWidth &lt; height) {
                 viewBoxY -= (height - viewBoxHeight * relativeWidth) / 2 / relativeWidth;
             }
+
             size = 1 / Math.max(viewBoxWidth / width, viewBoxHeight / height);
-            // Scale and translate group
+
             me.viewBoxShift = {
                 dx: -viewBoxX,
                 dy: -viewBoxY,
                 scale: size
             };
-            items = me.items.items;
-            for (i = 0, len = items.length; i &lt; len; i++) {
-                me.transform(items[i]);
-            }
+            me.items.each(function(item) {
+                me.transform(item);
+            });
         }
-        this.callParent(arguments);
-    },
-
-    setViewBox: function(x, y, width, height) {
-        this.callParent(arguments);
-        this.viewBox = {
-            x: x,
-            y: y,
-            width: width,
-            height: height
-        };
     },
 
     onAdd: function(item) {
@@ -668,24 +689,26 @@ Ext.define('Ext.draw.engine.Vml', {
         this.callParent(arguments);
     },
 
+    // VML Node factory method (createNode)
+    createNode : (function () {
+        try {
+            var doc = Ext.getDoc().dom;
+            if (!doc.namespaces.rvml) {
+                doc.namespaces.add(&quot;rvml&quot;, &quot;urn:schemas-microsoft-com:vml&quot;);
+            }
+            return function (tagName) {
+                return doc.createElement(&quot;&lt;rvml:&quot; + tagName + ' class=&quot;rvml&quot;&gt;');
+            };
+        } catch (e) {
+            return function (tagName) {
+                return doc.createElement(&quot;&lt;&quot; + tagName + ' xmlns=&quot;urn:schemas-microsoft.com:vml&quot; class=&quot;rvml&quot;&gt;');
+            };
+        }
+    })(),
+
     render: function (container) {
         var me = this,
             doc = Ext.getDoc().dom;
-        // VML Node factory method (createNode)
-        if (!me.createNode) {
-            try {
-                if (!doc.namespaces.rvml) {
-                    doc.namespaces.add(&quot;rvml&quot;, &quot;urn:schemas-microsoft-com:vml&quot;);
-                }
-                me.createNode = function (tagName) {
-                    return doc.createElement(&quot;&lt;rvml:&quot; + tagName + ' class=&quot;rvml&quot;&gt;');
-                };
-            } catch (e) {
-                me.createNode = function (tagName) {
-                    return doc.createElement(&quot;&lt;&quot; + tagName + ' xmlns=&quot;urn:schemas-microsoft.com:vml&quot; class=&quot;rvml&quot;&gt;');
-                };
-            }
-        }
 
         if (!me.el) {
             var el = doc.createElement(&quot;div&quot;);
@@ -750,92 +773,130 @@ Ext.define('Ext.draw.engine.Vml', {
         };
     },
 
-    transform: function(sprite) {
+    extractTransform: function (sprite) {
         var me = this,
-            matrix = Ext.create('Ext.draw.Matrix'),
-            transforms = sprite.transformations,
-            transformsLength = transforms.length,
-            i = 0,
-            deltaDegrees = 0,
-            deltaScaleX = 1,
-            deltaScaleY = 1,
-            flip = &quot;&quot;,
-            el = sprite.el,
-            dom = el.dom,
-            domStyle = dom.style,
-            zoom = me.zoom,
-            skew = sprite.skew,
-            deltaX, deltaY, transform, type, compensate, y, fill, newAngle,zoomScaleX, zoomScaleY, newOrigin;
-
-        for (; i &lt; transformsLength; i++) {
-            transform = transforms[i];
-            type = transform.type;
-            if (type == &quot;translate&quot;) {
-                matrix.translate(transform.x, transform.y);
-            }
-            else if (type == &quot;rotate&quot;) {
-                matrix.rotate(transform.degrees, transform.x, transform.y);
-                deltaDegrees += transform.degrees;
-            }
-            else if (type == &quot;scale&quot;) {
-                matrix.scale(transform.x, transform.y, transform.centerX, transform.centerY);
-                deltaScaleX *= transform.x;
-                deltaScaleY *= transform.y;
-            }
+            matrix = Ext.create('Ext.draw.Matrix'), scale,
+            transformstions, tranformationsLength,
+            transform, i = 0,
+            shift = me.viewBoxShift;
+
+        for(transformstions = sprite.transformations, tranformationsLength = transformstions.length;
+            i &lt; tranformationsLength; i ++) {
+            transform = transformstions[i];
+            switch (transform.type) {
+                case 'translate' :
+                    matrix.translate(transform.x, transform.y);
+                    break;
+                case 'rotate':
+                    matrix.rotate(transform.degrees, transform.x, transform.y);
+                    break;
+                case 'scale':
+                    matrix.scale(transform.x || transform.scale, transform.y || transform.scale, transform.centerX, transform.centerY);
+                    break;
+            }
+        }
+
+        if (shift) {
+            matrix.add(1, 0, 0, 1, shift.dx, shift.dy);
+            matrix.prepend(shift.scale, 0, 0, shift.scale, 0, 0);
         }
+        
+        return sprite.matrix = matrix;
+    },
 
-        if (me.viewBoxShift) {
-            matrix.scale(me.viewBoxShift.scale, me.viewBoxShift.scale, -1, -1);
-            matrix.add(1, 0, 0, 1, me.viewBoxShift.dx, me.viewBoxShift.dy);
+    setSimpleCoords: function(sprite, sx, sy, dx, dy, rotate) {
+        var me = this,
+            matrix = sprite.matrix,
+            dom = sprite.el.dom,
+            style = dom.style,
+            yFlipper = 1,
+            flip = &quot;&quot;,
+            fill = dom.getElementsByTagName('fill')[0],
+            kx = me.zoom / sx,
+            ky = me.zoom / sy,
+            rotationCompensation;
+        if (!sx || !sy) {
+            return;
+        }
+        dom.coordsize = Math.abs(kx) + ' ' + Math.abs(ky);
+        style.rotation = rotate * (sx * sy &lt; 0 ? -1 : 1);
+        if (rotate) {
+            rotationCompensation = me.rotationCompensation(rotate, dx, dy);
+            dx = rotationCompensation.x;
+            dy = rotationCompensation.y;
+        }
+        if (sx &lt; 0) {
+            flip += &quot;x&quot;
         }
+        if (sy &lt; 0) {
+            flip += &quot; y&quot;;
+            yFlipper = -1;
+        }
+        style.flip = flip;
+        dom.coordorigin = (dx * -kx) + ' ' + (dy * -ky);
+        if (fill) {
+            dom.removeChild(fill);
+            rotationCompensation = me.rotationCompensation(rotate, matrix.x(sprite.x, sprite.y), matrix.y(sprite.x, sprite.y));
+            fill.position = rotationCompensation.x * yFlipper + ' ' + rotationCompensation.y * yFlipper;
+            fill.size = sprite.width * Math.abs(sx) + ' ' + sprite.height * Math.abs(sy);
+            dom.appendChild(fill);
+        }
+    },
 
-        sprite.matrix = matrix;
+    transform : function (sprite) {
+        var me = this,
+            el = sprite.el,
+            skew = sprite.skew,
+            dom = el.dom,
+            domStyle = dom.style,
+            matrix = me.extractTransform(sprite).clone(),
+            split, zoom = me.zoom,
+            fill = dom.getElementsByTagName('fill')[0],
+            isPatt = !String(sprite.fill).indexOf(&quot;url(&quot;),
+            offset, c;
 
 
         // Hide element while we transform
 
-        if (sprite.type != &quot;image&quot; &amp;&amp; skew) {
+        if (sprite.type != &quot;image&quot; &amp;&amp; skew &amp;&amp; !isPatt) {
             // matrix transform via VML skew
             skew.matrix = matrix.toString();
-            skew.offset = matrix.offset();
-        }
-        else {
-            deltaX = matrix.matrix[0][2];
-            deltaY = matrix.matrix[1][2];
-            // Scale via coordsize property
-            zoomScaleX = zoom / deltaScaleX;
-            zoomScaleY = zoom / deltaScaleY;
-
-            dom.coordsize = Math.abs(zoomScaleX) + &quot; &quot; + Math.abs(zoomScaleY);
-
-            // Rotate via rotation property
-            newAngle = deltaDegrees * (deltaScaleX * ((deltaScaleY &lt; 0) ? -1 : 1));
-            if (newAngle != domStyle.rotation &amp;&amp; !(newAngle === 0 &amp;&amp; !domStyle.rotation)) {
-                domStyle.rotation = newAngle;
-            }
-            if (deltaDegrees) {
-                // Compensate x/y position due to rotation
-                compensate = me.rotationCompensation(deltaDegrees, deltaX, deltaY);
-                deltaX = compensate.x;
-                deltaY = compensate.y;
-            }
-
-            // Handle negative scaling via flipping
-            if (deltaScaleX &lt; 0) {
-                flip += &quot;x&quot;;
-            }
-            if (deltaScaleY &lt; 0) {
-                flip += &quot; y&quot;;
-                y = -1;
-            }
-            if (flip != &quot;&quot; &amp;&amp; !dom.style.flip) {
-                domStyle.flip = flip;
-            }
-
-            // Translate via coordorigin property
-            newOrigin = (deltaX * -zoomScaleX) + &quot; &quot; + (deltaY * -zoomScaleY);
-            if (newOrigin != dom.coordorigin) {
-                dom.coordorigin = (deltaX * -zoomScaleX) + &quot; &quot; + (deltaY * -zoomScaleY);
+            // skew.offset = '32767,1' OK
+            // skew.offset = '32768,1' Crash
+            // M$, R U kidding??
+            offset = matrix.offset();
+            if (offset[0] &gt; 32767) {
+                offset[0] = 32767;
+            } else if (offset[0] &lt; -32768) {
+                offset[0] = -32768
+            }
+            if (offset[1] &gt; 32767) {
+                offset[1] = 32767;
+            } else if (offset[1] &lt; -32768) {
+                offset[1] = -32768
+            }
+            skew.offset = offset;
+        } else {
+            if (skew) {
+                skew.matrix = &quot;1 0 0 1&quot;;
+                skew.offset = &quot;0 0&quot;;
+            }
+            split = matrix.split();
+            if (split.isSimple) {
+                domStyle.filter = '';
+                me.setSimpleCoords(sprite, split.scaleX, split.scaleY, split.translateX, split.translateY, split.rotate / Math.PI * 180);
+            } else {
+                domStyle.filter = matrix.toFilter();
+                var bb = me.getBBox(sprite),
+                    dx = bb.x - sprite.x,
+                    dy = bb.y - sprite.y;
+                dom.coordorigin = (dx * -zoom) + ' ' + (dy * -zoom);
+                if (fill) {
+                    dom.removeChild(fill);
+                    fill.position = dx + ' ' + dy;
+                    fill.size = sprite.width * sprite.scale.x + ' ' + sprite.height * 1.1;
+                    dom.appendChild(fill);
+                }
             }
         }
     },
@@ -860,7 +921,7 @@ Ext.define('Ext.draw.engine.Vml', {
         }
     },
 
-<span id='Ext-draw.engine.Vml-method-addGradient'>    /**
+<span id='Ext-draw-engine-Vml-method-addGradient'>    /**
 </span>     * Adds a definition to this Surface for a linear gradient. We convert the gradient definition
      * to its corresponding VML attributes and store it for later use by individual sprites.
      * @param {Object} gradient
@@ -897,4 +958,6 @@ Ext.define('Ext.draw.engine.Vml', {
         delete me.el;
     }
 });
-</pre></pre></body></html>
\ No newline at end of file
+</pre>
+</body>
+</html>