diff --git a/jsketch.svg.js b/jsketch.svg.js new file mode 100644 index 0000000..abbb378 --- /dev/null +++ b/jsketch.svg.js @@ -0,0 +1,244 @@ +/*! + * 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. + * @param {function} callback - Callback function, executed when SVG is ready. + * @return {string} + * @memberof jSketch + */ + window.jSketch.prototype.toSVG = function(callback) { + // 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 ''; + }, + }; + + function build() { + var svg = ''; + svg += ''; + svg += ''; + svg += 'Generated with jSketch: https://luis.leiva.name/jsketch/'; + svg += ''; + svg += ''; + svg += processElements(); + svg += ''; + svg += ''; + // Normalize whitespacing. + return svg.replace(/\s+/g, ' '); + } + + 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 queue to be empty:', asyncQueue); + } + } + }; + +})(this);