Comparing version 0.1.9 to 0.2.0
@@ -0,1 +1,8 @@ | ||
### [ [>](https://github.com/svg/svgo/tree/v0.2.0) ] 0.2.0 / 23.12.2012 | ||
* plugins/convertPathData: apply transforms to Path pata (close [#33](https://github.com/svg/svgo/issues/33)) | ||
* plugins/convertPathData: `-1.816-9.278.682-13.604` parsing error (fix [#85](https://github.com/svg/svgo/issues/85)) | ||
* plugins/convertTransform: `translate(10, 0)` eq `translate(10)`, but not `translate(10, 10)` eq `translate(10)` (fix [#83](https://github.com/svg/svgo/issues/83)) | ||
* run plugins/cleanupIDs before plugins/collapseGroups (fix [#84](https://github.com/svg/svgo/issues/84)) | ||
* update `.gitignore` | ||
### [ [>](https://github.com/svg/svgo/tree/v0.1.9) ] 0.1.9 / 17.12.2012 | ||
@@ -2,0 +9,0 @@ * plugins/cleanupIDs: renamed from removeUnusedIDs; minify used IDs (fix [#7](https://github.com/svg/svgo/issues/7)) |
@@ -57,3 +57,4 @@ 'use strict'; | ||
var str = '', | ||
delimiter; | ||
delimiter, | ||
prev; | ||
@@ -70,7 +71,16 @@ data.forEach(function(item, i) { | ||
// no extra space in front of negative number | ||
if (params.negativeExtraSpace && item < 0) { | ||
// no extra space in front of negative number or | ||
// in front of a floating number if a previous number is floating too | ||
if ( | ||
params.negativeExtraSpace && | ||
(item < 0 || | ||
(item > 0 && item < 1 && prev % 1 !== 0) | ||
) | ||
) { | ||
delimiter = ''; | ||
} | ||
// save prev item value | ||
prev = item; | ||
// remove floating-point numbers leading zeros | ||
@@ -77,0 +87,0 @@ // 0.5 → .5 |
{ | ||
"name": "svgo", | ||
"version": "0.1.9", | ||
"version": "0.2.0", | ||
"description": "Nodejs-based tool for optimizing SVG vector graphics files", | ||
@@ -9,3 +9,3 @@ "keywords": [ "svgo", "svg", "optimize", "minify" ], | ||
"url": "https://github.com/svg/svgo/issues", | ||
"email": "svgo@soulshine.in" | ||
"email": "kir@soulshine.in" | ||
}, | ||
@@ -12,0 +12,0 @@ "author": { |
@@ -5,5 +5,7 @@ 'use strict'; | ||
regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/, | ||
regPathData = /[\-+]?\d*\.?\d+(\.\d+)?([eE][\-+]?\d+)?/g, | ||
regPathData = /[\-+]?\d*\.?\d+([eE][\-+]?\d+)?/g, | ||
pathElems = ['path', 'glyph', 'missing-glyph'], | ||
hasMarkerMid; | ||
hasMarkerMid, | ||
transform2js = require('./_transforms.js').transform2js, | ||
transformsMultiply = require('./_transforms.js').transformsMultiply; | ||
@@ -34,8 +36,16 @@ /** | ||
// TODO: get rid of functions returns | ||
if (data.length) { | ||
data = convertToRelative(data); | ||
if (params.applyTransforms) { | ||
data = applyTransforms(item, data); | ||
} | ||
data = filters(data, params); | ||
data = collapseRepeated(data, params); | ||
if (params.collapseRepeated) { | ||
data = collapseRepeated(data, params); | ||
} | ||
@@ -54,3 +64,2 @@ item.attr('d').value = js2path(data, params); | ||
* @param {Object} params plugin params | ||
* | ||
* @return {Array} output array | ||
@@ -144,3 +153,2 @@ */ | ||
* @param {Object} params plugin params | ||
* | ||
* @return {Array} output path data | ||
@@ -306,2 +314,107 @@ */ | ||
/** | ||
* Apply transformation(s) to the Path data. | ||
* | ||
* @param {Object} elem current element | ||
* @param {Array} path input path data | ||
* @return {Array} output path data | ||
*/ | ||
function applyTransforms(elem, path) { | ||
// if there are no 'stroke' attr and 'a' segments | ||
if ( | ||
elem.hasAttr('transform') && | ||
!elem.hasAttr('stroke') && | ||
path.every(function(i) { return i.instruction !== 'a'; }) | ||
) { | ||
var matrix = transformsMultiply(transform2js(elem.attr('transform').value)), | ||
currentPoint; | ||
// if there is a translate() transform | ||
if (matrix.data[4] !== 0 || matrix.data[5] !== 0) { | ||
// then apply it only to the first absoluted M | ||
currentPoint = transformPoint(matrix.data, path[0].data[0], path[0].data[1]); | ||
path[0].data[0] = currentPoint[0]; | ||
path[0].data[1] = currentPoint[1]; | ||
// clear translate() data from transform matrix | ||
matrix.data[4] = 0; | ||
matrix.data[5] = 0; | ||
// apply transform to other segments | ||
path.slice(1).forEach(function(pathItem) { | ||
pathItem = transformData(matrix, pathItem); | ||
}); | ||
} else { | ||
path.forEach(function(pathItem) { | ||
pathItem = transformData(matrix, pathItem); | ||
}); | ||
} | ||
// remove transform attr | ||
elem.removeAttr('transform'); | ||
} | ||
return path; | ||
} | ||
/** | ||
* Apply transformation(s) to the Path item data. | ||
* | ||
* @param {Array} matrix transform 3x3 matrix | ||
* @param {Object} item input Path item | ||
* @return {Object} output Path item | ||
*/ | ||
function transformData(matrix, item) { | ||
if (item.data) { | ||
var currentPoint; | ||
// h | ||
if (item.instruction === 'h') { | ||
item.instruction = 'l'; | ||
item.data[1] = 0; | ||
// v | ||
} else if (item.instruction === 'v') { | ||
item.instruction = 'l'; | ||
item.data[1] = item.data[0]; | ||
item.data[0] = 0; | ||
} | ||
for (var i = 0; i < item.data.length; i += 2) { | ||
currentPoint = transformPoint(matrix.data, item.data[i], item.data[i + 1]); | ||
item.data[i] = currentPoint[0]; | ||
item.data[i + 1] = currentPoint[1]; | ||
} | ||
} | ||
return item; | ||
} | ||
/** | ||
* Apply transform 3x3 matrix to x-y point. | ||
* | ||
* @param {Array} matrix transform 3x3 matrix | ||
* @param {Array} point x-y point | ||
* @return {Array} point with new coordinates | ||
*/ | ||
function transformPoint(matrix, x, y) { | ||
return [ | ||
matrix[0] * x + matrix[2] * y + matrix[4], | ||
matrix[1] * x + matrix[3] * y + matrix[5] | ||
]; | ||
} | ||
/** | ||
* Main filters loop. | ||
@@ -311,3 +424,2 @@ * | ||
* @param {Object} params plugin params | ||
* | ||
* @return {Array} output path data | ||
@@ -546,3 +658,2 @@ */ | ||
// collapse repeated instructions data | ||
/** | ||
@@ -552,38 +663,32 @@ * Collapse repeated instructions data | ||
* @param {Array} path input path data | ||
* @param {Object} params plugin params | ||
* | ||
* @return {Array} output path data | ||
*/ | ||
function collapseRepeated(path, params) { | ||
function collapseRepeated(path) { | ||
if (params.collapseRepeated) { | ||
var prev; | ||
var prev; | ||
path = path.filter(function(item) { | ||
path = path.filter(function(item) { | ||
if ( | ||
!hasMarkerMid && | ||
prev && | ||
item.instruction === prev.instruction | ||
) { | ||
// increase previous h or v data with current | ||
if (item.instruction === 'h' || item.instruction === 'v') { | ||
prev.data[0] += item.data[0]; | ||
// concat previous data with current | ||
} else { | ||
prev.data = prev.data.concat(item.data); | ||
} | ||
// filter current item | ||
return false; | ||
if ( | ||
!hasMarkerMid && | ||
prev && | ||
item.instruction === prev.instruction | ||
) { | ||
// increase previous h or v data with current | ||
if (item.instruction === 'h' || item.instruction === 'v') { | ||
prev.data[0] += item.data[0]; | ||
// concat previous data with current | ||
} else { | ||
prev.data = prev.data.concat(item.data); | ||
} | ||
prev = item; | ||
// filter current item | ||
return false; | ||
} | ||
return true; | ||
prev = item; | ||
}); | ||
return true; | ||
} | ||
}); | ||
@@ -600,3 +705,2 @@ return path; | ||
* @param {Number} fixed number of decimals | ||
* | ||
* @return {Array} output data array | ||
@@ -619,3 +723,2 @@ */ | ||
* @param {Array} ys array of curve points y-coordinates | ||
* | ||
* @return {Boolean} | ||
@@ -646,3 +749,2 @@ */ | ||
* @param {Object} params plugin params | ||
* | ||
* @return {String} output path string | ||
@@ -652,3 +754,3 @@ */ | ||
// out path data string | ||
// output path data string | ||
var pathString = ''; | ||
@@ -655,0 +757,0 @@ |
'use strict'; | ||
var cleanupOutData = require('../lib/svgo/tools').cleanupOutData, | ||
regTransformTypes = /matrix|translate|scale|rotate|skewX|skewY/, | ||
regTransformSplit = /(matrix|translate|scale|rotate|skewX|skewY)\s*\((.+?)\)[\s,]*/, | ||
regTransformDataSplit = /[\s,]+/; | ||
transform2js = require('./_transforms.js').transform2js, | ||
transformsMultiply = require('./_transforms.js').transformsMultiply, | ||
matrixToTransform = require('./_transforms.js').matrixToTransform; | ||
@@ -64,4 +64,13 @@ /** | ||
if (params.collapseIntoOne) { | ||
data = collapseIntoOne(data, params); | ||
if ( | ||
params.collapseIntoOne && | ||
(data.length >= 3 || | ||
data.some(function(i) { return i.name === 'matrix'; }) | ||
) | ||
) { | ||
data = [transformsMultiply(data, params)]; | ||
if (params.matrixToTransform) { | ||
data = [matrixToTransform(data[0], params)]; | ||
} | ||
} | ||
@@ -74,42 +83,2 @@ | ||
/** | ||
* Convert transform string to JS representation. | ||
* | ||
* @param {String} transformString input string | ||
* @param {Object} params plugin params | ||
* | ||
* @return {Array} output array | ||
*/ | ||
function transform2js(transformString) { | ||
// JS representation of the transform data | ||
var transforms = [], | ||
// current transform context | ||
current; | ||
// split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', ''] | ||
transformString.split(regTransformSplit).forEach(function(item) { | ||
if (item) { | ||
// if item is a translate function | ||
if (regTransformTypes.test(item)) { | ||
// then collect it and change current context | ||
transforms.push(current = { | ||
name: item | ||
}); | ||
// else if item is data | ||
} else { | ||
// then split it into [10, 50] and collect as context.data | ||
current.data = item.split(regTransformDataSplit).map(function(i) { | ||
return +i; | ||
}); | ||
} | ||
} | ||
}); | ||
return transforms; | ||
} | ||
/** | ||
* Convert transforms to the shorthand alternatives. | ||
@@ -119,3 +88,2 @@ * | ||
* @param {Object} params plugin params | ||
* | ||
* @return {Array} output array | ||
@@ -146,11 +114,24 @@ */ | ||
// convert long translate or scale transform notations to the shorts ones | ||
// convert long translate transform notation to the shorts one | ||
// translate(10 0) → translate(10) | ||
if ( | ||
params.shortTranslateScale && | ||
(transform.name === 'translate' || | ||
transform.name === 'scale') | ||
params.shortTranslate && | ||
transform.name === 'translate' && | ||
transform.data.length === 2 && | ||
transform.data[1] === 0 | ||
) { | ||
transform.data = longTranslateScaleToShort(transform.data); | ||
transform.data = [transform.data[0]]; | ||
} | ||
// convert long scale transform notation to the shorts one | ||
// scale(2 2) → scale(2) | ||
if ( | ||
params.shortScale && | ||
transform.name === 'scale' && | ||
transform.data.length === 2 && | ||
transform.data[0] === transform.data[1] | ||
) { | ||
transform.data = [transform.data[0]]; | ||
} | ||
// convert long rotate transform notation to the short one | ||
@@ -192,3 +173,2 @@ // translate(cx cy) rotate(a) translate(-cx -cy) → rotate(a cx cy) | ||
* @param {Array} transforms input array | ||
* | ||
* @return {Array} output array | ||
@@ -223,45 +203,2 @@ */ | ||
/** | ||
* Collapse multiple transforms into one. | ||
* | ||
* @param {Array} transforms input array | ||
* @param {Object} params plugin params | ||
* | ||
* @return {Array} output array | ||
*/ | ||
function collapseIntoOne(transforms, params) { | ||
if ( | ||
(transforms.length >= 3 || | ||
transforms.some(function(i) { return i.name === 'matrix'; })) | ||
) { | ||
// convert transforms objects to the matrices | ||
transforms = transforms.map(function(transform) { | ||
return transform.name === 'martix' ? | ||
transform : | ||
transformToMatrix(transform, params); | ||
}); | ||
// multiply all matrices into one | ||
transforms = { | ||
name: 'matrix', | ||
data: transforms.reduce(function(a, b) { | ||
return multiplyTransformMatrices(a, b); | ||
}) | ||
}; | ||
// and try to get a jackpot | ||
if (params.matrixToTransform) { | ||
transforms = matrixToTransform(transforms, params); | ||
} | ||
transforms = [transforms]; | ||
} | ||
return transforms; | ||
} | ||
/** | ||
* Convert transforms JS representation to string. | ||
@@ -271,3 +208,2 @@ * | ||
* @param {Object} params plugin params | ||
* | ||
* @return {String} output string | ||
@@ -291,161 +227,2 @@ */ | ||
/** | ||
* Do math like a schoolgirl. | ||
* | ||
* @type {Object} | ||
*/ | ||
var mth = { | ||
rad: function(deg) { | ||
return deg * Math.PI / 180; | ||
}, | ||
deg: function(rad) { | ||
return rad * 180 / Math.PI; | ||
}, | ||
cos: function(deg) { | ||
return Math.cos(this.rad(deg)); | ||
}, | ||
acos: function(val, floatPrecision) { | ||
return +(this.deg(Math.acos(val)).toFixed(floatPrecision)); | ||
}, | ||
sin: function(deg) { | ||
return Math.sin(this.rad(deg)); | ||
}, | ||
asin: function(val, floatPrecision) { | ||
return +(this.deg(Math.asin(val)).toFixed(floatPrecision)); | ||
}, | ||
tan: function(deg) { | ||
return Math.tan(this.rad(deg)); | ||
}, | ||
atan: function(val, floatPrecision) { | ||
return +(this.deg(Math.atan(val)).toFixed(floatPrecision)); | ||
} | ||
}; | ||
/** | ||
* Convert transform to the matrix data. | ||
* | ||
* @param {Object} transform transform object | ||
* | ||
* @return {Array} matrix data | ||
*/ | ||
function transformToMatrix(transform) { | ||
if (transform.name === 'matrix') return transform.data; | ||
var matrix; | ||
switch(transform.name) { | ||
case 'translate': | ||
// [1, 0, 0, 1, tx, ty] | ||
matrix = [1, 0, 0, 1, transform.data[0], transform.data[1] || transform.data[0]]; | ||
break; | ||
case 'scale': | ||
// [sx, 0, 0, sy, 0, 0] | ||
matrix = [transform.data[0], 0, 0, transform.data[1] || transform.data[0], 0, 0]; | ||
break; | ||
case 'rotate': | ||
// [cos(a), sin(a), -sin(a), cos(a), 0, 0] | ||
var cos = mth.cos(transform.data[0]), | ||
sin = mth.sin(transform.data[0]); | ||
matrix = [cos, sin, -sin, cos, 0, 0]; | ||
break; | ||
case 'skewX': | ||
// [1, 0, tan(a), 1, 0, 0] | ||
matrix = [1, 0, mth.tan(transform.data[0]), 1, 0, 0]; | ||
break; | ||
case 'skewY': | ||
// [1, tan(a), 0, 1, 0, 0] | ||
matrix = [1, mth.tan(transform.data[0]), 0, 1, 0, 0]; | ||
break; | ||
} | ||
return matrix; | ||
} | ||
/** | ||
* Convert matrix data to the transform alias. | ||
* | ||
* @param {Object} data matrix transform object | ||
* | ||
* @return {Object} transform object | ||
*/ | ||
function matrixToTransform(transform, params) { | ||
var data = transform.data; | ||
// [1, 0, 0, 1, tx, ty] → translate(tx, ty) | ||
if ( | ||
data[0] === 1 && | ||
data[1] === 0 && | ||
data[2] === 0 && | ||
data[3] === 1 | ||
) { | ||
transform.name = 'translate'; | ||
transform.data = [data[4], data[5]]; | ||
// [sx, 0, 0, sy, 0, 0] → scale(sx, sy) | ||
} else if ( | ||
data[1] === 0 && | ||
data[2] === 0 && | ||
data[4] === 0 && | ||
data[5] === 0 | ||
) { | ||
transform.name = 'scale'; | ||
transform.data = [data[0], data[3]]; | ||
// [cos(a), sin(a), -sin(a), cos(a), 0 0] → rotate(a) | ||
} else if ( | ||
data[0] === data[3] && | ||
data[1] === -data[2] && | ||
data[4] === 0 && | ||
data[5] === 0 | ||
) { | ||
var a1 = mth.acos(data[0], params.floatPrecision), | ||
a2 = mth.asin(data[1], params.floatPrecision); | ||
a1 = a2 < 0 ? -a1 : a1; | ||
if (Math.round(a1) === Math.round(a2)) { | ||
transform.name = 'rotate'; | ||
transform.data = [a1]; | ||
} | ||
// [1, 0, tan(a), 1, 0, 0] → skewX(a) | ||
} else if ( | ||
data[0] === 1 && | ||
data[1] === 0 && | ||
data[3] === 1 && | ||
data[4] === 0 && | ||
data[5] === 0 | ||
) { | ||
transform.name = 'skewX'; | ||
transform.data = [mth.atan(data[2], params.floatPrecision)]; | ||
// [1, tan(a), 0, 1, 0, 0] → skewY(a) | ||
} else if ( | ||
data[0] === 1 && | ||
data[2] === 0 && | ||
data[3] === 1 && | ||
data[4] === 0 && | ||
data[5] === 0 | ||
) { | ||
transform.name = 'skewY'; | ||
transform.data = [mth.atan(data[1], params.floatPrecision)]; | ||
} | ||
return transform; | ||
} | ||
/** | ||
* Convert long translate or scale transforms to the shorts ones. | ||
@@ -468,22 +245,1 @@ * | ||
} | ||
/** | ||
* Multiply transformation matrices. | ||
* | ||
* @param {Array} a matrix A data | ||
* @param {Array} b matrix B data | ||
* | ||
* @return {Array} result | ||
*/ | ||
function multiplyTransformMatrices(a, b) { | ||
return [ | ||
+(a[0] * b[0] + a[2] * b[1]).toFixed(3), | ||
+(a[1] * b[0] + a[3] * b[1]).toFixed(3), | ||
+(a[0] * b[2] + a[2] * b[3]).toFixed(3), | ||
+(a[1] * b[2] + a[3] * b[3]).toFixed(3), | ||
+(a[0] * b[4] + a[2] * b[5] + a[4]).toFixed(3), | ||
+(a[1] * b[4] + a[3] * b[5] + a[5]).toFixed(3) | ||
]; | ||
} |
@@ -6,3 +6,3 @@ **english** | [русский](https://github.com/svg/svgo/blob/master/README.ru.md) | ||
## SVGO v0.1.9 [![Build Status](https://secure.travis-ci.org/svg/svgo.png)](http://travis-ci.org/svg/svgo) | ||
## SVGO v0.2.0 [![Build Status](https://secure.travis-ci.org/svg/svgo.png)](http://travis-ci.org/svg/svgo) | ||
@@ -9,0 +9,0 @@ **SVG O**ptimizer is a Nodejs-based tool for optimizing SVG vector graphics files. |
@@ -6,3 +6,3 @@ [english](https://github.com/svg/svgo/blob/master/README.md) | **русский** | ||
## SVGO v0.1.9 [![Build Status](https://secure.travis-ci.org/svg/svgo.png)](http://travis-ci.org/svg/svgo) | ||
## SVGO v0.2.0 [![Build Status](https://secure.travis-ci.org/svg/svgo.png)](http://travis-ci.org/svg/svgo) | ||
@@ -9,0 +9,0 @@ **SVG** **O**ptimizer – это инструмент для оптимизации векторной графики в формате SVG, написанный на Node.js. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
300132
212
6149