123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- '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;
- };
|