1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | (function(scope, testing) {
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | var _ = null;
|
21 | function cast(pattern) {
|
22 | return function(contents) {
|
23 | var i = 0;
|
24 | return pattern.map(function(x) { return x === _ ? contents[i++] : x; });
|
25 | }
|
26 | }
|
27 |
|
28 | function id(x) { return x; }
|
29 |
|
30 | var Opx = {px: 0};
|
31 | var Odeg = {deg: 0};
|
32 |
|
33 |
|
34 |
|
35 | var transformFunctions = {
|
36 | matrix: ['NNNNNN', [_, _, 0, 0, _, _, 0, 0, 0, 0, 1, 0, _, _, 0, 1], id],
|
37 | matrix3d: ['NNNNNNNNNNNNNNNN', id],
|
38 | rotate: ['A'],
|
39 | rotatex: ['A'],
|
40 | rotatey: ['A'],
|
41 | rotatez: ['A'],
|
42 | rotate3d: ['NNNA'],
|
43 | perspective: ['L'],
|
44 | scale: ['Nn', cast([_, _, 1]), id],
|
45 | scalex: ['N', cast([_, 1, 1]), cast([_, 1])],
|
46 | scaley: ['N', cast([1, _, 1]), cast([1, _])],
|
47 | scalez: ['N', cast([1, 1, _])],
|
48 | scale3d: ['NNN', id],
|
49 | skew: ['Aa', null, id],
|
50 | skewx: ['A', null, cast([_, Odeg])],
|
51 | skewy: ['A', null, cast([Odeg, _])],
|
52 | translate: ['Tt', cast([_, _, Opx]), id],
|
53 | translatex: ['T', cast([_, Opx, Opx]), cast([_, Opx])],
|
54 | translatey: ['T', cast([Opx, _, Opx]), cast([Opx, _])],
|
55 | translatez: ['L', cast([Opx, Opx, _])],
|
56 | translate3d: ['TTL', id],
|
57 | };
|
58 |
|
59 | function parseTransform(string) {
|
60 | string = string.toLowerCase().trim();
|
61 | if (string == 'none')
|
62 | return [];
|
63 |
|
64 | var transformRegExp = /\s*(\w+)\(([^)]*)\)/g;
|
65 | var result = [];
|
66 | var match;
|
67 | var prevLastIndex = 0;
|
68 | while (match = transformRegExp.exec(string)) {
|
69 | if (match.index != prevLastIndex)
|
70 | return;
|
71 | prevLastIndex = match.index + match[0].length;
|
72 | var functionName = match[1];
|
73 | var functionData = transformFunctions[functionName];
|
74 | if (!functionData)
|
75 | return;
|
76 | var args = match[2].split(',');
|
77 | var argTypes = functionData[0];
|
78 | if (argTypes.length < args.length)
|
79 | return;
|
80 |
|
81 | var parsedArgs = [];
|
82 | for (var i = 0; i < argTypes.length; i++) {
|
83 | var arg = args[i];
|
84 | var type = argTypes[i];
|
85 | var parsedArg;
|
86 | if (!arg)
|
87 | parsedArg = ({a: Odeg,
|
88 | n: parsedArgs[0],
|
89 | t: Opx})[type];
|
90 | else
|
91 | parsedArg = ({A: function(s) { return s.trim() == '0' ? Odeg : scope.parseAngle(s); },
|
92 | N: scope.parseNumber,
|
93 | T: scope.parseLengthOrPercent,
|
94 | L: scope.parseLength})[type.toUpperCase()](arg);
|
95 | if (parsedArg === undefined)
|
96 | return;
|
97 | parsedArgs.push(parsedArg);
|
98 | }
|
99 | result.push({t: functionName, d: parsedArgs});
|
100 |
|
101 | if (transformRegExp.lastIndex == string.length)
|
102 | return result;
|
103 | }
|
104 | };
|
105 |
|
106 | function numberToLongString(x) {
|
107 | return x.toFixed(6).replace('.000000', '');
|
108 | }
|
109 |
|
110 | function mergeMatrices(left, right) {
|
111 | if (left.decompositionPair !== right) {
|
112 | left.decompositionPair = right;
|
113 | var leftArgs = scope.makeMatrixDecomposition(left);
|
114 | }
|
115 | if (right.decompositionPair !== left) {
|
116 | right.decompositionPair = left;
|
117 | var rightArgs = scope.makeMatrixDecomposition(right);
|
118 | }
|
119 | if (leftArgs[0] == null || rightArgs[0] == null)
|
120 | return [[false], [true], function(x) { return x ? right[0].d : left[0].d; }];
|
121 | leftArgs[0].push(0);
|
122 | rightArgs[0].push(1);
|
123 | return [
|
124 | leftArgs,
|
125 | rightArgs,
|
126 | function(list) {
|
127 | var quat = scope.quat(leftArgs[0][3], rightArgs[0][3], list[5]);
|
128 | var mat = scope.composeMatrix(list[0], list[1], list[2], quat, list[4]);
|
129 | var stringifiedArgs = mat.map(numberToLongString).join(',');
|
130 | return stringifiedArgs;
|
131 | }
|
132 | ];
|
133 | }
|
134 |
|
135 | function typeTo2D(type) {
|
136 | return type.replace(/[xy]/, '');
|
137 | }
|
138 |
|
139 | function typeTo3D(type) {
|
140 | return type.replace(/(x|y|z|3d)?$/, '3d');
|
141 | }
|
142 |
|
143 | function mergeTransforms(left, right) {
|
144 | var matrixModulesLoaded = scope.makeMatrixDecomposition && true;
|
145 |
|
146 | var flipResults = false;
|
147 | if (!left.length || !right.length) {
|
148 | if (!left.length) {
|
149 | flipResults = true;
|
150 | left = right;
|
151 | right = [];
|
152 | }
|
153 | for (var i = 0; i < left.length; i++) {
|
154 | var type = left[i].t;
|
155 | var args = left[i].d;
|
156 | var defaultValue = type.substr(0, 5) == 'scale' ? 1 : 0;
|
157 | right.push({t: type, d: args.map(function(arg) {
|
158 | if (typeof arg == 'number')
|
159 | return defaultValue;
|
160 | var result = {};
|
161 | for (var unit in arg)
|
162 | result[unit] = defaultValue;
|
163 | return result;
|
164 | })});
|
165 | }
|
166 | }
|
167 |
|
168 | var isMatrixOrPerspective = function(lt, rt) {
|
169 | return ((lt == 'perspective') && (rt == 'perspective')) ||
|
170 | ((lt == 'matrix' || lt == 'matrix3d') && (rt == 'matrix' || rt == 'matrix3d'));
|
171 | };
|
172 | var leftResult = [];
|
173 | var rightResult = [];
|
174 | var types = [];
|
175 |
|
176 | if (left.length != right.length) {
|
177 | if (!matrixModulesLoaded)
|
178 | return;
|
179 | var merged = mergeMatrices(left, right);
|
180 | leftResult = [merged[0]];
|
181 | rightResult = [merged[1]];
|
182 | types = [['matrix', [merged[2]]]];
|
183 | } else {
|
184 | for (var i = 0; i < left.length; i++) {
|
185 | var leftType = left[i].t;
|
186 | var rightType = right[i].t;
|
187 | var leftArgs = left[i].d;
|
188 | var rightArgs = right[i].d;
|
189 |
|
190 | var leftFunctionData = transformFunctions[leftType];
|
191 | var rightFunctionData = transformFunctions[rightType];
|
192 |
|
193 | var type;
|
194 | if (isMatrixOrPerspective(leftType, rightType)) {
|
195 | if (!matrixModulesLoaded)
|
196 | return;
|
197 | var merged = mergeMatrices([left[i]], [right[i]]);
|
198 | leftResult.push(merged[0]);
|
199 | rightResult.push(merged[1]);
|
200 | types.push(['matrix', [merged[2]]]);
|
201 | continue;
|
202 | } else if (leftType == rightType) {
|
203 | type = leftType;
|
204 | } else if (leftFunctionData[2] && rightFunctionData[2] && typeTo2D(leftType) == typeTo2D(rightType)) {
|
205 | type = typeTo2D(leftType);
|
206 | leftArgs = leftFunctionData[2](leftArgs);
|
207 | rightArgs = rightFunctionData[2](rightArgs);
|
208 | } else if (leftFunctionData[1] && rightFunctionData[1] && typeTo3D(leftType) == typeTo3D(rightType)) {
|
209 | type = typeTo3D(leftType);
|
210 | leftArgs = leftFunctionData[1](leftArgs);
|
211 | rightArgs = rightFunctionData[1](rightArgs);
|
212 | } else {
|
213 | if (!matrixModulesLoaded)
|
214 | return;
|
215 | var merged = mergeMatrices(left, right);
|
216 | leftResult = [merged[0]];
|
217 | rightResult = [merged[1]];
|
218 | types = [['matrix', [merged[2]]]];
|
219 | break;
|
220 | }
|
221 |
|
222 | var leftArgsCopy = [];
|
223 | var rightArgsCopy = [];
|
224 | var stringConversions = [];
|
225 | for (var j = 0; j < leftArgs.length; j++) {
|
226 | var merge = typeof leftArgs[j] == 'number' ? scope.mergeNumbers : scope.mergeDimensions;
|
227 | var merged = merge(leftArgs[j], rightArgs[j]);
|
228 | leftArgsCopy[j] = merged[0];
|
229 | rightArgsCopy[j] = merged[1];
|
230 | stringConversions.push(merged[2]);
|
231 | }
|
232 | leftResult.push(leftArgsCopy);
|
233 | rightResult.push(rightArgsCopy);
|
234 | types.push([type, stringConversions]);
|
235 | }
|
236 | }
|
237 |
|
238 | if (flipResults) {
|
239 | var tmp = leftResult;
|
240 | leftResult = rightResult;
|
241 | rightResult = tmp;
|
242 | }
|
243 |
|
244 | return [leftResult, rightResult, function(list) {
|
245 | return list.map(function(args, i) {
|
246 | var stringifiedArgs = args.map(function(arg, j) {
|
247 | return types[i][1][j](arg);
|
248 | }).join(',');
|
249 | if (types[i][0] == 'matrix' && stringifiedArgs.split(',').length == 16)
|
250 | types[i][0] = 'matrix3d';
|
251 | return types[i][0] + '(' + stringifiedArgs + ')';
|
252 |
|
253 | }).join(' ');
|
254 | }];
|
255 | }
|
256 |
|
257 | scope.addPropertiesHandler(parseTransform, mergeTransforms, ['transform']);
|
258 |
|
259 | scope.transformToSvgMatrix = function(string) {
|
260 |
|
261 | var mat = scope.transformListToMatrix(parseTransform(string));
|
262 | return 'matrix(' +
|
263 | numberToLongString(mat[0]) + ' ' +
|
264 | numberToLongString(mat[1]) + ' ' +
|
265 | numberToLongString(mat[4]) + ' ' +
|
266 | numberToLongString(mat[5]) + ' ' +
|
267 | numberToLongString(mat[12]) + ' ' +
|
268 | numberToLongString(mat[13]) +
|
269 | ')';
|
270 | };
|
271 |
|
272 | if (WEB_ANIMATIONS_TESTING)
|
273 | testing.parseTransform = parseTransform;
|
274 |
|
275 | })(webAnimations1, webAnimationsTesting);
|