Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: lojjic/PIE
...
head fork: lojjic/PIE
Checking mergeability… Don't worry, you can still create the pull request.
  • 3 commits
  • 9 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jan 23, 2011
Jason Johnston Beginnings of transform parsing and matrix manipulation functions 10a6e29
Commits on Feb 06, 2011
Jason Johnston Add playground file for quick testing of arbitrary VML 4671d18
Jason Johnston Implement transform parsing, make getBoxPath accept x/y offsets to ma…
…ke transform origins of all shapes line up, add Matrix class that roughly implements CSSMatrix interface, add transforms test file
92b9c78
View
23 sources/Angle.js
@@ -17,18 +17,31 @@ PIE.Angle = (function() {
return this._unit || ( this._unit = this.val.match( this.unitRE )[0].toLowerCase() );
},
+ getNumber: function() {
+ return this._num || ( this._num = parseFloat( this.val, 10 ) );
+ },
+
/**
* Get the numeric value of the angle in degrees.
* @return {number} The degrees value
*/
degrees: function() {
- var deg = this._deg, u, n;
- if( deg === undefined ) {
- u = this.getUnit();
- n = parseFloat( this.val, 10 );
- deg = this._deg = ( u === 'deg' ? n : u === 'rad' ? n / Math.PI * 180 : u === 'grad' ? n / 400 * 360 : u === 'turn' ? n * 360 : 0 );
+ var deg = this._deg, unit, number, undef;
+ if( deg === undef ) {
+ unit = this.getUnit();
+ number = this.getNumber();
+ deg = this._deg = ( unit === 'deg' ? number : unit === 'rad' ? number / Math.PI * 180 : unit === 'grad' ? number / 400 * 360 : unit === 'turn' ? number * 360 : 0 );
}
return deg;
+ },
+
+ radians: function() {
+ var rad = this._rad, unit, number, undef;
+ if( rad === undef ) {
+ unit = this.getUnit();
+ number = this.getNumber();
+ rad = this._rad = ( unit === 'rad' ? number : this.degrees() / 180 * Math.PI );
+ }
}
};
View
2  sources/BackgroundStyleInfo.js
@@ -81,7 +81,7 @@ PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
tokType = token.type;
tokVal = token.value;
- if( !image.type && tokType & tok_type.FUNCTION && tokVal === 'linear-gradient(' ) {
+ if( !image.type && tokType & tok_type.FUNCTION && tokVal === 'linear-gradient' ) {
gradient = { stops: [], type: 'linear-gradient' };
stop = {};
while( token = tokenizer.next() ) {
View
17 sources/BoxShadowOutsetRenderer.js
@@ -34,11 +34,11 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( {
h = bounds.h,
clipAdjust = PIE.ieVersion === 8 ? 1 : 0, //workaround for IE8 bug where VML leaks out top/left of clip region by 1px
corners = [ 'tl', 'tr', 'br', 'bl' ], corner,
- shadowInfo, shape, fill, ss, xOff, yOff, spread, blur, shrink, color, alpha, path,
+ shadowInfo, shape, fill, ss, spread, blur, shrink, color, alpha, path,
totalW, totalH, focusX, focusY, isBottom, isRight;
- function getShadowShape( index, corner, xOff, yOff, color, blur, path ) {
+ function getShadowShape( index, corner, color, blur, path ) {
var shape = me.getShape( 'shadow' + index + corner, 'fill', box, len - index ),
fill = shape.fill;
@@ -61,8 +61,6 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( {
// This needs to go last for some reason, to prevent rendering at incorrect size
ss = shape.style;
- ss.left = xOff;
- ss.top = yOff;
ss.width = w;
ss.height = h;
@@ -72,8 +70,6 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( {
while( i-- ) {
shadowInfo = shadowInfos[ i ];
- xOff = shadowInfo.xOffset.pixels( el );
- yOff = shadowInfo.yOffset.pixels( el );
spread = shadowInfo.spread.pixels( el ),
blur = shadowInfo.blur.pixels( el );
color = shadowInfo.color;
@@ -84,7 +80,8 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( {
// round the corners of the expanded shadow shape rather than squaring them off.
radii = PIE.BorderRadiusStyleInfo.ALL_ZERO;
}
- path = this.getBoxPath( { t: shrink, r: shrink, b: shrink, l: shrink }, 2, radii );
+ path = this.getBoxPath( { t: shrink, r: shrink, b: shrink, l: shrink }, 2, radii,
+ shadowInfo.xOffset.pixels( el ), shadowInfo.yOffset.pixels( el ) );
if( blur ) {
totalW = ( spread + blur ) * 2 + w;
@@ -101,7 +98,7 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( {
corner = corners[j];
isBottom = corner.charAt( 0 ) === 'b';
isRight = corner.charAt( 1 ) === 'r';
- shape = getShadowShape( i, corner, xOff, yOff, color, blur, path );
+ shape = getShadowShape( i, corner, color, blur, path );
fill = shape.fill;
fill['focusposition'] = ( isRight ? 1 - focusX : focusX ) + ',' +
( isBottom ? 1 - focusY : focusY );
@@ -116,13 +113,13 @@ PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( {
}
} else {
// TODO delete old quadrant shapes if resizing expands past the barrier
- shape = getShadowShape( i, '', xOff, yOff, color, blur, path );
+ shape = getShadowShape( i, '', color, blur, path );
fill = shape.fill;
fill['focusposition'] = focusX + ',' + focusY;
fill['focussize'] = ( 1 - focusX * 2 ) + ',' + ( 1 - focusY * 2 );
}
} else {
- shape = getShadowShape( i, '', xOff, yOff, color, blur, path );
+ shape = getShadowShape( i, '', color, blur, path );
alpha = color.alpha();
if( alpha < 1 ) {
// shape.style.filter = 'alpha(opacity=' + ( alpha * 100 ) + ')';
View
162 sources/Matrix.js
@@ -0,0 +1,162 @@
+PIE.Matrix = function( a, b, c, d, e, f ) {
+ var me = this;
+ me['a'] = a,
+ me['b'] = b,
+ me['c'] = c,
+ me['d'] = d,
+ me['e'] = e,
+ me['f'] = f;
+};
+
+PIE.Matrix.prototype = {
+
+ ////////// CSSMatrix interface methods: //////////
+
+ /**
+ * The setMatrixValue method replaces the existing matrix with one computed from parsing the passed
+ * string as though it had been assigned to the transform property in a CSS style rule.
+ * @param {String} cssString The string to parse.
+ * @throws {DOMException} SYNTAX_ERR Thrown when the provided string can not be parsed into a CSSMatrix.
+ */
+ setMatrixValue: function( cssString ) {
+ // TODO
+ // The problem here is how to handle relative/percent units in translate() functions. Those type
+ // of values mean nothing without the context of a particular element to resolve them to pixel
+ // numbers. They cannot be multiplied until that conversion has been performed.
+ },
+
+ /**
+ * The multiply method returns a new CSSMatrix which is the result of this matrix multiplied by the
+ * passed matrix, with the passed matrix to the right. This matrix is not modified.
+ * @param {CSSMatrix} secondMatrix The matrix to multiply.
+ * @return {CSSMatrix} The result matrix.
+ */
+ multiply: function( secondMatrix ) {
+ var matrix = this;
+ return new PIE.Matrix(
+ matrix['a'] * secondMatrix['a'] + matrix['c'] * secondMatrix['b'],
+ matrix['b'] * secondMatrix['a'] + matrix['d'] * secondMatrix['b'],
+ matrix['a'] * secondMatrix['c'] + matrix['c'] * secondMatrix['d'],
+ matrix['b'] * secondMatrix['c'] + matrix['d'] * secondMatrix['d'],
+ matrix['a'] * secondMatrix['e'] + matrix['c'] * secondMatrix['f'] + matrix['e'],
+ matrix['b'] * secondMatrix['e'] + matrix['d'] * secondMatrix['f'] + matrix['f']
+ )
+ },
+
+ /**
+ * The multiplyLeft method returns a new CSSMatrix which is the result of this matrix multiplied
+ * by the passed matrix, with the passed matrix to the left. This matrix is not modified.
+ * @param {CSSMatrix} secondMatrix The matrix to multiply.
+ * @return {CSSMatrix} The result matrix.
+ */
+ multiplyLeft: function( secondMatrix ) {
+ return secondMatrix.multiply( this );
+ },
+
+ /**
+ * The inverse method returns a new matrix which is the inverse of this matrix. This matrix is not modified.
+ * @return {CSSMatrix} The inverted matrix.
+ * @throws {DOMException} NOT_SUPPORTED_ERR Thrown when the CSSMatrix can not be inverted.
+ */
+ inverse: function() {
+ // IS THIS USEFUL?
+ },
+
+ /**
+ * The translate method returns a new matrix which is this matrix post multiplied by a translation
+ * matrix containing the passed values. This matrix is not modified.
+ * @param {Number} x The X component of the translation value.
+ * @param {Number} y The Y component of the translation value.
+ * @return {CSSMatrix} The result matrix.
+ */
+ translate: function( x, y ) {
+ return this.multiply( new PIE.Matrix( 1, 0, 0, 1, x, y ) );
+ },
+
+ /**
+ * The scale method returns a new matrix which is this matrix post multiplied by a scale matrix
+ * containing the passed values. If the y component is undefined, the x component value is used in its
+ * place. This matrix is not modified.
+ * @param {Number} x The X component of the scale value.
+ * @param {Number} y The (optional) Y component of the scale value.
+ * @return {CSSMatrix} The result matrix.
+ */
+ scale: function( x, y, undef ) {
+ return this.multiply( new PIE.Matrix( x, 0, 0, y === undef ? x : y, 0, 0 ) );
+ },
+
+ /**
+ * The rotate method returns a new matrix which is this matrix post multiplied by a rotation matrix.
+ * The rotation value is in degrees. This matrix is not modified.
+ * @param {Number} angle The angle of rotation (in degrees).
+ * @return {CSSMatrix} The result matrix.
+ */
+ rotate: function( angle ) {
+ var maths = Math,
+ radians = angle / 180 * maths.PI,
+ cosine = maths.cos( radians ),
+ sine = maths.sin( radians );
+ return this.multiply( new PIE.Matrix( cosine, -sine, sine, cosine, 0, 0 ) );
+ },
+
+ /**
+ * The skew method returns a new matrix which is this matrix post multiplied by a skew matrix. The
+ * rotation value is in degrees. This matrix is not modified.
+ * @param {Number} angleX The angle of skew along the X axis.
+ * @param {Number} angleY The angle of skew along the Y axis.
+ * @return {CSSMatrix} The result matrix.
+ */
+ skew: function( angleX, angleY ) {
+ var maths = Math,
+ pi = maths.PI;
+ return this.multiply( new PIE.Matrix( 1, maths.tan( angleX / 180 * pi ), maths.tan(angleY / 180 * pi ), 1, 0, 0 ) );
+ },
+
+ toString: function() {
+ var me = this;
+ return 'matrix(' + [me['a'], me['b'], me['c'], me['d'], me['e'], me['f']] + ')';
+ },
+
+
+
+ ////////// PIE private methods: //////////
+
+ /**
+ * Transform a given x/y point according to this matrix.
+ * @return {Object.<{x:number, y:number}>} The transformed x/y point
+ */
+ applyToPoint: function( x, y ) {
+ var matrix = this;
+ return {
+ x: matrix['a'] * x + matrix['c'] * y + matrix['e'],
+ y: matrix['b'] * x + matrix['d'] * y + matrix['f']
+ }
+ },
+
+ /**
+ * Transform a given bounding box according to this matrix and return the bounding box of the result
+ * @param {Object.<{x:number, y:number, w:number, h:number}>} bounds The bounding box to transform
+ * @return {Object.<{x:number, y:number, w:number, h:number}>} The resulting bounding box
+ */
+ getTransformedBounds: function( bounds ) {
+ var matrix = this,
+ tl = matrix.applyToPoint( 0, 0 ),
+ tr = matrix.applyToPoint( bounds.w, 0 ),
+ br = matrix.applyToPoint( bounds.w, bounds.h ),
+ bl = matrix.applyToPoint( 0, bounds.h ),
+ min = Math.min,
+ max = Math.max,
+ left = min( tl.x, tr.x, br.x, bl.x ),
+ top = min( tl.y, tr.y, br.y, bl.y );
+ return {
+ x: left,
+ y: top,
+ w: max( tl.x, tr.x, br.x, bl.x ) - left,
+ h: max( tl.y, tr.y, br.y, bl.y ) - top
+ }
+ }
+
+};
+
+// Alias to global CSSMatrix interface
+window.CSSMatrix = PIE.Matrix;
View
32 sources/RendererBase.js
@@ -220,10 +220,14 @@ PIE.RendererBase = {
* @param {number=} mult If specified, all coordinates will be multiplied by this number
* @param {Object=} radii If specified, this will be used for the corner radii instead of the properties
* from this renderer's borderRadiusInfo object.
+ * @param {number=} xOffset If specified, all points will be shifted by this amount on the x-axis
+ * @param {number=} yOffset If specified, all points will be shifted by this amount on the y-axis
* @return {string} the VML path
*/
- getBoxPath: function( shrink, mult, radii ) {
- mult = mult || 1;
+ getBoxPath: function( shrink, mult, radii, xOffset, yOffset ) {
+ mult || ( mult = 1 );
+ xOffset = ( xOffset || 0 ) * mult;
+ yOffset = ( yOffset || 0 ) * mult;
var r, str,
bounds = this.boundsInfo.getBounds(),
@@ -249,20 +253,20 @@ PIE.RendererBase = {
blX = r.x['bl'] * mult;
blY = r.y['bl'] * mult;
- str = 'm' + floor( shrinkL ) + ',' + floor( tlY ) +
- 'qy' + floor( tlX ) + ',' + floor( shrinkT ) +
- 'l' + ceil( w - trX ) + ',' + floor( shrinkT ) +
- 'qx' + ceil( w - shrinkR ) + ',' + floor( trY ) +
- 'l' + ceil( w - shrinkR ) + ',' + ceil( h - brY ) +
- 'qy' + ceil( w - brX ) + ',' + ceil( h - shrinkB ) +
- 'l' + floor( blX ) + ',' + ceil( h - shrinkB ) +
- 'qx' + floor( shrinkL ) + ',' + ceil( h - blY ) + ' x e';
+ str = 'm' + ( floor( shrinkL ) + xOffset ) + ',' + ( floor( tlY ) + yOffset ) +
+ 'qy' + ( floor( tlX ) + xOffset ) + ',' + ( floor( shrinkT ) + yOffset ) +
+ 'l' + ( ceil( w - trX ) + xOffset ) + ',' + ( floor( shrinkT ) + yOffset ) +
+ 'qx' + ( ceil( w - shrinkR ) + xOffset ) + ',' + ( floor( trY ) + yOffset ) +
+ 'l' + ( ceil( w - shrinkR ) + xOffset ) + ',' + ( ceil( h - brY ) + yOffset ) +
+ 'qy' + ( ceil( w - brX ) + xOffset ) + ',' + ( ceil( h - shrinkB ) + yOffset ) +
+ 'l' + ( floor( blX ) + xOffset ) + ',' + ( ceil( h - shrinkB ) + yOffset ) +
+ 'qx' + ( floor( shrinkL ) + xOffset ) + ',' + ( ceil( h - blY ) + yOffset ) + ' x e';
} else {
// simplified path for non-rounded box
- str = 'm' + floor( shrinkL ) + ',' + floor( shrinkT ) +
- 'l' + ceil( w - shrinkR ) + ',' + floor( shrinkT ) +
- 'l' + ceil( w - shrinkR ) + ',' + ceil( h - shrinkB ) +
- 'l' + floor( shrinkL ) + ',' + ceil( h - shrinkB ) +
+ str = 'm' + ( floor( shrinkL ) + xOffset ) + ',' + ( floor( shrinkT ) + yOffset ) +
+ 'l' + ( ceil( w - shrinkR ) + xOffset ) + ',' + ( floor( shrinkT ) + yOffset ) +
+ 'l' + ( ceil( w - shrinkR ) + xOffset ) + ',' + ( ceil( h - shrinkB ) + yOffset ) +
+ 'l' + ( floor( shrinkL ) + xOffset ) + ',' + ( ceil( h - shrinkB ) + yOffset ) +
'xe';
}
return str;
View
2  sources/Tokenizer.js
@@ -208,7 +208,7 @@ PIE.Tokenizer = (function() {
return failure();
}
- return newToken( Type.FUNCTION, val + '(' );
+ return newToken( Type.FUNCTION, val );
}
// Other identifier
View
151 sources/TransformStyleInfo.js
@@ -0,0 +1,151 @@
+/**
+ * Handles parsing, caching, and detecting changes to CSS3 'transform' and 'transform-origin' properties
+ * @constructor
+ * @param {Element} el the target element
+ */
+PIE.TransformStyleInfo = PIE.StyleInfoBase.newStyleInfo( {
+ cssProperty: 'transform',
+ styleProperty: 'transform',
+
+ transformFunctions: (function() {
+ var Type = PIE.Tokenizer.Type,
+ NUMBER = Type.NUMBER,
+ ANGLE = Type.ANGLE,
+ LENGTH = Type.LENGTH,
+ PERCENT = Type.PERCENT,
+ LengthCls = PIE.Length,
+ AngleCls = PIE.Angle;
+ return {
+ // function_name: [ allowed_type, min_values, max_values, wrapper_class ]
+ 'matrix': [ NUMBER, 6, 6 ], //TODO moz allows (requires?) a length w/units for the final 2 args, should we?
+ 'translate': [ LENGTH | PERCENT, 1, 2, LengthCls ],
+ 'translateX': [ LENGTH | PERCENT, 1, 1, LengthCls ],
+ 'translateY': [ LENGTH | PERCENT, 1, 1, LengthCls ],
+ 'scale': [ NUMBER, 1, 2 ],
+ 'scaleX': [ NUMBER, 1, 1 ],
+ 'scaleY': [ NUMBER, 1, 1 ],
+ 'rotate': [ ANGLE, 1, 1, AngleCls ],
+ 'skew': [ ANGLE, 1, 2, AngleCls ],
+ 'skewX': [ ANGLE, 1, 1, AngleCls ],
+ 'skewY': [ ANGLE, 1, 1, AngleCls ]
+ };
+ })(),
+
+ xyFunctionRE: /^(.+)(X|Y)$/,
+
+ /**
+ * Returns object in the format:
+ * {
+ * origin: <PIE.BgPosition>,
+ * transforms: [
+ * { type: 'matrix', value: [ <Number>, <Number>, <Number>, <Number>, <Number>, <Number> ] },
+ * { type: 'translate', value: [ <PIE.Length>, <PIE.Length> ] },
+ * { type: 'skew', value: [ <PIE.Angle>, <PIE.Angle> ] },
+ * { type: 'scale', value: [ <Number>, <Number> ] },
+ * { type: 'rotate', value: <PIE.Angle> }
+ * ]
+ * }
+ *
+ * Note that XY-specific functions will be pre-combined into their single counterparts:
+ * scaleX(n) -> scale(n)
+ * scaleY(n) -> scale(1, n)
+ * skewX(a) -> skew(a)
+ * skewY(a) -> skew(0, a)
+ * translateX(l) -> translate(l)
+ * translateY(l) -> translate(0, l)
+ */
+ parseCss: function( css ) {
+ var tokenizer = new PIE.Tokenizer( css ),
+ Type = PIE.Tokenizer.Type,
+ transformFunctions = this.transformFunctions,
+ xyFunctionRE = this.xyFunctionRE,
+ YEP = true,
+ NOPE = false,
+ NULL = null,
+ token, tokenType, tokenValue, fnSignature, fnName, fnArgs, hangingArg, hangingComma, xyMatch,
+ transforms = [];
+
+ while( token = tokenizer.next() ) {
+ tokenType = token.type;
+ tokenValue = token.value;
+
+ // Start of function - set up for collection of args
+ if( !fnName && ( tokenType & Type.FUNCTION ) && tokenValue in transformFunctions ) {
+ fnName = tokenValue;
+ fnSignature = transformFunctions[tokenValue];
+ fnArgs = [];
+ }
+
+ // End of function - validate number of args is within allowed range, push onto transforms list, and reset
+ else if ( ( tokenType & Type.CHARACTER ) && tokenValue === ')' && fnName && !hangingComma &&
+ fnArgs.length >= fnSignature[1] && fnArgs.length <= fnSignature[2] ) {
+
+ // Combine XY-specific functions into single functions, e.g. scaleY(n) -> scale(1, n)
+ if ( xyMatch = fnName.match( xyFunctionRE ) ) {
+ fnName = xyMatch[1];
+ // For fooX we use the arg untouched, for fooY we push an x value onto the front of the args
+ if ( xyMatch[2] === 'Y' ) {
+ fnArgs.unshift( fnName === 'scale' ? 1 : 0 );
+ }
+ }
+ // Fill in optional second argument
+ else if ( fnArgs.length < 2 ) {
+ fnArgs[1] = fnName === 'scale' ? fnArgs[0] : 0;
+ }
+
+ transforms.push( { type: fnName, value: fnArgs } );
+ fnSignature = fnName = fnArgs = hangingArg = hangingComma = NOPE;
+ }
+
+ // Commas - allowed in between function args
+ else if ( ( tokenType & Type.CHARACTER ) && tokenValue === ',' && hangingArg ) {
+ hangingArg = NOPE;
+ hangingComma = YEP;
+ }
+
+ // Function args - allowed at start of function or after comma
+ else if ( fnName && ( hangingComma || !hangingArg ) && ( tokenType & fnSignature[0] ) ) {
+ fnArgs.push( fnSignature[3] ? new fnSignature[3]( tokenValue ) : parseFloat( tokenValue, 10 ) );
+ hangingArg = YEP;
+ hangingComma = NOPE;
+ }
+
+ // Something not allowed - FAIL!
+ else {
+ return NULL;
+ }
+ }
+
+ return transforms[0] && !fnName ? {
+ origin: [],
+ transforms: transforms
+ } : NULL;
+ },
+
+
+ /**
+ * Return the {@link PIE.Matrix}
+ */
+ getMatrix: PIE.StyleInfoBase.cacheWhenLocked( function( bounds ) {
+ var me = this,
+ el = me.targetElement,
+ props = me.getProps(),
+ origin = props.origin.coords( el, bounds.w, bounds.h ),
+ transforms = props.transforms,
+ matrix = new PIE.Matrix( 1, 0, 0, 1, origin.x, origin.y ),
+ i = 0, len = transforms.length,
+ type, value;
+
+ // apply each transform in order
+ for( ; i < len; i++ ) {
+ type = transforms[i].type;
+ value = transforms[i].value;
+ matrix = matrix[ type ].apply(
+ matrix,
+ type === 'translate' ? [ value[0].pixels( el ), value[1].pixels( el ) ] : value
+ );
+ }
+
+ return matrix;
+ } )
+} );
View
113 tests/2dtransforms.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>CSS3 2D Transforms</title>
+
+ <style type="text/css">
+ .cont {
+ border: 100px solid #EEF;
+ width: 200px;
+ height: 200px;
+ margin: 50px;
+ float: left;
+ }
+
+ .test {
+ width: 180px;
+ height: 180px;
+ border: 1px solid #CCC;
+ padding: 9px;
+ background: rgba(200, 255, 200, 0.2);
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+ }
+
+ .shadow .test {
+ -moz-box-shadow: 0 3px 5px #000;
+ -webkit-box-shadow: 0 3px 5px #000;
+ box-shadow: 0 3px 5px #000;
+ }
+
+ .gradient .test {
+ background: -webkit-gradient(linear, 0 0, 100% 0, from(#FCC), to(#CCF));
+ background: -moz-linear-gradient(left, #FCC, #CCF);
+ background: linear-gradient(left, #FCC, #CCF);
+ -pie-background: linear-gradient(left, #FCC, #CCF);
+ }
+
+ .matrix {
+ display: block;
+ color: #999;
+ font-size: 10px;
+ margin-top: 1em;
+ }
+
+ #controls {
+ position: fixed;
+ top: 1em;
+ right: 1em;
+ }
+ </style>
+
+ <script type="text/javascript">
+ window.onload = function() {
+ var divs = document.getElementsByTagName("div"),
+ i = 0, len = divs.length;
+ for( ; i < len; i++ ) {
+ if (divs[i].className.match(/\btest\b/)) {
+ divs[i].style.MozTransform = divs[i].innerHTML;
+ divs[i].style.webkitTransform = divs[i].innerHTML;
+ divs[i].style.transform = divs[i].innerHTML;
+
+ divs[i].innerHTML += '<span class="matrix">' + (
+ getComputedStyle(divs[i], null).getPropertyValue('transform') ||
+ getComputedStyle(divs[i], null).getPropertyValue('-webkit-transform') ||
+ getComputedStyle(divs[i], null).getPropertyValue('-moz-transform') ||
+ 'could not get matrix value'
+ ) + '</span>'
+ }
+ }
+ };
+
+ function toggleBodyClass(cls) {
+ var re = new RegExp("\\b" + cls + "\\b", 'g'),
+ body = document.body;
+ if (re.test(body.className)) {
+ body.className = body.className.replace(re, '');
+ } else {
+ body.className += ' ' + cls;
+ }
+ }
+ </script>
+</head>
+<body>
+
+ <p id="controls">
+ <button onclick="toggleBodyClass('shadow')">Toggle Shadow</button>
+ <button onclick="toggleBodyClass('gradient')">Toggle Gradient</button>
+ </p>
+
+ <div class="cont"><div class="test">rotate(45deg)</div></div>
+ <div class="cont"><div class="test">rotate(1rad)</div></div>
+
+ <div class="cont"><div class="test">scale(1.5)</div></div>
+ <div class="cont"><div class="test">scaleX(1.5)</div></div>
+ <div class="cont"><div class="test">scaleY(1.5)</div></div>
+
+ <div class="cont"><div class="test">skew(25deg,25deg)</div></div>
+ <div class="cont"><div class="test">skewX(25deg)</div></div>
+ <div class="cont"><div class="test">skewY(25deg)</div></div>
+
+ <div class="cont"><div class="test">translate(100px,100px)</div></div>
+ <div class="cont"><div class="test">translateX(100px)</div></div>
+ <div class="cont"><div class="test">translateY(100px)</div></div>
+ <div class="cont"><div class="test">translate(2em, 50%)</div></div>
+
+ <div class="cont"><div class="test">translate(50px) rotate(45deg)</div></div>
+ <div class="cont"><div class="test">rotate(45deg) translate(50px)</div></div>
+
+ <!--<div class="cont"><div class="test"></div></div>-->
+
+</body>
+</html>
View
84 tests/playground.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+<head xmlns:v="urn:">
+ <title>VML Playground</title>
+
+ <style type="text/css">
+ #input {
+ width: 90%;
+ height: 200px;
+ margin: 10px;
+ }
+
+ #output {
+ margin: 10px;
+ height: 400px;
+ position: relative;
+ border: 1px solid #CCC;
+ }
+
+ v\:*, v\:* * {
+ behavior: url(#default#VML);
+ position: absolute;
+ }
+ </style>
+
+ <script type="text/javascript">
+ window.onload = function() {
+ var input = document.getElementById('input'),
+ output = document.getElementById('output'),
+ timer;
+
+ function update() {
+ output.innerHTML = input.value;
+ }
+
+ input.onkeyup = function() {
+ if (timer) {
+ clearTimeout(timer);
+ }
+ timer = setTimeout(update, 500);
+ };
+
+ update();
+ }
+ </script>
+
+</head>
+<body>
+
+ <textarea id="input">
+<outset-box-shadow style="POSITION: absolute; TOP: 0px; LEFT: 0px">
+ <group1>
+ <v:shape coordsize="408,208" coordorigin="1,1" path=" m-16,32 qy32,-16 l376,-16 qx424,32 l424,176 qy376,224 l32,224 qx-16,176 x e" stroked="false" filled="true"
+ style="POSITION: absolute; WIDTH: 204px; HEIGHT: 104px; TOP: 4px; LEFT: 0px">
+ <v:fill type="gradientTitle" color="#999" color2="#999" colors="" opacity="0" src="" position="0,0" angle="0" method="any" focusposition="4766f,8738f" focussize="56003f,48059f" />
+ <v:stroke color="black" weight="0.75" dashstyle="" linestyle="single" />
+ </v:shape>
+ </group1>
+</outset-box-shadow>
+<background style="POSITION: absolute; TOP: 0px; LEFT: 0px">
+ <group2>
+ <v:shape coordsize="408,208" coordorigin="1,1" path=" m0,32 qy32,0 l376,0 qx408,32 l408,176 qy376,208 l32,208 qx0,176 x e" stroked="false" filled="true"
+ style="POSITION: absolute; WIDTH: 204px; HEIGHT: 104px; TOP: 0px; LEFT: 0px">
+ <v:fill type="gradient" color="#9cf" color2="#03c" colors="" opacity="1" src="" position="0,0" angle="180" method="sigma" focusposition="0,0" focussize="0,0" />
+ <v:stroke color="black" weight="0.75" dashstyle="" linestyle="single" />
+ </v:shape>
+ </group2>
+</background>
+<border style="POSITION: absolute; TOP: 0px; LEFT: 0px">
+ <v:shape coordsize="408,208" coordorigin="1,1" path=" m2,32 qy32,2 l376,2 qx406,32 l406,176 qy376,206 l32,206 qx2,176 x e" stroked="true" filled="false"
+ style="POSITION: absolute; WIDTH: 204px; HEIGHT: 104px; TOP: 0px; LEFT: 0px">
+ <v:fill type="solid" color="white" color2="white" colors="" opacity="1" src="" position="0,0" angle="0" method="any" focusposition="0,0" focussize="0,0" />
+ <v:stroke color="#00c" weight="1.5" dashstyle="solid" linestyle="single" />
+ </v:shape>
+</border>
+<!-- <v:skew on="t" origin="0,0" matrix="1 0 0 1 0 0" /> -->
+ </textarea>
+
+ <div id="output">
+ <!-- VML will get inserted here -->
+ </div>
+
+</body>
+</html>

No commit comments for this range

Something went wrong with that request. Please try again.