Last active
August 30, 2016 20:32
-
-
Save thednp/0b93068e20adb84658b5840ead0a07f8 to your computer and use it in GitHub Desktop.
process SVG transforms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// function to process a **string value of a SVG transform attribute** to have same aspect as a CSS3 transform | |
// with the transform origin of 50% 50% | |
// http://stackoverflow.com/questions/39191054/how-to-compensate-translate-when-skewx-and-skewy-are-used-on-svg/39210937 | |
function combineTranslates(transform) { | |
var ts = [], // will contain list of elementary transformations | |
r = /\s*([A-Za-z0-9]+\s*\([\-0-9.,\s]*\))/g, | |
match, | |
pos = 0, // used during tokenization | |
deg = Math.PI/180.0, | |
x = 0, y = 0, // translation gets accumulated here | |
tmp; | |
// Tokenize transform into individual elementary transformations | |
while (match = r.exec(transform)) { | |
if (match.index !== pos) throw Error('Invalid transform: ' + transform); | |
pos += match[0].length; | |
ts.push(match[1]); | |
} | |
// TODO: check that only whitespace remains after matches | |
//console.log(ts); | |
// Iterate over transformations from inside to outside | |
for (var i = ts.length - 1; i >= 0; --i) { | |
match = /([A-Za-z0-9]+)\s*\(([\-0-9.,\s]*)\)/.exec(ts[i]); | |
var op = match[1], | |
args = match[2].replace(/\s+/g, '').split(',').map(Number); | |
//console.log(op, args); | |
switch (op) { | |
// Apply given transformation to (x,y) vector | |
case 'translate': | |
x += args[0]; | |
y += args[1]; | |
ts.splice(i, 1); // Drop translate from ts array | |
break; | |
case 'rotate': | |
var angle = args[0]*deg, | |
cos = Math.cos(angle), | |
sin = Math.sin(angle); | |
tmp = cos*x - sin*y; | |
y = sin*x + cos*y; | |
x = tmp; | |
break; | |
case 'scale': | |
x *= args[0]; | |
y *= (args.length === 1 ? args[0] : args[1]); | |
break; | |
case 'skewX': | |
x += y*Math.tan(args[0]*deg); | |
break; | |
case 'skewY': | |
y += x*Math.tan(args[0]*deg); | |
break; | |
default: | |
throw Error('Unknown transform ' + op) | |
} | |
} | |
ts.unshift('translate('+x+','+y+')'); // add as first element | |
//console.log('From '+transform+'\n to '+ts.join(' ')); | |
return ts.join(' '); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// my clean take on the problem, with almost working code | |
var tf = { translate: [0,0], rotate: [0,0,0], skewX: 0, skewY: 0, scale: 1 } | |
if ('scale' in tf) { | |
!('translate' in tf) && ( tf['translate'] = [0,0] ); // if no translate is found in current value or next value, we default to 0 | |
tf['translate'][0] += (1-tf['scale']) * bb.width/2; | |
tf['translate'][1] += (1-tf['scale']) * bb.height/2; | |
// adjust rotation transform origin and translation when skews are used, to make the animation look exactly the same as if we were't using svgTransform | |
// http://stackoverflow.com/questions/39191054/how-to-compensate-translate-when-skewx-and-skewy-are-used-on-svg/39192565#39192565 | |
if ('rotate' in tf) { | |
tf['rotate'][1] -= 'skewX' in tf ? Math.tan(tf['skewX']) * bb.height : 0; | |
tf['rotate'][2] -= 'skewY' in tf ? Math.tan(tf['skewY']) * bb.width : 0; | |
} | |
tf['translate'][0] += 'skewX' in tf ? Math.tan(tf['skewX']) * bb.height*2 : 0; | |
tf['translate'][1] += 'skewY' in tf ? Math.tan(tf['skewY']) * bb.width*2 : 0; | |
} else if (!('scale' in tf) && !('rotate' in tf) ) { | |
!('translate' in tf) && ( tf['translate'] = [bb.x,bb.y] ); // if no translate is found in current value or next value, we default to 0 | |
tf['translate'][0] += 'skewX' in tf ? (Math.tan(tf['skewX']) * bb.height/Math.PI)/2 : 0; | |
tf['translate'][1] += 'skewY' in tf ? (Math.tan(tf['skewY']) * bb.width/Math.PI)/2 : 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// function to process an **object** with SVG transform attribute values | |
// to have same aspect as a CSS3 transform with the transform origin of 50% 50% | |
// http://stackoverflow.com/questions/39191054/how-to-compensate-translate-when-skewx-and-skewy-are-used-on-svg/39210937 | |
function combineTranslates(t) { | |
var deg = Math.PI/180.0, | |
x = 0, y = 0, tmp; // translation gets accumulated here | |
// Iterate over transformations from inside to outside | |
for (var op in t) { | |
var args = t[op]; | |
switch (op) { | |
// Apply given transformation to (x,y) vector | |
case 'translate': x += args[0]; y += args.length === 2 ? args[1] : 0; break; // Drop translate from ts array | |
case 'rotate': | |
var angle = args[0]*deg, cos = Math.cos(angle), sin = Math.sin(angle); | |
tmp = cos*x - sin*y; y = sin*x + cos*y; x = tmp; | |
break; | |
case 'scale': x *= args; y *= args; break; // x *= args[0]; y *= (args.length === 1 ? args[0] : args[1]); | |
case 'skewX': x += y*Math.tan(args*deg); break; | |
case 'skewY': y += x*Math.tan(args*deg); break; | |
default: throw Error('Unknown transform function ' + op) | |
} | |
} | |
return [x,y]; | |
}; | |
// console.log(combineTranslates(tf) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment