Path data processing improvements.
Improved path data saving. Collapse repeated now works at writing path data and doesn't affect pathJS to make further processing easier. Resolves #204.
268
plugins/_path.js
@ -1,8 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/,
|
||||
regPathData = /[\-+]?\d*\.?\d+([eE][\-+]?\d+)?/g,
|
||||
regNumericValues = /[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?/,
|
||||
regPathData = /[-+]?(?:\d*\.\d+|\d+\.?)([eE][-+]?\d+)?/g,
|
||||
regNumericValues = /[-+]?(\d*\.\d+|\d+\.?)(?:[eE][-+]?\d+)?/,
|
||||
transform2js = require('./_transforms').transform2js,
|
||||
transformsMultiply = require('./_transforms').transformsMultiply,
|
||||
collections = require('./_collections.js'),
|
||||
@ -18,85 +18,69 @@ var regPathInstructions = /([MmLlHhVvCcSsQqTtAaZz])\s*/,
|
||||
* @param {Object} params plugin params
|
||||
* @return {Array} output array
|
||||
*/
|
||||
exports.path2js = function(pathString) {
|
||||
exports.path2js = function(path) {
|
||||
if (path.pathJS) return path.pathJS;
|
||||
|
||||
// JS representation of the path data
|
||||
var path = [],
|
||||
// current instruction context
|
||||
instruction;
|
||||
var paramsLength = { // Number of parameters of every path command
|
||||
H: 1, V: 1, M: 2, L: 2, T: 2, Q: 4, S: 4, C: 6, A: 7,
|
||||
h: 1, v: 1, m: 2, l: 2, t: 2, q: 4, s: 4, c: 6, a: 7
|
||||
},
|
||||
pathData = [], // JS representation of the path data
|
||||
instruction, // current instruction context
|
||||
startMoveto = false;
|
||||
|
||||
// splitting path string into array like ['M', '10 50', 'L', '20 30']
|
||||
pathString.split(regPathInstructions).forEach(function(data) {
|
||||
if (data) {
|
||||
path.attr('d').value.split(regPathInstructions).forEach(function(data) {
|
||||
if (!data) return;
|
||||
if (!startMoveto) {
|
||||
if (data == 'M' || data == 'm') {
|
||||
startMoveto = true;
|
||||
} else return;
|
||||
}
|
||||
|
||||
// instruction item
|
||||
if (regPathInstructions.test(data)) {
|
||||
instruction = data;
|
||||
|
||||
// z - instruction w/o data
|
||||
if ('Zz'.indexOf(instruction) > -1) {
|
||||
path.push({
|
||||
if (instruction == 'Z' || instruction == 'z') {
|
||||
pathData.push({
|
||||
instruction: 'z'
|
||||
});
|
||||
}
|
||||
// data item
|
||||
} else {
|
||||
data = data.match(regPathData);
|
||||
if (!data) return;
|
||||
|
||||
data = data.trim().match(regPathData);
|
||||
data = data.map(Number);
|
||||
|
||||
if (data) {
|
||||
|
||||
var index = 0,
|
||||
pair = 2;
|
||||
|
||||
data = data.map(function(str) {
|
||||
return +str;
|
||||
// Subsequent moveto pairs of coordinates are threated as implicit lineto commands
|
||||
// http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
|
||||
if (instruction == 'M' || instruction == 'm') {
|
||||
pathData.push({
|
||||
instruction: pathData.length == 0 ? 'M' : instruction,
|
||||
data: data.splice(0, 2)
|
||||
});
|
||||
instruction = instruction == 'M' ? 'L' : 'l';
|
||||
}
|
||||
|
||||
// deal with very first 'Mm' and multiple points data
|
||||
if ('Mm'.indexOf(instruction) > -1) {
|
||||
|
||||
path.push({
|
||||
for (var pair = paramsLength[instruction]; data.length;) {
|
||||
pathData.push({
|
||||
instruction: instruction,
|
||||
data: data.slice(index, index + pair)
|
||||
data: data.splice(0, pair)
|
||||
});
|
||||
|
||||
index += pair;
|
||||
|
||||
if (data.length) {
|
||||
instruction = instruction === instruction.toLowerCase() ? 'l' : 'L';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ('HhVv'.indexOf(instruction) > -1) {
|
||||
pair = 1;
|
||||
} else if ('LlTt'.indexOf(instruction) > -1) {
|
||||
pair = 2;
|
||||
} else if ('QqSs'.indexOf(instruction) > -1) {
|
||||
pair = 4;
|
||||
} else if ('Cc'.indexOf(instruction) > -1) {
|
||||
pair = 6;
|
||||
} else if ('Aa'.indexOf(instruction) > -1) {
|
||||
pair = 7;
|
||||
}
|
||||
|
||||
while(index < data.length) {
|
||||
path.push({
|
||||
instruction: instruction,
|
||||
data: data.slice(index, index + pair)
|
||||
});
|
||||
|
||||
index += pair;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return path;
|
||||
// First moveto is actually absolute. Subsequent coordinates were separated above.
|
||||
if (pathData.length && pathData[0].instruction == 'm') {
|
||||
pathData[0].instruction = 'M';
|
||||
}
|
||||
path.pathJS = pathData;
|
||||
|
||||
return pathData;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -105,79 +89,76 @@ exports.path2js = function(pathString) {
|
||||
* @param {Array} data input data
|
||||
* @return {Array} output data
|
||||
*/
|
||||
exports.relative2absolute = function(data) {
|
||||
|
||||
var relative2absolute = exports.relative2absolute = function(data) {
|
||||
var currentPoint = [0, 0],
|
||||
subpathPoint = [0, 0],
|
||||
i;
|
||||
|
||||
data.forEach(function(item) {
|
||||
data = data.map(function(item) {
|
||||
|
||||
if (item.instruction === 'M') {
|
||||
var instruction = item.instruction,
|
||||
itemData = item.data && item.data.slice();
|
||||
|
||||
currentPoint = item.data.slice(-2);
|
||||
subpathPoint = item.data.slice(-2);
|
||||
if (instruction == 'M') {
|
||||
|
||||
} else if ('mlcsqta'.indexOf(item.instruction) > -1) {
|
||||
set(currentPoint, itemData);
|
||||
set(subpathPoint, itemData);
|
||||
|
||||
for (i = 0; i < item.data.length; i++) {
|
||||
if (i % 2 === 0) {
|
||||
item.data[i] += currentPoint[0];
|
||||
} else {
|
||||
item.data[i] += currentPoint[1];
|
||||
} else if ('mlcsqt'.indexOf(instruction) > -1) {
|
||||
|
||||
for (i = 0; i < itemData.length; i++) {
|
||||
itemData[i] += currentPoint[i % 2];
|
||||
}
|
||||
set(currentPoint, itemData);
|
||||
|
||||
if (instruction == 'm') {
|
||||
set(subpathPoint, itemData);
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
var index = i + 1;
|
||||
} else if (instruction == 'a') {
|
||||
|
||||
if ('mlt'.indexOf(item.instruction) > -1 && index % 2 === 0) {
|
||||
currentPoint[0] = item.data[i - 1];
|
||||
currentPoint[1] = item.data[i];
|
||||
} else if ('qs'.indexOf(item.instruction) > -1 && index % 4 === 0) {
|
||||
currentPoint[0] = item.data[i - 1];
|
||||
currentPoint[1] = item.data[i];
|
||||
} else if (item.instruction === 'c' && index % 6 === 0) {
|
||||
currentPoint[0] = item.data[i - 1];
|
||||
currentPoint[1] = item.data[i];
|
||||
} else if (item.instruction === 'a' && index % 7 === 0) {
|
||||
currentPoint[0] = item.data[i - 1];
|
||||
currentPoint[1] = item.data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
itemData[5] += currentPoint[0];
|
||||
itemData[6] += currentPoint[1];
|
||||
set(currentPoint, itemData);
|
||||
|
||||
if (item.instruction === 'm') {
|
||||
subpathPoint = item.data.slice(-2);
|
||||
}
|
||||
} else if (instruction == 'h') {
|
||||
|
||||
} else if (item.instruction === 'h') {
|
||||
itemData[0] += currentPoint[0];
|
||||
currentPoint[0] = itemData[0];
|
||||
|
||||
for (i = 0; i < item.data.length; i++) {
|
||||
item.data[i] += currentPoint[0];
|
||||
}
|
||||
} else if (instruction == 'v') {
|
||||
|
||||
currentPoint[0] = item.data[item.data.length - 1];
|
||||
itemData[0] += currentPoint[1];
|
||||
currentPoint[1] = itemData[0];
|
||||
|
||||
} else if (item.instruction === 'v') {
|
||||
} else if ('MZLCSQTA'.indexOf(instruction) > -1) {
|
||||
|
||||
for (i = 0; i < item.data.length; i++) {
|
||||
item.data[i] += currentPoint[1];
|
||||
}
|
||||
set(currentPoint, itemData);
|
||||
|
||||
currentPoint[1] = item.data[item.data.length - 1];
|
||||
} else if (instruction == 'H') {
|
||||
|
||||
} else {
|
||||
currentPoint[0] = itemData[0];
|
||||
|
||||
currentPoint = subpathPoint;
|
||||
} else if (instruction == 'V') {
|
||||
|
||||
currentPoint[1] = itemData[0];
|
||||
|
||||
} else if (instruction == 'z') {
|
||||
|
||||
set(currentPoint, subpathPoint);
|
||||
|
||||
}
|
||||
|
||||
item.instruction = item.instruction.toUpperCase();
|
||||
return instruction == 'z' ?
|
||||
{ instruction: 'z' } :
|
||||
{
|
||||
instruction: instruction.toUpperCase(),
|
||||
data: itemData
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
return data;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -241,27 +222,26 @@ exports.applyTransforms = function(elem, path, applyTransformsStroked, floatPrec
|
||||
// If an 'a' command can't be transformed directly, convert path to curves.
|
||||
if (!splittedMatrix.isSimple && path.some(function(i) { return i.instruction == 'a' })) {
|
||||
var prev;
|
||||
path = path.reduce(function(newPath, item){
|
||||
path.forEach(function(item, index, path){
|
||||
if (item.instruction == 'a') {
|
||||
var curves = a2c.apply(0, [0, 0].concat(item.data)),
|
||||
items = [],
|
||||
curveData;
|
||||
while ((curveData = curves.splice(0,6)).length) {
|
||||
item = {
|
||||
var base = prev.coords;
|
||||
items.push(prev = {
|
||||
instruction: 'c',
|
||||
data: curveData,
|
||||
coords: [base[0] + item.data[4], base[1] + item.data[5]],
|
||||
base: prev.coords
|
||||
};
|
||||
item.coords = [item.base[0] + item.data[4], item.base[1] + item.data[5]];
|
||||
prev = item;
|
||||
newPath.push(item);
|
||||
});
|
||||
}
|
||||
path.splice.apply(path, [index, 1].concat(items));
|
||||
} else {
|
||||
newPath.push(item);
|
||||
if (prev) item.base = prev.coords;
|
||||
prev = item;
|
||||
}
|
||||
return newPath;
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
path.forEach(function(pathItem) {
|
||||
@ -291,8 +271,8 @@ exports.applyTransforms = function(elem, path, applyTransformsStroked, floatPrec
|
||||
|
||||
// then apply it only to the first absoluted M
|
||||
newPoint = transformPoint(matrix.data, pathItem.data[0], pathItem.data[1]);
|
||||
pathItem.data[0] = pathItem.coords[0] = newPoint[0];
|
||||
pathItem.data[1] = pathItem.coords[1] = newPoint[1];
|
||||
set(pathItem.data, newPoint);
|
||||
set(pathItem.coords, newPoint);
|
||||
|
||||
// clear translate() data from transform matrix
|
||||
matrix.data[4] = 0;
|
||||
@ -553,21 +533,63 @@ function computeQuadraticFirstDerivativeRoot(a, b, c) {
|
||||
* @param {Object} params plugin params
|
||||
* @return {String} output path string
|
||||
*/
|
||||
exports.js2path = function(path, params) {
|
||||
exports.js2path = function(path, data, params) {
|
||||
|
||||
// output path data string
|
||||
var pathString = '';
|
||||
path.pathJS = data;
|
||||
|
||||
path.forEach(function(item) {
|
||||
if (params.collapseRepeated) {
|
||||
data = collapseRepeated(data);
|
||||
}
|
||||
|
||||
pathString += item.instruction + (item.data ? cleanupOutData(item.data, params) : '');
|
||||
|
||||
});
|
||||
|
||||
return pathString;
|
||||
path.attr('d').value = data.reduce(function(pathString, item) {
|
||||
return pathString += item.instruction + (item.data ? cleanupOutData(item.data, params) : '');
|
||||
}, '');
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Collapse repeated instructions data
|
||||
*
|
||||
* @param {Array} path input path data
|
||||
* @return {Array} output path data
|
||||
*/
|
||||
function collapseRepeated(data) {
|
||||
|
||||
var prev,
|
||||
prevIndex;
|
||||
|
||||
// copy an array and modifieds item to keep original data untouched
|
||||
data = data.reduce(function(newPath, item) {
|
||||
if (
|
||||
prev && item.data &&
|
||||
item.instruction == prev.instruction
|
||||
) {
|
||||
// concat previous data with current
|
||||
prev = newPath[prevIndex] = {
|
||||
instruction: prev.instruction,
|
||||
data: prev.data.concat(item.data),
|
||||
coords: item.coords,
|
||||
base: prev.base
|
||||
}
|
||||
} else {
|
||||
newPath.push(item);
|
||||
prev = item;
|
||||
prevIndex = newPath.length - 1;
|
||||
}
|
||||
|
||||
return newPath;
|
||||
}, []);
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
function set(dest, source) {
|
||||
dest[0] = source[source.length - 2];
|
||||
dest[1] = source[source.length - 1];
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* Based on code from Snap.svg (Apache 2 license). http://snapsvg.io/
|
||||
* Thanks to Dmitry Baranovskiy for his great work!
|
||||
*/
|
||||
|
@ -51,7 +51,7 @@ exports.fn = function(item, params) {
|
||||
error = precision !== false ? +Math.pow(.1, precision).toFixed(precision) : 1e-2;
|
||||
hasMarkerMid = item.hasAttr('marker-mid');
|
||||
|
||||
var data = path2js(item.attr('d').value);
|
||||
var data = path2js(item);
|
||||
|
||||
// TODO: get rid of functions returns
|
||||
if (data.length) {
|
||||
@ -63,17 +63,11 @@ exports.fn = function(item, params) {
|
||||
|
||||
data = filters(data, params);
|
||||
|
||||
if (params.collapseRepeated) {
|
||||
data = collapseRepeated(data, params);
|
||||
}
|
||||
|
||||
if (params.utilizeAbsolute) {
|
||||
data = convertToMixed(data, params);
|
||||
}
|
||||
|
||||
item.pathJS = data;
|
||||
|
||||
item.attr('d').value = js2path(data, params);
|
||||
js2path(item, data, params);
|
||||
}
|
||||
|
||||
}
|
||||
@ -91,7 +85,6 @@ function convertToRelative(path) {
|
||||
|
||||
var point = [0, 0],
|
||||
subpathPoint = [0, 0],
|
||||
mM = false,
|
||||
baseItem;
|
||||
|
||||
path.forEach(function(item, index) {
|
||||
@ -106,18 +99,12 @@ function convertToRelative(path) {
|
||||
// recalculate current point
|
||||
if ('mcslqta'.indexOf(instruction) > -1) {
|
||||
|
||||
var newPoint = data.slice(-2);
|
||||
|
||||
point[0] += newPoint[0];
|
||||
point[1] += newPoint[1];
|
||||
point[0] += data[data.length - 2];
|
||||
point[1] += data[data.length - 1];
|
||||
|
||||
if (instruction === 'm') {
|
||||
if (index === 0) {
|
||||
instruction = 'M';
|
||||
mM = true;
|
||||
}
|
||||
|
||||
subpathPoint = point.slice(-2);
|
||||
subpathPoint[0] = point[0];
|
||||
subpathPoint[1] = point[1];
|
||||
baseItem = item;
|
||||
}
|
||||
|
||||
@ -134,20 +121,16 @@ function convertToRelative(path) {
|
||||
// convert absolute path data coordinates to relative
|
||||
// if "M" was not transformed from "m"
|
||||
// M → m
|
||||
if (
|
||||
instruction === 'M' &&
|
||||
(!mM || index > 0)
|
||||
) {
|
||||
if (instruction === 'M') {
|
||||
|
||||
if (index > 0) instruction = 'm';
|
||||
|
||||
data[0] -= point[0];
|
||||
data[1] -= point[1];
|
||||
|
||||
point[0] += data[0];
|
||||
point[1] += data[1];
|
||||
subpathPoint[0] = point[0] += data[0];
|
||||
subpathPoint[1] = point[1] += data[1];
|
||||
|
||||
subpathPoint = point.slice(-2);
|
||||
baseItem = item;
|
||||
|
||||
}
|
||||
@ -241,11 +224,12 @@ function convertToRelative(path) {
|
||||
}
|
||||
|
||||
// !data === z, reset current point
|
||||
else {
|
||||
if(baseItem)
|
||||
else if (instruction == 'z') {
|
||||
if (baseItem) {
|
||||
item.coords = baseItem.coords;
|
||||
point = subpathPoint;
|
||||
mM = false;
|
||||
}
|
||||
point[0] = subpathPoint[0];
|
||||
point[1] = subpathPoint[1];
|
||||
}
|
||||
|
||||
item.base = index > 0 ? path[index - 1].coords : [0, 0];
|
||||
@ -267,7 +251,7 @@ function filters(path, params) {
|
||||
|
||||
var relSubpoint = [0, 0],
|
||||
pathBase = [0, 0],
|
||||
prev;
|
||||
prev = {};
|
||||
|
||||
path = path.filter(function(item, index) {
|
||||
|
||||
@ -279,7 +263,7 @@ function filters(path, params) {
|
||||
if (instruction === 's') {
|
||||
var sdata = [0, 0].concat(data);
|
||||
|
||||
if (prev && 'cs'.indexOf(prev.instruction) > -1) {
|
||||
if ('cs'.indexOf(prev.instruction) > -1) {
|
||||
var pdata = prev.data,
|
||||
n = pdata.length;
|
||||
|
||||
@ -351,7 +335,6 @@ function filters(path, params) {
|
||||
|
||||
// q
|
||||
else if (
|
||||
prev &&
|
||||
instruction === 'q' &&
|
||||
isCurveStraightLine(
|
||||
[ 0, data[0], data[2] ],
|
||||
@ -372,7 +355,6 @@ function filters(path, params) {
|
||||
|
||||
// q (original) + t
|
||||
if (
|
||||
prev &&
|
||||
prev.original &&
|
||||
prev.original.instruction === 'q'
|
||||
) {
|
||||
@ -389,7 +371,7 @@ function filters(path, params) {
|
||||
}
|
||||
|
||||
// [^qt] + t
|
||||
else if (!prev || 'qt'.indexOf(prev.instruction) === -1) {
|
||||
else if ('qt'.indexOf(prev.instruction) < 0) {
|
||||
instruction = 'l';
|
||||
data = data.slice(-2);
|
||||
}
|
||||
@ -422,8 +404,30 @@ function filters(path, params) {
|
||||
}
|
||||
}
|
||||
|
||||
// collapse repeated commands
|
||||
// h 20 h 30 -> h 50
|
||||
if (
|
||||
params.collapseRepeated &&
|
||||
!hasMarkerMid &&
|
||||
('mhv'.indexOf(instruction) > -1) &&
|
||||
prev.instruction &&
|
||||
instruction == prev.instruction.toLowerCase() &&
|
||||
(
|
||||
(instruction != 'h' && instruction != 'v') ||
|
||||
(prev.data[0] >= 0) == (item.data[0] >= 0)
|
||||
)) {
|
||||
prev.data[0] += data[0];
|
||||
if (instruction != 'h' && instruction != 'v') {
|
||||
prev.data[1] += data[1];
|
||||
}
|
||||
prev.coords = item.coords;
|
||||
if (prev.original) prev.original = null;
|
||||
path[index] = prev;
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert curves into smooth shorthands
|
||||
if (params.curveSmoothShorthands && prev) {
|
||||
if (params.curveSmoothShorthands && prev.instruction) {
|
||||
|
||||
// curveto
|
||||
if (instruction === 'c') {
|
||||
@ -523,6 +527,8 @@ function filters(path, params) {
|
||||
// z resets coordinates
|
||||
relSubpoint[0] = pathBase[0];
|
||||
relSubpoint[1] = pathBase[1];
|
||||
if (prev.instruction == 'z') return false;
|
||||
prev = item;
|
||||
|
||||
}
|
||||
|
||||
@ -581,74 +587,15 @@ function convertToMixed(path, params) {
|
||||
if (
|
||||
absoluteDataStr.length < relativeDataStr.length &&
|
||||
!(
|
||||
params.negativeExtraSpace && instruction == prev.instruction &&
|
||||
params.negativeExtraSpace &&
|
||||
instruction == prev.instruction &&
|
||||
prev.instruction.charCodeAt(0) > 96 &&
|
||||
absoluteDataStr.length == relativeDataStr.length - 1 &&
|
||||
(data[0] < 0 || 0 < data[0] && data[0] < 1 && prev.data[prev.data.length - 1] % 1)
|
||||
)
|
||||
) {
|
||||
if (instruction.toUpperCase() != prev.instruction) {
|
||||
item.instruction = instruction.toUpperCase();
|
||||
item.data = adata;
|
||||
} else {
|
||||
prev.data = prev.data.concat(adata);
|
||||
prev.coords = item.coords;
|
||||
path[index] = prev;
|
||||
return false;
|
||||
}
|
||||
} else if (instruction == prev.instruction) {
|
||||
prev.data = prev.data.concat(data);
|
||||
prev.coords = item.coords;
|
||||
path[index] = prev;
|
||||
return false;
|
||||
}
|
||||
|
||||
prev = item;
|
||||
|
||||
return true;
|
||||
|
||||
});
|
||||
|
||||
return path;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse repeated instructions data
|
||||
*
|
||||
* @param {Array} path input path data
|
||||
* @return {Array} output path data
|
||||
*/
|
||||
function collapseRepeated(path, params) {
|
||||
|
||||
var prev;
|
||||
|
||||
path = path.filter(function(item) {
|
||||
|
||||
if (
|
||||
!hasMarkerMid &&
|
||||
prev &&
|
||||
item.instruction === prev.instruction &&
|
||||
(
|
||||
'Mmz'.indexOf(item.instruction) > -1 ||
|
||||
'hv'.indexOf(item.instruction) > -1 && (prev.data[0] >= 0) == (item.data[0] >= 0) ||
|
||||
!params.utilizeAbsolute
|
||||
)
|
||||
) {
|
||||
// increase previous h or v data with current
|
||||
if ('hv'.indexOf(item.instruction) > -1) {
|
||||
prev.data[0] += item.data[0];
|
||||
} else if (item.instruction.toLowerCase() === 'm') {
|
||||
prev.data[0] += item.data[0];
|
||||
prev.data[1] += item.data[1];
|
||||
// concat previous data with current if it is not z
|
||||
} else if (item.data) {
|
||||
prev.data = prev.data.concat(item.data);
|
||||
}
|
||||
prev.coords = item.coords;
|
||||
|
||||
// filter out current item
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
prev = item;
|
||||
|
@ -4,8 +4,14 @@ exports.type = 'perItem';
|
||||
|
||||
exports.active = true;
|
||||
|
||||
exports.params = {
|
||||
collapseRepeated: true,
|
||||
leadingZero: true,
|
||||
negativeExtraSpace: true
|
||||
};
|
||||
|
||||
var path2js = require('./_path.js').path2js,
|
||||
relative2absolute = require('./_path.js').relative2absolute;
|
||||
js2path = require('./_path.js').js2path;
|
||||
|
||||
/**
|
||||
* Merge multiple Paths into one.
|
||||
@ -13,13 +19,13 @@ var path2js = require('./_path.js').path2js,
|
||||
* @param {Object} item current iteration item
|
||||
* @return {Boolean} if false, item will be filtered out
|
||||
*
|
||||
* @author Kir Belevich
|
||||
* @author Kir Belevich, Lev Solntsev
|
||||
*/
|
||||
exports.fn = function(item) {
|
||||
exports.fn = function(item, params) {
|
||||
|
||||
if (!item.isElem() || item.isEmpty()) return;
|
||||
|
||||
var prevContentItem,
|
||||
var prevContentItem = null,
|
||||
prevContentItemKeys = null;
|
||||
|
||||
item.content = item.content.filter(function(contentItem) {
|
||||
@ -31,7 +37,7 @@ exports.fn = function(item) {
|
||||
contentItem.hasAttr('d')
|
||||
) {
|
||||
|
||||
if (prevContentItemKeys == null) {
|
||||
if (!prevContentItemKeys) {
|
||||
prevContentItemKeys = Object.keys(prevContentItem.attrs);
|
||||
}
|
||||
|
||||
@ -41,15 +47,12 @@ exports.fn = function(item) {
|
||||
return key == 'd' ||
|
||||
prevContentItem.hasAttr(key) &&
|
||||
prevContentItem.attr(key).value == contentItem.attr(key).value;
|
||||
});
|
||||
}),
|
||||
prevPathJS = path2js(prevContentItem),
|
||||
curPathJS = path2js(contentItem);
|
||||
|
||||
if (equalData) {
|
||||
var prevPathJS = prevContentItem.pathJS;
|
||||
if (prevContentItem.pathJS) {
|
||||
prevPathJS.push.apply(prevPathJS, contentItem.pathJS);
|
||||
}
|
||||
|
||||
prevContentItem.attr('d').value += contentItem.attr('d').value.replace(/m/i, 'M');
|
||||
js2path(prevContentItem, prevPathJS.concat(curPathJS), params);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -32,11 +32,13 @@ exports.params = {
|
||||
negativeExtraSpace: true
|
||||
};
|
||||
|
||||
var relative2absolute = require('./_path.js').relative2absolute,
|
||||
computeCubicBoundingBox = require('./_path.js').computeCubicBoundingBox,
|
||||
computeQuadraticBoundingBox = require('./_path.js').computeQuadraticBoundingBox,
|
||||
applyTransforms = require('./_path.js').applyTransforms,
|
||||
js2path = require('./_path.js').js2path,
|
||||
var _path = require('./_path.js'),
|
||||
relative2absolute = _path.relative2absolute,
|
||||
computeCubicBoundingBox = _path.computeCubicBoundingBox,
|
||||
computeQuadraticBoundingBox = _path.computeQuadraticBoundingBox,
|
||||
applyTransforms = _path.applyTransforms,
|
||||
js2path = _path.js2path,
|
||||
path2js = _path.path2js,
|
||||
EXTEND = require('whet.extend');
|
||||
|
||||
exports.fn = function(data, params) {
|
||||
@ -52,7 +54,7 @@ exports.fn = function(data, params) {
|
||||
var svgElem = item,
|
||||
pathElem = svgElem.content[0],
|
||||
// get absoluted Path data
|
||||
path = relative2absolute(EXTEND(true, [], pathElem.pathJS)),
|
||||
path = relative2absolute(EXTEND(true, [], path2js(pathElem))),
|
||||
xs = [],
|
||||
ys = [],
|
||||
cubicСontrolPoint = [0, 0],
|
||||
@ -312,7 +314,7 @@ exports.fn = function(data, params) {
|
||||
});
|
||||
|
||||
// save new
|
||||
pathElem.attr('d').value = js2path(path, params);
|
||||
js2path(pathElem, path, params);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
@@@
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 50m10 10"/>
|
||||
<path d="M20 60"/>
|
||||
<path d="M10 50l10 10"/>
|
||||
<path d="M10 50l10-20 20 30"/>
|
||||
<path d="M10 50l10-20 20 30"/>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -1,21 +1,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 0,0"/>
|
||||
<path d="l 0,0"/>
|
||||
<path d="h 0"/>
|
||||
<path d="v 0"/>
|
||||
<path d="c 0,0 0,0 0,0 s 0,0 0,0"/>
|
||||
<path d="q 0,0 0,0 t 0,0"/>
|
||||
<path d="a 25,25 -30 0,1 0,0"/>
|
||||
<path d="m 0,0l 0,0"/>
|
||||
<path d="m 0,0h 0"/>
|
||||
<path d="m 0,0v 0"/>
|
||||
<path d="m 0,0c 0,0 0,0 0,0 s 0,0 0,0"/>
|
||||
<path d="m 0,0q 0,0 0,0 t 0,0"/>
|
||||
<path d="m 0,0a 25,25 -30 0,1 0,0"/>
|
||||
</svg>
|
||||
|
||||
@@@
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 0"/>
|
||||
<path d=""/>
|
||||
<path d=""/>
|
||||
<path d=""/>
|
||||
<path d=""/>
|
||||
<path d=""/>
|
||||
<path d=""/>
|
||||
<path d="M0 0"/>
|
||||
<path d="M0 0"/>
|
||||
<path d="M0 0"/>
|
||||
<path d="M0 0"/>
|
||||
<path d="M0 0"/>
|
||||
<path d="M0 0"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 471 B |
@ -9,6 +9,7 @@
|
||||
<path d="M10 50v30v50"/>
|
||||
<path d="M10 50L10 80L10 0"/>
|
||||
<path d="M10 50L10 10L10 80"/>
|
||||
<path d="M10 50l10 10l20 20l10 10"/>
|
||||
<path d="M10 50L80 50L0 50"/>
|
||||
<path d="M10 50L0 50L80 50"/>
|
||||
<path d="M10 50L0 50M80 50M30 10L10 80"/>
|
||||
@ -27,6 +28,7 @@
|
||||
<path d="M10 50v80"/>
|
||||
<path d="M10 50v30V0"/>
|
||||
<path d="M10 50V10v70"/>
|
||||
<path d="M10 50l10 10 20 20 10 10"/>
|
||||
<path d="M10 50h70H0"/>
|
||||
<path d="M10 50H0h80"/>
|
||||
<path d="M10 50H0m30-40L10 80"/>
|
||||
|
Before Width: | Height: | Size: 898 B After Width: | Height: | Size: 980 B |
@ -1,7 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0,0 z"/>
|
||||
<path d="M 10,10 z"/>
|
||||
<path d="M 20,20"/>
|
||||
<path d="M 20,20 l 10,10 M 30,0 c 10,0 20,10 20,20"/>
|
||||
<path d="M 30,30 z"/>
|
||||
<path d="M 30,30 z" fill="#f00"/>
|
||||
<path d="M 40,40 z"/>
|
||||
@ -11,7 +11,7 @@
|
||||
@@@
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0,0 zM 10,10 zM 20,20M 30,30 z"/>
|
||||
<path d="M0 0zM10 10zM20 20l10 10M30 0c10 0 20 10 20 20M30 30z"/>
|
||||
<path d="M 30,30 z" fill="#f00"/>
|
||||
<path d="M 40,40 zM 50,50 z"/>
|
||||
<path d="M40 40zM50 50z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 414 B After Width: | Height: | Size: 465 B |
@ -18,8 +18,8 @@
|
||||
@@@
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 0,0 zM 10,10 zM 20,20M 30,30 z" fill="#fff" stroke="#333"/>
|
||||
<path d="M0 0zM10 10zM20 20 30 30z" fill="#fff" stroke="#333"/>
|
||||
<path d="M 30,30 z" fill="#f00"/>
|
||||
<path d="M 40,40 zM 50,50 zM 40,40M 50,50"/>
|
||||
<path d="M 40,40 zM 50,50 zM 40,40M 50,50M 50,50 z" fill="#fff" stroke="#333"/>
|
||||
<path d="M40 40zM50 50zM40 40 50 50"/>
|
||||
<path d="M40 40zM50 50zM40 40 50 50 50 50z" fill="#fff" stroke="#333"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 946 B After Width: | Height: | Size: 925 B |