animated-path-helpers.js (3066B)
1 function roundNumbers(value, digits) { 2 // Round numbers to |digits| decimal places. 3 return value. 4 replace(/-?\d*\.\d+(e-?\d+)?/g, function(n) { 5 return (parseFloat(n).toFixed(digits)). 6 replace(/\.\d+/, function(m) { 7 return m.replace(/0+$/, ''); 8 }). 9 replace(/\.$/, ''). 10 replace(/^-0$/, '0'); 11 }); 12 } 13 14 function normalizeValue(value, digits) { 15 // Round numbers and place whitespace between tokens. 16 return roundNumbers(value, digits). 17 replace(/([\w\d.]+|[^\s])/g, '$1 '). 18 replace(/\s+/g, ' '); 19 } 20 21 // Transform a path seg list into a path string, rounding numbers to |digits| 22 // decimal places. 23 function serializePathSegList(list, digits) { 24 function segmentArguments(segment) { 25 const kCommandDescriptor = { 26 'M': ['x', 'y'], 27 'L': ['x', 'y'], 28 'C': ['x1', 'y1', 'x2', 'y2', 'x', 'y'], 29 'Q': ['x1', 'y1', 'x', 'y'], 30 'S': ['x2', 'y2', 'x', 'y'], 31 'T': ['x', 'y'], 32 'A': ['r1', 'r2', 'angle', 'largeArcFlag', 'sweepFlag', 'x', 'y'], 33 'H': ['x'], 34 'V': ['y'], 35 'Z': [] 36 }; 37 let command = segment.pathSegTypeAsLetter.toUpperCase(); 38 return kCommandDescriptor[command].map(field => { 39 return Number(segment[field]).toFixed(digits); 40 }); 41 } 42 return Array.from(list).map(segment => { 43 let command = segment.pathSegTypeAsLetter; 44 if (command === 'z') 45 command = 'Z'; 46 return [command, ...segmentArguments(segment)].join(' '); 47 }).join(' '); 48 } 49 50 function normalizeProperty(path_string) { 51 let probePathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 52 probePathElement.setAttribute('d', path_string); 53 document.documentElement.appendChild(probePathElement); 54 let string = getComputedStyle(probePathElement).getPropertyValue('d'); 55 probePathElement.remove(); 56 return string; 57 } 58 59 // Assert that the animated path data of |target| matches one of 60 // |expected_paths|. Numbers will be rounded to 2 decimal places. 61 function assert_animated_path_in_array(target, expected_paths) { 62 const kDecimals = 2; 63 let expected, actual; 64 if ('animatedPathSegList' in target) { 65 let probePathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 66 expected = expected_paths.map(p => { 67 probePathElement.setAttribute('d', p); 68 return serializePathSegList(probePathElement.pathSegList, kDecimals) 69 }); 70 actual = serializePathSegList(target.animatedPathSegList, kDecimals); 71 } else if ('d' in target.style) { 72 expected = expected_paths.map(p => normalizeValue(normalizeProperty(p), kDecimals)); 73 actual = normalizeValue(getComputedStyle(target).getPropertyValue('d'), kDecimals); 74 } else { 75 assert_unreached('no animated path data'); 76 } 77 assert_in_array(actual, expected); 78 } 79 80 // Assert that the animated path data of |target| matches that of 81 // |expected_path_string|. Numbers will be rounded to 2 decimal places. 82 function assert_animated_path_equals(target, expected_path_string) { 83 return assert_animated_path_in_array(target, [expected_path_string]); 84 }