svgo
Version:
Nodejs-based tool for optimizing SVG vector graphics files
265 lines (204 loc) • 5.73 kB
JavaScript
var INHERIT = require('inherit');
/**
* Convert SVG-as-JS object to SVG (XML) string.
*
* @module js2svg
*
* @param {Object} jsdata input data
* @param {Object} config config
* @param {Class} [converter] custom converter class
* @return {Object} output data
*/
module.exports = function(jsdata, config, converter) {
return new (converter || Converter)(config).run(jsdata);
};
/**
* @class Converter
*/
var Converter = exports.Converter = INHERIT(/** @lends Nodes.prototype */{
/**
* @constructs
* @private
*/
__constructor: function(config) {
/**
* Converter config.
*
* @type {Object}
*/
this.config = config;
/**
* Current indent level hack.
*
* @type {Number}
*/
this.indentLevel = 0;
// pretty
if (this.config.pretty) {
this.config.doctypeEnd += '\n';
this.config.procInstEnd += '\n';
this.config.commentEnd += '\n';
this.config.cdataEnd += '\n';
this.config.tagShortEnd += '\n';
this.config.tagOpenEnd += '\n';
this.config.tagCloseEnd += '\n';
this.config.textEnd += '\n';
}
},
/**
* Start conversion.
*
* @param {Object} svg-as-js data object
* @return {String}
*/
run: function(data) {
var svg = '';
if (data.content) {
this.indentLevel++;
data.content.forEach(function(item) {
if (item.isElem()) {
svg += this.createElem(item);
} else if (item.isText()) {
svg += this.createText(item.text);
} else if (item.isDoctype()) {
svg += this.createDoctype(item.doctype);
} else if (item.isProcInst()) {
svg += this.createProcInst(item.processinginstruction);
} else if (item.isComment()) {
svg += this.createComment(item.comment);
} else if (item.isCDATA()) {
svg += this.createCDATA(item.cdata);
}
}, this);
}
this.indentLevel--;
return svg;
},
/**
* Create indent string in accordance with the current node level.
*
* @return {String}
*/
createIndent: function() {
var indent = ''
if (this.config.pretty) {
for (var i = 1; i < this.indentLevel; i++) {
indent += this.config.indent;
}
}
return indent;
},
/**
* Create doctype tag.
*
* @param {String} doctype doctype body string
* @return {String}
*/
createDoctype: function(doctype) {
return this.config.doctypeStart +
doctype +
this.config.doctypeEnd;
},
/**
* Create XML Processing Instruction tag.
*
* @param {Object} instruction instruction object
* @return {String}
*/
createProcInst: function(instruction) {
return this.config.procInstStart +
instruction.name +
' ' +
instruction.body +
this.config.procInstEnd;
},
/**
* Create comment tag.
*
* @param {String} comment comment body
* @return {String}
*/
createComment: function(comment) {
return this.config.commentStart +
comment +
this.config.commentEnd;
},
/**
* Create CDATA section.
*
* @param {String} cdata CDATA body
* @return {String}
*/
createCDATA: function(cdata) {
return this.config.cdataStart +
cdata +
this.config.cdataEnd;
},
/**
* Create element tag.
*
* @param {Object} data element object
* @return {String}
*/
createElem: function(data) {
// empty element and short tag
if (data.isEmpty()) {
return this.createIndent() +
this.config.tagShortStart +
data.elem +
this.createAttrs(data) +
this.config.tagShortEnd;
// non-empty element
} else {
return this.createIndent() +
this.config.tagOpenStart +
data.elem +
this.createAttrs(data) +
this.config.tagOpenEnd +
this.run(data) +
this.createIndent() +
this.config.tagCloseStart +
data.elem +
this.config.tagCloseEnd;
}
},
/**
* Create element attributes.
*
* @param {Object} elem attributes object
* @return {String}
*/
createAttrs: function(elem) {
var self = this,
attrs = '';
if (elem.hasAttr()) {
elem.eachAttr(function(attr) {
attrs += ' ' +
attr.name +
self.config.attrStart +
attr.value +
self.config.attrEnd;
});
}
return attrs;
},
/**
* Create text node.
*
* @param {String} text text
* @return {String}
*/
createText: function(text) {
return this.createIndent() +
this.config.textStart +
text +
this.config.textEnd;
}
});
/*
var MyConv = INHERIT(Converter, {
__constructor: function(options) {
this.__base();
}
});
*/