/** * @private */ Ext.define('Ext.draw.engine.SvgExporter', { singleton: true, statics: (function(){ var surface, len, width, height, init = function(s){ surface = s; len = surface.length; width = surface.width; height = surface.height; }, spriteProcessor = { path: function(sprite){ var attr = sprite.attr, path = attr.path, pathString = '', props, p, pLen; if(Ext.isArray(path[0])){ pLen = path.length; for (p = 0; p < pLen; p++) { pathString += path[p].join(' '); } }else if(Ext.isArray(path)){ pathString = path.join(' '); }else{ pathString = path.replace(/,/g,' '); } props = toPropertyString({ d: pathString, fill: attr.fill || 'none', stroke: attr.stroke, 'fill-opacity': attr.opacity, 'stroke-width': attr['stroke-width'], 'stroke-opacity': attr['stroke-opacity'], "z-index": attr.zIndex, transform: sprite.matrix.toSvg() }); return ''; }, text: function(sprite){ // TODO // implement multi line support (@see Svg.js tuneText) var attr = sprite.attr, fontRegex = /(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)\s('*.*'*)/, match = fontRegex.exec(attr.font), size = (match && match[1]) || "12", // default font family is Arial family = (match && match[3]) || 'Arial', text = attr.text, factor = (Ext.isFF3_0 || Ext.isFF3_5) ? 2 : 4, tspanString = '', props; sprite.getBBox(); tspanString += ''; tspanString += Ext.htmlEncode(text) + ''; props = toPropertyString({ x: attr.x, y: attr.y, 'font-size': size, 'font-family': family, 'font-weight': attr['font-weight'], 'text-anchor': attr['text-anchor'], // if no fill property is set it will be black fill: attr.fill || '#000', 'fill-opacity': attr.opacity, transform: sprite.matrix.toSvg() }); return '' + tspanString + ''; }, rect: function(sprite){ var attr = sprite.attr, props = toPropertyString({ x: attr.x, y: attr.y, rx: attr.rx, ry: attr.ry, width: attr.width, height: attr.height, fill: attr.fill || 'none', 'fill-opacity': attr.opacity, stroke: attr.stroke, 'stroke-opacity': attr['stroke-opacity'], 'stroke-width':attr['stroke-width'], transform: sprite.matrix && sprite.matrix.toSvg() }); return ''; }, circle: function(sprite){ var attr = sprite.attr, props = toPropertyString({ cx: attr.x, cy: attr.y, r: attr.radius, fill: attr.translation.fill || attr.fill || 'none', 'fill-opacity': attr.opacity, stroke: attr.stroke, 'stroke-opacity': attr['stroke-opacity'], 'stroke-width':attr['stroke-width'], transform: sprite.matrix.toSvg() }); return ''; }, image: function(sprite){ var attr = sprite.attr, props = toPropertyString({ x: attr.x - (attr.width/2 >> 0), y: attr.y - (attr.height/2 >> 0), width: attr.width, height: attr.height, 'xlink:href': attr.src, transform: sprite.matrix.toSvg() }); return ''; } }, svgHeader = function(){ var svg = ''; svg += ''; return svg; }, svgContent = function(){ var svg = '', defs = '', item, itemsLen, items, gradient, getSvgString, colorstops, stop, coll, keys, colls, k, kLen, key, collI, i, j, stopsLen, sortedItems, za, zb; items = surface.items.items; itemsLen = items.length; getSvgString = function(node){ var childs = node.childNodes, childLength = childs.length, i = 0, attrLength, j, svgString = '', child, attr, tagName, attrItem; for(; i < childLength; i++){ child = childs[i]; attr = child.attributes; tagName = child.tagName; svgString += '<' +tagName; for(j = 0, attrLength = attr.length; j < attrLength; j++){ attrItem = attr.item(j); svgString += ' '+attrItem.name+'="'+attrItem.value+'"'; } svgString += '>'; if(child.childNodes.length > 0){ svgString += getSvgString(child); } svgString += ''; } return svgString; }; if(surface.getDefs){ defs = getSvgString(surface.getDefs()); }else{ // IE coll = surface.gradientsColl; if (coll) { keys = coll.keys; colls = coll.items; k = 0; kLen = keys.length; } for (; k < kLen; k++) { key = keys[k]; collI = colls[k]; gradient = surface.gradientsColl.getByKey(key); defs += ''; var color = gradient.colors.replace(/rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g, 'rgb($1|$2|$3)'); color = color.replace(/rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,([\d\.]+)\)/g, 'rgba($1|$2|$3|$4)') colorstops = color.split(','); for(i=0, stopsLen = colorstops.length; i < stopsLen; i++){ stop = colorstops[i].split(' '); color = Ext.draw.Color.fromString(stop[1].replace(/\|/g,',')); defs += ''; } defs += ''; } } svg += '' + defs + ''; // thats the background rectangle svg += spriteProcessor.rect({ attr: { width: '100%', height: '100%', fill: '#fff', stroke: 'none', opacity: '0' } }); // Sort the items (stable sort guaranteed) sortedItems = new Array(itemsLen); for(i = 0; i < itemsLen; i++){ sortedItems[i] = i; } sortedItems.sort(function (a, b) { za = items[a].attr.zIndex || 0; zb = items[b].attr.zIndex || 0; if (za == zb) { return a - b; } return za - zb; }); for(i = 0; i < itemsLen; i++){ item = items[sortedItems[i]]; if(!item.attr.hidden){ svg += spriteProcessor[item.type](item); } } svg += ''; return svg; }, toPropertyString = function(obj){ var propString = '', key; for(key in obj){ if(obj.hasOwnProperty(key) && obj[key] != null){ propString += key +'="'+ obj[key]+'" '; } } return propString; }; return { generate: function(config, surface){ init(surface); return svgHeader() + svgContent(); } }; }()) });