X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/7a654f8d43fdb43d78b63d90528bed6e86b608cc..f562e4c6e5fac7bcb445985b99acbea4d706e6f0:/src/draw/engine/Vml.js diff --git a/src/draw/engine/Vml.js b/src/draw/engine/Vml.js index 336609ee..5926e6f4 100644 --- a/src/draw/engine/Vml.js +++ b/src/draw/engine/Vml.js @@ -1,3 +1,17 @@ +/* + +This file is part of Ext JS 4 + +Copyright (c) 2011 Sencha Inc + +Contact: http://www.sencha.com/contact + +GNU General Public License Usage +This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. + +If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact. + +*/ /** * @class Ext.draw.engine.Vml * @extends Ext.draw.Surface @@ -10,7 +24,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 +46,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 +202,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 +282,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 +316,7 @@ Ext.define('Ext.draw.engine.Vml', { Math.round(cx * me.zoom)); sprite.dirtyPath = false; } - else if (sprite.type !== "text" && sprite.type !== 'image') { + else if (sprite.type !== "text") { sprite.attr.path = scrubbedAttrs.path = me.setPaths(sprite, scrubbedAttrs) || scrubbedAttrs.path; dom.path = me.path2vml(scrubbedAttrs.path); sprite.dirtyPath = false; @@ -332,7 +334,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 +376,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 +388,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("fill"); - 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 == "none") { + if (sprite.type == 'image') { + fillEl.on = true; + fillEl.src = params.src; + fillEl.type = "tile"; + fillEl.rotate = true; + } else if (params.fill == "none") { fillEl.on = false; - } - else { + } else { if (typeof params.opacity == "number") { fillEl.opacity = params.opacity; } @@ -429,24 +435,23 @@ Ext.define('Ext.draw.engine.Vml', { fillEl.angle = angle; fillEl.type = "gradient"; fillEl.method = "sigma"; - fillEl.colors.value = gradient.colors; + fillEl.colors = gradient.colors; } // Otherwise treat it as an image else { fillEl.src = fillUrl; fillEl.type = "tile"; + fillEl.rotate = true; } } else { - fillEl.color = Ext.draw.Color.toHex(params.fill); + fillEl.color = Ext.draw.Color.toHex(params.fill) || params.fill; fillEl.src = ""; fillEl.type = "solid"; } } } - if (newfill) { - el.appendChild(fillEl); - } + dom.appendChild(fillEl); }, setStroke: function(sprite, params) { @@ -593,64 +598,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(); + }, + + /** + * @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 && (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 < width) { viewBoxX -= (width - viewBoxWidth * relativeHeight) / 2 / relativeHeight; } if (viewBoxHeight * relativeWidth < 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 < 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 +686,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("rvml", "urn:schemas-microsoft-com:vml"); + } + return function (tagName) { + return doc.createElement("'); + }; + } catch (e) { + return function (tagName) { + return doc.createElement("<" + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); + }; + } + })(), + 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("rvml", "urn:schemas-microsoft-com:vml"); - } - me.createNode = function (tagName) { - return doc.createElement("'); - }; - } catch (e) { - me.createNode = function (tagName) { - return doc.createElement("<" + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); - }; - } - } if (!me.el) { var el = doc.createElement("div"); @@ -750,92 +770,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 = "", - 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 < transformsLength; i++) { - transform = transforms[i]; - type = transform.type; - if (type == "translate") { - matrix.translate(transform.x, transform.y); - } - else if (type == "rotate") { - matrix.rotate(transform.degrees, transform.x, transform.y); - deltaDegrees += transform.degrees; - } - else if (type == "scale") { - 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 < 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 = "", + 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 < 0 ? -1 : 1); + if (rotate) { + rotationCompensation = me.rotationCompensation(rotate, dx, dy); + dx = rotationCompensation.x; + dy = rotationCompensation.y; + } + if (sx < 0) { + flip += "x" } + if (sy < 0) { + flip += " y"; + 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("url("), + offset, c; // Hide element while we transform - if (sprite.type != "image" && skew) { + if (sprite.type != "image" && skew && !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) + " " + Math.abs(zoomScaleY); - - // Rotate via rotation property - newAngle = deltaDegrees * (deltaScaleX * ((deltaScaleY < 0) ? -1 : 1)); - if (newAngle != domStyle.rotation && !(newAngle === 0 && !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 < 0) { - flip += "x"; - } - if (deltaScaleY < 0) { - flip += " y"; - y = -1; - } - if (flip != "" && !dom.style.flip) { - domStyle.flip = flip; - } - - // Translate via coordorigin property - newOrigin = (deltaX * -zoomScaleX) + " " + (deltaY * -zoomScaleY); - if (newOrigin != dom.coordorigin) { - dom.coordorigin = (deltaX * -zoomScaleX) + " " + (deltaY * -zoomScaleY); + // skew.offset = '32767,1' OK + // skew.offset = '32768,1' Crash + // M$, R U kidding?? + offset = matrix.offset(); + if (offset[0] > 32767) { + offset[0] = 32767; + } else if (offset[0] < -32768) { + offset[0] = -32768 + } + if (offset[1] > 32767) { + offset[1] = 32767; + } else if (offset[1] < -32768) { + offset[1] = -32768 + } + skew.offset = offset; + } else { + if (skew) { + skew.matrix = "1 0 0 1"; + skew.offset = "0 0"; + } + 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); + } } } }, @@ -897,3 +955,4 @@ Ext.define('Ext.draw.engine.Vml', { delete me.el; } }); +