328 lines
11 KiB
JavaScript
328 lines
11 KiB
JavaScript
'use strict';
|
||
|
||
/*
|
||
* Thanks to http://fontello.com project for sponsoring this plugin
|
||
*/
|
||
|
||
exports.type = 'full';
|
||
|
||
exports.active = false;
|
||
|
||
exports.description = 'performs a set of operations on SVG with one path inside (disabled by default)';
|
||
|
||
exports.params = {
|
||
// width and height to resize SVG and rescale inner Path
|
||
width: false,
|
||
height: false,
|
||
|
||
// scale inner Path without resizing SVG
|
||
scale: false,
|
||
|
||
// shiftX/Y inner Path
|
||
shiftX: false,
|
||
shiftY: false,
|
||
|
||
// crop SVG width along the real width of inner Path
|
||
hcrop: false,
|
||
|
||
// vertical center inner Path inside SVG height
|
||
vcenter: false,
|
||
|
||
// stringify params
|
||
floatPrecision: 3,
|
||
leadingZero: true,
|
||
negativeExtraSpace: true
|
||
};
|
||
|
||
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) {
|
||
|
||
data.content.forEach(function(item) {
|
||
|
||
// only for SVG with one Path inside
|
||
if (item.isElem('svg') &&
|
||
item.content.length === 1 &&
|
||
item.content[0].isElem('path')
|
||
) {
|
||
|
||
var svgElem = item,
|
||
pathElem = svgElem.content[0],
|
||
// get absoluted Path data
|
||
path = relative2absolute(EXTEND(true, [], path2js(pathElem))),
|
||
xs = [],
|
||
ys = [],
|
||
cubicСontrolPoint = [0, 0],
|
||
quadraticСontrolPoint = [0, 0],
|
||
lastPoint = [0, 0],
|
||
cubicBoundingBox,
|
||
quadraticBoundingBox,
|
||
i,
|
||
segment;
|
||
|
||
path.forEach(function(pathItem) {
|
||
|
||
// ML
|
||
if ('ML'.indexOf(pathItem.instruction) > -1) {
|
||
|
||
for (i = 0; i < pathItem.data.length; i++) {
|
||
if (i % 2 === 0) {
|
||
xs.push(pathItem.data[i]);
|
||
} else {
|
||
ys.push(pathItem.data[i]);
|
||
}
|
||
}
|
||
|
||
lastPoint = cubicСontrolPoint = quadraticСontrolPoint = pathItem.data.slice(-2);
|
||
|
||
// H
|
||
} else if (pathItem.instruction === 'H') {
|
||
|
||
pathItem.data.forEach(function(d) {
|
||
xs.push(d);
|
||
});
|
||
|
||
lastPoint[0] = cubicСontrolPoint[0] = quadraticСontrolPoint[0] = pathItem.data[pathItem.data.length - 2];
|
||
|
||
// V
|
||
} else if (pathItem.instruction === 'V') {
|
||
|
||
pathItem.data.forEach(function(d) {
|
||
ys.push(d);
|
||
});
|
||
|
||
lastPoint[1] = cubicСontrolPoint[1] = quadraticСontrolPoint[1] = pathItem.data[pathItem.data.length - 1];
|
||
|
||
// C
|
||
} else if (pathItem.instruction === 'C') {
|
||
|
||
for (i = 0; i < pathItem.data.length; i += 6) {
|
||
|
||
segment = pathItem.data.slice(i, i + 6);
|
||
|
||
cubicBoundingBox = computeCubicBoundingBox.apply(this, lastPoint.concat(segment));
|
||
|
||
xs.push(cubicBoundingBox.minx);
|
||
xs.push(cubicBoundingBox.maxx);
|
||
|
||
ys.push(cubicBoundingBox.miny);
|
||
ys.push(cubicBoundingBox.maxy);
|
||
|
||
// reflected control point for the next possible S
|
||
cubicСontrolPoint = [
|
||
2 * segment[4] - segment[2],
|
||
2 * segment[5] - segment[3]
|
||
];
|
||
|
||
lastPoint = segment.slice(-2);
|
||
|
||
}
|
||
|
||
// S
|
||
} else if (pathItem.instruction === 'S') {
|
||
|
||
for (i = 0; i < pathItem.data.length; i += 4) {
|
||
|
||
segment = pathItem.data.slice(i, i + 4);
|
||
|
||
cubicBoundingBox = computeCubicBoundingBox.apply(this, lastPoint.concat(cubicСontrolPoint).concat(segment));
|
||
|
||
xs.push(cubicBoundingBox.minx);
|
||
xs.push(cubicBoundingBox.maxx);
|
||
|
||
ys.push(cubicBoundingBox.miny);
|
||
ys.push(cubicBoundingBox.maxy);
|
||
|
||
// reflected control point for the next possible S
|
||
cubicСontrolPoint = [
|
||
2 * segment[2] - cubicСontrolPoint[0],
|
||
2 * segment[3] - cubicСontrolPoint[1],
|
||
];
|
||
|
||
lastPoint = segment.slice(-2);
|
||
|
||
}
|
||
|
||
// Q
|
||
} else if (pathItem.instruction === 'Q') {
|
||
|
||
for (i = 0; i < pathItem.data.length; i += 4) {
|
||
|
||
segment = pathItem.data.slice(i, i + 4);
|
||
|
||
quadraticBoundingBox = computeQuadraticBoundingBox.apply(this, lastPoint.concat(segment));
|
||
|
||
xs.push(quadraticBoundingBox.minx);
|
||
xs.push(quadraticBoundingBox.maxx);
|
||
|
||
ys.push(quadraticBoundingBox.miny);
|
||
ys.push(quadraticBoundingBox.maxy);
|
||
|
||
// reflected control point for the next possible T
|
||
quadraticСontrolPoint = [
|
||
2 * segment[2] - segment[0],
|
||
2 * segment[3] - segment[1]
|
||
];
|
||
|
||
lastPoint = segment.slice(-2);
|
||
|
||
}
|
||
|
||
// S
|
||
} else if (pathItem.instruction === 'T') {
|
||
|
||
for (i = 0; i < pathItem.data.length; i += 2) {
|
||
|
||
segment = pathItem.data.slice(i, i + 2);
|
||
|
||
quadraticBoundingBox = computeQuadraticBoundingBox.apply(this, lastPoint.concat(quadraticСontrolPoint).concat(segment));
|
||
|
||
xs.push(quadraticBoundingBox.minx);
|
||
xs.push(quadraticBoundingBox.maxx);
|
||
|
||
ys.push(quadraticBoundingBox.miny);
|
||
ys.push(quadraticBoundingBox.maxy);
|
||
|
||
// reflected control point for the next possible T
|
||
quadraticСontrolPoint = [
|
||
2 * segment[0] - quadraticСontrolPoint[0],
|
||
2 * segment[1] - quadraticСontrolPoint[1]
|
||
];
|
||
|
||
lastPoint = segment.slice(-2);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
});
|
||
|
||
var xmin = Math.min.apply(this, xs).toFixed(params.floatPrecision),
|
||
xmax = Math.max.apply(this, xs).toFixed(params.floatPrecision),
|
||
ymin = Math.min.apply(this, ys).toFixed(params.floatPrecision),
|
||
ymax = Math.max.apply(this, ys).toFixed(params.floatPrecision),
|
||
svgWidth = +svgElem.attr('width').value,
|
||
svgHeight = +svgElem.attr('height').value,
|
||
realWidth = Math.round(xmax - xmin),
|
||
realHeight = Math.round(ymax - ymin),
|
||
transform = '',
|
||
scale;
|
||
|
||
// width & height
|
||
if (params.width && params.height) {
|
||
|
||
scale = Math.min(params.width / svgWidth, params.height / svgHeight);
|
||
|
||
realWidth = realWidth * scale;
|
||
realHeight = realHeight * scale;
|
||
|
||
svgWidth = svgElem.attr('width').value = params.width;
|
||
svgHeight = svgElem.attr('height').value = params.height;
|
||
|
||
transform += ' scale(' + scale + ')';
|
||
|
||
// width
|
||
} else if (params.width && !params.height) {
|
||
|
||
scale = params.width / svgWidth;
|
||
|
||
realWidth = realWidth * scale;
|
||
realHeight = realHeight * scale;
|
||
|
||
svgWidth = svgElem.attr('width').value = params.width;
|
||
svgHeight = svgElem.attr('height').value = svgHeight * scale;
|
||
|
||
transform += ' scale(' + scale + ')';
|
||
|
||
// height
|
||
} else if (params.height && !params.width) {
|
||
|
||
scale = params.height / svgHeight;
|
||
|
||
realWidth = realWidth * scale;
|
||
realHeight = realHeight * scale;
|
||
|
||
svgWidth = svgElem.attr('width').value = svgWidth * scale;
|
||
svgHeight = svgElem.attr('height').value = params.height;
|
||
|
||
transform += ' scale(' + scale + ')';
|
||
|
||
}
|
||
|
||
// shiftX
|
||
if (params.shiftX) {
|
||
transform += ' translate(' + realWidth * params.shiftX + ', 0)';
|
||
}
|
||
|
||
// shiftY
|
||
if (params.shiftY) {
|
||
transform += ' translate(0, ' + realHeight * params.shiftY + ')';
|
||
}
|
||
|
||
// scale
|
||
if (params.scale) {
|
||
scale = params.scale;
|
||
|
||
var shiftX = svgWidth / 2,
|
||
shiftY = svgHeight / 2;
|
||
|
||
realWidth = realWidth * scale;
|
||
realHeight = realHeight * scale;
|
||
|
||
if (params.shiftX || params.shiftY) {
|
||
transform += ' scale(' + scale + ')';
|
||
} else {
|
||
transform += ' translate(' + shiftX + ' ' + shiftY + ') scale(' + scale + ') translate(-' + shiftX + ' -' + shiftY + ')';
|
||
}
|
||
}
|
||
|
||
// hcrop
|
||
if (params.hcrop) {
|
||
transform += ' translate(' + (-xmin) + ' 0)';
|
||
|
||
svgElem.attr('width').value = realWidth;
|
||
}
|
||
|
||
// vcenter
|
||
if (params.vcenter) {
|
||
transform += ' translate(0 ' + (((svgHeight - realHeight) / 2) - ymin) + ')';
|
||
}
|
||
|
||
if (transform) {
|
||
pathElem.addAttr({
|
||
name: 'transform',
|
||
prefix: '',
|
||
local: 'transform',
|
||
value: transform
|
||
});
|
||
|
||
path = applyTransforms(pathElem, pathElem.pathJS, true, params.floatPrecision);
|
||
|
||
// transformed data rounding
|
||
path.forEach(function(pathItem) {
|
||
if (pathItem.data) {
|
||
pathItem.data = pathItem.data.map(function(num) {
|
||
return +num.toFixed(params.floatPrecision);
|
||
});
|
||
}
|
||
});
|
||
|
||
// save new
|
||
js2path(pathElem, path, params);
|
||
}
|
||
|
||
}
|
||
|
||
});
|
||
|
||
return data;
|
||
|
||
};
|