From 9dbae9c67d7949b0689b67e2e1f28a11114b1ede Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 18 Jan 2019 15:12:19 +0800 Subject: [PATCH] Fix #5648 - New design for post release report --- plugins/raphael.export.js | 483 +++++++++++++++++++------------------- 1 file changed, 248 insertions(+), 235 deletions(-) diff --git a/plugins/raphael.export.js b/plugins/raphael.export.js index e8a4503..16eb187 100644 --- a/plugins/raphael.export.js +++ b/plugins/raphael.export.js @@ -6,16 +6,17 @@ * */ -(function(R) { - /** - * Escapes string for XML interpolation - * @param value string or number value to escape - * @returns string escaped - */ - function escapeXML(s) { - if ( typeof s === 'number' ) return s.toString(); - - var replace = { +(function (R) { + /** + * Escapes string for XML interpolation + * @param value string or number value to escape + * @returns string escaped + */ + function escapeXML(s) { + if (typeof s === 'number') + return s.toString(); + + var replace = { '&': 'amp', '<': 'lt', '>': 'gt', @@ -23,250 +24,262 @@ '\'': 'apos' }; - for ( var entity in replace ) { - s = s.replace(new RegExp(entity, 'g'), '&' + replace[entity] + ';'); - } - - return s; - } - - /** - * Generic map function - * @param iterable the array or object to be mapped - * @param callback the callback function(element, key) - * @returns array - */ - function map(iterable, callback) { - var mapped = new Array; - - for ( var i in iterable ) { - if ( iterable.hasOwnProperty(i) ) { - var value = callback.call(this, iterable[i], i); - - if ( value !== null ) mapped.push(value); - } - } - - return mapped; - } - - /** - * Generic reduce function - * @param iterable array or object to be reduced - * @param callback the callback function(initial, element, i) - * @param initial the initial value - * @return the reduced value - */ - function reduce(iterable, callback, initial) { - for ( var i in iterable ) { - if ( iterable.hasOwnProperty(i) ) { - initial = callback.call(this, initial, iterable[i], i); - } - } - - return initial; - } - - /** - * Utility method for creating a tag - * @param name the tag name, e.g., 'text' - * @param attrs the attribute string, e.g., name1="val1" name2="val2" - * or attribute map, e.g., { name1 : 'val1', name2 : 'val2' } - * @param content the content string inside the tag - * @returns string of the tag - */ - function tag(name, attrs, matrix, content) { - if ( typeof content === 'undefined' || content === null ) { - content = ''; - } - - if ( typeof attrs === 'object' ) { - attrs = map(attrs, function(element, name) { - if ( name === 'transform') return; - - return name + '="' + escapeXML(element) + '"'; - }).join(' '); - } - - return '<' + name + ( matrix ? ' transform="matrix(' + matrix.toString().replace(/^matrix\(|\)$/g, '') + ')" ' : ' ' ) + attrs + '>' + - content + - '' + "\n"; - } - - /** - * @return object the style object - */ - function extractStyle(node) { - return { - font: { - family: node.attrs.font.replace(/^.*?"(\w+)".*$/, '$1'), - size: typeof node.attrs['font-size'] === 'undefined' ? null : node.attrs['font-size'], - anchor : typeof node.attrs['text-anchor'] === 'undefined' ? null : node.attrs['text-anchor'], - } - }; - } - - /** - * @param style object from style() - * @return string - */ - function styleToString(style) { - // TODO figure out what is 'normal' - + for (var entity in replace) { + s = s.replace(new RegExp(entity, 'g'), '&' + replace[entity] + ';'); + } + + return s; + } + + /** + * Generic map function + * @param iterable the array or object to be mapped + * @param callback the callback function(element, key) + * @returns array + */ + function map(iterable, callback) { + var mapped = new Array; + + for (var i in iterable) { + if (iterable.hasOwnProperty(i)) { + var value = callback.call(this, iterable[i], i); + + if (value !== null) + mapped.push(value); + } + } + + return mapped; + } + + /** + * Generic reduce function + * @param iterable array or object to be reduced + * @param callback the callback function(initial, element, i) + * @param initial the initial value + * @return the reduced value + */ + function reduce(iterable, callback, initial) { + for (var i in iterable) { + if (iterable.hasOwnProperty(i)) { + initial = callback.call(this, initial, iterable[i], i); + } + } + + return initial; + } + + /** + * Utility method for creating a tag + * @param name the tag name, e.g., 'text' + * @param attrs the attribute string, e.g., name1="val1" name2="val2" + * or attribute map, e.g., { name1 : 'val1', name2 : 'val2' } + * @param content the content string inside the tag + * @returns string of the tag + */ + function tag(name, attrs, matrix, content) { + if (typeof content === 'undefined' || content === null) { + content = ''; + } + + if (typeof attrs === 'object') { + attrs = map(attrs, function (element, name) { + if (name === 'transform') + return; + + return name + '="' + escapeXML(element) + '"'; + }).join(' '); + } + + return '<' + name + (matrix ? ' transform="matrix(' + matrix.toString().replace(/^matrix\(|\)$/g, '') + ')" ' : ' ') + attrs + '>' + + content + + '' + "\n"; + } + + /** + * @return object the style object + */ + function extractStyle(node) { + return { + font: { + family: node.attrs.font.replace(/^.*?"(\w+)".*$/, '$1'), + size: typeof node.attrs['font-size'] === 'undefined' ? null : node.attrs['font-size'], + anchor: typeof node.attrs['text-anchor'] === 'undefined' ? null : node.attrs['text-anchor'], + } + }; + } + + /** + * @param style object from style() + * @return string + */ + function styleToString(style) { + // TODO figure out what is 'normal' + var r = [ - 'font-family:' + style.font.family, - 'font-weight:normal', - 'font-style:normal', - 'font-stretch:normal', - 'font-variant:normal' + 'font-family:' + style.font.family, + 'font-weight:normal', + 'font-style:normal', + 'font-stretch:normal', + 'font-variant:normal' ]; - if (style.font.size !== null ) { - r.push('font-size: ' + style.font.size + 'px') + if (style.font.size !== null) { + r.push('font-size: ' + style.font.size + 'px') } - + return r.join(';') - - } - - /** - * Computes tspan dy using font size. This formula was empircally determined - * using a best-fit line. Works well in both VML and SVG browsers. - * @param fontSize number - * @return number - */ - function computeTSpanDy(fontSize, line, lines) { - if ( fontSize === null ) fontSize = 10; - - //return fontSize * 4.5 / 13 - return fontSize * 4.5 / 13 * ( line - .2 - lines / 2 ) * 3.5; - } - - var serializer = { - 'text': function(node) { - style = extractStyle(node); - Roo.log(style); - var tags = new Array; - - map(node.attrs['text'].split('\n'), function(text, iterable, line) { - line = line || 0; - tags.push(tag( - 'text', - reduce( - node.attrs, - function(initial, value, name) { - if ( name !== 'text' && name !== 'w' && name !== 'h' ) { - if ( name === 'font-size') value = value + 'px'; - - initial[name] = escapeXML(value.toString()); - } - - return initial; - }, - { - style: 'text-anchor: ' + (style.font.anchor ? (style.font.anchor +';' ): 'middle;') + - styleToString(style) + ';' - } - ), - node.matrix, - tag('tspan', - { - dy: computeTSpanDy(style.font.size, line + 1, node.attrs['text'].split('\n').length) - }, - null, - escapeXML(text) - ) - )); - }); - - return tags; - }, - 'path' : function(node) { - var initial = ( node.matrix.a === 1 && node.matrix.d === 1 ) ? {} : { 'transform' : node.matrix.toString() }; + + } + + /** + * Computes tspan dy using font size. This formula was empircally determined + * using a best-fit line. Works well in both VML and SVG browsers. + * @param fontSize number + * @return number + */ + function computeTSpanDy(fontSize, line, lines) { + if (fontSize === null) + fontSize = 10; + + //return fontSize * 4.5 / 13 + return fontSize * 4.5 / 13 * (line - .2 - lines / 2) * 3.5; + } + + var serializer = { + 'text': function (node) { + var style = extractStyle(node); + var tags = new Array; - return tag( - 'path', - reduce( - node.attrs, - function(initial, value, name) { - if ( name === 'path' ) { - name = 'd'; + var content = []; + + var textArray = node.attrs['text'].split('\n'); + + textArray.forEach((v,k) => { + content.push(tag('tspan', + { + x: node.attrs.x, + dy: computeTSpanDy(style.font.size, k + 1, textArray.length) + }, + null, + escapeXML(v) + )) + + }); + + tags.push(tag( + 'text', + reduce( + node.attrs, + function (initial, value, name) { + if (name !== 'text' && name !== 'w' && name !== 'h') { + if (name === 'font-size') + value = value + 'px'; + + initial[name] = escapeXML(value.toString()); } - initial[name] = (typeof(value) == 'undefined') ? '' : value.toString(); - - return initial; - }, + return initial; + }, { - style: 'fill:' + Raphael.color(node.attrs.fill).hex + ';' + style: 'text-anchor: ' + (style.font.anchor ? (style.font.anchor + ';') : 'middle;') + + styleToString(style) + ';' } - ), - node.matrix - ); - } - // Other serializers should go here - }; - - R.fn.toSVG = function() { - var - paper = this, - restore = { svg: R.svg, vml: R.vml }, - svg = '' - ; - - R.svg = true; - R.vml = false; - - for ( var node = paper.bottom; node != null; node = node.next ) { - if ( node.node.style.display === 'none' ) continue; - - var attrs = ''; - - // Use serializer - if ( typeof serializer[node.type] === 'function' ) { - svg += serializer[node.type](node); - - continue; - } - - switch ( node.type ) { - case 'image': - attrs += ' preserveAspectRatio="none"'; - break; - } - - for ( i in node.attrs ) { - var name = i; + ), + node.matrix, + content.join("") + )); + + return tags; + }, + 'path': function (node) { + var initial = (node.matrix.a === 1 && node.matrix.d === 1) ? {} : {'transform': node.matrix.toString()}; + + + + return tag( + 'path', + reduce( + node.attrs, + function (initial, value, name) { + if (name === 'path') { + name = 'd'; + } + + initial[name] = (typeof (value) == 'undefined') ? '' : value.toString(); + + return initial; + }, + { + style: 'fill:' + Raphael.color(node.attrs.fill).hex + ';' + } + ), + node.matrix + ); + } + // Other serializers should go here + }; + + R.fn.toSVG = function () { + var + paper = this, + restore = {svg: R.svg, vml: R.vml}, + svg = ''; + + R.svg = true; + R.vml = false; + + for (var node = paper.bottom; node != null; node = node.next) { + if (node.node.style.display === 'none') + continue; + + var attrs = ''; + + // Use serializer + if (typeof serializer[node.type] === 'function') { + svg += serializer[node.type](node); + + continue; + } + + switch (node.type) { + case 'image': + attrs += ' preserveAspectRatio="none"'; + break; + } + + for (i in node.attrs) { + var name = i; var val = node.attrs[i].toString(); - switch ( i ) { - case 'src': - name = 'xlink:href'; - - break; - case 'transform': - name = ''; - break; - + switch (i) { + case 'src': + name = 'xlink:href'; + + break; + case 'transform': + name = ''; + break; + case 'stroke': case 'fill': val = Raphael.getRGB(val).hex; break; - } + } - if ( name ) { - attrs += ' ' + name + '="' + escapeXML(val) + '"'; - } - } + if (name) { + attrs += ' ' + name + '="' + escapeXML(val) + '"'; + } + } - svg += '<' + node.type + ' transform="matrix(' + node.matrix.toString().replace(/^matrix\(|\)$/g, '') + ')"' + attrs + '>'; - } + svg += '<' + node.type + ' transform="matrix(' + node.matrix.toString().replace(/^matrix\(|\)$/g, '') + ')"' + attrs + '>'; + } - svg += ''; + svg += ''; - R.svg = restore.svg; - R.vml = restore.vml; + R.svg = restore.svg; + R.vml = restore.vml; - return svg; - }; + return svg; + }; })(window.Raphael); \ No newline at end of file -- 2.39.2