/*!
* jSketch SVG 1.0 | Luis A. Leiva | MIT license
*/
// XXX: Requires `jsketch.js` to be loaded first.
/**
* SVG serializer for the jSketch lib.
* @version 1.0
* @author Luis A. Leiva
* @license MIT license
*/
;(function(window) {
/**
* Convert jSketch canvas to SVG.
* This method is asynchronous, and will be invoked when the SVG is ready.
* @param {function} callback - Callback function, to be invoked with the SVG (string) as argument.
* @return {jSketch}
* @memberof jSketch
* @method
* @name toSVG
*/
window.jSketch.prototype.toSVG = function(callback) {
// No callback, no SVG.
if (typeof callback !== 'function') throw new Error('You must supply a callback in toSVG() method.');
// Save pointer for use in closures.
var self = this;
// Gather lines together until path is closed.
var paths = [];
// TODO: Save composite operations. See https://www.w3.org/TR/2002/WD-SVG11-20020215/masking.html
var comps = {};
// Flag async stuff, like image loading.
var asyncOps = 0;
// Process jSketch properties.
var graphics = {};
// Process jSketch methods.
var methods = {
/**
* Add async flag.
* @return {string}
*/
addAsync: function() {
asyncOps++;
return '';
},
/**
* Remove async flag.
* @return {string}
*/
removeAsync: function() {
asyncOps--;
return '';
},
/**
* Serialize image.
* @param {object} img - Image element.
* @param {number} [x] - Horizontal coordinate.
* @param {number} [y] - Vertical coordinate.
* @return {string}
*/
drawImage: function(img, x, y) {
return '';
},
/**
* Serialize filled rectangle.
* @param {number} x - Horizontal coordinate.
* @param {number} y - Vertical coordinate.
* @param {number} width - Rectangle width.
* @param {number} height - Rectangle height.
* @return {string}
*/
fillRect: function(x, y, width, height) {
return '';
},
/**
* Serialize stroked rectangle.
* @param {number} x - Horizontal coordinate.
* @param {number} y - Vertical coordinate.
* @param {number} width - Rectangle width.
* @param {number} height - Rectangle height.
* @return {string}
*/
strokeRect: function(x, y, width, height) {
return '';
},
/**
* Serialize stroked circle.
* @param {number} x - Horizontal coordinate.
* @param {number} y - Vertical coordinate.
* @param {number} radius - Circle radius.
* @return {string}
*/
strokeCircle: function(x, y, radius) {
return '';
},
/**
* Serialize filled circle.
* @param {number} x - Horizontal coordinate.
* @param {number} y - Vertical coordinate.
* @param {number} radius - Circle radius.
* @return {string}
*/
fillCircle: function(x, y, radius) {
return '';
},
/**
* Mark start of path.
* @return {string}
*/
beginPath: function() {
paths = [];
return '';
},
/**
* Mark end of path. Actually serializes the path.
* @return {string}
*/
closePath: function() {
var path = '';
if (paths.length > 0) {
path = '';
paths = [];
}
return path;
},
/**
* Add point origin to path.
* @param {number} x - Horizontal coordinate.
* @param {number} y - Vertical coordinate.
* @return {string}
*/
moveTo: function(x, y) {
paths.push('M '+ x +' '+ y);
return '';
},
/**
* Add line to path.
* @param {number} x - Horizontal coordinate.
* @param {number} y - Vertical coordinate.
* @return {string}
*/
lineTo: function(x, y) {
paths.push('L '+ x +' '+ y);
return '';
},
/**
* Add curve to path.
* @param {number} cpx - Horizontal coordinate of control point.
* @param {number} cpy - Vertical coordinate of control point.
* @param {number} x - Horizontal coordinate.
* @param {number} y - Vertical coordinate.
* @return {string}
*/
quadraticCurveTo: function(cpx, cpy, x, y) {
paths.push('Q '+ cpx +' '+ cpy + ' '+ x +' '+ y);
return '';
},
};
// Create SVG.
function build() {
var svg = '';
svg += '';
svg += '';
// Normalize whitespacing.
return svg.replace(/\s+/g, ' ');
}
// Serialize jSketch elements.
function processElements() {
var ret = '';
for (var i = 0; i < self.callStack.length; i++) {
var entry = self.callStack[i];
if (entry.property && typeof entry.value !== 'object') {
// Save properties for later processing.
graphics[entry.property] = entry.value;
} else if (entry.method) {
// Ensure method.
if (!methods[entry.method]) {
console.warn('Method not implemented:', entry.method);
continue;
}
// Process method.
ret += methods[entry.method].apply(null, entry.args);
} else {
console.warn('Unknown call:', entry);
}
}
return ret;
}
// Throttle svg readiness.
var timer = setInterval(checkReady, 150);
function checkReady() {
if (asyncOps <= 0) {
clearInterval(timer);
var contents = build();
callback(contents);
} else {
console.info('Waiting for %s async operations to be finished ...', asyncOps);
}
}
return this;
};
})(this);